[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <702d21d34368b1dcd896343771b00a2303e9a312.1750689857.git.y.j3ms.n@gmail.com>
Date: Mon, 23 Jun 2025 15:14:27 +0000
From: Jesung Yang <y.j3ms.n@...il.com>
To: Miguel Ojeda <ojeda@...nel.org>,
Alex Gaynor <alex.gaynor@...il.com>,
Boqun Feng <boqun.feng@...il.com>,
Gary Guo <gary@...yguo.net>,
Björn Roy Baron <bjorn3_gh@...tonmail.com>,
Benno Lossin <lossin@...nel.org>,
Andreas Hindborg <a.hindborg@...nel.org>,
Alice Ryhl <aliceryhl@...gle.com>,
Trevor Gross <tmgross@...ch.edu>,
Danilo Krummrich <dakr@...nel.org>
Cc: linux-kernel@...r.kernel.org,
rust-for-linux@...r.kernel.org,
nouveau@...ts.freedesktop.org,
Jesung Yang <y.j3ms.n@...il.com>
Subject: [PATCH 1/4] rust: introduce `FromPrimitive` trait
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@...il.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
Powered by blists - more mailing lists