From: Jesung Yang <y.j3ms.n@gmail.com>
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" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>
Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
nouveau@lists.freedesktop.org, Jesung Yang <y.j3ms.n@gmail.com>
Subject: [PATCH 1/4] rust: introduce `FromPrimitive` trait
Date: Mon, 23 Jun 2025 15:14:27 +0000 [thread overview]
Message-ID: <702d21d34368b1dcd896343771b00a2303e9a312.1750689857.git.y.j3ms.n@gmail.com> (raw)
In-Reply-To: <cover.1750689857.git.y.j3ms.n@gmail.com>
Introduce a new `FromPrimitive` trait under `kernel::convert` that
enables fallible conversion from primitive types to user-defined
types.
This is useful when numeric values need to be interpreted as structured
representations such as enums. These situations often arise when
working with low-level data sources, for example when reading values
from hardware registers.
Signed-off-by: Jesung Yang <y.j3ms.n@gmail.com>
---
rust/kernel/convert.rs | 154 +++++++++++++++++++++++++++++++++++++++++
rust/kernel/lib.rs | 1 +
2 files changed, 155 insertions(+)
create mode 100644 rust/kernel/convert.rs
diff --git a/rust/kernel/convert.rs b/rust/kernel/convert.rs
new file mode 100644
index 000000000000..fb01a0e1507a
--- /dev/null
+++ b/rust/kernel/convert.rs
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Traits for type conversion.
+
+/// A trait for fallible conversions from primitive types.
+///
+/// [`FromPrimitive`] allows converting from various built-in primitive types
+/// (such as integers and `bool`) into a user-defined type, typically an `enum`.
+///
+/// At least [`from_i64`] and [`from_u64`] should be implemented. All other methods
+/// have default implementations that convert to `i64` or `u64` using fallible casts and
+/// delegate to those two core methods.
+///
+/// Enums with wide representations such as `#[repr(i128)]` or `#[repr(u128)]` may lose
+/// information through narrowing in the default implementations. In such cases, override
+/// [`from_i128`] and [`from_u128`] explicitly.
+///
+/// This trait can be used with `#[derive]`.
+/// See [`FromPrimitive`](../../macros/derive.FromPrimitive.html) derive macro for more
+/// information.
+///
+/// [`from_i64`]: FromPrimitive::from_i64
+/// [`from_i128`]: FromPrimitive::from_i128
+/// [`from_u64`]: FromPrimitive::from_u64
+/// [`from_u128`]: FromPrimitive::from_u128
+///
+/// # Examples
+///
+/// ```rust
+/// use kernel::convert::FromPrimitive;
+///
+/// #[derive(PartialEq)]
+/// enum Foo {
+/// A,
+/// B = 0x17,
+/// C = -2,
+/// }
+///
+/// impl FromPrimitive for Foo {
+/// fn from_i64(n: i64) -> Option<Self> {
+/// match n {
+/// 0 => Some(Self::A),
+/// 0x17 => Some(Self::B),
+/// -2 => Some(Self::C),
+/// _ => None,
+/// }
+/// }
+///
+/// fn from_u64(n: u64) -> Option<Self> {
+/// i64::try_from(n).ok().and_then(Self::from_i64)
+/// }
+/// }
+///
+/// assert_eq!(Foo::from_u64(0), Some(Foo::A));
+/// assert_eq!(Foo::from_u64(0x17), Some(Foo::B));
+/// assert_eq!(Foo::from_i64(-2), Some(Foo::C));
+/// assert_eq!(Foo::from_i64(-3), None);
+/// ```
+pub trait FromPrimitive: Sized {
+ /// Attempts to convert a `bool` to `Self`. Returns `Some(Self)` if the input
+ /// corresponds to a known value; otherwise, `None`.
+ #[inline]
+ fn from_bool(b: bool) -> Option<Self> {
+ Self::from_u64(u64::from(b))
+ }
+
+ /// Attempts to convert an `isize` to `Self`. Returns `Some(Self)` if the input
+ /// corresponds to a known value; otherwise, `None`.
+ #[inline]
+ fn from_isize(n: isize) -> Option<Self> {
+ i64::try_from(n).ok().and_then(Self::from_i64)
+ }
+
+ /// Attempts to convert an `i8` to `Self`. Returns `Some(Self)` if the input
+ /// corresponds to a known value; otherwise, `None`.
+ #[inline]
+ fn from_i8(n: i8) -> Option<Self> {
+ Self::from_i64(i64::from(n))
+ }
+
+ /// Attempts to convert an `i16` to `Self`. Returns `Some(Self)` if the input
+ /// corresponds to a known value; otherwise, `None`.
+ #[inline]
+ fn from_i16(n: i16) -> Option<Self> {
+ Self::from_i64(i64::from(n))
+ }
+
+ /// Attempts to convert an `i32` to `Self`. Returns `Some(Self)` if the input
+ /// corresponds to a known value; otherwise, `None`.
+ #[inline]
+ fn from_i32(n: i32) -> Option<Self> {
+ Self::from_i64(i64::from(n))
+ }
+
+ /// Attempts to convert an `i64` to `Self`. Returns `Some(Self)` if the input
+ /// corresponds to a known value; otherwise, `None`.
+ fn from_i64(n: i64) -> Option<Self>;
+
+ /// Attempts to convert an `i128` to `Self`. Returns `Some(Self)` if the input
+ /// corresponds to a known value; otherwise, `None`.
+ ///
+ /// The default implementation delegates to [`from_i64`](FromPrimitive::from_i64)
+ /// by downcasting from `i128` to `i64`, which may result in information loss.
+ /// Consider overriding this method if `Self` can represent values outside the
+ /// `i64` range.
+ #[inline]
+ fn from_i128(n: i128) -> Option<Self> {
+ i64::try_from(n).ok().and_then(Self::from_i64)
+ }
+
+ /// Attempts to convert a `usize` to `Self`. Returns `Some(Self)` if the input
+ /// corresponds to a known value; otherwise, `None`.
+ #[inline]
+ fn from_usize(n: usize) -> Option<Self> {
+ u64::try_from(n).ok().and_then(Self::from_u64)
+ }
+
+ /// Attempts to convert a `u8` to `Self`. Returns `Some(Self)` if the input
+ /// corresponds to a known value; otherwise, `None`.
+ #[inline]
+ fn from_u8(n: u8) -> Option<Self> {
+ Self::from_u64(u64::from(n))
+ }
+
+ /// Attempts to convert a `u16` to `Self`. Returns `Some(Self)` if the input
+ /// corresponds to a known value; otherwise, `None`.
+ #[inline]
+ fn from_u16(n: u16) -> Option<Self> {
+ Self::from_u64(u64::from(n))
+ }
+
+ /// Attempts to convert a `u32` to `Self`. Returns `Some(Self)` if the input
+ /// corresponds to a known value; otherwise, `None`.
+ #[inline]
+ fn from_u32(n: u32) -> Option<Self> {
+ Self::from_u64(u64::from(n))
+ }
+
+ /// Attempts to convert a `u64` to `Self`. Returns `Some(Self)` if the input
+ /// corresponds to a known value; otherwise, `None`.
+ fn from_u64(n: u64) -> Option<Self>;
+
+ /// Attempts to convert a `u128` to `Self`. Returns `Some(Self)` if the input
+ /// corresponds to a known value; otherwise, `None`.
+ ///
+ /// The default implementation delegates to [`from_u64`](FromPrimitive::from_u64)
+ /// by downcasting from `u128` to `u64`, which may result in information loss.
+ /// Consider overriding this method if `Self` can represent values outside the
+ /// `u64` range.
+ #[inline]
+ fn from_u128(n: u128) -> Option<Self> {
+ u64::try_from(n).ok().and_then(Self::from_u64)
+ }
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 6b4774b2b1c3..861c9340d9c2 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -61,6 +61,7 @@
pub mod clk;
#[cfg(CONFIG_CONFIGFS_FS)]
pub mod configfs;
+pub mod convert;
pub mod cpu;
#[cfg(CONFIG_CPU_FREQ)]
pub mod cpufreq;
--
2.39.5
next prev parent reply other threads:[~2025-06-23 15:14 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-23 15:14 [PATCH 0/4] rust: add `FromPrimitive` support Jesung Yang
2025-06-23 15:14 ` Jesung Yang [this message]
2025-06-23 15:14 ` [PATCH 2/4] rust: macros: extend custom `quote!` macro Jesung Yang
2025-06-23 15:14 ` [PATCH 3/4] rust: macros: prefix variable `span` with underscore Jesung Yang
2025-06-23 15:14 ` [PATCH 4/4] rust: macros: add derive macro for `FromPrimitive` Jesung Yang
2025-06-25 14:07 ` [PATCH 0/4] rust: add `FromPrimitive` support Alexandre Courbot
2025-06-26 14:23 ` Jesung Yang
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=702d21d34368b1dcd896343771b00a2303e9a312.1750689857.git.y.j3ms.n@gmail.com \
--to=y.j3ms.n@gmail.com \
--cc=a.hindborg@kernel.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dakr@kernel.org \
--cc=gary@garyguo.net \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=nouveau@lists.freedesktop.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--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
all inboxes | Powered by JetHome®