pub trait Refcounted: Clone {
type WeakRef;
fn upgrade(this: &Self::WeakRef) -> Option<Self>
where
Self: Sized;
fn downgrade(&self) -> Self::WeakRef;
}
pub(crate) fn new_refcounted<T>(inner: T) -> std::sync::Arc<T> {
std::sync::Arc::new(inner)
}
#[macro_export]
macro_rules! refcounted {
(
// FIXME: bounds can be non-types, so we probably need something that munches tts
$(#[$($attrs:meta)*])*
$visibility:vis struct $name:ident $(<$($generic:tt $(: $bound:ty)?),*>)? {
$($body:tt)*
}
) => {
paste::paste! {
$(#[$($attrs)*])*
#[derive(Clone)]
$visibility struct $name $(<$($generic $(: $bound)?),*>)? {
inner: std::sync::Arc<[<Inner $name>] $(<$($generic),*>)?>,
}
unsafe impl $(<$($generic $(: $bound)?),*>)? Send for $name $(<$($generic),*>)? {}
unsafe impl $(<$($generic $(: $bound)?),*>)? Sync for $name $(<$($generic),*>)? {}
#[derive(Clone)]
pub struct [<Weak $name>] $(<$($generic $(: $bound)?),*>)? {
inner: std::sync::Weak<[<Inner $name>] $(<$($generic>)?),*>,
}
unsafe impl $(<$($generic $(: $bound)?),*>)? Send for [<Weak $name>] $(<$($generic),*>)? {}
unsafe impl $(<$($generic $(: $bound)?),*>)? Sync for [<Weak $name>] $(<$($generic),*>)? {}
impl $(<$($generic $(: $bound)?),*>)? $name $(<$($generic),*>)? {
#[doc(hidden)]
pub fn downgrade(&self) -> [<Weak $name>] $(<$($generic),*>)? {
[<Weak $name>] {
inner: std::sync::Arc::downgrade(&self.inner),
}
}
}
impl $(<$($generic $(: $bound)?),*>)? [<Weak $name>] $(<$($generic),*>)? {
#[doc(hidden)]
pub fn upgrade(&self) -> Option<$name $(<$($generic),*>)?> {
self.inner.upgrade().map(|inner| $name { inner })
}
}
impl $(<$($generic $(: $bound)?),*>)? $crate::Refcounted for $name $(<$($generic),*>)? {
type WeakRef = [<Weak $name>] $(<$($generic),*>)?;
fn upgrade(this: &Self::WeakRef) -> Option<Self> {
this.upgrade()
}
fn downgrade(&self) -> Self::WeakRef {
self.downgrade()
}
}
struct [<Inner $name>] $(<$($generic $(: $bound)?),*>)? {
$($body)*
}
}
}
}