Skip to main content

rx_rust/observer/
mod.rs

1pub mod boxed_observer;
2pub mod callback_observer;
3
4use crate::{observer::boxed_observer::BoxedObserver, utils::types::MaybeSend};
5use educe::Educe;
6
7/// Represents the termination state of an operation, which can either be completed successfully or with an error.
8#[derive(Educe)]
9#[educe(Debug, Clone, PartialEq, Eq)]
10pub enum Termination<E> {
11    /// Indicates that the operation has completed successfully.
12    Completed,
13    /// Indicates that the operation has completed with an error.
14    Error(E),
15}
16
17/// Whether an observer still accepts events, as reported by [`Observer::on_next`].
18///
19/// This is the only way an observer can tell the source that is pushing into it to stop, while
20/// that push is running. It matters most for a synchronous source, which delivers its whole
21/// sequence before `subscribe` returns: until it does, nobody holds the subscription yet, so
22/// disposing it is not yet possible, and an infinite synchronous source would never end.
23///
24/// It does not replace disposal, and no source may rely on it alone: an observer can also go away
25/// between two events, which no return value can report. See the variants for what each one
26/// promises.
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28#[must_use = "an upstream that ignores the flow keeps pushing into an observer that stopped"]
29pub enum Flow {
30    /// The observer is not known to have stopped, so the source may keep pushing.
31    ///
32    /// This is a hint, not a guarantee: it means "no stop has been observed here", and the
33    /// observer may still be disposed before the next event, or already have been disposed
34    /// somewhere this call could not see — a value queued behind a delivery running elsewhere is
35    /// reported as `Continue` even when that delivery is about to stop. A source must therefore
36    /// still honor its disposal; treating `Continue` as proof that downstream is alive is wrong.
37    Continue,
38    /// The observer will never accept another event.
39    ///
40    /// The caller must not call [`Observer::on_next`] again, must not call
41    /// [`Observer::on_termination`], and should drop the observer instead: it has either already
42    /// delivered its own termination downstream or been disposed, so a termination sent now would
43    /// be a second one. Unlike [`Flow::Continue`], this is a guarantee, never a hint.
44    Stop,
45}
46
47impl Flow {
48    /// Returns whether this is [`Flow::Continue`].
49    #[inline]
50    pub fn is_continue(self) -> bool {
51        matches!(self, Flow::Continue)
52    }
53
54    /// Returns whether this is [`Flow::Stop`].
55    #[inline]
56    pub fn is_stop(self) -> bool {
57        matches!(self, Flow::Stop)
58    }
59}
60
61/// A trait for observing the progress and termination state of an operation.
62pub trait Observer<T, E> {
63    /// Called when the next value in the operation is available.
64    ///
65    /// Returns whether the observer accepts further events. [`Flow::Stop`] means it accepts none
66    /// and must not be terminated either, so the caller stops pushing and drops it; see [`Flow`]
67    /// for the exact promise each variant makes. An operator that forwards values must return what
68    /// its own downstream returned, so that the answer reaches the source at the end of the chain.
69    fn on_next(&mut self, value: T) -> Flow;
70
71    /// Called when the operation has reached its termination state.
72    fn on_termination(self, termination: Termination<E>);
73}
74
75#[derive(Educe)]
76#[educe(Debug, Clone, PartialEq, Eq)]
77pub enum Event<T, E> {
78    Next(T),
79    Termination(Termination<E>),
80}
81
82pub trait BoxedObserverExt<T, E>: Observer<T, E> + Sized {
83    fn into_boxed<'or>(self) -> BoxedObserver<'or, T, E>
84    where
85        Self: MaybeSend + 'or,
86    {
87        BoxedObserver::new(self)
88    }
89}
90
91impl<T, E, OR> BoxedObserverExt<T, E> for OR where OR: Observer<T, E> {}