public inbox for rust-for-linux@vger.kernel.org
 help / color / mirror / Atom feed
From: David Rheinsberg <david@readahead.eu>
To: rust-for-linux@vger.kernel.org
Cc: teg@jklm.no, Miguel Ojeda <ojeda@kernel.org>,
	David Rheinsberg <david@readahead.eu>
Subject: [RFC 10/16] bus1/util: add IntoDeref/FromDeref
Date: Tue, 31 Mar 2026 21:03:02 +0200	[thread overview]
Message-ID: <20260331190308.141622-11-david@readahead.eu> (raw)
In-Reply-To: <20260331190308.141622-1-david@readahead.eu>

Introduce two new utility traits: IntoDeref and FromDeref.

The traits are an abstraction for `Box::into_raw()` and
`Box::from_raw()`, as well as their equivalents in `Arc`. At the same
time, the traits can be implemented for plain references as no-ops.

The traits will be used by intrusive collections to generalize over the
data-type stored in a collection, without moving the actual data into
the collection.

Signed-off-by: David Rheinsberg <david@readahead.eu>
---
 ipc/bus1/util/convert.rs | 259 +++++++++++++++++++++++++++++++++++++++
 ipc/bus1/util/mod.rs     |   1 +
 2 files changed, 260 insertions(+)
 create mode 100644 ipc/bus1/util/convert.rs

diff --git a/ipc/bus1/util/convert.rs b/ipc/bus1/util/convert.rs
new file mode 100644
index 000000000000..2b918f3b7db2
--- /dev/null
+++ b/ipc/bus1/util/convert.rs
@@ -0,0 +1,259 @@
+//! # Utilities for conversions between types
+//!
+//! This module contains utilities to help dealing with conversions between
+//! types.
+
+use core::ptr::NonNull;
+use kernel::prelude::*;
+use crate::util;
+
+/// Convert a value into a raw pointer to its dereferenced value.
+///
+/// This trait extends [`core::ops::Deref`] and allows converting a value
+/// into a raw pointer to its dereferenced value. While
+/// [`core::ops::Deref`] retains the original value and merely borrows to
+/// dereference it, [`IntoDeref`] actually converts the value into a raw
+/// pointer to the dereferenced value without retaining the original.
+///
+/// Note that in many cases this will leak the original value if no extra
+/// steps are taken. Usually, you want to restore the original value to ensure
+/// the correct drop handlers are run (see [`FromDeref`]).
+///
+/// This trait is a generic version of
+/// [`Box::into_raw()`](kernel::alloc::Box::into_raw),
+/// [`Arc::into_raw()`](kernel::sync::Arc::into_raw), and more.
+///
+/// ## Mutability
+///
+/// [`IntoDeref`] serves for immutable and mutable conversions. The returned
+/// pointer does not reflect whether mutable access is granted. That is, the
+/// trait can be used for owned values like [`Box`](kernel::alloc::Box)
+/// where mutable access is granted, and shared values like
+/// [`Arc`](kernel::sync::Arc) where no mutable access is granted.
+///
+/// If [`DerefMut`] is implemented as well, then the value is available
+/// mutably. If it is not implemented, then mutably is left undefined.
+///
+/// ## Safety
+///
+/// The implementations of [`Deref`](core::ops::Deref) and [`IntoDeref`] must
+/// be compatible. That is, `deref()` must return the same pointer as
+/// `into_deref()`. If [`DerefMut`] is implemented, `deref_mut()` must also
+/// return the same pointer.
+///
+/// Furthermore, for types that provide [pinned](core::pin) variants,
+/// [`IntoDeref`] is part of the safety requirements of
+/// [`core::pin::Pin::new_unchecked()`] just like
+/// [`Deref`](core::ops::Deref) is.
+///
+/// An implementation must uphold the documented guarantees of the individual
+/// methods.
+pub unsafe trait IntoDeref: Sized + core::ops::Deref {
+    /// Convert a value into a raw pointer to its dereferenced value.
+    ///
+    /// This consumes a dereferencable value and yields a raw pointer
+    /// to the dereferenced value.
+    ///
+    /// The returned pointer is guaranteed to be convertible to a shared
+    /// reference for any caller-chosen lifetime `'a` where `Self: 'a`.
+    ///
+    /// If [`DerefMut`](core::ops::DerefMut) is implemented for [`Self`],
+    /// then the pointer is guaranteed to be convertible to a mutable
+    /// reference for any caller-chosen lifetime `'a` where `Self: 'a`.
+    ///
+    /// Conversion to a reference is subject to exclusivity guarantees as
+    /// required by `&` and `&mut`.
+    fn into_deref(v: Self) -> NonNull<Self::Target>;
+
+    /// Convert a pinned value into a raw pointer to its dereferenced value.
+    ///
+    /// This is the pinned equivalent of [`Self::into_deref()`]. The pointer
+    /// is only convertible to a pinned reference.
+    fn pin_into_deref(v: Pin<Self>) -> NonNull<Self::Target> {
+        // SAFETY: Pinned types must ensure they uphold pinning guarantees
+        //     just like `Deref` does (see trait requirements).
+        Self::into_deref(unsafe { Pin::into_inner_unchecked(v) })
+    }
+}
+
+/// Convert a dereferenced value back to its original value.
+///
+/// This trait provides the inverse operation of [`IntoDeref`]. It takes a
+/// raw pointer to a dereferenced value and restores the original pointer.
+/// This operation is unsafe and requires the caller to guarantee that the
+/// pointer was acquired via [`IntoDeref`] or similar means.
+///
+/// This trait is a generic version of
+/// [`Box::from_raw()`](kernel::alloc::Box::from_raw),
+/// [`Arc::from_raw()`](kernel::sync::Arc::from_raw), and more.
+///
+/// ## Safety
+///
+/// An implementation must uphold the documented guarantees of the individual
+/// methods.
+pub unsafe trait FromDeref: IntoDeref {
+    /// Convert a dereferenced value back to its original value.
+    ///
+    /// This returns the value that was originally passed to
+    /// [`IntoDeref::into_deref()`].
+    ///
+    /// ## Safety
+    ///
+    /// The wrapped pointer must have been acquired via [`IntoDeref`] or a
+    /// matching equivalent.
+    ///
+    /// The caller must guarantee that they do not make use of any retained
+    /// copies of the wrapped pointer.
+    ///
+    /// It is always safe to call this on values obtained via [`IntoDeref`], as
+    /// long as the raw pointer is no longer used afterwards.
+    unsafe fn from_deref(v: NonNull<Self::Target>) -> Self;
+
+    /// Convert a dereferenced value back to its original pinned value.
+    ///
+    /// This is the pinned equivalent of [`Self::from_deref()`].
+    ///
+    /// ## Safety
+    ///
+    /// The caller must guarantee that the original value was a pinned pointer.
+    /// Furthermore, all requirements of [`Self::from_deref()`] apply.
+    unsafe fn pin_from_deref(v: NonNull<Self::Target>) -> Pin<Self> {
+        // SAFETY: Pinned types must ensure they uphold pinning guarantees
+        //     just like `Deref` does (see trait requirements of `IntoDeref`).
+        //     Also, the caller must ensure the original value was pinned.
+        unsafe { Pin::new_unchecked(Self::from_deref(v)) }
+    }
+}
+
+mod impls {
+    use super::*;
+    use kernel::alloc::{Allocator, Box};
+    use kernel::sync::Arc;
+
+    // SAFETY: Coherent with `Deref` and pinning. Upholds method guarantees.
+    unsafe impl<T: ?Sized> IntoDeref for &T {
+        fn into_deref(v: Self) -> NonNull<Self::Target> {
+            util::nonnull_from_ref(v)
+        }
+    }
+
+    // SAFETY: Upholds method guarantees.
+    unsafe impl<T: ?Sized> FromDeref for &T {
+        unsafe fn from_deref(v: NonNull<Self::Target>) -> Self {
+            // SAFETY: Caller guarantees `v` is a `&T`.
+            unsafe { v.as_ref() }
+        }
+    }
+
+    // SAFETY: Coherent with `Deref` and pinning. Upholds method guarantees.
+    unsafe impl<T: ?Sized> IntoDeref for &mut T {
+        fn into_deref(v: Self) -> NonNull<Self::Target> {
+            util::nonnull_from_mut(v)
+        }
+    }
+
+    // SAFETY: Upholds method guarantees.
+    unsafe impl<T: ?Sized> FromDeref for &mut T {
+        unsafe fn from_deref(mut v: NonNull<Self::Target>) -> Self {
+            // SAFETY: Caller guarantees `v` is a `&mut T`.
+            unsafe { v.as_mut() }
+        }
+    }
+
+    // SAFETY: Coherent with `Deref` and pinning. Upholds method guarantees.
+    unsafe impl<T: ?Sized, A: Allocator> IntoDeref for Box<T, A> {
+        fn into_deref(v: Self) -> NonNull<Self::Target> {
+            // SAFETY: `Box::into_raw()` never returns NULL.
+            unsafe { NonNull::new_unchecked(Box::into_raw(v)) }
+        }
+    }
+
+    // SAFETY: Upholds method guarantees.
+    unsafe impl<T: ?Sized, A: Allocator> FromDeref for Box<T, A> {
+        unsafe fn from_deref(v: NonNull<Self::Target>) -> Self {
+            // SAFETY: Caller guarantees `v` is from `IntoDeref`.
+            unsafe { Box::from_raw(v.as_ptr()) }
+        }
+    }
+
+    // SAFETY: Coherent with `Deref` and pinning. Upholds method guarantees.
+    unsafe impl<T: ?Sized> IntoDeref for Arc<T> {
+        fn into_deref(v: Self) -> NonNull<Self::Target> {
+            // SAFETY: `Arc::into_raw()` never returns NULL.
+            unsafe { NonNull::new_unchecked(Arc::into_raw(v).cast_mut()) }
+        }
+    }
+
+    // SAFETY: Upholds method guarantees.
+    unsafe impl<T: ?Sized> FromDeref for Arc<T> {
+        unsafe fn from_deref(v: NonNull<Self::Target>) -> Self {
+            // SAFETY: Caller guarantees `v` is from `IntoDeref`.
+            unsafe { Arc::from_raw(v.as_ptr()) }
+        }
+    }
+}
+
+#[allow(clippy::undocumented_unsafe_blocks)]
+#[kunit_tests(bus1_util_convert)]
+mod test {
+    use super::*;
+    use kernel::alloc::KBox;
+    use kernel::sync::Arc;
+
+    #[test]
+    fn into_from_deref() {
+        let mut v: u64 = 71;
+
+        {
+            let p: *const u64 = &raw const v;
+            let f: &u64 = &v;
+
+            let d: NonNull<u64> = IntoDeref::into_deref(f);
+            assert_eq!(71, unsafe { *d.as_ref() });
+            assert!(core::ptr::eq(p, d.as_ptr()));
+
+            let r: &u64 = unsafe { FromDeref::from_deref(d) };
+            assert_eq!(71, *r);
+            assert!(core::ptr::eq(p, r));
+        }
+
+        {
+            let p: *mut u64 = &raw mut v;
+            let f: &mut u64 = &mut v;
+
+            let d: NonNull<u64> = IntoDeref::into_deref(f);
+            assert_eq!(71, unsafe { *d.as_ref() });
+            assert!(core::ptr::eq(p, d.as_ptr()));
+
+            let r: &mut u64 = unsafe { FromDeref::from_deref(d) };
+            assert_eq!(71, *r);
+            assert!(core::ptr::eq(p, r));
+        }
+
+        {
+            let f: KBox<u64> = KBox::new(v, GFP_KERNEL).unwrap();
+            let p: *const u64 = &raw const *f;
+
+            let d: NonNull<u64> = IntoDeref::into_deref(f);
+            assert_eq!(71, unsafe { *d.as_ref() });
+            assert!(core::ptr::eq(p, d.as_ptr()));
+
+            let r: KBox<u64> = unsafe { FromDeref::from_deref(d) };
+            assert_eq!(71, *r);
+            assert!(core::ptr::eq(p, &raw const *r));
+        }
+
+        {
+            let f: Arc<u64> = Arc::new(v, GFP_KERNEL).unwrap();
+            let p: *const u64 = &raw const *f;
+
+            let d: NonNull<u64> = IntoDeref::into_deref(f);
+            assert_eq!(71, unsafe { *d.as_ref() });
+            assert!(core::ptr::eq(p, d.as_ptr()));
+
+            let r: Arc<u64> = unsafe { FromDeref::from_deref(d) };
+            assert_eq!(71, *r);
+            assert!(core::ptr::eq(p, &raw const *r));
+        }
+    }
+}
diff --git a/ipc/bus1/util/mod.rs b/ipc/bus1/util/mod.rs
index ad1ceef35f3d..b8922cfb74cc 100644
--- a/ipc/bus1/util/mod.rs
+++ b/ipc/bus1/util/mod.rs
@@ -7,6 +7,7 @@
 use kernel::prelude::*;
 use kernel::sync::{Arc, ArcBorrow};
 
+pub mod convert;
 pub mod field;
 
 /// Convert an Arc to its pinned version.
-- 
2.53.0


  parent reply	other threads:[~2026-03-31 19:06 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-31 19:02 [RFC 00/16] bus1: Capability-based IPC for Linux David Rheinsberg
2026-03-31 19:02 ` [RFC 01/16] rust/sync: add LockedBy::access_mut_unchecked() David Rheinsberg
2026-03-31 19:29   ` Miguel Ojeda
2026-03-31 19:02 ` [RFC 02/16] rust/sync: add Arc::drop_unless_unique() David Rheinsberg
2026-03-31 19:02 ` [RFC 03/16] rust/alloc: add Vec::into_boxed_slice() David Rheinsberg
2026-03-31 19:28   ` Miguel Ojeda
2026-03-31 21:10   ` Gary Guo
2026-03-31 22:07   ` Danilo Krummrich
2026-04-01  9:28     ` David Rheinsberg
2026-03-31 19:02 ` [RFC 04/16] rust/error: add EXFULL, EBADRQC, EDQUOT, ENOTRECOVERABLE David Rheinsberg
2026-03-31 19:02 ` [RFC 05/16] bus1: add module scaffolding David Rheinsberg
2026-03-31 19:02 ` [RFC 06/16] bus1: add the user-space API David Rheinsberg
2026-03-31 19:02 ` [RFC 07/16] bus1: add man-page David Rheinsberg
2026-04-01 16:30   ` Jonathan Corbet
2026-04-01 18:01     ` David Rheinsberg
2026-04-01 18:06       ` David Rheinsberg
2026-04-04 15:30   ` Thomas Meyer
2026-03-31 19:03 ` [RFC 08/16] bus1/util: add basic utilities David Rheinsberg
2026-03-31 19:35   ` Miguel Ojeda
2026-04-01 11:05     ` David Rheinsberg
2026-04-01 11:25       ` Miguel Ojeda
2026-03-31 19:03 ` [RFC 09/16] bus1/util: add field projections David Rheinsberg
2026-03-31 19:38   ` Miguel Ojeda
2026-03-31 19:03 ` David Rheinsberg [this message]
2026-03-31 19:44   ` [RFC 10/16] bus1/util: add IntoDeref/FromDeref Miguel Ojeda
2026-03-31 19:03 ` [RFC 11/16] bus1/util: add intrusive data-type helpers David Rheinsberg
2026-03-31 19:03 ` [RFC 12/16] bus1/util: add intrusive single linked lists David Rheinsberg
2026-03-31 19:03 ` [RFC 13/16] bus1/util: add intrusive rb-tree David Rheinsberg
2026-03-31 19:43   ` Miguel Ojeda
2026-03-31 19:03 ` [RFC 14/16] bus1/acct: add resouce accounting David Rheinsberg
2026-03-31 19:03 ` [RFC 15/16] bus1: introduce peers, handles, and nodes David Rheinsberg
2026-03-31 19:03 ` [RFC 16/16] bus1: implement the uapi David Rheinsberg
2026-03-31 19:46 ` [RFC 00/16] bus1: Capability-based IPC for Linux Miguel Ojeda

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260331190308.141622-11-david@readahead.eu \
    --to=david@readahead.eu \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=teg@jklm.no \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox