From: Andreas Hindborg <a.hindborg@kernel.org>
To: "Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <benno.lossin@proton.me>,
"Alice Ryhl" <aliceryhl@google.com>,
"Masahiro Yamada" <masahiroy@kernel.org>,
"Nathan Chancellor" <nathan@kernel.org>,
"Luis Chamberlain" <mcgrof@kernel.org>,
"Danilo Krummrich" <dakr@kernel.org>,
"Nicolas Schier" <nicolas.schier@linux.dev>
Cc: Trevor Gross <tmgross@umich.edu>,
Adam Bratschi-Kaye <ark.email@gmail.com>,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-kbuild@vger.kernel.org, Petr Pavlu <petr.pavlu@suse.com>,
Sami Tolvanen <samitolvanen@google.com>,
Daniel Gomez <da.gomez@samsung.com>,
Simona Vetter <simona.vetter@ffwll.ch>,
Greg KH <gregkh@linuxfoundation.org>,
Fiona Behrens <me@kloenk.dev>,
Daniel Almeida <daniel.almeida@collabora.com>,
linux-modules@vger.kernel.org,
Andreas Hindborg <a.hindborg@kernel.org>
Subject: [PATCH v12 1/3] rust: str: add radix prefixed integer parsing functions
Date: Tue, 06 May 2025 15:02:28 +0200 [thread overview]
Message-ID: <20250506-module-params-v3-v12-1-c04d80c8a2b1@kernel.org> (raw)
In-Reply-To: <20250506-module-params-v3-v12-0-c04d80c8a2b1@kernel.org>
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.
Tested-by: Daniel Gomez <da.gomez@samsung.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/str.rs | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 171 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 878111cb77bc..174e70397305 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -573,7 +573,6 @@ macro_rules! c_str {
}
#[cfg(test)]
-#[expect(clippy::items_after_test_module)]
mod tests {
use super::*;
@@ -946,3 +945,174 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
macro_rules! fmt {
($($f:tt)*) => ( core::format_args!($($f)*) )
}
+
+/// Integer parsing functions for parsing signed and unsigned integers
+/// potentially prefixed with `0x`, `0o`, or `0b`.
+pub mod parse_int {
+ 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::str::BStr;
+
+ /// Trait that allows parsing a [`&BStr`] to an integer with a radix.
+ ///
+ /// # Safety
+ ///
+ /// The member functions of this trait must be implemented according to
+ /// their documentation.
+ ///
+ /// [`&BStr`]: kernel::str::BStr
+ // This is required because the `from_str_radix` function on the primitive
+ // integer types is not part of any trait.
+ pub unsafe trait FromStrRadix: Sized {
+ /// The minimum value this integer type can assume.
+ const MIN: Self;
+
+ /// Parse `src` to [`Self`] using radix `radix`.
+ fn from_str_radix(src: &BStr, radix: u32) -> Result<Self, crate::error::Error>;
+
+ /// Return the absolute value of [`Self::MIN`].
+ fn abs_min() -> u64;
+
+ /// Perform bitwise 2's complement on `self`.
+ ///
+ /// Note: This function does not make sense for unsigned integers.
+ fn complement(self) -> 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)?;
+
+ if val > Self::abs_min() {
+ return Err(EINVAL);
+ }
+
+ if val == Self::abs_min() {
+ return Ok(Self::MIN);
+ }
+
+ // SAFETY: We checked that `val` will fit in `Self` above.
+ let val: Self = unsafe { val.try_into().unwrap_unchecked() };
+
+ Ok(val.complement())
+ }
+ _ => {
+ let (radix, digits) = strip_radix(src);
+ Self::from_str_radix(digits, radix).map_err(|_| EINVAL)
+ }
+ }
+ }
+ }
+
+ macro_rules! impl_parse_int {
+ ($ty:ty) => {
+ // SAFETY: We implement the trait according to the documentation.
+ unsafe impl private::FromStrRadix for $ty {
+ const MIN: Self = <$ty>::MIN;
+
+ fn from_str_radix(src: &BStr, radix: u32) -> Result<Self, crate::error::Error> {
+ <$ty>::from_str_radix(core::str::from_utf8(src).map_err(|_| EINVAL)?, radix)
+ .map_err(|_| EINVAL)
+ }
+
+ fn abs_min() -> u64 {
+ #[allow(unused_comparisons)]
+ if Self::MIN < 0 {
+ 1u64 << (Self::BITS - 1)
+ } else {
+ 0
+ }
+ }
+
+ fn complement(self) -> Self {
+ (!self).wrapping_add((1 as $ty))
+ }
+ }
+
+ impl ParseInt for $ty {}
+ };
+ }
+
+ impl_parse_int!(i8);
+ impl_parse_int!(u8);
+ impl_parse_int!(i16);
+ impl_parse_int!(u16);
+ impl_parse_int!(i32);
+ impl_parse_int!(u32);
+ impl_parse_int!(i64);
+ impl_parse_int!(u64);
+ impl_parse_int!(isize);
+ impl_parse_int!(usize);
+}
--
2.47.2
next prev parent reply other threads:[~2025-05-06 13:02 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-06 13:02 [PATCH v12 0/3] rust: extend `module!` macro with integer parameter support Andreas Hindborg
2025-05-06 13:02 ` Andreas Hindborg [this message]
2025-05-07 8:58 ` [PATCH v12 1/3] rust: str: add radix prefixed integer parsing functions Benno Lossin
2025-05-07 9:15 ` Andreas Hindborg
2025-05-07 11:29 ` Benno Lossin
2025-05-06 13:02 ` [PATCH v12 2/3] rust: add parameter support to the `module!` macro Andreas Hindborg
2025-05-07 11:22 ` Benno Lossin
2025-06-11 10:31 ` Andreas Hindborg
2025-06-11 12:24 ` Andreas Hindborg
2025-06-11 12:36 ` Miguel Ojeda
2025-06-11 13:28 ` Andreas Hindborg
2025-06-12 7:52 ` Benno Lossin
2025-06-12 11:05 ` Andreas Hindborg
2025-06-11 12:39 ` Miguel Ojeda
2025-05-06 13:02 ` [PATCH v12 3/3] modules: add rust modules files to MAINTAINERS Andreas Hindborg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250506-module-params-v3-v12-1-c04d80c8a2b1@kernel.org \
--to=a.hindborg@kernel.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=ark.email@gmail.com \
--cc=benno.lossin@proton.me \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=da.gomez@samsung.com \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kbuild@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-modules@vger.kernel.org \
--cc=masahiroy@kernel.org \
--cc=mcgrof@kernel.org \
--cc=me@kloenk.dev \
--cc=nathan@kernel.org \
--cc=nicolas.schier@linux.dev \
--cc=ojeda@kernel.org \
--cc=petr.pavlu@suse.com \
--cc=rust-for-linux@vger.kernel.org \
--cc=samitolvanen@google.com \
--cc=simona.vetter@ffwll.ch \
--cc=tmgross@umich.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).