werkzeug/src/ptr.rs
2025-07-02 17:42:01 +02:00

159 lines
4.1 KiB
Rust

use core::{
cmp::Ordering,
fmt, hash,
marker::Send,
num::NonZero,
ops::{Deref, DerefMut},
ptr::NonNull,
};
#[repr(transparent)]
pub struct SendNonNull<T>(NonNull<T>);
impl<T> fmt::Debug for SendNonNull<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.as_ptr(), f)
}
}
impl<T> Copy for SendNonNull<T> {}
impl<T> Clone for SendNonNull<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Eq for SendNonNull<T> {}
impl<T> PartialEq for SendNonNull<T> {
fn eq(&self, other: &Self) -> bool {
self.as_ptr() == other.as_ptr()
}
}
impl<T> Ord for SendNonNull<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.as_ptr().cmp(&other.as_ptr())
}
}
impl<T> PartialOrd for SendNonNull<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.as_ptr().partial_cmp(&other.as_ptr())
}
}
impl<T> hash::Hash for SendNonNull<T> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.as_ptr().hash(state);
}
}
impl<T> From<NonNull<T>> for SendNonNull<T> {
fn from(ptr: NonNull<T>) -> Self {
Self(ptr)
}
}
impl<T> From<SendNonNull<T>> for NonNull<T> {
fn from(ptr: SendNonNull<T>) -> Self {
ptr.0
}
}
impl<T> From<&mut T> for SendNonNull<T> {
fn from(ptr: &mut T) -> Self {
Self(NonNull::from(ptr))
}
}
impl<T> From<&T> for SendNonNull<T> {
fn from(ptr: &T) -> Self {
Self(NonNull::from(ptr))
}
}
impl<T> fmt::Pointer for SendNonNull<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<NonNull<T> as fmt::Pointer>::fmt(&self.0, f)
}
}
unsafe impl<T> Send for SendNonNull<T> {}
impl<T> Deref for SendNonNull<T> {
type Target = NonNull<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for SendNonNull<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> SendNonNull<T> {
pub const fn new(ptr: *mut T) -> Option<Self> {
match NonNull::new(ptr) {
Some(ptr) => Some(Self(ptr)),
None => None,
}
}
pub const fn dangling() -> Self {
Self(NonNull::dangling())
}
pub const fn cast<U>(self) -> SendNonNull<U> {
SendNonNull(self.0.cast())
}
pub fn with_addr(self, addr: NonZero<usize>) -> Self {
// SAFETY: addr is non-zero, so the pointer is valid.
unsafe {
Self(NonNull::new_unchecked(
self.as_ptr().with_addr(addr.get()) as *mut _
))
}
}
pub fn map_addr(self, f: impl FnOnce(NonZero<usize>) -> NonZero<usize>) -> Self {
// SAFETY: addr is non-zero, so the pointer is valid.
self.with_addr(f(self.addr()))
}
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`
unsafe { Self(NonNull::new_unchecked(self.as_ptr().offset(offset))) }
}
pub unsafe fn byte_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`
unsafe { Self(NonNull::new_unchecked(self.as_ptr().byte_offset(offset))) }
}
pub unsafe fn add(self, count: usize) -> Self {
// SAFETY: self is a valid pointer, count is guaranteed to point to a valid memory location by the contract of `add`
unsafe { Self(NonNull::new_unchecked(self.as_ptr().add(count))) }
}
pub unsafe fn byte_add(self, count: usize) -> Self {
// SAFETY: self is a valid pointer, count is guaranteed to point to a valid memory location by the contract of `add`
unsafe { Self(NonNull::new_unchecked(self.as_ptr().byte_add(count))) }
}
pub const fn new_const(ptr: *const T) -> Option<Self> {
Self::new(ptr.cast_mut())
}
/// ptr must be non-null
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
// SAFETY: ptr must be non-null, which is guaranteed by the caller.
unsafe { Self(NonNull::new_unchecked(ptr)) }
}
}