mod erased_rc;
use alloc::rc::Rc;
use core::{
clone::Clone,
cmp::{Eq, Ord, PartialEq, PartialOrd},
convert::{AsRef, From, Into},
hash::Hash,
iter::{FromIterator, IntoIterator},
marker::{Sized, Unpin},
ops::Deref,
ops::FnOnce,
option::{Option, Option::Some},
ptr::NonNull,
};
use erased_rc::{TypeErasedRc, TypeErasedWeak};
pub struct Prc<T: ?Sized> {
rc: TypeErasedRc,
projected: NonNull<T>,
}
impl<T> Prc<T>
where
T: 'static,
{
pub fn new(value: T) -> Prc<T> {
Rc::new(value).into()
}
}
impl<T: ?Sized> Prc<T> {
#[inline]
pub fn from_rc<U, F>(rc: &Rc<U>, project: F) -> Self
where
U: ?Sized + 'static,
T: 'static,
F: FnOnce(&U) -> &T,
{
let projected = project(rc);
let projected = unsafe { NonNull::new_unchecked(projected as *const T as *mut T) };
Self {
rc: TypeErasedRc::new(rc.clone()),
projected,
}
}
#[inline]
pub fn try_from_rc<U, E, F>(rc: &Rc<U>, project: F) -> Result<Self, E>
where
U: ?Sized + 'static,
T: 'static,
F: FnOnce(&U) -> Result<&T, E>,
{
let projected = project(rc)?;
let projected = unsafe { NonNull::new_unchecked(projected as *const T as *mut T) };
Ok(Self {
rc: TypeErasedRc::new(rc.clone()),
projected,
})
}
#[inline]
pub fn project<U, F>(&self, project: F) -> Prc<U>
where
U: ?Sized + 'static,
T: 'static,
F: FnOnce(&T) -> &U,
{
let projected = project(self);
let projected = unsafe { NonNull::new_unchecked(projected as *const U as *mut U) };
Prc::<U> {
rc: self.rc.clone(),
projected,
}
}
#[inline]
pub fn try_project<U, E, F>(&self, project: F) -> Result<Prc<U>, E>
where
U: ?Sized + 'static,
F: FnOnce(&T) -> Result<&U, E>,
{
let projected = project(self)?;
let projected = unsafe { NonNull::new_unchecked(projected as *const U as *mut U) };
Ok(Prc::<U> {
rc: self.rc.clone(),
projected,
})
}
#[must_use]
pub fn as_ptr(this: &Self) -> *const T {
NonNull::as_ptr(this.projected)
}
pub fn downgrade(this: &Prc<T>) -> Weak<T> {
Weak::<T> {
weak: this.rc.downgrade(),
projected: this.projected,
}
}
#[inline]
pub fn weak_count(this: &Prc<T>) -> usize {
this.rc.weak_count()
}
#[inline]
pub fn strong_count(this: &Prc<T>) -> usize {
this.rc.strong_count()
}
pub fn ptr_eq(this: &Prc<T>, other: &Prc<T>) -> bool {
core::ptr::eq(this.projected.as_ptr(), other.projected.as_ptr())
}
}
impl<T: ?Sized> AsRef<T> for Prc<T> {
#[inline]
fn as_ref(&self) -> &T {
self.deref()
}
}
impl<T: ?Sized> core::borrow::Borrow<T> for Prc<T> {
#[inline]
fn borrow(&self) -> &T {
self.deref()
}
}
impl<T: ?Sized> Clone for Prc<T> {
#[inline]
fn clone(&self) -> Self {
Self {
rc: self.rc.clone(),
projected: self.projected,
}
}
}
impl<T: ?Sized + core::fmt::Debug> core::fmt::Debug for Prc<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Prc")
.field("projected", &self.deref())
.finish()
}
}
impl<T> core::fmt::Display for Prc<T>
where
T: core::fmt::Display + ?Sized,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.deref().fmt(f)
}
}
impl<T: ?Sized> Deref for Prc<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { self.projected.as_ref() }
}
}
#[cfg(feature = "std")]
impl<T> std::error::Error for Prc<T>
where
T: std::error::Error + ?Sized,
{
#[inline]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.deref().source()
}
}
impl<T, F> From<F> for Prc<T>
where
T: ?Sized + 'static,
F: Into<Rc<T>>,
{
#[inline]
fn from(value: F) -> Self {
Prc::from_rc(&value.into(), |x| x)
}
}
impl<T> FromIterator<T> for Prc<[T]>
where
T: 'static,
{
#[inline]
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
iter.into_iter().collect::<Rc<[T]>>().into()
}
}
impl<T> Hash for Prc<T>
where
T: Hash + ?Sized,
{
#[inline]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.deref().hash(state)
}
}
impl<T> PartialEq<Prc<T>> for Prc<T>
where
T: PartialEq<T> + ?Sized,
{
#[inline]
fn eq(&self, other: &Prc<T>) -> bool {
let this: &T = self;
let other: &T = other;
this.eq(other)
}
}
impl<T> Eq for Prc<T> where T: Eq + ?Sized {}
impl<T> Ord for Prc<T>
where
T: Ord + ?Sized,
{
#[inline]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
let this: &T = self;
let other: &T = other;
this.cmp(other)
}
}
impl<T> PartialOrd<Prc<T>> for Prc<T>
where
T: PartialOrd<T> + ?Sized,
{
#[inline]
fn partial_cmp(&self, other: &Prc<T>) -> Option<core::cmp::Ordering> {
self.deref().partial_cmp(other)
}
}
impl<T> core::fmt::Pointer for Prc<T>
where
T: ?Sized,
{
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Pointer::fmt(&self.projected, f)
}
}
impl<T> Unpin for Prc<T> where T: ?Sized {}
impl<T> core::panic::UnwindSafe for Prc<T> where T: core::panic::RefUnwindSafe + ?Sized {}
pub struct Weak<T: ?Sized> {
weak: TypeErasedWeak,
projected: NonNull<T>,
}
impl<T: ?Sized> Weak<T> {
#[must_use]
#[inline]
pub fn as_ptr(&self) -> *const T {
NonNull::as_ptr(self.projected)
}
#[inline]
pub fn upgrade(&self) -> Option<Prc<T>> {
Some(Prc {
rc: self.weak.upgrade()?,
projected: self.projected,
})
}
#[inline]
pub fn strong_count(&self) -> usize {
self.weak.strong_count()
}
#[inline]
pub fn weak_count(&self) -> usize {
self.weak.weak_count()
}
#[inline]
pub fn ptr_eq(&self, other: &Weak<T>) -> bool {
core::ptr::eq(self.projected.as_ptr(), other.projected.as_ptr())
}
}
impl<T: ?Sized> Clone for Weak<T> {
#[inline]
fn clone(&self) -> Self {
Self {
weak: self.weak.clone(),
projected: self.projected,
}
}
}
impl<T: ?Sized> core::fmt::Debug for Weak<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "(Weak)")
}
}