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>,
"Nicolas Schier" <nicolas@fjasle.eu>,
"Luis Chamberlain" <mcgrof@kernel.org>
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 v8 5/7] rust: str: add radix prefixed integer parsing functions
Date: Thu, 27 Feb 2025 15:38:11 +0100 [thread overview]
Message-ID: <20250227-module-params-v3-v8-5-ceeee85d9347@kernel.org> (raw)
In-Reply-To: <20250227-module-params-v3-v8-0-ceeee85d9347@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 Almeida <daniel.almeida@collabora.com>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/str.rs | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 155 insertions(+)
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index db272d2198fc..a708cf219348 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -945,3 +945,158 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
macro_rules! fmt {
($($f:tt)*) => ( core::format_args!($($f)*) )
}
+
+pub mod parse_int {
+ //! 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::str::BStr;
+
+ /// Trait that allows parsing a [`&BStr`] to an integer with a radix.
+ ///
+ /// [`&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 trait FromStrRadix: Sized {
+ /// 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://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.kstrtol
+ /// [`kstrtoul()`]: https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#c.kstrtoul
+ ///
+ /// # Example
+ /// ```
+ /// use kernel::str::parse_int::ParseInt;
+ /// use kernel::b_str;
+ ///
+ /// assert_eq!(Ok(0), 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(127), i8::from_str(b_str!("127")));
+ /// assert!(i8::from_str(b_str!("128")).is_err());
+ /// assert_eq!(Ok(-128), i8::from_str(b_str!("-128")));
+ /// assert!(i8::from_str(b_str!("-129")).is_err());
+ /// assert_eq!(Ok(255), 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 bit.
+ 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);
+ }
+
+ // 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) => {
+ impl private::FromStrRadix for $ty {
+ 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.0
next prev parent reply other threads:[~2025-02-27 14:39 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-27 14:38 [PATCH v8 0/7] rust: extend `module!` macro with integer parameter support Andreas Hindborg
2025-02-27 14:38 ` [PATCH v8 1/7] rust: str: implement `PartialEq` for `BStr` Andreas Hindborg
2025-03-04 11:07 ` Fiona Behrens
2025-02-27 14:38 ` [PATCH v8 2/7] rust: str: implement `Index` " Andreas Hindborg
2025-02-28 9:10 ` Alice Ryhl
2025-02-27 14:38 ` [PATCH v8 3/7] rust: str: implement `AsRef<BStr>` for `[u8]` and `BStr` Andreas Hindborg
2025-03-04 11:09 ` Fiona Behrens
2025-02-27 14:38 ` [PATCH v8 4/7] rust: str: implement `strip_prefix` for `BStr` Andreas Hindborg
2025-02-27 14:38 ` Andreas Hindborg [this message]
2025-03-20 20:21 ` [PATCH v8 5/7] rust: str: add radix prefixed integer parsing functions Miguel Ojeda
2025-03-21 7:53 ` Andreas Hindborg
2025-02-27 14:38 ` [PATCH v8 6/7] rust: add parameter support to the `module!` macro Andreas Hindborg
2025-02-27 14:38 ` [PATCH v8 7/7] modules: add rust modules files to MAINTAINERS Andreas Hindborg
2025-03-20 8:54 ` Daniel Gomez
2025-03-20 8:41 ` [PATCH v8 0/7] rust: extend `module!` macro with integer parameter support Daniel Gomez
2025-03-20 10:26 ` Andreas Hindborg
2025-03-20 12:00 ` Miguel Ojeda
2025-03-20 12:47 ` Petr Pavlu
2025-03-20 23:23 ` Miguel Ojeda
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=20250227-module-params-v3-v8-5-ceeee85d9347@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=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@fjasle.eu \
--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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.