use core::ffi::c_void;
use core::marker::PhantomData;
pub(crate) type AddressableSize = u64;
pub type TagType = u16;
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct TaggedPtr(u64);
impl TaggedPtr {
const ADDR_BITS: u32 = 49;
const ADDR_MASK: u64 = (1u64 << Self::ADDR_BITS) - 1;
const TAG_MASK: u16 = (1u16 << 15) - 1;
#[inline]
pub fn init<T>(ptr: *const T, data: TagType) -> TaggedPtr {
let address = ptr as usize;
TaggedPtr(
(address as u64 & Self::ADDR_MASK) | ((data as u64 & Self::TAG_MASK as u64) << Self::ADDR_BITS),
)
}
#[inline]
fn ptr_bits(self) -> AddressableSize {
self.0 & Self::ADDR_MASK
}
#[inline]
fn set_ptr_bits(&mut self, value: AddressableSize) {
self.0 = (self.0 & !Self::ADDR_MASK) | (value & Self::ADDR_MASK);
}
#[inline]
pub fn data(self) -> TagType {
(self.0 >> Self::ADDR_BITS) as TagType
}
#[inline]
pub fn get<Type>(self) -> *mut Type {
self.ptr_bits() as usize as *mut Type
}
#[inline]
pub fn to(self) -> *mut c_void {
self.0 as usize as *mut c_void
}
}
impl From<u64> for TaggedPtr {
#[inline]
fn from(val: u64) -> Self {
TaggedPtr(val)
}
}
impl From<i64> for TaggedPtr {
#[inline]
fn from(val: i64) -> Self {
TaggedPtr(val as u64)
}
}
impl From<f64> for TaggedPtr {
#[inline]
fn from(val: f64) -> Self {
TaggedPtr(val.to_bits())
}
}
impl From<*mut c_void> for TaggedPtr {
#[inline]
fn from(val: *mut c_void) -> Self {
TaggedPtr(val as usize as u64)
}
}
impl From<Option<*mut c_void>> for TaggedPtr {
#[inline]
fn from(val: Option<*mut c_void>) -> Self {
TaggedPtr(val.map_or(0, |p| p as usize as u64))
}
}
pub trait TypeList {
const LEN: usize;
const MIN_TAG: TagType;
const MAX_TAG: TagType = 1024;
fn type_name_from_tag(tag: TagType) -> Option<&'static str>;
}
pub trait UnionMember<Ts: TypeList> {
const TAG: TagType;
const NAME: &'static str;
}
#[macro_export]
macro_rules! impl_tagged_ptr_union {
($($T:ty),+ $(,)?) => {
impl $crate::tagged_pointer::TypeList for ($($T,)+) {
const LEN: usize = $crate::impl_tagged_ptr_union!(@count $($T),+);
const MIN_TAG: $crate::tagged_pointer::TagType =
1024 - (Self::LEN as $crate::tagged_pointer::TagType - 1);
fn type_name_from_tag(
tag: $crate::tagged_pointer::TagType,
) -> Option<&'static str> {
$crate::impl_tagged_ptr_union!(@names tag, 0, $($T),+);
None
}
}
$crate::impl_tagged_ptr_union!(@members ($($T,)+), 0, $($T),+);
};
(@count $H:ty $(, $T:ty)*) => { 1usize $(+ $crate::impl_tagged_ptr_union!(@count $T))* };
(@count) => { 0usize };
(@names $tag:ident, $i:expr, $H:ty $(, $T:ty)*) => {
if $tag == (1024 - $i) { return Some(::core::stringify!($H)); }
$crate::impl_tagged_ptr_union!(@names $tag, $i + 1, $($T),*);
};
(@names $tag:ident, $i:expr,) => {};
(@members $Ts:ty, $i:expr, $H:ty $(, $T:ty)*) => {
impl $crate::tagged_pointer::UnionMember<$Ts> for $H {
const TAG: $crate::tagged_pointer::TagType = 1024 - $i;
const NAME: &'static str = ::core::stringify!($H);
}
$crate::impl_tagged_ptr_union!(@members $Ts, $i + 1, $($T),*);
};
(@members $Ts:ty, $i:expr,) => {};
}
#[repr(transparent)]
pub struct TaggedPtrUnion<Ts: TypeList> {
pub repr: TaggedPtr,
_types: PhantomData<Ts>,
}
impl<Ts: TypeList> Clone for TaggedPtrUnion<Ts> {
fn clone(&self) -> Self {
*self
}
}
impl<Ts: TypeList> Copy for TaggedPtrUnion<Ts> {}
impl<Ts: TypeList> TaggedPtrUnion<Ts> {
pub const NULL: Self = Self {
repr: TaggedPtr(0),
_types: PhantomData,
};
pub fn clear(&mut self) {
*self = Self::NULL;
}
pub fn type_name_from_tag(the_tag: TagType) -> Option<&'static str> {
Ts::type_name_from_tag(the_tag)
}
pub fn type_name(self) -> Option<&'static str> {
Ts::type_name_from_tag(self.repr.data())
}
#[inline]
pub fn get<Type: UnionMember<Ts>>(self) -> Option<*mut Type> {
if self.is::<Type>() {
Some(self.as_unchecked::<Type>())
} else {
None
}
}
#[inline]
pub fn tag(self) -> TagType {
self.repr.data()
}
#[inline]
pub const fn case<Type: UnionMember<Ts>>() -> TagType {
Type::TAG
}
#[inline]
pub fn as_unchecked<Type: UnionMember<Ts>>(self) -> *mut Type {
self.repr.get::<Type>()
}
#[inline]
pub fn set_uintptr(&mut self, value: AddressableSize) {
self.repr.set_ptr_bits(value);
}
#[inline]
pub fn as_uintptr(self) -> AddressableSize {
self.repr.ptr_bits()
}
#[inline]
pub fn is<Type: UnionMember<Ts>>(self) -> bool {
self.repr.data() == Type::TAG
}
pub fn set<Type: UnionMember<Ts>>(&mut self, ptr: *const Type) {
*self = Self::init(ptr);
}
#[inline]
pub fn is_valid_ptr(ptr: Option<*mut c_void>) -> bool {
Self::from(ptr).is_valid()
}
#[inline]
pub fn is_valid(self) -> bool {
let d = self.repr.data();
d >= Ts::MIN_TAG && d <= Ts::MAX_TAG
}
#[inline]
pub fn from(ptr: Option<*mut c_void>) -> Self {
Self {
repr: TaggedPtr::from(ptr),
_types: PhantomData,
}
}
#[inline]
pub fn ptr(self) -> *mut c_void {
self.repr.to()
}
#[inline]
pub fn ptr_unsafe(self) -> *mut c_void {
self.repr.to()
}
#[inline]
pub fn init<Type: UnionMember<Ts>>(ptr: *const Type) -> Self {
Self::init_with_type::<Type>(ptr)
}
#[inline]
pub fn init_with_type<Type: UnionMember<Ts>>(ptr: *const Type) -> Self {
Self {
repr: TaggedPtr::init(ptr, Type::TAG),
_types: PhantomData,
}
}
#[inline]
pub fn is_null(self) -> bool {
self.repr.ptr_bits() == 0
}
}