#![no_std]
extern crate alloc;
#[cfg(doc)]
use alloc::{rc::Rc, sync::Arc};
#[cfg(doc)]
use core::pin::Pin;
macro_rules! implementation {
($Rc:ident, $Weak:ident, $rc_lit:literal) => {
#[doc(no_inline)]
pub use core::pin::Pin;
#[derive(Debug)]
pub struct PinWeak<T: ?Sized>(Weak<T>);
impl<T> Default for PinWeak<T> {
fn default() -> Self {
Self(Weak::default())
}
}
impl<T: ?Sized> Clone for PinWeak<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T: ?Sized> PinWeak<T> {
#[doc = concat!("Equivalent function to [`", $rc_lit, "::downgrade`], but taking a `Pin<", $rc_lit, "<T>>` instead.")]
pub fn downgrade(rc: Pin<$Rc<T>>) -> Self {
unsafe { Self($Rc::downgrade(&Pin::into_inner_unchecked(rc))) }
}
#[doc = concat!("Equivalent function to [`Weak::upgrade`], but taking a `Pin<", $rc_lit, "<T>>` instead.")]
pub fn upgrade(&self) -> Option<Pin<$Rc<T>>> {
self.0.upgrade().map(|rc| unsafe { Pin::new_unchecked(rc) })
}
pub fn strong_count(&self) -> usize {
self.0.strong_count()
}
pub fn weak_count(&self) -> usize {
self.0.weak_count()
}
pub fn ptr_eq(&self, other: &Self) -> bool {
self.0.ptr_eq(&other.0)
}
}
#[test]
fn test() {
struct Foo {
_p: core::marker::PhantomPinned,
u: u32,
}
impl Foo {
fn new(u: u32) -> Self {
Self { _p: core::marker::PhantomPinned, u }
}
}
let c = $Rc::pin(Foo::new(44));
let weak1 = PinWeak::downgrade(c.clone());
assert_eq!(weak1.upgrade().unwrap().u, 44);
assert_eq!(weak1.clone().upgrade().unwrap().u, 44);
assert_eq!(weak1.strong_count(), 1);
assert_eq!(weak1.weak_count(), 1);
let weak2 = PinWeak::downgrade(c.clone());
assert_eq!(weak2.upgrade().unwrap().u, 44);
assert_eq!(weak1.upgrade().unwrap().u, 44);
assert_eq!(weak2.strong_count(), 1);
assert_eq!(weak2.weak_count(), 2);
assert!(weak1.ptr_eq(&weak2));
assert!(!weak1.ptr_eq(&Default::default()));
let weak3 = PinWeak::downgrade(c);
assert!(weak3.upgrade().is_none());
assert!(weak2.upgrade().is_none());
assert!(weak1.upgrade().is_none());
assert!(weak1.clone().upgrade().is_none());
assert_eq!(weak2.strong_count(), 0);
assert_eq!(weak2.weak_count(), 0);
let def = PinWeak::<alloc::boxed::Box<&'static mut ()>>::default();
assert!(def.upgrade().is_none());
assert!(def.clone().upgrade().is_none());
}
};
}
pub mod rc {
#[doc(no_inline)]
pub use alloc::rc::{Rc, Weak};
implementation! {Rc, Weak, "Rc"}
}
#[cfg(feature = "sync")]
pub mod sync {
#[doc(no_inline)]
pub use alloc::sync::{Arc, Weak};
implementation! {Arc, Weak, "Arc"}
}