FILE
parse_int.rs
File preview with syntax highlighting.
linux-6.19.14/rust/kernel/str/parse_int.rs
1// SPDX-License-Identifier: GPL-2.0 2 3//! Integer parsing functions. 4//! 5//! Integer parsing functions for parsing signed and unsigned integers 6//! potentially prefixed with `0x`, `0o`, or `0b`. 7 8use crate::prelude::*; 9use crate::str::BStr; 10use core::ops::Deref; 11 12// Make `FromStrRadix` a public type with a private name. This seals 13// `ParseInt`, that is, prevents downstream users from implementing the 14// trait. 15mod private { 16 use crate::prelude::*; 17 use crate::str::BStr; 18 19 /// Trait that allows parsing a [`&BStr`] to an integer with a radix. 20 pub trait FromStrRadix: Sized { 21 /// Parse `src` to [`Self`] using radix `radix`. 22 fn from_str_radix(src: &BStr, radix: u32) -> Result<Self>; 23 24 /// Tries to convert `value` into [`Self`] and negates the resulting value. 25 fn from_u64_negated(value: u64) -> Result<Self>; 26 } 27} 28 29/// Extract the radix from an integer literal optionally prefixed with 30/// one of `0x`, `0X`, `0o`, `0O`, `0b`, `0B`, `0`. 31fn strip_radix(src: &BStr) -> (u32, &BStr) { 32 match src.deref() { 33 [b'0', b'x' | b'X', rest @ ..] => (16, rest.as_ref()), 34 [b'0', b'o' | b'O', rest @ ..] => (8, rest.as_ref()), 35 [b'0', b'b' | b'B', rest @ ..] => (2, rest.as_ref()), 36 // NOTE: We are including the leading zero to be able to parse 37 // literal `0` here. If we removed it as a radix prefix, we would 38 // not be able to parse `0`. 39 [b'0', ..] => (8, src), 40 _ => (10, src), 41 } 42} 43 44/// Trait for parsing string representations of integers. 45/// 46/// Strings beginning with `0x`, `0o`, or `0b` are parsed as hex, octal, or 47/// binary respectively. Strings beginning with `0` otherwise are parsed as 48/// octal. Anything else is parsed as decimal. A leading `+` or `-` is also 49/// permitted. Any string parsed by [`kstrtol()`] or [`kstrtoul()`] will be 50/// successfully parsed. 51/// 52/// [`kstrtol()`]: https://docs.kernel.org/core-api/kernel-api.html#c.kstrtol 53/// [`kstrtoul()`]: https://docs.kernel.org/core-api/kernel-api.html#c.kstrtoul 54/// 55/// # Examples 56/// 57/// ``` 58/// # use kernel::str::parse_int::ParseInt; 59/// # use kernel::b_str; 60/// 61/// assert_eq!(Ok(0u8), u8::from_str(b_str!("0"))); 62/// 63/// assert_eq!(Ok(0xa2u8), u8::from_str(b_str!("0xa2"))); 64/// assert_eq!(Ok(-0xa2i32), i32::from_str(b_str!("-0xa2"))); 65/// 66/// assert_eq!(Ok(-0o57i8), i8::from_str(b_str!("-0o57"))); 67/// assert_eq!(Ok(0o57i8), i8::from_str(b_str!("057"))); 68/// 69/// assert_eq!(Ok(0b1001i16), i16::from_str(b_str!("0b1001"))); 70/// assert_eq!(Ok(-0b1001i16), i16::from_str(b_str!("-0b1001"))); 71/// 72/// assert_eq!(Ok(127i8), i8::from_str(b_str!("127"))); 73/// assert!(i8::from_str(b_str!("128")).is_err()); 74/// assert_eq!(Ok(-128i8), i8::from_str(b_str!("-128"))); 75/// assert!(i8::from_str(b_str!("-129")).is_err()); 76/// assert_eq!(Ok(255u8), u8::from_str(b_str!("255"))); 77/// assert!(u8::from_str(b_str!("256")).is_err()); 78/// ``` 79pub trait ParseInt: private::FromStrRadix + TryFrom<u64> { 80 /// Parse a string according to the description in [`Self`]. 81 fn from_str(src: &BStr) -> Result<Self> { 82 match src.deref() { 83 [b'-', rest @ ..] => { 84 let (radix, digits) = strip_radix(rest.as_ref()); 85 // 2's complement values range from -2^(b-1) to 2^(b-1)-1. 86 // So if we want to parse negative numbers as positive and 87 // later multiply by -1, we have to parse into a larger 88 // integer. We choose `u64` as sufficiently large. 89 // 90 // NOTE: 128 bit integers are not available on all 91 // platforms, hence the choice of 64 bits. 92 let val = 93 u64::from_str_radix(core::str::from_utf8(digits).map_err(|_| EINVAL)?, radix) 94 .map_err(|_| EINVAL)?; 95 Self::from_u64_negated(val) 96 } 97 _ => { 98 let (radix, digits) = strip_radix(src); 99 Self::from_str_radix(digits, radix).map_err(|_| EINVAL) 100 } 101 } 102 } 103} 104 105macro_rules! impl_parse_int { 106 ($($ty:ty),*) => { 107 $( 108 impl private::FromStrRadix for $ty { 109 fn from_str_radix(src: &BStr, radix: u32) -> Result<Self> { 110 <$ty>::from_str_radix(core::str::from_utf8(src).map_err(|_| EINVAL)?, radix) 111 .map_err(|_| EINVAL) 112 } 113 114 fn from_u64_negated(value: u64) -> Result<Self> { 115 const ABS_MIN: u64 = { 116 #[allow(unused_comparisons)] 117 if <$ty>::MIN < 0 { 118 1u64 << (<$ty>::BITS - 1) 119 } else { 120 0 121 } 122 }; 123 124 if value > ABS_MIN { 125 return Err(EINVAL); 126 } 127 128 if value == ABS_MIN { 129 return Ok(<$ty>::MIN); 130 } 131 132 // SAFETY: The above checks guarantee that `value` fits into `Self`: 133 // - if `Self` is unsigned, then `ABS_MIN == 0` and thus we have returned above 134 // (either `EINVAL` or `MIN`). 135 // - if `Self` is signed, then we have that `0 <= value < ABS_MIN`. And since 136 // `ABS_MIN - 1` fits into `Self` by construction, `value` also does. 137 let value: Self = unsafe { value.try_into().unwrap_unchecked() }; 138 139 Ok((!value).wrapping_add(1)) 140 } 141 } 142 143 impl ParseInt for $ty {} 144 )* 145 }; 146} 147 148impl_parse_int![i8, u8, i16, u16, i32, u32, i64, u64, isize, usize];
~/
Read-only file preview.