diff options
author | Christian S. Lima <christiansantoslima21@gmail.com> | 2025-08-24 18:31:33 -0300 |
---|---|---|
committer | Alexandre Courbot <acourbot@nvidia.com> | 2025-08-28 20:41:36 +0900 |
commit | 72031905cf2e36519a98b5becbe62dc10ebb4b97 (patch) | |
tree | 7bf7c1aea373ffd4dd987a8e134e07a2d11ac10c | |
parent | 331c24e6ce814af2af74bac648d1ac1708873e9c (diff) |
rust: transmute: Add methods for FromBytes trait
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>
-rw-r--r-- | rust/kernel/lib.rs | 1 | ||||
-rw-r--r-- | rust/kernel/transmute.rs | 69 |
2 files changed, 69 insertions, 1 deletions
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index ed53169e795c..c859a8984bae 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -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)] diff --git a/rust/kernel/transmute.rs b/rust/kernel/transmute.rs index 517a432ac693..5fc7d4ed76b4 100644 --- a/rust/kernel/transmute.rs +++ b/rust/kernel/transmute.rs @@ -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 @@ -9,10 +11,75 @@ /// /// 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, )*) => { |