use super::{subscribe_sink, Sink};
use ferroui_system::{IDisposable, IObservable, IObserver};
use std::rc::Rc;
pub(crate) trait OperatorSink<T, U>: IObserver<T> + IDisposable {
fn sink(&self) -> &Sink<U>;
}
struct UnaryOperator<T, U, S> {
source: Rc<dyn IObservable<T>>,
make: Rc<dyn Fn(Rc<dyn IObserver<U>>) -> Rc<S>>,
}
impl<T: 'static, U: 'static, S: OperatorSink<T, U> + 'static> IObservable<U> for UnaryOperator<T, U, S> {
fn subscribe(&self, observer: Rc<dyn IObserver<U>>) -> Rc<dyn IDisposable> {
let source = self.source.clone();
let make = self.make.clone();
subscribe_sink(observer, move |observer| make(observer), move |sink: &Rc<S>| {
let upstream = source.subscribe(sink.clone());
sink.sink().set_upstream(upstream);
})
}
}
pub(crate) fn unary<T: 'static, U: 'static, S: OperatorSink<T, U> + 'static>(
source: Rc<dyn IObservable<T>>,
make: impl Fn(Rc<dyn IObserver<U>>) -> Rc<S> + 'static,
) -> Rc<dyn IObservable<U>> {
Rc::new(UnaryOperator { source, make: Rc::new(make) })
}
macro_rules! impl_sink_dispose {
($sink:ident<$($param:ident),*> $(where $($bound:tt)*)?) => {
impl<$($param: 'static),*> ferroui_system::IDisposable for $sink<$($param),*> $(where $($bound)*)? {
fn dispose(&self) {
$crate::internal::OperatorSink::sink(self).dispose();
}
}
};
}
pub(crate) use impl_sink_dispose;