Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149// SPDX-License-Identifier: GPL-2.0
//! Integer parsing functions.//!//! Integer parsing functions for parsing signed and unsigned integers//! potentially prefixed with `0x`, `0o`, or `0b`.
use crate::prelude::*;use crate::str::BStr;use core::ops::Deref;
// Make `FromStrRadix` a public type with a private name. This seals// `ParseInt`, that is, prevents downstream users from implementing the// trait.mod private { use crate::prelude::*; use crate::str::BStr;
/// Trait that allows parsing a [`&BStr`] to an integer with a radix. pub trait FromStrRadix: Sized { /// Parse `src` to [`Self`] using radix `radix`. fn from_str_radix(src: &BStr, radix: u32) -> Result<Self>;
/// Tries to convert `value` into [`Self`] and negates the resulting value. fn from_u64_negated(value: u64) -> Result<Self>; }}
/// Extract the radix from an integer literal optionally prefixed with/// one of `0x`, `0X`, `0o`, `0O`, `0b`, `0B`, `0`.fn strip_radix(src: &BStr) -> (u32, &BStr) { match src.deref() { [b'0', b'x' | b'X', rest @ ..] => (16, rest.as_ref()), [b'0', b'o' | b'O', rest @ ..] => (8, rest.as_ref()), [b'0', b'b' | b'B', rest @ ..] => (2, rest.as_ref()), // NOTE: We are including the leading zero to be able to parse // literal `0` here. If we removed it as a radix prefix, we would // not be able to parse `0`. [b'0', ..] => (8, src), _ => (10, src), }}
/// Trait for parsing string representations of integers.////// Strings beginning with `0x`, `0o`, or `0b` are parsed as hex, octal, or/// binary respectively. Strings beginning with `0` otherwise are parsed as/// octal. Anything else is parsed as decimal. A leading `+` or `-` is also/// permitted. Any string parsed by [`kstrtol()`] or [`kstrtoul()`] will be/// successfully parsed.////// [`kstrtol()`]: https://docs.kernel.org/core-api/kernel-api.html#c.kstrtol/// [`kstrtoul()`]: https://docs.kernel.org/core-api/kernel-api.html#c.kstrtoul////// # Examples////// ```/// # use kernel::str::parse_int::ParseInt;/// # use kernel::b_str;////// assert_eq!(Ok(0u8), u8::from_str(b_str!("0")));////// assert_eq!(Ok(0xa2u8), u8::from_str(b_str!("0xa2")));/// assert_eq!(Ok(-0xa2i32), i32::from_str(b_str!("-0xa2")));////// assert_eq!(Ok(-0o57i8), i8::from_str(b_str!("-0o57")));/// assert_eq!(Ok(0o57i8), i8::from_str(b_str!("057")));////// assert_eq!(Ok(0b1001i16), i16::from_str(b_str!("0b1001")));/// assert_eq!(Ok(-0b1001i16), i16::from_str(b_str!("-0b1001")));////// assert_eq!(Ok(127i8), i8::from_str(b_str!("127")));/// assert!(i8::from_str(b_str!("128")).is_err());/// assert_eq!(Ok(-128i8), i8::from_str(b_str!("-128")));/// assert!(i8::from_str(b_str!("-129")).is_err());/// assert_eq!(Ok(255u8), u8::from_str(b_str!("255")));/// assert!(u8::from_str(b_str!("256")).is_err());/// ```pub trait ParseInt: private::FromStrRadix + TryFrom<u64> { /// Parse a string according to the description in [`Self`]. fn from_str(src: &BStr) -> Result<Self> { match src.deref() { [b'-', rest @ ..] => { let (radix, digits) = strip_radix(rest.as_ref()); // 2's complement values range from -2^(b-1) to 2^(b-1)-1. // So if we want to parse negative numbers as positive and // later multiply by -1, we have to parse into a larger // integer. We choose `u64` as sufficiently large. // // NOTE: 128 bit integers are not available on all // platforms, hence the choice of 64 bits. let val = u64::from_str_radix(core::str::from_utf8(digits).map_err(|_| EINVAL)?, radix) .map_err(|_| EINVAL)?; Self::from_u64_negated(val) } _ => { let (radix, digits) = strip_radix(src); Self::from_str_radix(digits, radix).map_err(|_| EINVAL) } } }}
macro_rules! impl_parse_int { ($($ty:ty),*) => { $( impl private::FromStrRadix for $ty { fn from_str_radix(src: &BStr, radix: u32) -> Result<Self> { <$ty>::from_str_radix(core::str::from_utf8(src).map_err(|_| EINVAL)?, radix) .map_err(|_| EINVAL) }
fn from_u64_negated(value: u64) -> Result<Self> { const ABS_MIN: u64 = { #[allow(unused_comparisons)] if <$ty>::MIN < 0 { 1u64 << (<$ty>::BITS - 1) } else { 0 } };
if value > ABS_MIN { return Err(EINVAL); }
if value == ABS_MIN { return Ok(<$ty>::MIN); }
// SAFETY: The above checks guarantee that `value` fits into `Self`: // - if `Self` is unsigned, then `ABS_MIN == 0` and thus we have returned above // (either `EINVAL` or `MIN`). // - if `Self` is signed, then we have that `0 <= value < ABS_MIN`. And since // `ABS_MIN - 1` fits into `Self` by construction, `value` also does. let value: Self = unsafe { value.try_into().unwrap_unchecked() };
Ok((!value).wrapping_add(1)) } }
impl ParseInt for $ty {} )* };}
impl_parse_int![i8, u8, i16, u16, i32, u32, i64, u64, isize, usize];