* [PATCH] rust: transmute: add `as_bytes` method for `AsBytes` trait
@ 2025-07-25 2:11 Alexandre Courbot
2025-07-25 7:52 ` Alice Ryhl
0 siblings, 1 reply; 3+ messages in thread
From: Alexandre Courbot @ 2025-07-25 2:11 UTC (permalink / raw)
To: Abdiel Janulgue, Danilo Krummrich, Daniel Almeida, Robin Murphy,
Andreas Hindborg, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Alice Ryhl, Trevor Gross
Cc: Christian S. Lima, rust-for-linux, linux-kernel,
Alexandre Courbot
Every time that implements `AsBytes` should be able to provide its byte
representation. Introduce the `as_bytes` method that returns the
implementer as a stream of bytes.
Since types implementing `Sized` can trivially be represented as a
stream of bytes, introduce the `AsBytesSized` proxy trait that can be
implemented for any `Sized` type and provides an `AsBytes`
implementation suitable for such types. Types that are not `Sized` need
to implement `AsBytes` directly and provide a method implementation.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
This is the sister patch of [1], requiring `AsBytes` implementors to
provide an `as_bytes` method, and adding the convenience trait
`AsBytesSized` that can be implemented on any sized type in order to
benefit from a suitable `AsBytes` implementation.
It is going to be used in Nova, but should also be universally useful -
if anything, it felt a bit strange that `AsBytes` did not require this
method so far as for unsized types the bytes representation cannot be
obviously inferred.
[1] https://lore.kernel.org/rust-for-linux/20250624042802.105623-1-christiansantoslima21@gmail.com/
---
rust/kernel/dma.rs | 4 ++--
rust/kernel/transmute.rs | 48 ++++++++++++++++++++++++++++++++++++++++++------
samples/rust/rust_dma.rs | 2 +-
3 files changed, 45 insertions(+), 9 deletions(-)
diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs
index 25dfa0e6cc3ce50aa85463dae00fbdebcf8975d2..2ada95fdb41186957ee8dd39d43e473286f01d2c 100644
--- a/rust/kernel/dma.rs
+++ b/rust/kernel/dma.rs
@@ -439,7 +439,7 @@ unsafe impl<T: AsBytes + FromBytes + Send> Send for CoherentAllocation<T> {}
/// // SAFETY: All bit patterns are acceptable values for `MyStruct`.
/// unsafe impl kernel::transmute::FromBytes for MyStruct{};
/// // SAFETY: Instances of `MyStruct` have no uninitialized portions.
-/// unsafe impl kernel::transmute::AsBytes for MyStruct{};
+/// unsafe impl kernel::transmute::AsBytesSized for MyStruct{};
///
/// # fn test(alloc: &kernel::dma::CoherentAllocation<MyStruct>) -> Result {
/// let whole = kernel::dma_read!(alloc[2]);
@@ -483,7 +483,7 @@ macro_rules! dma_read {
/// // SAFETY: All bit patterns are acceptable values for `MyStruct`.
/// unsafe impl kernel::transmute::FromBytes for MyStruct{};
/// // SAFETY: Instances of `MyStruct` have no uninitialized portions.
-/// unsafe impl kernel::transmute::AsBytes for MyStruct{};
+/// unsafe impl kernel::transmute::AsBytesSized for MyStruct{};
///
/// # fn test(alloc: &kernel::dma::CoherentAllocation<MyStruct>) -> Result {
/// kernel::dma_write!(alloc[2].member = 0xf);
diff --git a/rust/kernel/transmute.rs b/rust/kernel/transmute.rs
index 1c7d43771a37b90150de86699f114a2ffb84db91..91d977e035626bfb23910829653f1fc971e0e0f8 100644
--- a/rust/kernel/transmute.rs
+++ b/rust/kernel/transmute.rs
@@ -47,25 +47,61 @@ macro_rules! impl_frombytes {
///
/// Values of this type may not contain any uninitialized bytes. This type must not have interior
/// mutability.
-pub unsafe trait AsBytes {}
+pub unsafe trait AsBytes {
+ /// Returns `self` as a slice of bytes.
+ fn as_bytes(&self) -> &[u8];
+}
-macro_rules! impl_asbytes {
+/// Proxy trait for `AsBytes`, providing an implementation valid for all sized types.
+///
+/// If your type implements `Sized`, then you want to implement this instead of `AsBytes`.
+///
+/// # Safety
+///
+/// Values of this type may not contain any uninitialized bytes. This type must not have interior
+/// mutability.
+pub unsafe trait AsBytesSized: Sized {}
+
+unsafe impl<T: AsBytesSized> AsBytes for T {
+ fn as_bytes(&self) -> &[u8] {
+ unsafe {
+ core::slice::from_raw_parts((self as *const Self).cast::<u8>(), size_of::<Self>())
+ }
+ }
+}
+
+macro_rules! impl_asbytessized {
($($({$($generics:tt)*})? $t:ty, )*) => {
// SAFETY: Safety comments written in the macro invocation.
- $(unsafe impl$($($generics)*)? AsBytes for $t {})*
+ $(unsafe impl$($($generics)*)? AsBytesSized for $t {})*
};
}
-impl_asbytes! {
+impl_asbytessized! {
// SAFETY: Instances of the following types have no uninitialized portions.
u8, u16, u32, u64, usize,
i8, i16, i32, i64, isize,
bool,
char,
- str,
// SAFETY: If individual values in an array have no uninitialized portions, then the array
// itself does not have any uninitialized portions either.
- {<T: AsBytes>} [T],
{<T: AsBytes, const N: usize>} [T; N],
}
+
+unsafe impl AsBytes for str {
+ fn as_bytes(&self) -> &[u8] {
+ self.as_bytes()
+ }
+}
+
+unsafe impl<T> AsBytes for [T]
+where
+ T: AsBytes,
+{
+ fn as_bytes(&self) -> &[u8] {
+ unsafe {
+ core::slice::from_raw_parts(self.as_ptr().cast::<u8>(), self.len() * size_of::<T>())
+ }
+ }
+}
diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs
index 9e05d5c0cdaeb3b36fcf204a91b52e382e73fbe6..ab4814c848f928240fc49d57ac6a2efe636fb39f 100644
--- a/samples/rust/rust_dma.rs
+++ b/samples/rust/rust_dma.rs
@@ -30,7 +30,7 @@ fn new(h: u32, b: u32) -> Self {
}
}
// SAFETY: All bit patterns are acceptable values for `MyStruct`.
-unsafe impl kernel::transmute::AsBytes for MyStruct {}
+unsafe impl kernel::transmute::AsBytesSized for MyStruct {}
// SAFETY: Instances of `MyStruct` have no uninitialized portions.
unsafe impl kernel::transmute::FromBytes for MyStruct {}
---
base-commit: 14ae91a81ec8fa0bc23170d4aa16dd2a20d54105
change-id: 20250725-as_bytes-6cbc11f2e8c3
Best regards,
--
Alexandre Courbot <acourbot@nvidia.com>
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] rust: transmute: add `as_bytes` method for `AsBytes` trait
2025-07-25 2:11 [PATCH] rust: transmute: add `as_bytes` method for `AsBytes` trait Alexandre Courbot
@ 2025-07-25 7:52 ` Alice Ryhl
2025-07-25 12:12 ` Alexandre Courbot
0 siblings, 1 reply; 3+ messages in thread
From: Alice Ryhl @ 2025-07-25 7:52 UTC (permalink / raw)
To: Alexandre Courbot
Cc: Abdiel Janulgue, Danilo Krummrich, Daniel Almeida, Robin Murphy,
Andreas Hindborg, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Trevor Gross,
Christian S. Lima, rust-for-linux, linux-kernel
On Fri, Jul 25, 2025 at 4:11 AM Alexandre Courbot <acourbot@nvidia.com> wrote:
>
> Every time that implements `AsBytes` should be able to provide its byte
> representation. Introduce the `as_bytes` method that returns the
> implementer as a stream of bytes.
>
> Since types implementing `Sized` can trivially be represented as a
> stream of bytes, introduce the `AsBytesSized` proxy trait that can be
> implemented for any `Sized` type and provides an `AsBytes`
> implementation suitable for such types. Types that are not `Sized` need
> to implement `AsBytes` directly and provide a method implementation.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Is the AsBytesSized trait necessary? Can't we just do this?
pub unsafe trait AsBytes {
/// Returns `self` as a slice of bytes.
fn as_bytes(&self) -> &[u8] {
let size = size_of_val(self);
let ptr = self as *const Self as *const u8;
unsafe { slice::from_raw_parts(ptr, size) }
}
}
Alice
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] rust: transmute: add `as_bytes` method for `AsBytes` trait
2025-07-25 7:52 ` Alice Ryhl
@ 2025-07-25 12:12 ` Alexandre Courbot
0 siblings, 0 replies; 3+ messages in thread
From: Alexandre Courbot @ 2025-07-25 12:12 UTC (permalink / raw)
To: Alice Ryhl
Cc: Abdiel Janulgue, Danilo Krummrich, Daniel Almeida, Robin Murphy,
Andreas Hindborg, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Trevor Gross,
Christian S. Lima, rust-for-linux, linux-kernel
On Fri Jul 25, 2025 at 4:52 PM JST, Alice Ryhl wrote:
> On Fri, Jul 25, 2025 at 4:11 AM Alexandre Courbot <acourbot@nvidia.com> wrote:
>>
>> Every time that implements `AsBytes` should be able to provide its byte
>> representation. Introduce the `as_bytes` method that returns the
>> implementer as a stream of bytes.
>>
>> Since types implementing `Sized` can trivially be represented as a
>> stream of bytes, introduce the `AsBytesSized` proxy trait that can be
>> implemented for any `Sized` type and provides an `AsBytes`
>> implementation suitable for such types. Types that are not `Sized` need
>> to implement `AsBytes` directly and provide a method implementation.
>>
>> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
>
> Is the AsBytesSized trait necessary? Can't we just do this?
>
> pub unsafe trait AsBytes {
> /// Returns `self` as a slice of bytes.
> fn as_bytes(&self) -> &[u8] {
> let size = size_of_val(self);
> let ptr = self as *const Self as *const u8;
> unsafe { slice::from_raw_parts(ptr, size) }
> }
> }
Wow, I was completely oblivious of the fact that `size_of_val` also
worked with non-Sized types! Yes, this works perfectly well and is much
less intrusive and overall way better. Thanks a lot.
... now it also makes me anxious about why we didn't include this
method when the trait was introduced, since it is so simple. ^_^;
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-07-25 12:12 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-25 2:11 [PATCH] rust: transmute: add `as_bytes` method for `AsBytes` trait Alexandre Courbot
2025-07-25 7:52 ` Alice Ryhl
2025-07-25 12:12 ` Alexandre Courbot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).