Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rust: str: add radix prefixed integer parsing functions

Add the trait `ParseInt` for parsing string representations of integers
where the string representations are optionally prefixed by a radix
specifier. Implement the trait for the primitive integer types.

Suggested-by: Benno Lossin <benno.lossin@proton.me>
Tested-by: Daniel Gomez <da.gomez@samsung.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Benno Lossin <lossin@kernel.org>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
Signed-off-by: Daniel Gomez <da.gomez@kernel.org>

authored by

Andreas Hindborg and committed by
Daniel Gomez
51d9ee90 821fe7bf

+150
+2
rust/kernel/str.rs
··· 13 13 ops::{self, Deref, DerefMut, Index}, 14 14 }; 15 15 16 + pub mod parse_int; 17 + 16 18 /// Byte string without UTF-8 validity guarantee. 17 19 #[repr(transparent)] 18 20 pub struct BStr([u8]);
+148
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 + 8 + use crate::prelude::*; 9 + use crate::str::BStr; 10 + use 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. 15 + mod 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`. 31 + fn 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 + /// ``` 79 + pub 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 + 105 + macro_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 + 148 + impl_parse_int![i8, u8, i16, u16, i32, u32, i64, u64, isize, usize];