Skip to main content

ferroui_reactive/linq/
dematerialize.rs

1//! `Dematerialize` (`Linq/Observable/Dematerialize.cs`).
2
3use crate::internal::{impl_sink_dispose, unary, OperatorSink, Sink};
4use crate::notification::Notification;
5use ferroui_system::{IObservable, IObserver, ObservableError};
6use std::rc::Rc;
7
8/// A value that is a notification: implemented for [`Notification<T>`], so that `dematerialize`
9/// is a method of the sequences of notifications (upstream's `Dematerialize<TSource>` extends
10/// `IObservable<Notification<TSource>>`).
11pub trait NotificationValue: 'static {
12    /// The type of the values of the notification.
13    type Value: 'static;
14
15    /// The notification.
16    fn into_notification(self) -> Notification<Self::Value>;
17}
18
19impl<T: 'static> NotificationValue for Notification<T> {
20    type Value = T;
21
22    fn into_notification(self) -> Notification<T> {
23        self
24    }
25}
26
27/// The sink of `Dematerialize` (`Dematerialize<TSource>._`): notifies what each notification of
28/// the source is.
29struct DematerializeSink<N: NotificationValue> {
30    sink: Sink<N::Value>,
31}
32
33impl<N: NotificationValue> OperatorSink<N, N::Value> for DematerializeSink<N> {
34    fn sink(&self) -> &Sink<N::Value> {
35        &self.sink
36    }
37}
38
39impl_sink_dispose!(DematerializeSink<N> where N: NotificationValue);
40
41impl<N: NotificationValue> IObserver<N> for DematerializeSink<N> {
42    fn on_next(&self, value: N) {
43        match value.into_notification() {
44            Notification::OnNext(value) => self.sink.forward_on_next(value),
45            Notification::OnError(error) => self.sink.forward_on_error(error),
46            Notification::OnCompleted => self.sink.forward_on_completed(),
47        }
48    }
49
50    fn on_error(&self, error: ObservableError) {
51        self.sink.forward_on_error(error);
52    }
53
54    fn on_completed(&self) {
55        self.sink.forward_on_completed();
56    }
57}
58
59pub(crate) fn dematerialize<N: NotificationValue>(source: Rc<dyn IObservable<N>>) -> Rc<dyn IObservable<N::Value>> {
60    // Deviation (DEVIATIONS.md, Reactive): upstream returns `source.AsObservable()` for the
61    // sequence of `Materialize` of `source`; the handle of a sequence in the port does not reveal
62    // the type of the sequence, so the notifications always go through the operator (the result
63    // is the same).
64    unary(source, |observer| Rc::new(DematerializeSink::<N> { sink: Sink::new(observer) }))
65}
66
67/// The methods of `Dematerialize` (provided methods of [`ObservableExt`](super::ObservableExt)).
68macro_rules! dematerialize_methods {
69    () => {
70        /// The notifications of a sequence of [`Notification`](crate::Notification)s as the
71        /// notifications of the result: its values, then its error or its completion, which ends
72        /// the result (`Dematerialize()`).
73        fn dematerialize(
74            &self,
75        ) -> std::rc::Rc<dyn ferroui_system::IObservable<<T as crate::linq::dematerialize::NotificationValue>::Value>>
76        where
77            T: crate::linq::dematerialize::NotificationValue,
78        {
79            crate::linq::dematerialize::dematerialize(self.observable())
80        }
81    };
82}
83pub(crate) use dematerialize_methods;