use super::underlying::Underlying;
use super::{Arc, Tag};
use std::convert::TryInto;
use std::marker::PhantomData;
use std::{ops::Deref, ptr, ptr::NonNull};
#[derive(Debug)]
pub struct Ptr<'b, T> {
instance_ptr: *const Underlying<T>,
_phantom: PhantomData<&'b T>,
}
impl<'b, T> Ptr<'b, T> {
#[must_use]
#[inline]
pub fn null() -> Ptr<'b, T> {
Ptr {
instance_ptr: ptr::null(),
_phantom: PhantomData,
}
}
#[must_use]
#[inline]
pub fn is_null(&self) -> bool {
Tag::unset_tag(self.instance_ptr).is_null()
}
#[must_use]
#[inline]
pub fn as_ref(&self) -> Option<&'b T> {
unsafe { Tag::unset_tag(self.instance_ptr).as_ref().map(Deref::deref) }
}
#[must_use]
#[inline]
pub fn as_raw(&self) -> *const T {
unsafe {
Tag::unset_tag(self.instance_ptr)
.as_ref()
.map_or_else(ptr::null, |u| &**u as *const T)
}
}
#[must_use]
#[inline]
pub fn tag(&self) -> Tag {
Tag::into_tag(self.instance_ptr)
}
#[inline]
pub fn set_tag(&mut self, tag: Tag) -> Tag {
let old_tag = Tag::into_tag(self.instance_ptr);
self.instance_ptr = Tag::update_tag(self.instance_ptr, tag);
old_tag
}
#[inline]
pub fn unset_tag(&mut self) -> Tag {
let old_tag = Tag::into_tag(self.instance_ptr);
self.instance_ptr = Tag::unset_tag(self.instance_ptr);
old_tag
}
#[must_use]
pub fn with_tag(self, tag: Tag) -> Ptr<'b, T> {
Ptr::from(Tag::update_tag(self.instance_ptr, tag))
}
#[must_use]
pub fn without_tag(self) -> Ptr<'b, T> {
Ptr::from(Tag::unset_tag(self.instance_ptr))
}
#[must_use]
#[inline]
pub fn try_into_arc(self) -> Option<Arc<T>> {
unsafe {
if let Some(ptr) = NonNull::new(Tag::unset_tag(self.instance_ptr) as *mut Underlying<T>)
{
if ptr.as_ref().try_add_ref() {
return Some(Arc::from(ptr));
}
}
}
None
}
pub(super) fn from(ptr: *const Underlying<T>) -> Ptr<'b, T> {
Ptr {
instance_ptr: ptr,
_phantom: std::marker::PhantomData,
}
}
pub(super) fn raw_ptr(self) -> *const Underlying<T> {
self.instance_ptr
}
}
impl<'b, T> Clone for Ptr<'b, T> {
fn clone(&self) -> Self {
Self {
instance_ptr: self.instance_ptr,
_phantom: std::marker::PhantomData,
}
}
}
impl<'b, T> Copy for Ptr<'b, T> {}
impl<'b, T> Default for Ptr<'b, T> {
#[inline]
fn default() -> Self {
Ptr::null()
}
}
impl<'b, T> Eq for Ptr<'b, T> {}
impl<'b, T> PartialEq for Ptr<'b, T> {
fn eq(&self, other: &Self) -> bool {
self.instance_ptr == other.instance_ptr
}
}
impl<'b, T> TryInto<Arc<T>> for Ptr<'b, T> {
type Error = ();
#[inline]
fn try_into(self) -> Result<Arc<T>, Self::Error> {
if let Some(arc) = self.try_into_arc() {
return Ok(arc);
}
Err(())
}
}