1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
// 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];
|