[PATCH] rust: transmute: Add implementation for FromBytes trait

Christian dos Santos de Lima posted 1 patch 1 month, 2 weeks ago
There is a newer version of this series
rust/kernel/lib.rs       |   2 +
rust/kernel/transmute.rs | 302 +++++++++++++++++++++++++++++++++++++--
2 files changed, 290 insertions(+), 14 deletions(-)
[PATCH] rust: transmute: Add implementation for FromBytes trait
Posted by Christian dos Santos de Lima 1 month, 2 weeks ago
Add implementation and documentation for FromBytes trait.

Add new feature block in order to allow using ToBytes
and bound to from_bytes_mut function.

Link: https://github.com/Rust-for-Linux/linux/issues/1119
Signed-off-by: Christian dos Santos de Lima <christiansantoslima21@gmail.com>
---
 rust/kernel/lib.rs       |   2 +
 rust/kernel/transmute.rs | 302 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 290 insertions(+), 14 deletions(-)

diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index dc37aef6a008..5215f5744e12 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -18,6 +18,8 @@
 #![feature(lint_reasons)]
 #![feature(new_uninit)]
 #![feature(unsize)]
+#![feature(portable_simd)]
+#![feature(trivial_bounds)]
 
 // Ensure conditional compilation based on the kernel configuration works;
 // otherwise we may silently break things like initcall handling.
diff --git a/rust/kernel/transmute.rs b/rust/kernel/transmute.rs
index 1c7d43771a37..f2d99c136017 100644
--- a/rust/kernel/transmute.rs
+++ b/rust/kernel/transmute.rs
@@ -12,24 +12,298 @@
 /// # 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 into a Reference to Self
+    ///
+    /// # Examples
+    /// ```
+    ///    pub unsafe trait FromBytes {
+    ///        unsafe fn from_bytes(slice_of_bytes: &[u8]) -> &Self;
+    ///        unsafe fn from_bytes_mut(slice_of_bytes: &mut [u8]) -> &mut Self
+    ///        where
+    ///            Self: ToBytes;
+    ///    }
+    ///
+    ///unsafe impl FromBytes for u32 {
+    ///    unsafe fn from_bytes(slice_of_bytes: &[u8]) -> &Self {
+    ///        let slice_ptr = slice_of_bytes.as_ptr() as *const Self;
+    ///        &*slice_ptr
+    ///    }
+    ///
+    ///    unsafe fn from_bytes_mut(slice_of_bytes: &mut [u8]) -> &mut Self
+    ///    where
+    ///        Self: ToBytes,
+    ///    {
+    ///        let slice_ptr = slice_of_bytes.as_mut_ptr() as *mut Self;
+    ///        &mut *slice_ptr
+    ///    }
+    ///}
+    ///
+    ///let slice_of_bytes : &[u8] = &[1, 2, 3, 4];
+    ///let result = u32::from_bytes(slice_of_bytes);
+    ///assert_eq!(*result, 0x4030201);
+    ///```
+    ///# Safety
+    ///
+    ///Guarantee that all values are initiliazed
+    unsafe fn from_bytes(slice_of_bytes: &[u8]) -> &Self;
+    ///Converts a mutabble slice of Bytes into a mutable Reference to Self
+    /// # Safety
+    ///
+    /// ToBytes in order to allow only types that implements ToBytes
+    unsafe fn from_bytes_mut(slice_of_bytes: &mut [u8]) -> &mut Self
+    where
+        Self: ToBytes;
+}
 
-macro_rules! impl_frombytes {
-    ($($({$($generics:tt)*})? $t:ty, )*) => {
-        // SAFETY: Safety comments written in the macro invocation.
-        $(unsafe impl$($($generics)*)? FromBytes for $t {})*
-    };
+// SAFETY: All bit patterns are acceptable values of the types below.
+unsafe impl FromBytes for u8 {
+    unsafe fn from_bytes(slice_of_bytes: &[u8]) -> &Self {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_ptr() as *const Self;
+            &*slice_ptr
+        }
+    }
+
+    unsafe fn from_bytes_mut(slice_of_bytes: &mut [u8]) -> &mut Self
+    where
+        Self: ToBytes,
+    {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_mut_ptr() as *mut Self;
+            &mut *slice_ptr
+        }
+    }
 }
 
-impl_frombytes! {
-    // SAFETY: All bit patterns are acceptable values of the types below.
-    u8, u16, u32, u64, usize,
-    i8, i16, i32, i64, isize,
+unsafe impl FromBytes for u16 {
+    unsafe fn from_bytes(slice_of_bytes: &[u8]) -> &Self {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_ptr() as *const Self;
+            &*slice_ptr
+        }
+    }
+
+    unsafe fn from_bytes_mut(slice_of_bytes: &mut [u8]) -> &mut Self
+    where
+        Self: ToBytes,
+    {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_mut_ptr() as *mut Self;
+            &mut *slice_ptr
+        }
+    }
+}
+
+unsafe impl FromBytes for u32 {
+    unsafe fn from_bytes(slice_of_bytes: &[u8]) -> &Self {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_ptr() as *const Self;
+            &*slice_ptr
+        }
+    }
+
+    unsafe fn from_bytes_mut(slice_of_bytes: &mut [u8]) -> &mut Self
+    where
+        Self: ToBytes,
+    {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_mut_ptr() as *mut Self;
+            &mut *slice_ptr
+        }
+    }
+}
+
+unsafe impl FromBytes for u64 {
+    unsafe fn from_bytes(slice_of_bytes: &[u8]) -> &Self {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_ptr() as *const Self;
+            &*slice_ptr
+        }
+    }
+
+    unsafe fn from_bytes_mut(slice_of_bytes: &mut [u8]) -> &mut Self
+    where
+        Self: ToBytes,
+    {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_mut_ptr() as *mut Self;
+            &mut *slice_ptr
+        }
+    }
+}
+
+unsafe impl FromBytes for usize {
+    unsafe fn from_bytes(slice_of_bytes: &[u8]) -> &Self {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_ptr() as *const Self;
+            &*slice_ptr
+        }
+    }
+
+    unsafe fn from_bytes_mut(slice_of_bytes: &mut [u8]) -> &mut Self
+    where
+        Self: ToBytes,
+    {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_mut_ptr() as *mut Self;
+            &mut *slice_ptr
+        }
+    }
+}
+
+unsafe impl FromBytes for i8 {
+    unsafe fn from_bytes(slice_of_bytes: &[u8]) -> &Self {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_ptr() as *const Self;
+            &*slice_ptr
+        }
+    }
+
+    unsafe fn from_bytes_mut(slice_of_bytes: &mut [u8]) -> &mut Self
+    where
+        Self: ToBytes,
+    {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_mut_ptr() as *mut Self;
+            &mut *slice_ptr
+        }
+    }
+}
+
+unsafe impl FromBytes for i16 {
+    unsafe fn from_bytes(slice_of_bytes: &[u8]) -> &Self {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_ptr() as *const Self;
+            &*slice_ptr
+        }
+    }
+
+    unsafe fn from_bytes_mut(slice_of_bytes: &mut [u8]) -> &mut Self
+    where
+        Self: ToBytes,
+    {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_mut_ptr() as *mut Self;
+            &mut *slice_ptr
+        }
+    }
+}
+
+unsafe impl FromBytes for i32 {
+    unsafe fn from_bytes(slice_of_bytes: &[u8]) -> &Self {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_ptr() as *const Self;
+            &*slice_ptr
+        }
+    }
+
+    unsafe fn from_bytes_mut(slice_of_bytes: &mut [u8]) -> &mut Self
+    where
+        Self: ToBytes,
+    {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_mut_ptr() as *mut Self;
+            &mut *slice_ptr
+        }
+    }
+}
+
+unsafe impl FromBytes for i64 {
+    unsafe fn from_bytes(slice_of_bytes: &[u8]) -> &Self {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_ptr() as *const Self;
+            &*slice_ptr
+        }
+    }
+
+    unsafe fn from_bytes_mut(slice_of_bytes: &mut [u8]) -> &mut Self
+    where
+        Self: ToBytes,
+    {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_mut_ptr() as *mut Self;
+            &mut *slice_ptr
+        }
+    }
+}
+
+unsafe impl FromBytes for isize {
+    unsafe fn from_bytes(slice_of_bytes: &[u8]) -> &Self {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_ptr() as *const Self;
+            &*slice_ptr
+        }
+    }
+
+    unsafe fn from_bytes_mut(slice_of_bytes: &mut [u8]) -> &mut Self
+    where
+        Self: ToBytes,
+    {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_mut_ptr() as *mut Self;
+            &mut *slice_ptr
+        }
+    }
+}
+// SAFETY: If all bit patterns are acceptable for individual values in an array, then all bit
+// patterns are also acceptable for arrays of that type.
+unsafe impl<T: FromBytes> FromBytes for [T] {
+    unsafe fn from_bytes(slice_of_bytes: &[u8]) -> &Self {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_ptr() as *const T;
+            let slice_len = slice_of_bytes.len() / core::mem::size_of::<T>();
+            core::slice::from_raw_parts(slice_ptr, slice_len)
+        }
+    }
+
+    unsafe fn from_bytes_mut(slice_of_bytes: &mut [u8]) -> &mut Self
+    where
+        Self: ToBytes,
+    {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_mut_ptr() as *mut T;
+            let slice_len = slice_of_bytes.len() / core::mem::size_of::<T>();
+            core::slice::from_raw_parts_mut(slice_ptr, slice_len)
+        }
+    }
+}
+
+/// # Examples
+///```
+///let slice_of_bytes: &[u8] = &[
+///    1, 0, 0, 0,
+///    2, 0, 0, 0,
+///    3, 0, 0, 0,
+///    4, 0, 0, 0,
+///    5, 0, 0, 0,
+///    6, 0, 0, 0,
+///    7, 0, 0, 0,
+///    8, 0, 0, 0,
+///];
+///
+///let foo = <[u32; 8]>::from_bytes(slice_of_bytes);
+///let expected: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
+///
+///assert_eq!(*foo, expected);
+///```
+unsafe impl<T: FromBytes, const N: usize> FromBytes for [T; N] {
+    unsafe fn from_bytes(slice_of_bytes: &[u8]) -> &Self {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_ptr() as *const T;
+            &*(slice_ptr as *const [T; N])
+        }
+    }
 
-    // SAFETY: If all bit patterns are acceptable for individual values in an array, then all bit
-    // patterns are also acceptable for arrays of that type.
-    {<T: FromBytes>} [T],
-    {<T: FromBytes, const N: usize>} [T; N],
+    unsafe fn from_bytes_mut(slice_of_bytes: &mut [u8]) -> &mut Self
+    where
+        Self: ToBytes,
+    {
+        unsafe {
+            let slice_ptr = slice_of_bytes.as_ptr() as *mut T;
+            &mut *(slice_ptr as *mut [T; N])
+        }
+    }
 }
 
 /// Types that can be viewed as an immutable slice of initialized bytes.
-- 
2.46.2
Re: [PATCH] rust: transmute: Add implementation for FromBytes trait
Posted by Dirk Behme 1 month, 2 weeks ago
Am 09.10.24 um 03:47 schrieb Christian dos Santos de Lima:
> Add implementation and documentation for FromBytes trait.
> 
> Add new feature block in order to allow using ToBytes
> and bound to from_bytes_mut function.
> 
> Link: https://github.com/Rust-for-Linux/linux/issues/1119
> Signed-off-by: Christian dos Santos de Lima <christiansantoslima21@gmail.com>
> ---
>   rust/kernel/lib.rs       |   2 +
>   rust/kernel/transmute.rs | 302 +++++++++++++++++++++++++++++++++++++--
>   2 files changed, 290 insertions(+), 14 deletions(-)
> 
...
> --- a/rust/kernel/transmute.rs
> +++ b/rust/kernel/transmute.rs
...
> +unsafe impl FromBytes for u8 {
...
> +unsafe impl FromBytes for u16 {
...
> +unsafe impl FromBytes for u32 {
...
> +unsafe impl FromBytes for u64 {
...
> +unsafe impl FromBytes for usize {
...
> +unsafe impl FromBytes for i8 {
...
> +unsafe impl FromBytes for i16 {
...
> +unsafe impl FromBytes for i32 {
...
> +unsafe impl FromBytes for i64 {
...
> +unsafe impl FromBytes for isize {
...

Asahi Lina's device tree code which reads the device tree node's data 
as a byte slice and then has to convert it

https://github.com/Fabo/linux/blob/9e496b356ee8e25f9bee9258491aa6ae3a4f1ddf/rust/kernel/of.rs#L390

uses macros to avoid code dublication:

prop_int_type!(u8);
prop_int_type!(u16);
prop_int_type!(u32);
prop_int_type!(u64);
prop_int_type!(i8);
prop_int_type!(i16);
prop_int_type!(i32);
prop_int_type!(i64);

Would anything like this be possible here, as well? To avoid code 
dublication?

Best regards

Dirk
Re: [PATCH] rust: transmute: Add implementation for FromBytes trait
Posted by Benno Lossin 1 month, 2 weeks ago
On 09.10.24 15:03, Dirk Behme wrote:
> Am 09.10.24 um 03:47 schrieb Christian dos Santos de Lima:
>> Add implementation and documentation for FromBytes trait.
>>
>> Add new feature block in order to allow using ToBytes
>> and bound to from_bytes_mut function.
>>
>> Link: https://github.com/Rust-for-Linux/linux/issues/1119
>> Signed-off-by: Christian dos Santos de Lima <christiansantoslima21@gmail.com>
>> ---
>>   rust/kernel/lib.rs       |   2 +
>>   rust/kernel/transmute.rs | 302 +++++++++++++++++++++++++++++++++++++--
>>   2 files changed, 290 insertions(+), 14 deletions(-)
>>
> ...
>> --- a/rust/kernel/transmute.rs
>> +++ b/rust/kernel/transmute.rs
> ...
>> +unsafe impl FromBytes for u8 {
> ...
>> +unsafe impl FromBytes for u16 {
> ...
>> +unsafe impl FromBytes for u32 {
> ...
>> +unsafe impl FromBytes for u64 {
> ...
>> +unsafe impl FromBytes for usize {
> ...
>> +unsafe impl FromBytes for i8 {
> ...
>> +unsafe impl FromBytes for i16 {
> ...
>> +unsafe impl FromBytes for i32 {
> ...
>> +unsafe impl FromBytes for i64 {
> ...
>> +unsafe impl FromBytes for isize {
> ...
> 
> Asahi Lina's device tree code which reads the device tree node's data
> as a byte slice and then has to convert it
> 
> https://github.com/Fabo/linux/blob/9e496b356ee8e25f9bee9258491aa6ae3a4f1ddf/rust/kernel/of.rs#L390
> 
> uses macros to avoid code dublication:
> 
> prop_int_type!(u8);
> prop_int_type!(u16);
> prop_int_type!(u32);
> prop_int_type!(u64);
> prop_int_type!(i8);
> prop_int_type!(i16);
> prop_int_type!(i32);
> prop_int_type!(i64);
> 
> Would anything like this be possible here, as well? To avoid code
> dublication?

Yes please, create a macro.

---
Cheers,
Benno
Re: [PATCH] rust: transmute: Add implementation for FromBytes trait
Posted by Miguel Ojeda 1 month, 2 weeks ago
On Wed, Oct 9, 2024 at 3:48 AM Christian dos Santos de Lima
<christiansantoslima21@gmail.com> wrote:
>
> +pub unsafe trait FromBytes {
> +    ///Converts a slice of Bytes into a Reference to Self
> +    ///
> +    /// # Examples
> +    /// ```
> +    ///    pub unsafe trait FromBytes {

Apart from what Alice mentions (which is critical, since we are
looking to get into stable Rust as soon as feasible -- please see
https://rust-for-linux.com/unstable-features#usage-in-the-kernel),
please also format the code, documentation and examples appropriately
(please see other files to see how it is usually done, we mostly
follow Rust's standard library conventions).

> +        unsafe {
> +            let slice_ptr = slice_of_bytes.as_ptr() as *const Self;
> +            &*slice_ptr
> +        }

Please note that we require `// SAFETY` comments too. Missing those is
already a warning/error (depending on the kernel configuration) in
rust-next.

Thanks for the patch!

Cheers,
Miguel
Re: [PATCH] rust: transmute: Add implementation for FromBytes trait
Posted by Alice Ryhl 1 month, 2 weeks ago
On Wed, Oct 9, 2024 at 3:48 AM Christian dos Santos de Lima
<christiansantoslima21@gmail.com> wrote:
>
> Add implementation and documentation for FromBytes trait.
>
> Add new feature block in order to allow using ToBytes
> and bound to from_bytes_mut function.
>
> Link: https://github.com/Rust-for-Linux/linux/issues/1119
> Signed-off-by: Christian dos Santos de Lima <christiansantoslima21@gmail.com>
> ---
>  rust/kernel/lib.rs       |   2 +
>  rust/kernel/transmute.rs | 302 +++++++++++++++++++++++++++++++++++++--
>  2 files changed, 290 insertions(+), 14 deletions(-)
>
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index dc37aef6a008..5215f5744e12 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -18,6 +18,8 @@
>  #![feature(lint_reasons)]
>  #![feature(new_uninit)]
>  #![feature(unsize)]
> +#![feature(portable_simd)]
> +#![feature(trivial_bounds)]

New unstable features must come with a good justification. Why are you
adding these? Why can't we avoid adding them? This information needs
to be in the commit message.

Alice