pub mod boxed;
pub mod dynamic;
pub mod either;
pub mod source_with_dynamic;
pub mod source_with_handle;
pub mod tuple;
pub use boxed::{BoxedSubscription, BoxedSubscriptionSend, IntoBoxedSubscription};
pub use dynamic::DynamicSubscriptions;
pub use either::EitherSubscription;
pub use source_with_dynamic::SourceWithDynamicSubs;
pub use source_with_handle::SourceWithHandle;
pub use tuple::TupleSubscription;
pub struct ClosureSubscription<F>(pub F);
impl<F> Subscription for ClosureSubscription<F>
where
F: FnOnce(),
{
fn unsubscribe(self) { (self.0)() }
fn is_closed(&self) -> bool { false }
}
#[must_use]
pub struct SubscriptionGuard<T: Subscription>(pub(crate) Option<T>);
impl<T: Subscription> SubscriptionGuard<T> {
pub fn new(subscription: T) -> SubscriptionGuard<T> { SubscriptionGuard(Some(subscription)) }
}
impl<T: Subscription> Drop for SubscriptionGuard<T> {
fn drop(&mut self) {
if let Some(u) = self.0.take() {
u.unsubscribe()
}
}
}
pub trait Subscription {
fn unsubscribe(self);
fn is_closed(&self) -> bool;
fn unsubscribe_when_dropped(self) -> SubscriptionGuard<Self>
where
Self: Sized,
{
SubscriptionGuard::new(self)
}
}
impl Subscription for () {
fn unsubscribe(self) {}
fn is_closed(&self) -> bool { true }
}
impl<P: Subscription> Subscription for Option<P> {
fn unsubscribe(self) {
if let Some(inner) = self {
inner.unsubscribe()
}
}
fn is_closed(&self) -> bool {
match self {
Some(inner) => inner.is_closed(),
None => true,
}
}
}
use crate::context::{MutArc, MutRc, RcDeref, RcDerefMut};
impl<P: Subscription> Subscription for MutArc<Option<P>> {
fn unsubscribe(self) {
let Some(inner) = self.rc_deref_mut().take() else {
return;
};
inner.unsubscribe()
}
fn is_closed(&self) -> bool { self.rc_deref().is_none() }
}
impl<P: Subscription> Subscription for MutRc<Option<P>> {
fn unsubscribe(self) {
let Some(inner) = self.rc_deref_mut().take() else {
return;
};
inner.unsubscribe()
}
fn is_closed(&self) -> bool { self.rc_deref().is_none() }
}
#[cfg(test)]
mod test {
use std::{cell::RefCell, rc::Rc};
use super::*;
#[rxrust_macro::test]
fn test_subscription_guard_drop() {
let unsubscribed = Rc::new(RefCell::new(false));
let unsubscribed_clone = unsubscribed.clone();
struct TestSubscription {
is_closed: bool,
unsubscribed_flag: Rc<RefCell<bool>>,
}
impl Subscription for TestSubscription {
fn unsubscribe(mut self) {
*self.unsubscribed_flag.borrow_mut() = true;
self.is_closed = true;
}
fn is_closed(&self) -> bool { self.is_closed }
}
let sub = TestSubscription { is_closed: false, unsubscribed_flag: unsubscribed_clone };
assert!(!*unsubscribed.borrow());
{
let _guard = sub.unsubscribe_when_dropped();
assert!(!*unsubscribed.borrow());
}
assert!(*unsubscribed.borrow());
}
}