use core::marker::PhantomData;
pub struct PackedTaggedPtr<T>(PhantomData<fn() -> *mut T>);
impl<T> PackedTaggedPtr<T> {
#[cfg(target_pointer_width = "64")]
pub const PACKED_PTR_BITS: u32 = 48;
#[cfg(target_pointer_width = "64")]
pub const PTR_MASK: usize = (1usize << Self::PACKED_PTR_BITS) - 1;
#[cfg(target_pointer_width = "64")]
pub const TAG_MASK: usize = (1usize << (usize::BITS - Self::PACKED_PTR_BITS)) - 1;
#[inline(always)]
pub fn ptr(state: *mut T) -> *mut T {
#[cfg(target_pointer_width = "64")]
{
state.map_addr(|addr| addr & Self::PTR_MASK)
}
#[cfg(not(target_pointer_width = "64"))]
{
state
}
}
#[inline(always)]
pub fn tag(state: *mut T) -> usize {
#[cfg(target_pointer_width = "64")]
{
state.addr() >> Self::PACKED_PTR_BITS
}
#[cfg(not(target_pointer_width = "64"))]
{
let _ = state;
0
}
}
#[inline(always)]
pub fn tagged_successor(next: *mut T, current: *mut T) -> *mut T {
#[cfg(target_pointer_width = "64")]
{
let tag = (Self::tag(current) + 1) & Self::TAG_MASK;
next.map_addr(|addr| (tag << Self::PACKED_PTR_BITS) | (addr & Self::PTR_MASK))
}
#[cfg(not(target_pointer_width = "64"))]
{
let _ = current;
next
}
}
#[inline(always)]
pub fn checked_pack(addr: *mut T) -> Result<*mut T, &'static str> {
#[cfg(target_pointer_width = "64")]
{
if (addr.addr() & !Self::PTR_MASK) != 0 {
Err("packed head address does not fit in the 48-bit address field")
} else {
Ok(addr)
}
}
#[cfg(not(target_pointer_width = "64"))]
{
Ok(addr)
}
}
}