]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
rust: transmute: Add methods for FromBytes trait
authorChristian S. Lima <christiansantoslima21@gmail.com>
Sun, 24 Aug 2025 21:31:33 +0000 (18:31 -0300)
committerAlexandre Courbot <acourbot@nvidia.com>
Thu, 28 Aug 2025 11:41:36 +0000 (20:41 +0900)
The two methods added take a slice of bytes and return those bytes in
a specific type. These methods are useful when we need to transform
the stream of bytes into specific type.

Since the `is_aligned` method for pointer types has been stabilized in
`1.79` version and is being used in this patch, I'm enabling the
feature. In this case, using this method is useful to check the
alignment and avoid a giant boilerplate, such as `(foo.as_ptr() as
usize) % core::mem::align_of::<T>() == 0`.

Also add `#[allow(clippy::incompatible_msrv)]` where needed until the
MSRV is updated to `1.79`.

Suggested-by: Benno Lossin <benno.lossin@proton.me>
Link: https://github.com/Rust-for-Linux/linux/issues/1119
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Tested-by: Alexandre Courbot <acourbot@nvidia.com>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Christian S. Lima <christiansantoslima21@gmail.com>
Link: https://lore.kernel.org/r/20250824213134.27079-1-christiansantoslima21@gmail.com
Acked-by: Miguel Ojeda <ojeda@kernel.org>
[acourbot@nvidia.com: minor rewording of commit messages and doccomments]
[acourbot@nvidia.com: revert slice implementation removal]
[acourbot@nvidia.com: move incompatible_msrv clippy allow closer to site of need]
[acourbot@nvidia.com: call the doctest method]
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
rust/kernel/lib.rs
rust/kernel/transmute.rs

index ed53169e795c0badf548025a57f946fa18bc73e3..c859a8984bae1b3efc9078c8bf7979c3d94d1863 100644 (file)
@@ -18,6 +18,7 @@
 //
 // Stable since Rust 1.79.0.
 #![feature(inline_const)]
+#![feature(pointer_is_aligned)]
 //
 // Stable since Rust 1.81.0.
 #![feature(lint_reasons)]
index 517a432ac6937d3dca01f3aa277e714439a15576..5fc7d4ed76b4280fb58d6d19507efc2ce1f73ae3 100644 (file)
@@ -2,6 +2,8 @@
 
 //! Traits for transmuting types.
 
+use core::mem::size_of;
+
 /// Types for which any bit pattern is valid.
 ///
 /// Not all types are valid for all values. For example, a `bool` must be either zero or one, so
 ///
 /// It's okay for the type to have padding, as initializing those bytes has no effect.
 ///
+/// # Examples
+///
+/// ```
+/// use kernel::transmute::FromBytes;
+///
+/// # fn test() -> Option<()> {
+/// let raw = [1, 2, 3, 4];
+///
+/// let result = u32::from_bytes(&raw)?;
+///
+/// #[cfg(target_endian = "little")]
+/// assert_eq!(*result, 0x4030201);
+///
+/// #[cfg(target_endian = "big")]
+/// assert_eq!(*result, 0x1020304);
+///
+/// # Some(()) }
+/// # test().ok_or(EINVAL)?;
+/// # Ok::<(), Error>(())
+/// ```
+///
 /// # Safety
 ///
 /// All bit-patterns must be valid for this type. This type must not have interior mutability.
-pub unsafe trait FromBytes {}
+pub unsafe trait FromBytes {
+    /// Converts a slice of bytes to a reference to `Self`.
+    ///
+    /// Succeeds if the reference is properly aligned, and the size of `bytes` is equal to that of
+    /// `T` and different from zero.
+    ///
+    /// Otherwise, returns [`None`].
+    fn from_bytes(bytes: &[u8]) -> Option<&Self>
+    where
+        Self: Sized,
+    {
+        let slice_ptr = bytes.as_ptr().cast::<Self>();
+        let size = size_of::<Self>();
+
+        #[allow(clippy::incompatible_msrv)]
+        if bytes.len() == size && slice_ptr.is_aligned() {
+            // SAFETY: Size and alignment were just checked.
+            unsafe { Some(&*slice_ptr) }
+        } else {
+            None
+        }
+    }
+
+    /// Converts a mutable slice of bytes to a reference to `Self`.
+    ///
+    /// Succeeds if the reference is properly aligned, and the size of `bytes` is equal to that of
+    /// `T` and different from zero.
+    ///
+    /// Otherwise, returns [`None`].
+    fn from_bytes_mut(bytes: &mut [u8]) -> Option<&mut Self>
+    where
+        Self: AsBytes + Sized,
+    {
+        let slice_ptr = bytes.as_mut_ptr().cast::<Self>();
+        let size = size_of::<Self>();
+
+        #[allow(clippy::incompatible_msrv)]
+        if bytes.len() == size && slice_ptr.is_aligned() {
+            // SAFETY: Size and alignment were just checked.
+            unsafe { Some(&mut *slice_ptr) }
+        } else {
+            None
+        }
+    }
+}
 
 macro_rules! impl_frombytes {
     ($($({$($generics:tt)*})? $t:ty, )*) => {