ferroui_reactive/
notification.rs1use crate::concurrency::{IScheduler, SchedulerExt};
4use crate::linq::Observable;
5use ferroui_system::{IObservable, IObserver, ObservableError};
6use std::fmt;
7use std::hash::{Hash, Hasher};
8use std::rc::Rc;
9
10pub trait IObserverWithResult<T, R> {
13 fn on_next(&self, value: T) -> R;
15
16 fn on_error(&self, error: ObservableError) -> R;
18
19 fn on_completed(&self) -> R;
21}
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
25pub enum NotificationKind {
26 OnNext,
27 OnError,
28 OnCompleted,
29}
30
31#[derive(Clone)]
36pub enum Notification<T> {
37 OnNext(T),
39 OnError(ObservableError),
41 OnCompleted,
43}
44
45impl<T> Notification<T> {
46 pub fn kind(&self) -> NotificationKind {
48 match self {
49 Self::OnNext(_) => NotificationKind::OnNext,
50 Self::OnError(_) => NotificationKind::OnError,
51 Self::OnCompleted => NotificationKind::OnCompleted,
52 }
53 }
54
55 pub fn has_value(&self) -> bool {
57 matches!(self, Self::OnNext(_))
58 }
59
60 pub fn value(&self) -> Option<&T> {
63 match self {
64 Self::OnNext(value) => Some(value),
65 _ => None,
66 }
67 }
68
69 pub fn exception(&self) -> Option<&ObservableError> {
71 match self {
72 Self::OnError(error) => Some(error),
73 _ => None,
74 }
75 }
76
77 pub fn accept(self, observer: &dyn IObserver<T>) {
79 match self {
80 Self::OnNext(value) => observer.on_next(value),
81 Self::OnError(error) => observer.on_error(error),
82 Self::OnCompleted => observer.on_completed(),
83 }
84 }
85
86 pub fn accept_observer_with_result<R>(self, observer: &dyn IObserverWithResult<T, R>) -> R {
89 match self {
90 Self::OnNext(value) => observer.on_next(value),
91 Self::OnError(error) => observer.on_error(error),
92 Self::OnCompleted => observer.on_completed(),
93 }
94 }
95
96 pub fn accept_fns<R>(
98 self,
99 on_next: impl FnOnce(T) -> R,
100 on_error: impl FnOnce(ObservableError) -> R,
101 on_completed: impl FnOnce() -> R,
102 ) -> R {
103 match self {
104 Self::OnNext(value) => on_next(value),
105 Self::OnError(error) => on_error(error),
106 Self::OnCompleted => on_completed(),
107 }
108 }
109}
110
111impl<T: Clone + 'static> Notification<T> {
112 pub fn to_observable(&self) -> Rc<dyn IObservable<T>> {
114 self.to_observable_on(crate::concurrency::Scheduler::immediate())
115 }
116
117 pub fn to_observable_on(&self, scheduler: Rc<dyn IScheduler>) -> Rc<dyn IObservable<T>> {
120 let notification = self.clone();
121 Observable::create(move |observer: Rc<dyn IObserver<T>>| {
122 let notification = notification.clone();
123 scheduler.schedule_action(move || {
124 let is_next = notification.has_value();
125 notification.accept(&*observer);
126 if is_next {
127 observer.on_completed();
128 }
129 })
130 })
131 }
132}
133
134impl<T: PartialEq> PartialEq for Notification<T> {
135 fn eq(&self, other: &Self) -> bool {
136 match (self, other) {
137 (Self::OnNext(a), Self::OnNext(b)) => a == b,
138 (Self::OnError(a), Self::OnError(b)) => Rc::ptr_eq(a, b),
139 (Self::OnCompleted, Self::OnCompleted) => true,
140 _ => false,
141 }
142 }
143}
144
145impl<T: Hash> Hash for Notification<T> {
150 fn hash<H: Hasher>(&self, state: &mut H) {
151 match self {
152 Self::OnNext(value) => value.hash(state),
153 Self::OnError(error) => (Rc::as_ptr(error) as *const () as usize).hash(state),
154 Self::OnCompleted => {
155 std::any::type_name::<T>().hash(state);
156 8510u32.hash(state);
157 }
158 }
159 }
160}
161
162impl<T: fmt::Debug> fmt::Debug for Notification<T> {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 match self {
165 Self::OnNext(value) => write!(f, "OnNext({value:?})"),
166 Self::OnError(error) => write!(f, "OnError({error})"),
167 Self::OnCompleted => f.write_str("OnCompleted()"),
168 }
169 }
170}