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
next prev 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