use crate::{
delegate_disposal,
disposable::{Disposable, DisposableExt, shared_disposal::SharedDisposal},
observable::Subscription,
observer::{Flow, Observer, Termination},
utils::on_panic::on_panic,
};
use educe::Educe;
delegate_disposal!(
Disposal<D>,
SharedDisposal<Subscription<D>>,
where D: Disposable
);
pub fn subscribe_with_auto_dispose_on_termination<OR, D, F>(
observer: OR,
builder: F,
) -> Subscription<Disposal<D>>
where
D: Disposable,
F: FnOnce(AutoDisposeOnTerminationObserver<OR, D>) -> Subscription<D>,
{
let shared_disposal = SharedDisposal::default();
let observer = AutoDisposeOnTerminationObserver {
observer,
shared_disposal: shared_disposal.clone(),
};
shared_disposal.replace(|| builder(observer));
shared_disposal.into_subscription()
}
pub(crate) fn is_auto_dispose_on_termination_observer<OR>() -> bool {
fn type_name_without_generics<T>() -> &'static str {
let name = std::any::type_name::<T>();
name.split_once('<').map_or(name, |(name, _)| name)
}
type_name_without_generics::<OR>()
== type_name_without_generics::<AutoDisposeOnTerminationObserver<(), ()>>()
}
#[derive(Educe)]
#[educe(Debug)]
pub struct AutoDisposeOnTerminationObserver<OR, D: Disposable> {
observer: OR,
shared_disposal: SharedDisposal<Subscription<D>>,
}
impl<T, E, OR, D> Observer<T, E> for AutoDisposeOnTerminationObserver<OR, D>
where
OR: Observer<T, E>,
D: Disposable,
{
fn on_next(&mut self, value: T) -> Flow {
let flow = self.observer.on_next(value);
if flow.is_stop() {
self.shared_disposal.clone().dispose();
}
flow
}
fn on_termination(self, termination: Termination<E>) {
let Self {
observer,
shared_disposal,
} = self;
let guard = on_panic(|| shared_disposal.clone().dispose());
observer.on_termination(termination);
drop(guard);
shared_disposal.dispose();
}
}