diff --git a/lib/tinyptr/src/ptr/mod.rs b/lib/tinyptr/src/ptr/mod.rs index 55e8033..4c42cec 100644 --- a/lib/tinyptr/src/ptr/mod.rs +++ b/lib/tinyptr/src/ptr/mod.rs @@ -5,3 +5,5 @@ mod const_ptr; pub use const_ptr::*; mod mut_ptr; pub use mut_ptr::*; +mod non_null; +pub use non_null::*; diff --git a/lib/tinyptr/src/ptr/non_null.rs b/lib/tinyptr/src/ptr/non_null.rs new file mode 100644 index 0000000..c178670 --- /dev/null +++ b/lib/tinyptr/src/ptr/non_null.rs @@ -0,0 +1,155 @@ +use core::{num::NonZeroU16, marker::{PhantomData, Unsize}, ops::CoerceUnsized, fmt, cmp::Ordering, hash}; + +use crate::Pointable; + +use super::MutPtr; + +/// `*mut T` but non-zero and covariant +pub struct NonNull { + pub(crate) ptr: NonZeroU16, + pub(crate) meta: ::PointerMetaTiny, + pub(crate) _marker: PhantomData> +} + +impl + Sized, const BASE: usize> NonNull { + /// Creates a dangling but well-aligned `NonNull` + pub const fn dangling() -> Self { + // SAFE: align_of is never 0 + unsafe { + Self::new_unchecked(MutPtr::from_raw_parts(core::mem::align_of::() as u16, ())) + } + } + // TODO: as_uninit_ref + // TODO: as_uninit_mut +} +impl NonNull { + pub const unsafe fn new_unchecked(ptr: MutPtr) -> Self { + NonNull { + ptr: NonZeroU16::new_unchecked(ptr.ptr), + meta: ptr.meta, + _marker: PhantomData + } + } + pub const fn new(ptr: MutPtr) -> Option { + if ptr.is_null() { + None + } else { + // SAFETY: Just checked for null + unsafe { + Some(Self::new_unchecked(ptr)) + } + } + } + pub const fn from_raw_parts( + data_address: NonNull<(), BASE>, + metadata: ::PointerMetaTiny + ) -> Self { + unsafe { + Self::new_unchecked(MutPtr::from_raw_parts(data_address.as_ptr().addr(), metadata)) + } + } + pub const fn to_raw_parts(self) -> (NonNull<(), BASE>, ::PointerMetaTiny) { + (self.cast(), self.meta) + } + pub const fn addr(self) -> NonZeroU16 { + self.ptr + } + pub const fn with_addr(self, addr: NonZeroU16) -> Self + where + T: Sized + { + Self { + ptr: addr, + meta: self.meta, + _marker: PhantomData + } + } + pub fn map_addr(self, f: impl FnOnce(NonZeroU16) -> NonZeroU16) -> Self + where T: Sized + { + self.with_addr(f(self.addr())) + } + pub const fn as_ptr(self) -> MutPtr { + MutPtr::from_raw_parts(self.ptr.get(), self.meta) + } + // TODO: as_ref + // TODO: as_mut + pub const fn cast(self) -> NonNull + where U: Pointable + { + NonNull { + ptr: self.ptr, + meta: (), + _marker: PhantomData + } + } +} + +impl, const BASE: usize> NonNull<[T], BASE> { + pub const fn slice_from_raw_parts(data: NonNull, len: u16) -> Self { + Self { + ptr: data.ptr, + meta: len, + _marker: PhantomData + } + } + pub const fn len(self) -> u16 { + self.meta + } + pub const fn as_non_null_ptr(self) -> NonNull { + NonNull { + ptr: self.ptr, + meta: (), + _marker: PhantomData + } + } + pub const fn as_mut_ptr(self) -> MutPtr { + self.as_non_null_ptr().as_ptr() + } + // TODO: as_uninit_slice + // TODO: as_uninit_slice_mut +} + +impl Clone for NonNull { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for NonNull {} +impl CoerceUnsized> for NonNull where T: Unsize, ::PointerMetaTiny: CoerceUnsized<::PointerMetaTiny> {} + +impl fmt::Debug for NonNull { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&self.as_ptr(), f) + } +} +impl fmt::Pointer for NonNull { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&self.as_ptr(), f) + } +} +impl Eq for NonNull {} +impl PartialEq for NonNull { + fn eq(&self, other: &Self) -> bool { + self.as_ptr() == other.as_ptr() + } +} +impl Ord for NonNull { + fn cmp(&self, other: &Self) -> Ordering { + self.as_ptr().cmp(&other.as_ptr()) + } +} +impl PartialOrd for NonNull { + fn partial_cmp(&self, other: &Self) -> Option { + self.as_ptr().partial_cmp(&other.as_ptr()) + } +} +impl hash::Hash for NonNull { + fn hash(&self, state: &mut H) { + self.as_ptr().hash(state) + } +} +// TODO: From> +// TODO: From> +// TODO: From>