unique ptr

This commit is contained in:
janis 2025-09-16 18:55:26 +02:00
parent 41f8763f18
commit a8cebcc805
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8

View file

@ -2,13 +2,17 @@ use core::{
cmp::Ordering, cmp::Ordering,
fmt, hash, fmt, hash,
marker::{PhantomData, Send}, marker::{PhantomData, Send},
mem, mem::{self, ManuallyDrop},
num::NonZero, num::NonZero,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
pin::Pin,
ptr::NonNull, ptr::NonNull,
sync::atomic::{self, AtomicPtr}, sync::atomic::{self, AtomicPtr},
}; };
/// This is a wrapper around `NonNull<T>` that is `Send` even if `T` is not
/// `Send`. This is useful for types that use `NonNull<T>` internally but are
/// safe to send to other threads.
#[repr(transparent)] #[repr(transparent)]
pub struct SendNonNull<T>(NonNull<T>); pub struct SendNonNull<T>(NonNull<T>);
@ -99,6 +103,7 @@ impl<T> DerefMut for SendNonNull<T> {
} }
impl<T> SendNonNull<T> { impl<T> SendNonNull<T> {
/// Creates a new `SendNonNull<T>` if `ptr` is non-null, otherwise returns `None`.
pub const fn new(ptr: *mut T) -> Option<Self> { pub const fn new(ptr: *mut T) -> Option<Self> {
match NonNull::new(ptr) { match NonNull::new(ptr) {
Some(ptr) => Some(Self(ptr)), Some(ptr) => Some(Self(ptr)),
@ -106,14 +111,17 @@ impl<T> SendNonNull<T> {
} }
} }
/// Creates a new `SendNonNull<T>` that is dangling.
pub const fn dangling() -> Self { pub const fn dangling() -> Self {
Self(NonNull::dangling()) Self(NonNull::dangling())
} }
/// Casts the pointer to a different type
pub const fn cast<U>(self) -> SendNonNull<U> { pub const fn cast<U>(self) -> SendNonNull<U> {
SendNonNull(self.0.cast()) SendNonNull(self.0.cast())
} }
/// Creates a new `SendNonNull<T>` with the given address, keeping the provenance of `self`.
pub fn with_addr(self, addr: NonZero<usize>) -> Self { pub fn with_addr(self, addr: NonZero<usize>) -> Self {
// SAFETY: addr is non-zero, so the pointer is valid. // SAFETY: addr is non-zero, so the pointer is valid.
unsafe { unsafe {
@ -123,11 +131,17 @@ impl<T> SendNonNull<T> {
} }
} }
/// Maps the address of the pointer using the given function, keeping the provenance of `self`.
pub fn map_addr(self, f: impl FnOnce(NonZero<usize>) -> NonZero<usize>) -> Self { pub fn map_addr(self, f: impl FnOnce(NonZero<usize>) -> NonZero<usize>) -> Self {
// SAFETY: addr is non-zero, so the pointer is valid. // SAFETY: addr is non-zero, so the pointer is valid.
self.with_addr(f(self.addr())) self.with_addr(f(self.addr()))
} }
/// Returns a new pointer, offset from `self` by `offset` elements.
///
/// # Safety
///
/// The caller must ensure that the resulting pointer points at the same allocation as `self`.
pub unsafe fn offset(self, offset: isize) -> Self { pub unsafe fn offset(self, offset: isize) -> Self {
// SAFETY: self is a valid pointer, offset is guaranteed to point to a valid memory location by the contract of `offset` // SAFETY: self is a valid pointer, offset is guaranteed to point to a valid memory location by the contract of `offset`
unsafe { Self(NonNull::new_unchecked(self.as_ptr().offset(offset))) } unsafe { Self(NonNull::new_unchecked(self.as_ptr().offset(offset))) }
@ -453,6 +467,85 @@ impl<T, const BITS: u8> TaggedAtomicPtr<T, BITS> {
} }
} }
#[repr(transparent)]
pub struct UniquePtr<'a, T> {
ptr: NonNull<T>,
_marker: PhantomData<&'a mut T>,
}
impl<'a, T> UniquePtr<'a, T> {
#[inline]
pub fn map<U, F>(value: T, f: F) -> U
where
F: FnOnce(UniquePtr<'_, T>) -> U,
{
let mut inner = ManuallyDrop::new(value);
let this = UniquePtr::new(&mut inner);
f(this)
}
pub fn new_pinned(inner: Pin<&'a mut ManuallyDrop<T>>) -> Pin<Self> {
// SAFETY: `inner` is pinned, so it must remain pinned for the lifetime of `Self`.
unsafe {
Pin::new_unchecked(Self {
ptr: NonNull::new_unchecked(core::mem::transmute::<_, _>(inner)),
_marker: PhantomData,
})
}
}
pub fn new(inner: &'a mut ManuallyDrop<T>) -> Self {
Self {
ptr: NonNull::from(&mut **inner),
_marker: PhantomData,
}
}
pub unsafe fn new_unchecked(ptr: *mut T) -> Self {
Self {
ptr: unsafe { NonNull::new_unchecked(ptr) },
_marker: PhantomData,
}
}
pub fn as_ptr(&self) -> *mut T {
self.ptr.as_ptr()
}
pub fn as_non_null(&self) -> NonNull<T> {
self.ptr
}
pub unsafe fn cast<U>(self) -> UniquePtr<'a, U> {
UniquePtr {
ptr: self.ptr.cast(),
_marker: PhantomData,
}
}
}
impl<'a, T> Deref for UniquePtr<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.ptr.as_ref() }
}
}
impl<'a, T> DerefMut for UniquePtr<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.ptr.as_mut() }
}
}
impl<'a, T> Drop for UniquePtr<'a, T> {
fn drop(&mut self) {
unsafe {
core::ptr::drop_in_place(&raw mut **self);
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use core::sync::atomic::Ordering; use core::sync::atomic::Ordering;