use super::OptionExtensions;
use ferroui_reactive::{Observable, ObservableExt};
use ferroui_system::{IObservable, IObserver, ObservableError};
use std::rc::Rc;
pub trait OptionObservableExtensions<T: Clone + 'static> {
fn options(&self) -> Rc<dyn IObservable<Option<T>>>;
fn convert<U: 'static>(&self, converter: impl Fn(T) -> U + 'static) -> Rc<dyn IObservable<Option<U>>> {
self.options().select(move |optional: Option<T>| optional.map(&converter))
}
fn convert_optional<U: 'static>(&self, converter: impl Fn(T) -> Option<U> + 'static) -> Rc<dyn IObservable<Option<U>>> {
self.options().select(move |optional: Option<T>| optional.and_then(&converter))
}
fn convert_or<U: 'static>(&self, converter: impl Fn(T) -> U + 'static, fallback_converter: impl Fn() -> U + 'static) -> Rc<dyn IObservable<U>> {
self.options().select(move |optional: Option<T>| match optional {
Some(value) => converter(value),
None => fallback_converter(),
})
}
fn or_else(&self, fallback_operation: impl Fn() -> Option<T> + 'static) -> Rc<dyn IObservable<Option<T>>> {
self.options().select(move |optional: Option<T>| match optional {
Some(value) => Some(value),
None => fallback_operation(),
})
}
fn on_has_value(&self, action: impl Fn(&T) + 'static) -> Rc<dyn IObservable<Option<T>>> {
self.options().do_(move |optional: &Option<T>| {
optional.as_ref().if_has_value(|value| action(value));
})
}
fn on_has_value_with_else(&self, action: impl Fn(&T) + 'static, else_action: impl Fn() + 'static) -> Rc<dyn IObservable<Option<T>>> {
self.options().do_(move |optional: &Option<T>| {
optional.as_ref().if_has_value(|value| action(value)).else_(&else_action);
})
}
fn on_has_no_value(&self, action: impl Fn() + 'static) -> Rc<dyn IObservable<Option<T>>> {
self.options().do_(move |optional: &Option<T>| {
optional.as_ref().if_has_value(|_| {}).else_(&action);
})
}
fn on_has_no_value_with_else(&self, action: impl Fn() + 'static, else_action: impl Fn(&T) + 'static) -> Rc<dyn IObservable<Option<T>>> {
self.options().do_(move |optional: &Option<T>| {
optional.as_ref().if_has_value(|value| else_action(value)).else_(&action);
})
}
fn select_values(&self) -> Rc<dyn IObservable<T>> {
self.options().where_(|optional: &Option<T>| optional.is_some()).select(|optional: Option<T>| optional.expect("filtered to values"))
}
fn value_or(&self, value_selector: impl Fn() -> T + 'static) -> Rc<dyn IObservable<T>> {
self.options().select(move |optional: Option<T>| optional.unwrap_or_else(&value_selector))
}
fn value_or_default(&self) -> Rc<dyn IObservable<T>>
where
T: Default,
{
self.options().select(|optional: Option<T>| optional.unwrap_or_default())
}
fn value_or_throw(&self, exception_generator: impl Fn() -> ObservableError + 'static) -> Rc<dyn IObservable<T>> {
let source = self.options();
let exception_generator = Rc::new(exception_generator);
Observable::create(move |observer: Rc<dyn IObserver<T>>| {
let (on_next, on_error, on_completed) = (observer.clone(), observer.clone(), observer);
let exception_generator = exception_generator.clone();
source.subscribe_all(
move |optional: Option<T>| match optional {
Some(value) => on_next.on_next(value),
None => on_next.on_error(exception_generator()),
},
move |error| on_error.on_error(error),
move || on_completed.on_completed(),
)
})
}
fn edit_diff_optional<K: Eq + std::hash::Hash + Clone + 'static>(
&self,
key_selector: impl Fn(&T) -> K + 'static,
) -> Rc<dyn IObservable<crate::cache::ChangeSet<T, K>>>
where
T: PartialEq,
{
crate::cache::internal::edit_diff_change_set_optional(self.options(), Rc::new(key_selector), Rc::new(|a: &T, b: &T| a == b))
}
fn edit_diff_optional_with_comparer<K: Eq + std::hash::Hash + Clone + 'static>(
&self,
key_selector: impl Fn(&T) -> K + 'static,
equality_comparer: impl Fn(&T, &T) -> bool + 'static,
) -> Rc<dyn IObservable<crate::cache::ChangeSet<T, K>>> {
crate::cache::internal::edit_diff_change_set_optional(self.options(), Rc::new(key_selector), Rc::new(equality_comparer))
}
}
impl<T: Clone + 'static> OptionObservableExtensions<T> for Rc<dyn IObservable<Option<T>>> {
fn options(&self) -> Rc<dyn IObservable<Option<T>>> {
self.clone()
}
}