ferroui_dynamic_data/kernel/
option_observable_extensions.rs1use super::OptionExtensions;
5use ferroui_reactive::{Observable, ObservableExt};
6use ferroui_system::{IObservable, IObserver, ObservableError};
7use std::rc::Rc;
8
9pub trait OptionObservableExtensions<T: Clone + 'static> {
15 fn options(&self) -> Rc<dyn IObservable<Option<T>>>;
17
18 fn convert<U: 'static>(&self, converter: impl Fn(T) -> U + 'static) -> Rc<dyn IObservable<Option<U>>> {
20 self.options().select(move |optional: Option<T>| optional.map(&converter))
21 }
22
23 fn convert_optional<U: 'static>(&self, converter: impl Fn(T) -> Option<U> + 'static) -> Rc<dyn IObservable<Option<U>>> {
26 self.options().select(move |optional: Option<T>| optional.and_then(&converter))
27 }
28
29 fn convert_or<U: 'static>(&self, converter: impl Fn(T) -> U + 'static, fallback_converter: impl Fn() -> U + 'static) -> Rc<dyn IObservable<U>> {
32 self.options().select(move |optional: Option<T>| match optional {
33 Some(value) => converter(value),
34 None => fallback_converter(),
35 })
36 }
37
38 fn or_else(&self, fallback_operation: impl Fn() -> Option<T> + 'static) -> Rc<dyn IObservable<Option<T>>> {
40 self.options().select(move |optional: Option<T>| match optional {
41 Some(value) => Some(value),
42 None => fallback_operation(),
43 })
44 }
45
46 fn on_has_value(&self, action: impl Fn(&T) + 'static) -> Rc<dyn IObservable<Option<T>>> {
48 self.options().do_(move |optional: &Option<T>| {
49 optional.as_ref().if_has_value(|value| action(value));
50 })
51 }
52
53 fn on_has_value_with_else(&self, action: impl Fn(&T) + 'static, else_action: impl Fn() + 'static) -> Rc<dyn IObservable<Option<T>>> {
56 self.options().do_(move |optional: &Option<T>| {
57 optional.as_ref().if_has_value(|value| action(value)).else_(&else_action);
58 })
59 }
60
61 fn on_has_no_value(&self, action: impl Fn() + 'static) -> Rc<dyn IObservable<Option<T>>> {
63 self.options().do_(move |optional: &Option<T>| {
64 optional.as_ref().if_has_value(|_| {}).else_(&action);
65 })
66 }
67
68 fn on_has_no_value_with_else(&self, action: impl Fn() + 'static, else_action: impl Fn(&T) + 'static) -> Rc<dyn IObservable<Option<T>>> {
71 self.options().do_(move |optional: &Option<T>| {
72 optional.as_ref().if_has_value(|value| else_action(value)).else_(&action);
73 })
74 }
75
76 fn select_values(&self) -> Rc<dyn IObservable<T>> {
78 self.options().where_(|optional: &Option<T>| optional.is_some()).select(|optional: Option<T>| optional.expect("filtered to values"))
79 }
80
81 fn value_or(&self, value_selector: impl Fn() -> T + 'static) -> Rc<dyn IObservable<T>> {
83 self.options().select(move |optional: Option<T>| optional.unwrap_or_else(&value_selector))
84 }
85
86 fn value_or_default(&self) -> Rc<dyn IObservable<T>>
88 where
89 T: Default,
90 {
91 self.options().select(|optional: Option<T>| optional.unwrap_or_default())
92 }
93
94 fn value_or_throw(&self, exception_generator: impl Fn() -> ObservableError + 'static) -> Rc<dyn IObservable<T>> {
97 let source = self.options();
98 let exception_generator = Rc::new(exception_generator);
99 Observable::create(move |observer: Rc<dyn IObserver<T>>| {
100 let (on_next, on_error, on_completed) = (observer.clone(), observer.clone(), observer);
101 let exception_generator = exception_generator.clone();
102 source.subscribe_all(
103 move |optional: Option<T>| match optional {
104 Some(value) => on_next.on_next(value),
105 None => on_next.on_error(exception_generator()),
106 },
107 move |error| on_error.on_error(error),
108 move || on_completed.on_completed(),
109 )
110 })
111 }
112
113 fn edit_diff_optional<K: Eq + std::hash::Hash + Clone + 'static>(
118 &self,
119 key_selector: impl Fn(&T) -> K + 'static,
120 ) -> Rc<dyn IObservable<crate::cache::ChangeSet<T, K>>>
121 where
122 T: PartialEq,
123 {
124 crate::cache::internal::edit_diff_change_set_optional(self.options(), Rc::new(key_selector), Rc::new(|a: &T, b: &T| a == b))
125 }
126
127 fn edit_diff_optional_with_comparer<K: Eq + std::hash::Hash + Clone + 'static>(
130 &self,
131 key_selector: impl Fn(&T) -> K + 'static,
132 equality_comparer: impl Fn(&T, &T) -> bool + 'static,
133 ) -> Rc<dyn IObservable<crate::cache::ChangeSet<T, K>>> {
134 crate::cache::internal::edit_diff_change_set_optional(self.options(), Rc::new(key_selector), Rc::new(equality_comparer))
135 }
136}
137
138impl<T: Clone + 'static> OptionObservableExtensions<T> for Rc<dyn IObservable<Option<T>>> {
139 fn options(&self) -> Rc<dyn IObservable<Option<T>>> {
140 self.clone()
141 }
142}