unique ptr
This commit is contained in:
parent
41f8763f18
commit
a8cebcc805
95
src/ptr.rs
95
src/ptr.rs
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue