From: Danilo Krummrich <dakr@kernel.org>
To: ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com,
boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com,
benno.lossin@proton.me, a.hindborg@samsung.com,
aliceryhl@google.com, akpm@linux-foundation.org
Cc: daniel.almeida@collabora.com, faith.ekstrand@collabora.com,
boris.brezillon@collabora.com, lina@asahilina.net,
mcanal@igalia.com, zhiw@nvidia.com, acurrid@nvidia.com,
cjia@nvidia.com, jhubbard@nvidia.com, airlied@redhat.com,
ajanulgu@redhat.com, lyude@redhat.com,
linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
linux-mm@kvack.org, Danilo Krummrich <dakr@kernel.org>
Subject: [PATCH v3 08/25] rust: types: implement `Unique<T>`
Date: Thu, 1 Aug 2024 02:02:07 +0200 [thread overview]
Message-ID: <20240801000641.1882-9-dakr@kernel.org> (raw)
In-Reply-To: <20240801000641.1882-1-dakr@kernel.org>
Implement the `Unique` type as a prerequisite for `Box` and `Vec`
introduced in subsequent patches.
`Unique` serves as wrapper around a `NonNull`, but indicates that the
possessor of this wrapper owns the referent.
This type already exists in Rust's core library, but, unfortunately, is
exposed as unstable API and hence shouldn't be used in the kernel.
This implementation of `Unique` is almost identical, but mostly stripped
down to the functionality we need for `Box` and `Vec`. Additionally, all
unstable features are removed and / or replaced by stable ones.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
rust/kernel/types.rs | 183 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 183 insertions(+)
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index bd189d646adb..7cf89067b5fc 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -473,3 +473,186 @@ unsafe impl AsBytes for str {}
// does not have any uninitialized portions either.
unsafe impl<T: AsBytes> AsBytes for [T] {}
unsafe impl<T: AsBytes, const N: usize> AsBytes for [T; N] {}
+
+/// A wrapper around a raw non-null `*mut T` that indicates that the possessor
+/// of this wrapper owns the referent. Useful for building abstractions like
+/// `Box<T>`, `Vec<T>`, `String`, and `HashMap<K, V>`.
+///
+/// Unlike `*mut T`, `Unique<T>` behaves "as if" it were an instance of `T`.
+/// It implements `Send`/`Sync` if `T` is `Send`/`Sync`. It also implies
+/// the kind of strong aliasing guarantees an instance of `T` can expect:
+/// the referent of the pointer should not be modified without a unique path to
+/// its owning Unique.
+///
+/// If you're uncertain of whether it's correct to use `Unique` for your purposes,
+/// consider using `NonNull`, which has weaker semantics.
+///
+/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer
+/// is never dereferenced. This is so that enums may use this forbidden value
+/// as a discriminant -- `Option<Unique<T>>` has the same size as `Unique<T>`.
+/// However the pointer may still dangle if it isn't dereferenced.
+///
+/// Unlike `*mut T`, `Unique<T>` is covariant over `T`. This should always be correct
+/// for any type which upholds Unique's aliasing requirements.
+#[repr(transparent)]
+pub struct Unique<T: ?Sized> {
+ pointer: NonNull<T>,
+ // NOTE: this marker has no consequences for variance, but is necessary
+ // for dropck to understand that we logically own a `T`.
+ //
+ // For details, see:
+ // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data
+ _marker: PhantomData<T>,
+}
+
+/// `Unique` pointers are `Send` if `T` is `Send` because the data they
+/// reference is unaliased. Note that this aliasing invariant is
+/// unenforced by the type system; the abstraction using the
+/// `Unique` must enforce it.
+unsafe impl<T: Send + ?Sized> Send for Unique<T> {}
+
+/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they
+/// reference is unaliased. Note that this aliasing invariant is
+/// unenforced by the type system; the abstraction using the
+/// `Unique` must enforce it.
+unsafe impl<T: Sync + ?Sized> Sync for Unique<T> {}
+
+impl<T: Sized> Unique<T> {
+ /// Creates a new `Unique` that is dangling, but well-aligned.
+ ///
+ /// This is useful for initializing types which lazily allocate, like
+ /// `Vec::new` does.
+ ///
+ /// Note that the pointer value may potentially represent a valid pointer to
+ /// a `T`, which means this must not be used as a "not yet initialized"
+ /// sentinel value. Types that lazily allocate must track initialization by
+ /// some other means.
+ #[must_use]
+ #[inline]
+ pub const fn dangling() -> Self {
+ Unique {
+ pointer: NonNull::dangling(),
+ _marker: PhantomData,
+ }
+ }
+}
+
+impl<T: ?Sized> Unique<T> {
+ /// Creates a new `Unique`.
+ ///
+ /// # Safety
+ ///
+ /// `ptr` must be non-null.
+ #[inline]
+ pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
+ // SAFETY: the caller must guarantee that `ptr` is non-null.
+ unsafe {
+ Unique {
+ pointer: NonNull::new_unchecked(ptr),
+ _marker: PhantomData,
+ }
+ }
+ }
+
+ /// Creates a new `Unique` if `ptr` is non-null.
+ #[allow(clippy::manual_map)]
+ #[inline]
+ pub fn new(ptr: *mut T) -> Option<Self> {
+ if let Some(pointer) = NonNull::new(ptr) {
+ Some(Unique {
+ pointer,
+ _marker: PhantomData,
+ })
+ } else {
+ None
+ }
+ }
+
+ /// Acquires the underlying `*mut` pointer.
+ #[must_use = "`self` will be dropped if the result is not used"]
+ #[inline]
+ pub const fn as_ptr(self) -> *mut T {
+ self.pointer.as_ptr()
+ }
+
+ /// Dereferences the content.
+ ///
+ /// The resulting lifetime is bound to self so this behaves "as if"
+ /// it were actually an instance of T that is getting borrowed. If a longer
+ /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`.
+ ///
+ /// # Safety
+ ///
+ /// Safety requirements for this function are inherited from [NonNull::as_ref].
+ ///
+ #[must_use]
+ #[inline]
+ pub const unsafe fn as_ref(&self) -> &T {
+ // SAFETY: the caller must guarantee that `self` meets all the
+ // requirements for a reference.
+ unsafe { self.pointer.as_ref() }
+ }
+
+ /// Mutably dereferences the content.
+ ///
+ /// The resulting lifetime is bound to self so this behaves "as if"
+ /// it were actually an instance of T that is getting borrowed. If a longer
+ /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`.
+ ///
+ /// # Safety
+ ///
+ /// Safety requirements for this function are inherited from [NonNull::as_mut].
+ #[must_use]
+ #[inline]
+ pub unsafe fn as_mut(&mut self) -> &mut T {
+ // SAFETY: the caller must guarantee that `self` meets all the
+ // requirements for a mutable reference.
+ unsafe { self.pointer.as_mut() }
+ }
+
+ /// Casts to a pointer of another type.
+ #[must_use = "`self` will be dropped if the result is not used"]
+ #[inline]
+ pub fn cast<U>(self) -> Unique<U> {
+ Unique::from(self.pointer.cast())
+ }
+
+ /// Acquires the underlying `*mut` pointer.
+ #[must_use = "`self` will be dropped if the result is not used"]
+ #[inline]
+ pub const fn as_non_null(self) -> NonNull<T> {
+ self.pointer
+ }
+}
+
+impl<T: ?Sized> Clone for Unique<T> {
+ #[inline]
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<T: ?Sized> Copy for Unique<T> {}
+
+impl<T: ?Sized> From<&mut T> for Unique<T> {
+ /// Converts a `&mut T` to a `Unique<T>`.
+ ///
+ /// This conversion is infallible since references cannot be null.
+ #[inline]
+ fn from(reference: &mut T) -> Self {
+ Self::from(NonNull::from(reference))
+ }
+}
+
+impl<T: ?Sized> From<NonNull<T>> for Unique<T> {
+ /// Converts a `NonNull<T>` to a `Unique<T>`.
+ ///
+ /// This conversion is infallible since `NonNull` cannot be null.
+ #[inline]
+ fn from(pointer: NonNull<T>) -> Self {
+ Unique {
+ pointer,
+ _marker: PhantomData,
+ }
+ }
+}
--
2.45.2
next prev parent reply other threads:[~2024-08-01 0:07 UTC|newest]
Thread overview: 66+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-01 0:01 [PATCH v3 00/25] Generic `Allocator` support for Rust Danilo Krummrich
2024-08-01 0:02 ` [PATCH v3 01/25] rust: alloc: add `Allocator` trait Danilo Krummrich
2024-08-01 8:19 ` Alice Ryhl
2024-08-01 12:26 ` Danilo Krummrich
2024-08-01 14:25 ` Alice Ryhl
2024-08-01 15:09 ` Danilo Krummrich
2024-08-04 6:21 ` Boqun Feng
2024-08-04 12:29 ` Danilo Krummrich
2024-08-01 0:02 ` [PATCH v3 02/25] rust: alloc: separate `aligned_size` from `krealloc_aligned` Danilo Krummrich
2024-08-01 8:21 ` Alice Ryhl
2024-08-01 0:02 ` [PATCH v3 03/25] rust: alloc: rename `KernelAllocator` to `Kmalloc` Danilo Krummrich
2024-08-01 8:21 ` Alice Ryhl
2024-08-01 0:02 ` [PATCH v3 04/25] rust: alloc: implement `Allocator` for `Kmalloc` Danilo Krummrich
2024-08-01 8:28 ` Alice Ryhl
2024-08-01 12:30 ` Danilo Krummrich
2024-08-01 0:02 ` [PATCH v3 05/25] rust: alloc: add module `allocator_test` Danilo Krummrich
2024-08-01 8:41 ` Alice Ryhl
2024-08-01 0:02 ` [PATCH v3 06/25] rust: alloc: implement `Vmalloc` allocator Danilo Krummrich
2024-08-01 8:43 ` Alice Ryhl
2024-08-04 6:44 ` Boqun Feng
2024-08-04 12:41 ` Danilo Krummrich
2024-08-04 15:16 ` Danilo Krummrich
2024-08-04 17:39 ` Danilo Krummrich
2024-08-04 23:57 ` Boqun Feng
2024-08-05 0:54 ` Danilo Krummrich
2024-08-01 0:02 ` [PATCH v3 07/25] rust: alloc: implement `KVmalloc` allocator Danilo Krummrich
2024-08-01 8:43 ` Alice Ryhl
2024-08-01 12:31 ` Danilo Krummrich
2024-08-01 0:02 ` Danilo Krummrich [this message]
2024-08-01 8:45 ` [PATCH v3 08/25] rust: types: implement `Unique<T>` Alice Ryhl
2024-08-04 6:54 ` Boqun Feng
2024-08-01 0:02 ` [PATCH v3 09/25] rust: alloc: implement kernel `Box` Danilo Krummrich
2024-08-01 8:55 ` Alice Ryhl
2024-08-01 12:45 ` Danilo Krummrich
2024-08-01 12:48 ` Alice Ryhl
2024-08-01 0:02 ` [PATCH v3 10/25] rust: treewide: switch to our kernel `Box` type Danilo Krummrich
2024-08-01 0:02 ` [PATCH v3 11/25] rust: alloc: remove `BoxExt` extension Danilo Krummrich
2024-08-01 14:53 ` Alice Ryhl
2024-08-01 0:02 ` [PATCH v3 12/25] rust: alloc: add `Box` to prelude Danilo Krummrich
2024-08-01 14:54 ` Alice Ryhl
2024-08-01 0:02 ` [PATCH v3 13/25] rust: alloc: import kernel `Box` type in types.rs Danilo Krummrich
2024-08-01 14:54 ` Alice Ryhl
2024-08-01 0:02 ` [PATCH v3 14/25] rust: alloc: import kernel `Box` type in init.rs Danilo Krummrich
2024-08-01 14:55 ` Alice Ryhl
2024-08-01 0:02 ` [PATCH v3 15/25] rust: alloc: implement kernel `Vec` type Danilo Krummrich
2024-08-01 15:05 ` Alice Ryhl
2024-08-01 15:27 ` Danilo Krummrich
2024-08-01 15:31 ` Alice Ryhl
2024-08-01 15:46 ` Danilo Krummrich
2024-08-01 0:02 ` [PATCH v3 16/25] rust: alloc: implement `IntoIterator` for `Vec` Danilo Krummrich
2024-08-01 15:07 ` Alice Ryhl
2024-08-01 15:30 ` Danilo Krummrich
2024-08-01 0:02 ` [PATCH v3 17/25] rust: alloc: implement `collect` for `IntoIter` Danilo Krummrich
2024-08-01 15:10 ` Alice Ryhl
2024-08-01 15:37 ` Danilo Krummrich
2024-08-02 7:08 ` Alice Ryhl
2024-08-02 12:02 ` Danilo Krummrich
2024-08-02 12:08 ` Alice Ryhl
2024-08-01 0:02 ` [PATCH v3 18/25] rust: treewide: switch to the kernel `Vec` type Danilo Krummrich
2024-08-01 0:02 ` [PATCH v3 19/25] rust: alloc: remove `VecExt` extension Danilo Krummrich
2024-08-01 0:02 ` [PATCH v3 20/25] rust: alloc: add `Vec` to prelude Danilo Krummrich
2024-08-01 0:02 ` [PATCH v3 21/25] rust: alloc: remove `GlobalAlloc` and `krealloc_aligned` Danilo Krummrich
2024-08-01 0:02 ` [PATCH v3 22/25] rust: error: use `core::alloc::LayoutError` Danilo Krummrich
2024-08-01 0:02 ` [PATCH v3 23/25] rust: str: test: replace `alloc::format` Danilo Krummrich
2024-08-01 0:02 ` [PATCH v3 24/25] rust: alloc: update module comment of alloc.rs Danilo Krummrich
2024-08-01 0:02 ` [PATCH v3 25/25] kbuild: rust: remove the `alloc` crate Danilo Krummrich
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=20240801000641.1882-9-dakr@kernel.org \
--to=dakr@kernel.org \
--cc=a.hindborg@samsung.com \
--cc=acurrid@nvidia.com \
--cc=airlied@redhat.com \
--cc=ajanulgu@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=benno.lossin@proton.me \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=boris.brezillon@collabora.com \
--cc=cjia@nvidia.com \
--cc=daniel.almeida@collabora.com \
--cc=faith.ekstrand@collabora.com \
--cc=gary@garyguo.net \
--cc=jhubbard@nvidia.com \
--cc=lina@asahilina.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=lyude@redhat.com \
--cc=mcanal@igalia.com \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=wedsonaf@gmail.com \
--cc=zhiw@nvidia.com \
/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;
as well as URLs for NNTP newsgroup(s).