rx_rust/operators/combining/
zip.rs1use crate::utils::serialized_delivery::UpdateOutcome;
2use crate::utils::subscribe_with_context::{
3 self, SubscriptionContext, subscribe_with_context_owning_source,
4};
5use crate::utils::types::MaybeSend;
6use crate::{
7 disposable::Disposable,
8 observable::{Observable, Subscription},
9 observer::{Flow, Observer, Termination},
10};
11use educe::Educe;
12use std::collections::VecDeque;
13
14#[derive(Educe)]
44#[educe(Debug, Clone)]
45pub struct Zip<OE1, OE2> {
46 source_1: OE1,
47 source_2: OE2,
48}
49
50impl<OE1, OE2> Zip<OE1, OE2> {
51 pub fn new<'or, T1, T2, E>(source_1: OE1, source_2: OE2) -> Self
52 where
53 OE1: Observable<'or, T1, E>,
54 OE2: Observable<'or, T2, E>,
55 {
56 Self { source_1, source_2 }
57 }
58}
59
60impl<'or, T1, T2, E, OE1, OE2> Observable<'or, (T1, T2), E> for Zip<OE1, OE2>
61where
62 T1: MaybeSend + 'or,
63 T2: MaybeSend + 'or,
64 E: MaybeSend + 'or,
65 OE1: Observable<'or, T1, E>,
66 OE1::D: MaybeSend + 'or,
67 OE2: Observable<'or, T2, E>,
68 OE2::D: MaybeSend + 'or,
69{
70 type D = subscribe_with_context::OwningDisposal<'or>;
71
72 fn subscribe(
73 self,
74 observer: impl Observer<(T1, T2), E> + MaybeSend + 'or,
75 ) -> Subscription<Self::D> {
76 let model = Model {
77 first: (VecDeque::new(), false),
78 second: (VecDeque::new(), false),
79 };
80 subscribe_with_context_owning_source(observer, model, |context| {
81 let subscription_1 = self.source_1.subscribe(ZipObserver1(context.clone()));
82 let subscription_2 = self.source_2.subscribe(ZipObserver2(context));
83 subscription_1.preceded_by_bound(subscription_2)
84 })
85 }
86}
87
88struct Model<T1, T2> {
89 first: (VecDeque<T1>, bool), second: (VecDeque<T2>, bool), }
92
93macro_rules! impl_zip_observer {
94 ($name:ident, $input_t:ty, $this_field:ident, $other_field:ident, $make_pair:expr) => {
95 struct $name<T1, T2, E, OR, D: Disposable>(
96 SubscriptionContext<(T1, T2), E, OR, Model<T1, T2>, D>,
97 );
98
99 impl<T1, T2, E, OR, D> Observer<$input_t, E> for $name<T1, T2, E, OR, D>
100 where
101 OR: Observer<(T1, T2), E>,
102 D: Disposable,
103 {
104 fn on_next(&mut self, value: $input_t) -> Flow {
105 self.0.update_flow(|model| {
106 if let Some(other) = model.$other_field.0.pop_front() {
107 if model.$other_field.1 && model.$other_field.0.is_empty() {
108 UpdateOutcome::empty().with_next_and_termination_events(
109 $make_pair(value, other),
110 Termination::Completed,
111 )
112 } else {
113 UpdateOutcome::empty().with_next_event($make_pair(value, other))
114 }
115 } else {
116 model.$this_field.0.push_back(value);
117 UpdateOutcome::empty().without_events()
118 }
119 })
120 }
121
122 fn on_termination(self, termination: Termination<E>) {
123 match termination {
124 completion @ Termination::Completed => {
125 let _ = self.0.update(|model| {
126 model.$this_field.1 = true;
127 if model.$this_field.0.is_empty() {
128 UpdateOutcome::empty().with_termination_event(completion)
129 } else {
130 UpdateOutcome::empty().without_events()
131 }
132 });
133 }
134 error @ Termination::Error(_) => {
135 self.0.send_termination(error);
136 }
137 };
138 }
139 }
140 };
141}
142
143impl_zip_observer!(ZipObserver1, T1, first, second, |this, other| (this, other));
144impl_zip_observer!(ZipObserver2, T2, second, first, |this, other| (other, this));