Skip to main content

rx_rust/operators/combining/
merge_all.rs

1use crate::disposable::Disposable;
2use crate::operators::others::with_error_type::WithErrorType;
3use crate::utils::id_generator::{Id, IdGenerator};
4use crate::utils::serialized_delivery::UpdateOutcome;
5use crate::utils::subscribe_with_context::{
6    self, SubscriptionContext, subscribe_with_context_owning_source,
7};
8use crate::utils::types::MaybeSend;
9use crate::{
10    observable::{Observable, Subscription},
11    observer::{Flow, Observer, Termination},
12    operators::creating::from_iter::FromIter,
13    utils::types::MarkerType,
14};
15use educe::Educe;
16use std::collections::HashMap;
17use std::marker::PhantomData;
18
19/// Merges an Observable of Observables into a single Observable that emits all of their emissions.
20/// See <https://reactivex.io/documentation/operators/merge.html> (referencing merge operator for general concept)
21///
22/// # Examples
23/// ```rust
24/// use rx_rust::{
25///     observable::ObservableExt,
26///     observer::Termination,
27///     operators::{
28///         combining::merge_all::MergeAll,
29///         creating::from_iter::FromIter,
30///     },
31/// };
32///
33/// let mut values = Vec::new();
34/// let mut terminations = Vec::new();
35///
36/// let observable = MergeAll::new_from_iter([
37///     FromIter::new(vec![1, 3]),
38///     FromIter::new(vec![2, 4]),
39/// ]);
40/// observable.subscribe_with_callback(
41///     |value| values.push(value),
42///     |termination| terminations.push(termination),
43/// );
44///
45/// assert_eq!(values, vec![1, 3, 2, 4]);
46/// assert_eq!(terminations, vec![Termination::Completed]);
47/// ```
48#[derive(Educe)]
49#[educe(Debug, Clone)]
50pub struct MergeAll<OE, OE1> {
51    source: OE,
52    _marker: MarkerType<OE1>,
53}
54
55impl<OE, OE1> MergeAll<OE, OE1> {
56    pub fn new<'or, T, E>(source: OE) -> Self
57    where
58        OE: Observable<'or, OE1, E>,
59        OE1: Observable<'or, T, E>,
60    {
61        Self {
62            source,
63            _marker: PhantomData,
64        }
65    }
66}
67
68impl<E, OE1, I> MergeAll<WithErrorType<E, FromIter<I>>, OE1> {
69    pub fn new_from_iter<'or, T>(into_iterator: I) -> Self
70    where
71        I: IntoIterator<Item = OE1>,
72        OE1: Observable<'or, T, E>,
73    {
74        Self {
75            source: WithErrorType::new(FromIter::new(into_iterator)),
76            _marker: PhantomData,
77        }
78    }
79}
80
81impl<'or, T, E, OE, OE1> Observable<'or, T, E> for MergeAll<OE, OE1>
82where
83    T: MaybeSend + 'or,
84    E: MaybeSend + 'or,
85    OE: Observable<'or, OE1, E>,
86    OE::D: MaybeSend + 'or,
87    OE1: Observable<'or, T, E>,
88    OE1::D: MaybeSend + 'or,
89{
90    type D = subscribe_with_context::OwningDisposal<'or>;
91
92    fn subscribe(self, observer: impl Observer<T, E> + MaybeSend + 'or) -> Subscription<Self::D> {
93        let model = Model {
94            subscriptions: HashMap::new(),
95            keys: IdGenerator::default(),
96            is_source_terminated: false,
97        };
98        subscribe_with_context_owning_source(observer, model, |context| {
99            self.source.subscribe(MergeAllObserver(context))
100        })
101    }
102}
103
104struct Model<D: Disposable> {
105    /// Keys are never reused, so a late inner observer can never remove another
106    /// inner observer's subscription.
107    subscriptions: HashMap<Id, Option<Subscription<D>>>,
108    keys: IdGenerator,
109    is_source_terminated: bool,
110}
111
112impl<D: Disposable> Model<D> {
113    /// Inserts a placeholder subscription and returns its key.
114    fn insert_placeholder(&mut self) -> Id {
115        let key = self.keys.next_id();
116        self.subscriptions.insert(key, None);
117        key
118    }
119}
120
121struct MergeAllObserver<T, E, OR, ID: Disposable, SD: Disposable>(
122    SubscriptionContext<T, E, OR, Model<ID>, SD>,
123);
124
125impl<'or, T, E, OR, OE1, SD> Observer<OE1, E> for MergeAllObserver<T, E, OR, OE1::D, SD>
126where
127    T: MaybeSend + 'or,
128    E: MaybeSend + 'or,
129    OR: Observer<T, E> + MaybeSend + 'or,
130    OE1: Observable<'or, T, E>,
131    OE1::D: MaybeSend + 'or,
132    SD: Disposable + MaybeSend + 'or,
133{
134    fn on_next(&mut self, value: OE1) -> Flow {
135        // Insert a placeholder subscription.
136        let result = self
137            .0
138            .update(|model| UpdateOutcome::new(model.insert_placeholder()));
139        let key = match result {
140            Ok(key) => key,
141            Err(_) => return Flow::Stop,
142        };
143        let observer = MergeAllInnerObserver {
144            context: self.0.clone(),
145            key,
146        };
147        let sub = value.subscribe(observer);
148
149        self.0.update_flow(|model| {
150            if let Some(slot) = model.subscriptions.get_mut(&key) {
151                *slot = Some(sub);
152                UpdateOutcome::empty().without_drop_outside()
153            } else {
154                // already terminated
155                UpdateOutcome::empty().with_drop_outside(sub)
156            }
157        })
158    }
159
160    fn on_termination(self, termination: Termination<E>) {
161        match termination {
162            completion @ Termination::Completed => {
163                let _ = self.0.update(|model| {
164                    if model.subscriptions.is_empty() {
165                        UpdateOutcome::empty().with_termination_event(completion)
166                    } else {
167                        model.is_source_terminated = true;
168                        UpdateOutcome::empty().without_events()
169                    }
170                });
171            }
172            error @ Termination::Error(_) => {
173                self.0.send_termination(error);
174            }
175        }
176    }
177}
178
179struct MergeAllInnerObserver<T, E, OR, ID: Disposable, SD: Disposable> {
180    context: SubscriptionContext<T, E, OR, Model<ID>, SD>,
181    key: Id,
182}
183
184impl<T, E, OR, ID, SD> Observer<T, E> for MergeAllInnerObserver<T, E, OR, ID, SD>
185where
186    OR: Observer<T, E>,
187    ID: Disposable,
188    SD: Disposable,
189{
190    fn on_next(&mut self, value: T) -> Flow {
191        self.context.send_next(value)
192    }
193
194    fn on_termination(self, termination: Termination<E>) {
195        match termination {
196            completion @ Termination::Completed => {
197                let _ = self.context.update(|model| {
198                    let subscription = model.subscriptions.remove(&self.key);
199                    if model.is_source_terminated && model.subscriptions.is_empty() {
200                        UpdateOutcome::empty()
201                            .with_termination_event(completion)
202                            .with_drop_outside(subscription)
203                    } else {
204                        UpdateOutcome::empty()
205                            .without_events()
206                            .with_drop_outside(subscription)
207                    }
208                });
209            }
210            error @ Termination::Error(_) => {
211                self.context.send_termination(error);
212            }
213        }
214    }
215}