use core::fmt;
use core::mem;
use core::mem::MaybeUninit;
use core::ptr;
use crate::offset;
use crate::offset::Offset;
use crate::NonNull;
#[repr(transparent)]
pub struct Ptr<T: ?Sized> {
p: *mut T,
}
impl<T: ?Sized> PartialEq<Ptr<T>> for Ptr<T> {
fn eq(&self, other: &Ptr<T>) -> bool {
self.p == other.p
}
}
impl<T: ?Sized> PartialEq<NonNull<T>> for Ptr<T> {
fn eq(&self, other: &NonNull<T>) -> bool {
self.p == other.to_raw()
}
}
impl<T: ?Sized> Eq for Ptr<T> {}
impl<T: ?Sized> Clone for Ptr<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> Copy for Ptr<T> {}
impl<T: ?Sized> fmt::Debug for Ptr<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.p, f)
}
}
impl<T: ?Sized> fmt::Pointer for Ptr<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Pointer::fmt(&self.p, f)
}
}
impl<T: ?Sized> From<&T> for Ptr<T> {
fn from(value: &T) -> Self {
Self::new(value as *const T as *mut T)
}
}
impl<T: ?Sized> From<&mut T> for Ptr<T> {
fn from(value: &mut T) -> Self {
Self::new(value)
}
}
impl<T: ?Sized> From<*const T> for Ptr<T> {
fn from(value: *const T) -> Self {
Self::new(value as *mut T)
}
}
impl<T: ?Sized> From<*mut T> for Ptr<T> {
fn from(value: *mut T) -> Self {
Self::new(value)
}
}
impl<T: ?Sized> From<ptr::NonNull<T>> for Ptr<T> {
fn from(value: ptr::NonNull<T>) -> Self {
Self::new(value.as_ptr())
}
}
impl<T: ?Sized> From<NonNull<T>> for Ptr<T> {
fn from(value: NonNull<T>) -> Self {
Self::new(value.to_raw())
}
}
impl<T: ?Sized> From<Ptr<T>> for *const T {
fn from(value: Ptr<T>) -> Self {
value.to_raw()
}
}
impl<T: ?Sized> From<Ptr<T>> for *mut T {
fn from(value: Ptr<T>) -> Self {
value.to_raw()
}
}
impl<T: ?Sized> Ptr<T> {
pub const fn new(ptr: *mut T) -> Self {
Ptr { p: ptr }
}
pub const fn new_from_ref(ptr: &T) -> Self {
Ptr {
p: ptr as *const T as *mut T,
}
}
pub const fn is_null(self) -> bool {
unsafe { mem::transmute::<*mut T, Option<NonNull<T>>>(self.p) }.is_none()
}
pub const fn to_raw(self) -> *mut T {
self.p
}
pub fn addr(self) -> usize {
self.p as *mut u8 as usize
}
pub fn expose_addr(self) -> usize {
self.p as *mut u8 as usize
}
pub const fn to_non_null(self) -> Option<NonNull<T>> {
if self.is_null() {
return None;
}
unsafe { Some(self.to_non_null_unchecked()) }
}
pub const unsafe fn to_non_null_unchecked(self) -> NonNull<T> {
debug_assert!(
!self.is_null(),
"attempted to convert a null pointer to NonNull<T>"
);
NonNull::new(ptr::NonNull::new_unchecked(self.p))
}
pub const fn cast<U>(self) -> Ptr<U> {
Ptr {
p: self.p as *mut U,
}
}
pub const unsafe fn deref(&self) -> &T {
self.deref_unbound()
}
pub const unsafe fn deref_unbound<'a>(self) -> &'a T {
if cfg!(debug_assertions) {
match mem::transmute::<*mut T, Option<&T>>(self.p) {
Some(r) => return r,
None => panic!("attempted to deref null pointer"),
}
}
&*(self.p as *const T)
}
#[allow(clippy::mut_from_ref)]
pub unsafe fn deref_mut(&self) -> &mut T {
self.deref_mut_unbound()
}
pub unsafe fn deref_mut_unbound<'a>(self) -> &'a mut T {
debug_assert!(!self.is_null(), "attempted to deref null pointer");
&mut *self.p
}
pub unsafe fn destroy(self) {
debug_assert!(!self.is_null(), "attempted to destroy null pointer");
self.p.drop_in_place()
}
}
impl<T> Ptr<T> {
pub const fn null() -> Self {
Ptr::invalid(0)
}
pub const fn dangling() -> Self {
Ptr::invalid(mem::align_of::<T>())
}
pub const fn invalid(addr: usize) -> Self {
Ptr { p: addr as *mut T }
}
pub const fn from_exposed_addr(addr: usize) -> Self {
Ptr { p: addr as *mut T }
}
pub fn with_addr(self, addr: usize) -> Ptr<T> {
let off = (addr as isize).wrapping_sub(self.addr() as isize);
unsafe { self.at(offset::NotInBounds(offset::ByteOffset(off))) }
}
pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self {
self.with_addr(f(self.addr()))
}
pub fn is_aligned(self) -> bool {
self.misalignment() == 0
}
pub(crate) const fn is_aligned_const_for_assertions(self) -> bool {
crate::is_aligned_const_for_assertions(self.p)
}
pub fn misalignment(self) -> usize {
let mask = mem::align_of::<T>() - 1;
self.addr() & mask
}
pub fn align_down(self) -> Self {
let mask = mem::align_of::<T>() - 1;
self.map_addr(|a| a & !mask)
}
pub fn align_up(self) -> Self {
let mask = mem::align_of::<T>() - 1;
self.map_addr(|a| (a + mask) & !mask)
}
pub unsafe fn at<U>(self, offset: impl Offset<T, U>) -> Ptr<U> {
self.at_raw(offset.measure()).cast::<U>()
}
pub const unsafe fn at_raw(self, offset: offset::Measurement) -> Ptr<T> {
Ptr {
p: offset.apply(self.p),
}
}
pub fn to_slice(self, len: usize) -> Ptr<[T]> {
Ptr {
p: ptr::slice_from_raw_parts_mut(self.p, len),
}
}
pub const fn to_uninit(self) -> Ptr<MaybeUninit<T>> {
self.cast()
}
pub unsafe fn read(self) -> T {
debug_assert!(!self.is_null(), "attempted to read null pointer");
debug_assert!(
self.is_aligned_const_for_assertions(),
"attempted to read misaligned pointer {self:?}"
);
self.p.read()
}
pub unsafe fn read_at<U>(self, idx: impl Offset<T, U>) -> U {
self.at(idx).read()
}
pub unsafe fn write(self, val: T) {
debug_assert!(!self.is_null(), "attempted to write to null pointer");
debug_assert!(
self.is_aligned_const_for_assertions(),
"attempted to write to misaligned pointer {self:?}"
);
self.p.write(val)
}
pub unsafe fn write_at<U>(self, idx: impl Offset<T, U>, val: U) {
self.at(idx).write(val)
}
pub unsafe fn clear_to_zero(self) {
self.p.write_bytes(0, 1)
}
pub unsafe fn clear_to_zero_at<U>(self, idx: impl Offset<T, U>) {
self.at(idx).clear_to_zero()
}
pub unsafe fn destroy_at<U>(self, idx: impl Offset<T, U>) {
self.at(idx).destroy()
}
pub unsafe fn replace(self, val: T) -> T {
let x = self.read();
self.write(val);
x
}
pub unsafe fn replace_at<U>(self, idx: impl Offset<T, U>, val: U) -> U {
self.at(idx).replace(val)
}
pub unsafe fn deref_at<U>(&self, idx: impl Offset<T, U>) -> &U {
self.at(idx).deref_unbound()
}
pub unsafe fn deref_unbound_at<'a, U>(self, idx: impl Offset<T, U>) -> &'a U {
self.at(idx).deref_unbound()
}
#[allow(clippy::mut_from_ref)]
pub unsafe fn deref_mut_at<U>(&self, idx: impl Offset<T, U>) -> &mut U {
self.at(idx).deref_mut_unbound()
}
pub unsafe fn deref_mut_unbound_at<'a, U>(
self,
idx: impl Offset<T, U>,
) -> &'a mut U {
self.at(idx).deref_mut_unbound()
}
}
impl<T> Ptr<[T]> {
pub const fn element(self) -> Ptr<T> {
self.cast::<T>()
}
}
impl<T, const N: usize> Ptr<[T; N]> {
pub const fn element(self) -> Ptr<T> {
self.cast::<T>()
}
}