rx_rust/operators/transforming/group_by.rs
1use crate::{
2 observable::{Observable, Subscription},
3 observer::{Flow, Observer, Termination},
4 subject::unicast_subject::{UnicastObservable, UnicastSender, unicast_subject},
5 utils::types::{MarkerType, MaybeSend},
6};
7use educe::Educe;
8use std::{
9 collections::{HashMap, hash_map::Entry},
10 hash::Hash,
11 marker::PhantomData,
12};
13
14/// Divides an Observable into a set of Observables, each of which emits a different group of items from the original Observable, organized by key.
15///
16/// A group is emitted before its first item is delivered, so each group can be subscribed to
17/// before its items arrive. Items emitted while a group has no subscriber are buffered and
18/// replayed to a later subscriber; once the group is terminated, a late subscriber observes the
19/// buffered items followed by the termination.
20///
21/// A group ends when the source terminates, when its subscription is disposed, or when the group
22/// Observable is dropped without being subscribed to. Later items mapping to the key of an ended
23/// group are discarded, just like the items of a window whose subscriber is gone.
24///
25/// Each group is a single-consumer pipe: it can be subscribed to once, and it is serialized on its
26/// own rather than together with the outer Observable, so the items of a group keep their order
27/// among themselves, but they are not ordered against the emission of another group. Disposing the
28/// outer subscription closes the open groups, which drops their observers without notifying them
29/// and discards what they had buffered.
30///
31/// Disposing the subscription of a single group does not necessarily release its observer where it
32/// happens: the group releases it on its next item, when it ends, or when the outer subscription
33/// is disposed, whichever comes first. See [the unicast subject](crate::subject::unicast_subject)
34/// each group is built on.
35/// See <https://reactivex.io/documentation/operators/groupby.html>
36///
37/// # Examples
38/// ```rust
39/// use rx_rust::{
40/// observable::ObservableExt,
41/// observer::Termination,
42/// operators::{
43/// creating::from_iter::FromIter,
44/// transforming::group_by::GroupBy,
45/// },
46/// };
47/// use std::sync::{Arc, Mutex};
48///
49/// let groups = Arc::new(Mutex::new(Vec::<Vec<i32>>::new()));
50/// let terminations = Arc::new(Mutex::new(Vec::new()));
51/// let inner_subscriptions = Arc::new(Mutex::new(Vec::new()));
52/// let groups_observer = Arc::clone(&groups);
53/// let terminations_observer = Arc::clone(&terminations);
54/// let inner_subscriptions_observer = Arc::clone(&inner_subscriptions);
55///
56/// let subscription = GroupBy::new(FromIter::new(vec![1, 2, 3, 4]), |value| value % 2)
57/// .subscribe_with_callback(
58/// move |group| {
59/// let index = {
60/// let mut groups = groups_observer.lock().unwrap();
61/// groups.push(Vec::new());
62/// groups.len() - 1
63/// };
64/// let groups_for_values = Arc::clone(&groups_observer);
65/// let sub = group.subscribe_with_callback(
66/// move |value| {
67/// groups_for_values.lock().unwrap()[index].push(value);
68/// },
69/// |_| {},
70/// );
71/// inner_subscriptions_observer.lock().unwrap().push(sub);
72/// },
73/// move |termination| terminations_observer
74/// .lock()
75/// .unwrap()
76/// .push(termination),
77/// );
78///
79/// drop(subscription);
80/// inner_subscriptions
81/// .lock()
82/// .unwrap()
83/// .drain(..)
84/// .for_each(drop);
85///
86/// let mut grouped = groups.lock().unwrap().clone();
87/// grouped.iter_mut().for_each(|values| values.sort());
88/// grouped.sort();
89/// assert_eq!(grouped, vec![vec![1, 3], vec![2, 4]]);
90/// assert_eq!(
91/// &*terminations.lock().unwrap(),
92/// &[Termination::Completed]
93/// );
94/// ```
95#[derive(Educe)]
96#[educe(Debug, Clone)]
97pub struct GroupBy<OE, F, K> {
98 source: OE,
99 key_selector: F,
100 _marker: MarkerType<K>,
101}
102
103impl<OE, F, K> GroupBy<OE, F, K> {
104 pub fn new<'or, T, E>(source: OE, key_selector: F) -> Self
105 where
106 OE: Observable<'or, T, E>,
107 F: FnMut(&T) -> K,
108 {
109 Self {
110 source,
111 key_selector,
112 _marker: PhantomData,
113 }
114 }
115}
116
117impl<'or, T, E, OE, F, K> Observable<'or, UnicastObservable<'or, T, E>, E> for GroupBy<OE, F, K>
118where
119 T: MaybeSend + 'or,
120 E: Clone + MaybeSend + 'or,
121 OE: Observable<'or, T, E>,
122 F: FnMut(&T) -> K + MaybeSend + 'or,
123 K: Eq + Hash + MaybeSend + 'or,
124{
125 type D = OE::D;
126
127 fn subscribe(
128 self,
129 observer: impl Observer<UnicastObservable<'or, T, E>, E> + MaybeSend + 'or,
130 ) -> Subscription<Self::D> {
131 // The groups own their buffered items and the source is the only upstream, so this
132 // observer can own the sending ends directly: the upstream holds `&mut` to it while it
133 // delivers, which is what serializes the groups against each other.
134 self.source.subscribe(SourceObserver {
135 observer,
136 senders: HashMap::new(),
137 key_selector: self.key_selector,
138 })
139 }
140}
141
142struct SourceObserver<'or, T, E, OR, F, K> {
143 observer: OR,
144 /// The sending end of every group that has been opened. An ended group keeps its entry,
145 /// because the values of an ended group are discarded rather than opening a new one.
146 senders: HashMap<K, UnicastSender<'or, T, E>>,
147 key_selector: F,
148}
149
150impl<'or, T, E, OR, F, K> Observer<T, E> for SourceObserver<'or, T, E, OR, F, K>
151where
152 E: Clone,
153 OR: Observer<UnicastObservable<'or, T, E>, E>,
154 F: FnMut(&T) -> K,
155 K: Eq + Hash,
156{
157 fn on_next(&mut self, value: T) -> Flow {
158 let key = (self.key_selector)(&value);
159 // The consumer of one group stops that group, not the operator: the other groups, and the
160 // groups still to come, have their own consumers. Only the observer of the groups
161 // themselves can stop the source.
162 match self.senders.entry(key) {
163 // A group whose consumer is gone drops the value instead of buffering it.
164 Entry::Occupied(entry) => {
165 let _ = entry.into_mut().on_next(value);
166 Flow::Continue
167 }
168 Entry::Vacant(entry) => {
169 let (sender, group) = unicast_subject();
170 let sender = entry.insert(sender);
171 // The group is emitted before its first value, so it can be subscribed to before
172 // that value arrives. A value sent to a group that nobody subscribed to yet waits
173 // in the group itself.
174 let flow = self.observer.on_next(group);
175 let _ = sender.on_next(value);
176 flow
177 }
178 }
179 }
180
181 fn on_termination(mut self, termination: Termination<E>) {
182 // The groups end before the outer Observable does.
183 for (_, sender) in self.senders.drain() {
184 sender.on_termination(termination.clone());
185 }
186 self.observer.on_termination(termination);
187 }
188}