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