use crate::{Bits, TaggedPtr};
use core::marker::PhantomData;
macro_rules! impl_explicit_tagged_ref_common {
($name:ident $(,)?) => {
impl<T, const BITS: Bits> $name<'_, T, BITS> {
pub const BITS: u32 = BITS as _;
pub const MAX_TAG: usize = max_tag::<T, BITS>();
}
};
}
const fn max_tag<T, const BITS: Bits>() -> usize {
TaggedPtr::<T, BITS>::MAX_TAG
}
macro_rules! impl_tagged_ref_shared_mut_common {
(
$name:ident,
[$($ty_params:tt)*],
[$($ty_args:tt)*] $(,)?
) => { const _: () = {
use core::cmp::Ordering;
use core::fmt::{self, Debug};
use core::hash::{Hash, Hasher};
impl<$($ty_params)*> Eq for $name<'_, $($ty_args)*>
where
T: Eq,
{
}
impl<$($ty_params)*> PartialEq for $name<'_, $($ty_args)*>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.get() == other.get()
}
}
impl<$($ty_params)*> Ord for $name<'_, $($ty_args)*>
where
T: Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
self.get().cmp(&other.get())
}
}
impl<$($ty_params)*> PartialOrd for $name<'_, $($ty_args)*>
where
T: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.get().partial_cmp(&other.get())
}
}
impl<$($ty_params)*> Hash for $name<'_, $($ty_args)*>
where
T: Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.get().hash(state)
}
}
impl<$($ty_params)*> AsRef<T> for $name<'_, $($ty_args)*> {
fn as_ref(&self) -> &T {
self.get_ref()
}
}
impl<$($ty_params)*> Debug for $name<'_, $($ty_args)*>
where
T: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (r, tag) = self.get();
f.debug_struct(stringify!($name))
.field("data", r)
.field("tag", &tag)
.finish()
}
}
impl<$($ty_params)*> fmt::Pointer for $name<'_, $($ty_args)*> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:p}", self.get_ref())
}
}
}; };
}
with_bits_doc! {
#[repr(transparent)]
pub struct TaggedRef<'a, T, const BITS: Bits>(
TaggedPtr<T, BITS>,
PhantomData<&'a T>,
);
}
impl<'a, T, const BITS: Bits> TaggedRef<'a, T, BITS> {
pub fn new(reference: &'a T, tag: usize) -> Self {
Self::new_impl(reference, tag)
}
}
macro_rules! impl_tagged_ref_common {
(
[$($ty_params:tt)*],
[$($ty_args:tt)*],
$doctest_context:literal $(,)?
) => {
const _: () = {
use core::marker::PhantomData;
impl<'a, $($ty_params)*> TaggedRef<'a, $($ty_args)*> {
impl_tagged_ref_common!(
impl methods,
[$($ty_args)*],
$doctest_context,
);
}
};
impl<$($ty_params)*> Clone for TaggedRef<'_, $($ty_args)*> {
fn clone(&self) -> Self {
*self
}
}
impl<$($ty_params)*> Copy for TaggedRef<'_, $($ty_args)*> {}
unsafe impl<$($ty_params)*> Sync for TaggedRef<'_, $($ty_args)*>
where
T: Sync,
{
}
unsafe impl<$($ty_params)*> Send for TaggedRef<'_, $($ty_args)*>
where
T: Sync,
{
}
impl_tagged_ref_shared_mut_common!(
TaggedRef,
[$($ty_params)*],
[$($ty_args)*],
);
};
(impl methods, [$($ty_args:tt)*], $doctest_context:literal $(,)?) => {
fn new_impl(reference: &'a T, tag: usize) -> Self {
let tag = tag & Self::MAX_TAG;
unsafe { Self::new_unchecked(reference, tag) }
}
pub unsafe fn new_unchecked(reference: &'a T, tag: usize) -> Self {
let ptr = reference.into();
let tp = unsafe {
TaggedPtr::new_unchecked_dereferenceable(ptr, tag)
};
Self(tp, PhantomData)
}
pub fn get(self) -> (&'a T, usize) {
let (ptr, tag) = self.0.get();
(unsafe { &*ptr.as_ptr() }, tag)
}
pub fn get_ref(self) -> &'a T {
self.get().0
}
#[doc = $doctest_context]
pub fn set_ref(&mut self, reference: &'a T) {
*self = self.with_ref(reference);
}
#[doc = $doctest_context]
pub fn with_ref(
self,
reference: &T,
) -> TaggedRef<'_, $($ty_args)*> {
TaggedRef::new(reference, self.tag())
}
pub fn tag(self) -> usize {
self.get().1
}
#[doc = $doctest_context]
pub fn set_tag(&mut self, tag: usize) {
*self = Self::new(self.get_ref(), tag);
}
};
}
impl_explicit_tagged_ref_common!(TaggedRef);
impl_tagged_ref_common!(
[T, const BITS: Bits],
[T, BITS],
"# type TaggedRef<'a, T> = tagged_pointer::TaggedRef<'a, T, 0>;",
);
with_bits_doc! {
#[repr(transparent)]
pub struct TaggedMutRef<'a, T, const BITS: Bits>(
TaggedPtr<T, BITS>,
PhantomData<&'a mut T>,
);
}
impl<'a, T, const BITS: Bits> TaggedMutRef<'a, T, BITS> {
pub fn new(reference: &'a mut T, tag: usize) -> Self {
Self::new_impl(reference, tag)
}
}
macro_rules! impl_tagged_mut_ref_common {
(
[$($ty_params:tt)*],
[$($ty_args:tt)*],
$doctest_context:literal $(,)?
) => {
const _: () = {
use core::marker::PhantomData;
use core::ptr;
impl<'a, $($ty_params)*> TaggedMutRef<'a, $($ty_args)*> {
impl_tagged_mut_ref_common!(
impl methods,
[$($ty_args)*],
$doctest_context,
);
}
};
impl<$($ty_params)*> AsMut<T> for TaggedMutRef<'_, $($ty_args)*> {
fn as_mut(&mut self) -> &mut T {
self.get_mut_ref()
}
}
unsafe impl<$($ty_params)*> Sync for TaggedMutRef<'_, $($ty_args)*>
where
T: Sync,
{
}
unsafe impl<$($ty_params)*> Send for TaggedMutRef<'_, $($ty_args)*>
where
T: Send,
{
}
impl_tagged_ref_shared_mut_common!(
TaggedMutRef,
[$($ty_params)*],
[$($ty_args)*],
);
};
(impl methods, [$($ty_args:tt)*], $doctest_context:literal $(,)?) => {
fn new_impl(reference: &'a mut T, tag: usize) -> Self {
let tag = tag & Self::MAX_TAG;
unsafe { Self::new_unchecked(reference, tag) }
}
pub unsafe fn new_unchecked(reference: &'a mut T, tag: usize) -> Self {
let ptr = reference.into();
let tp = unsafe {
TaggedPtr::new_unchecked_dereferenceable(ptr, tag)
};
Self(tp, PhantomData)
}
pub fn to_tagged_ref(&self) -> TaggedRef<'_, $($ty_args)*> {
TaggedRef(self.0, PhantomData)
}
pub fn into_tagged_ref(self) -> TaggedRef<'a, $($ty_args)*> {
TaggedRef(self.0, PhantomData)
}
pub fn get(&self) -> (&T, usize) {
self.to_tagged_ref().get()
}
pub fn get_mut(&mut self) -> (&mut T, usize) {
let (ptr, tag) = self.0.get();
(unsafe { &mut *ptr.as_ptr() }, tag)
}
pub fn into_inner(self) -> (&'a mut T, usize) {
let (ptr, tag) = self.0.get();
(unsafe { &mut *ptr.as_ptr() }, tag)
}
pub fn get_ref(&self) -> &T {
self.get().0
}
pub fn get_mut_ref(&mut self) -> &mut T {
self.get_mut().0
}
pub fn into_ref(self) -> &'a mut T {
self.into_inner().0
}
#[doc = $doctest_context]
pub fn set_ref(&mut self, reference: &'a mut T) {
*self = self.with_ref(reference);
}
#[doc = $doctest_context]
pub fn with_ref<'b>(
&self,
reference: &'b mut T,
) -> TaggedMutRef<'b, $($ty_args)*> {
TaggedMutRef::new(reference, self.tag())
}
pub fn tag(&self) -> usize {
self.get().1
}
#[doc = $doctest_context]
pub fn set_tag(&mut self, tag: usize) {
let this = unsafe { ptr::read(self) };
let this = Self::new(this.into_ref(), tag);
unsafe {
ptr::write(self, this);
}
}
#[doc = $doctest_context]
pub fn reborrow(&mut self) -> TaggedMutRef<'_, $($ty_args)*> {
let (reference, tag) = self.get_mut();
TaggedMutRef::new(reference, tag)
}
};
}
impl_explicit_tagged_ref_common!(TaggedMutRef);
impl_tagged_mut_ref_common!(
[T, const BITS: Bits],
[T, BITS],
"# type TaggedMutRef<'a, T> = tagged_pointer::TaggedMutRef<'a, T, 0>;",
);
pub mod implied;