use super::{alignment, mask, messages};
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
use core::ptr::NonNull;
#[repr(transparent)]
pub struct PtrImpl<T, const BITS: usize>(NonNull<u8>, PhantomData<NonNull<T>>);
impl<T, const BITS: usize> PtrImpl<T, BITS> {
pub fn new(ptr: NonNull<T>, tag: usize) -> Self {
let ptr = ptr.as_ptr();
let tag = tag & mask(BITS);
let offset = ptr.align_offset(alignment(BITS));
assert!(offset != usize::MAX, "{}", messages::ALIGN_OFFSET_FAILED);
assert!(offset & mask(BITS) == 0, "`ptr` is not aligned enough");
Self(
NonNull::new(ptr.cast::<u8>().wrapping_add(tag))
.expect(messages::WRAPPED_TO_NULL),
PhantomData,
)
}
pub fn get(self) -> (NonNull<T>, usize) {
let ptr = self.0.as_ptr();
let offset = ptr.align_offset(alignment(BITS));
assert!(offset != usize::MAX, "{}", messages::ALIGN_OFFSET_FAILED);
let tag = alignment(BITS).wrapping_sub(offset) & mask(BITS);
let ptr = ptr.wrapping_sub(tag).cast::<T>();
debug_assert!(!ptr.is_null());
(unsafe { NonNull::new_unchecked(ptr) }, tag)
}
}
impl<T, const BITS: usize> Clone for PtrImpl<T, BITS> {
fn clone(&self) -> Self {
Self(self.0, self.1)
}
}
impl<T, const BITS: usize> PartialEq for PtrImpl<T, BITS> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T, const BITS: usize> Ord for PtrImpl<T, BITS> {
fn cmp(&self, other: &Self) -> Ordering {
self.0.cmp(&other.0)
}
}
impl<T, const BITS: usize> Hash for PtrImpl<T, BITS> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}