use crate::internal::try_subscribe_auto_detach;
use ferroui_system::{IDisposable, IObservable, IObserver, ObservableError};
use std::rc::Rc;
pub trait ObservableCore<T> {
fn subscribe_core(&self, observer: Rc<dyn IObserver<T>>) -> Result<Rc<dyn IDisposable>, ObservableError>;
}
struct FnCore<F>(F);
impl<T, F> ObservableCore<T> for FnCore<F>
where
F: Fn(Rc<dyn IObserver<T>>) -> Result<Rc<dyn IDisposable>, ObservableError>,
{
fn subscribe_core(&self, observer: Rc<dyn IObserver<T>>) -> Result<Rc<dyn IDisposable>, ObservableError> {
(self.0)(observer)
}
}
pub struct ObservableBase<T> {
core: Rc<dyn ObservableCore<T>>,
}
impl<T: 'static> ObservableBase<T> {
pub fn new(core: impl ObservableCore<T> + 'static) -> Self {
Self { core: Rc::new(core) }
}
pub fn from_fn(subscribe_core: impl Fn(Rc<dyn IObserver<T>>) -> Rc<dyn IDisposable> + 'static) -> Self {
Self::new(FnCore(move |observer: Rc<dyn IObserver<T>>| -> Result<Rc<dyn IDisposable>, ObservableError> {
Ok(subscribe_core(observer))
}))
}
pub fn try_from_fn(
subscribe_core: impl Fn(Rc<dyn IObserver<T>>) -> Result<Rc<dyn IDisposable>, ObservableError> + 'static,
) -> Self {
Self::new(FnCore(subscribe_core))
}
}
impl<T: 'static> IObservable<T> for ObservableBase<T> {
fn subscribe(&self, observer: Rc<dyn IObserver<T>>) -> Rc<dyn IDisposable> {
let core = self.core.clone();
try_subscribe_auto_detach(observer, move |observer: Rc<dyn IObserver<T>>| core.subscribe_core(observer))
}
}