[PATCH v3 03/16] rust: mem: add `AsRepr` and `AsReprMut`

Gary Guo <[email protected]>
Newsgroups org.kernel.vger.rust-for-linux,dev.linux.lists.driver-core,dev.linux.lists.nova-gpu,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci
Message-ID <[email protected]>
Some API like atomics and I/O operate on primitives only; therefore other
types would need to converted to these primitive first. Add two traits
`AsRepr` and `AsReprMut` to indicate that the type can be turned into a
primitive for these operations.

Conceptually, `T: AsRepr` means that `&T` can be viewed as `&T::Repr` and
thus it has only a round-trip transmutability requirement. `T: AsReprMut`
means that `&mut T` can be viewed as `&mut T::Repr` and thus it needs to
support bi-directional transmutability.

To avoid duplicating implementation, all repr types are normalized to
unsigned integers.

Signed-off-by: Gary Guo <[email protected]>
---
 rust/kernel/mem.rs | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 148 insertions(+)

diff --git a/rust/kernel/mem.rs b/rust/kernel/mem.rs
index a0901cbe1b2d..5bce381d8895 100644
--- a/rust/kernel/mem.rs
+++ b/rust/kernel/mem.rs
@@ -35,3 +35,151 @@ pub const fn transmute<Src: IntoBytes, Dst: FromBytes>(val: Src) -> Dst {
     // SAFETY: transmute is safe with `IntoBytes` and `FromBytes` bounds.
     unsafe { transmute_unchecked(val) }
 }
+
+/// Type that is layout-compatible with a primitive representation.
+///
+/// # Round-trip transmutability
+///
+/// `T` is round-trip transmutable to `U` if and only if both of these properties hold:
+///
+/// - Any valid bit pattern for `T` is also a valid bit pattern for `U`.
+/// - Transmuting a value of type `T` to `U` and then to `T` again
+///   yields a value that is in all aspects equivalent to the original value.
+///
+/// # Safety
+///
+/// - [`Self`] must have the same size and alignment as [`Self::Repr`].
+/// - [`Self`] must be [round-trip transmutable] to  [`Self::Repr`].
+///
+/// [round-trip transmutable]: AsRepr#round-trip-transmutability
+pub unsafe trait AsRepr: Sized {
+    /// Primitive representation of this type.
+    type Repr;
+
+    /// Convert from [`AsRepr::Repr`] to `Self`.
+    ///
+    /// # Safety
+    ///
+    /// `repr` must be a valid bit patern of `Self`. If `repr` is previously obtained using
+    /// [`AsRepr::into_repr`], then it will always be safe.
+    #[inline(always)]
+    unsafe fn from_repr_unchecked(repr: Self::Repr) -> Self {
+        // SAFETY: Per safety requirement of the trait.
+        unsafe { transmute_unchecked(repr) }
+    }
+
+    /// Convert from `Self` to [`AsRepr::Repr`].
+    #[inline(always)]
+    fn into_repr(this: Self) -> Self::Repr {
+        // SAFETY: Per safety requirement of the trait.
+        unsafe { transmute_unchecked(this) }
+    }
+}
+
+/// Type that is bi-directionally transmutable with a primitive representation.
+///
+/// # Safety
+///
+/// - [`Self`] must be [transmutable] from [`Self::Repr`].
+/// - Note that [`Self::Repr`] must be [transmutable] from `Self` as well, however that is a
+///   requirement of the [`AsRepr`] super trait already.
+///
+/// [`transmutable`]: core::mem::transmute
+pub unsafe trait AsReprMut: AsRepr {
+    /// Convert from [`AsRepr::Repr`] to `Self`.
+    #[inline(always)]
+    fn from_repr(repr: Self::Repr) -> Self {
+        // SAFETY: Per safety requirement of the trait.
+        unsafe { transmute_unchecked(repr) }
+    }
+}
+
+// SAFETY: `bool` has the same size and alignment as `u8`, and Rust guarantees that `bool` has
+// only two valid bit patterns: 0 (false) and 1 (true). Those are valid `u8` values, so `bool` is
+// round-trip transmutable to `u8`.
+unsafe impl AsRepr for bool {
+    type Repr = u8;
+}
+
+// SAFETY: `*mut T` has the same size and alignment with `*const c_void`, and is round-trip
+// transmutable to `*const c_void`.
+unsafe impl<T> AsRepr for *mut T {
+    type Repr = *const c_void;
+}
+
+// SAFETY: `*mut T` is transmutable from `*const c_void`.
+unsafe impl<T> AsReprMut for *mut T {}
+
+// SAFETY: `*const T` has the same size and alignment with `*const c_void`, and is round-trip
+// transmutable to `*const c_void`.
+unsafe impl<T> AsRepr for *const T {
+    type Repr = *const c_void;
+}
+
+// SAFETY: `*const T` is transmutable from `*const c_void`.
+unsafe impl<T> AsReprMut for *const T {}
+
+macro_rules! int_impl {
+    ($($unsigned:ident $signed:ident ,)*) => {$(
+        // SAFETY: $unsigned has the same size and alignment with itself, and is round-trip
+        // transmutable to itself.
+        unsafe impl AsRepr for $unsigned {
+            type Repr = $unsigned;
+        }
+
+        // SAFETY: $unsigned is transmutable from itself.
+        unsafe impl AsReprMut for $unsigned {}
+
+        // SAFETY: $signed has the same size and alignment with $unsigned, and is round-trip
+        // transmutable to it.
+        unsafe impl AsRepr for $signed {
+            type Repr = $unsigned;
+        }
+
+        // SAFETY: $signed is transmutable from $unsigned.
+        unsafe impl AsReprMut for $signed {}
+    )*};
+}
+
+int_impl! {
+    u8 i8,
+    u16 i16,
+    u32 i32,
+    u64 i64,
+}
+
+#[cfg(target_pointer_width = "32")]
+const _: () = {
+    // SAFETY: usize has the same size and alignment with u32, and is round-trip transmutable to it.
+    unsafe impl AsRepr for usize {
+        type Repr = u32;
+    }
+
+    // SAFETY: isize has the same size and alignment with u32, and is round-trip transmutable to it.
+    unsafe impl AsRepr for isize {
+        type Repr = u32;
+    }
+
+    // SAFETY: usize is transmutable from u32.
+    unsafe impl AsReprMut for usize {}
+    // SAFETY: isize is transmutable from u32.
+    unsafe impl AsReprMut for isize {}
+};
+
+#[cfg(target_pointer_width = "64")]
+const _: () = {
+    // SAFETY: usize has the same size and alignment with u64, and is round-trip transmutable to it.
+    unsafe impl AsRepr for usize {
+        type Repr = u64;
+    }
+
+    // SAFETY: isize has the same size and alignment with u64, and is round-trip transmutable to it.
+    unsafe impl AsRepr for isize {
+        type Repr = u64;
+    }
+
+    // SAFETY: usize is transmutable from u64.
+    unsafe impl AsReprMut for usize {}
+    // SAFETY: isize is transmutable from u64.
+    unsafe impl AsReprMut for isize {}
+};

-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.