diff --git a/src/value.rs b/src/value.rs index c500a0e..356bfca 100644 --- a/src/value.rs +++ b/src/value.rs @@ -8,7 +8,7 @@ use std::ops::{Deref, DerefMut, Not}; use std::panic::UnwindSafe; use std::str::FromStr; use std::sync::atomic::{self, AtomicBool}; -use std::sync::{Arc, Mutex, MutexGuard, TryLockError}; +use std::sync::{Arc, Mutex, MutexGuard, TryLockError, Weak}; use std::task::{Poll, Waker}; use std::thread::ThreadId; use std::time::Duration; @@ -50,6 +50,15 @@ impl Dynamic { })) } + /// Returns a weak reference to this dynamic. + /// + /// This is powered by [`Arc`]/[`Weak`] and follows the same semantics for + /// reference counting. + #[must_use] + pub fn downgrade(&self) -> WeakDynamic { + WeakDynamic::from(self) + } + /// Returns a new dynamic that has its contents linked with `self` by the /// pair of mapping functions provided. /// @@ -1104,6 +1113,59 @@ impl Drop for DynamicGuard<'_, T> { } } +/// A weak reference to a [`Dynamic`]. +/// +/// This is powered by [`Arc`]/[`Weak`] and follows the same semantics for +/// reference counting. +pub struct WeakDynamic(Weak>); + +impl WeakDynamic { + /// Returns the [`Dynamic`] this weak reference points to, unless no + /// remaining [`Dynamic`] instances exist for the underlying value. + #[must_use] + pub fn upgrade(&self) -> Option> { + self.0.upgrade().map(Dynamic) + } +} + +impl<'a, T> From<&'a Dynamic> for WeakDynamic { + fn from(value: &'a Dynamic) -> Self { + Self(Arc::downgrade(&value.0)) + } +} + +impl From> for WeakDynamic { + fn from(value: Dynamic) -> Self { + Self::from(&value) + } +} + +impl Clone for WeakDynamic { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +impl Eq for WeakDynamic {} + +impl PartialEq for WeakDynamic { + fn eq(&self, other: &Self) -> bool { + Weak::ptr_eq(&self.0, &other.0) + } +} + +impl PartialEq> for WeakDynamic { + fn eq(&self, other: &Dynamic) -> bool { + Weak::as_ptr(&self.0) == Arc::as_ptr(&other.0) + } +} + +impl PartialEq> for Dynamic { + fn eq(&self, other: &WeakDynamic) -> bool { + Arc::as_ptr(&self.0) == Weak::as_ptr(&other.0) + } +} + /// A reader that tracks the last generation accessed through this reader. #[derive(Debug)] pub struct DynamicReader {