ruststream_fred/pipeline/
source.rs1use std::fmt::{Debug, Formatter};
4use std::future::Future;
5use std::num::NonZeroUsize;
6use std::sync::Arc;
7
8use futures::Stream;
9#[cfg(feature = "asyncapi")]
10use ruststream::asyncapi::Bindings;
11use ruststream::{
12 AddressedCopies, BatchSubscriber, NamedCopies, RedeliveryAddress, RedeliveryAddressed,
13 RetryDeclaration, Seekable, Subscriber, SubscriptionSource,
14};
15
16use super::forms::{ListForm, PubSubForm, StreamForm};
17use super::window::{Form, Window};
18use super::{Pipelined, RoundMessage, WindowMode};
19use crate::broker::ConnectedRedisBroker;
20use crate::error::RedisError;
21use crate::list::{ListReader, RedisList};
22use crate::pubsub::{PubSubWire, RedisPubSub, RedisPubSubPattern};
23use crate::seek::RedisGroupSeeker;
24use crate::stream::RedisStream;
25use crate::subscriber::{PREFETCH, RedisSubscriber};
26
27fn prefetch() -> usize {
29 usize::try_from(PREFETCH).unwrap_or(usize::MAX)
30}
31
32pub struct PipelinedSubscriber<Inner, F: Form> {
36 inner: Inner,
37 window: Arc<Window<F>>,
38}
39
40impl<Inner, F: Form> Debug for PipelinedSubscriber<Inner, F> {
41 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
42 f.debug_struct("PipelinedSubscriber")
43 .field("window", &self.window)
44 .finish_non_exhaustive()
45 }
46}
47
48impl<Inner, F: Form> PipelinedSubscriber<Inner, F> {
49 fn new(inner: Inner, window: Window<F>) -> Self {
50 Self {
51 inner,
52 window: Arc::new(window),
53 }
54 }
55}
56
57impl<Inner, F: Form> Drop for PipelinedSubscriber<Inner, F> {
58 fn drop(&mut self) {
59 let window = Arc::clone(&self.window);
62 self.window.spawn(async move { window.drain().await });
63 }
64}
65
66impl Subscriber for PipelinedSubscriber<RedisSubscriber, StreamForm> {
67 type Message = RoundMessage<StreamForm>;
68 type Error = RedisError;
69
70 fn stream(&mut self) -> impl Stream<Item = Result<Self::Message, Self::Error>> + Send + '_ {
76 self.inner.round_stream(&self.window)
77 }
78}
79
80impl BatchSubscriber for PipelinedSubscriber<RedisSubscriber, StreamForm> {
81 type Batch = Vec<RoundMessage<StreamForm>>;
82
83 fn batches(
90 &mut self,
91 size: NonZeroUsize,
92 ) -> impl Stream<Item = Result<Self::Batch, Self::Error>> + Send + '_ {
93 self.inner.round_batches(&self.window, size)
94 }
95}
96
97impl Seekable for PipelinedSubscriber<RedisSubscriber, StreamForm> {
100 type Seeker = RedisGroupSeeker;
101
102 fn seeker(&self) -> RedisGroupSeeker {
103 self.inner.seeker()
104 }
105}
106
107pub struct ChannelReader(PubSubWire);
109
110impl Debug for ChannelReader {
111 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
112 f.debug_struct("ChannelReader").finish_non_exhaustive()
113 }
114}
115
116impl Subscriber for PipelinedSubscriber<ChannelReader, PubSubForm> {
117 type Message = RoundMessage<PubSubForm>;
118 type Error = RedisError;
119
120 fn stream(&mut self) -> impl Stream<Item = Result<Self::Message, Self::Error>> + Send + '_ {
126 self.inner.0.round_stream(&self.window)
127 }
128}
129
130impl Subscriber for PipelinedSubscriber<ListReader, ListForm> {
131 type Message = RoundMessage<ListForm>;
132 type Error = RedisError;
133
134 fn stream(&mut self) -> impl Stream<Item = Result<Self::Message, Self::Error>> + Send + '_ {
142 self.inner.round_stream(&self.window, prefetch())
143 }
144}
145
146impl BatchSubscriber for PipelinedSubscriber<ChannelReader, PubSubForm> {
147 type Batch = Vec<RoundMessage<PubSubForm>>;
148
149 fn batches(
156 &mut self,
157 size: NonZeroUsize,
158 ) -> impl Stream<Item = Result<Self::Batch, Self::Error>> + Send + '_ {
159 self.inner.0.round_batches(&self.window, size)
160 }
161}
162
163impl BatchSubscriber for PipelinedSubscriber<ListReader, ListForm> {
164 type Batch = Vec<RoundMessage<ListForm>>;
165
166 fn batches(
173 &mut self,
174 size: NonZeroUsize,
175 ) -> impl Stream<Item = Result<Self::Batch, Self::Error>> + Send + '_ {
176 self.inner.round_batches(&self.window, size)
177 }
178}
179
180macro_rules! delegates {
183 ($broker:ty, $name:ident) => {
184 fn name(&self) -> &str {
185 self.descriptor().$name()
186 }
187
188 fn declare_retry(self, declaration: &RetryDeclaration) -> Self {
189 Self::wrap(SubscriptionSource::<$broker>::declare_retry(
190 self.into_descriptor(),
191 declaration,
192 ))
193 }
194
195 #[cfg(feature = "asyncapi")]
196 fn channel_bindings(&self) -> Bindings {
197 SubscriptionSource::<$broker>::channel_bindings(self.descriptor())
198 }
199 };
200}
201
202macro_rules! addressed {
204 ($broker:ty, $descriptor:ty) => {
205 impl<Mode: WindowMode> RedeliveryAddressed<$broker> for Pipelined<$descriptor, Mode> {
206 fn redelivery_address(
207 &self,
208 connected: &$broker,
209 ) -> impl Future<Output = Result<RedeliveryAddress, RedisError>> {
210 self.descriptor().redelivery_address(connected)
211 }
212 }
213 };
214}
215
216impl<Mode: WindowMode> SubscriptionSource<ConnectedRedisBroker> for Pipelined<RedisStream, Mode> {
217 type Subscriber = PipelinedSubscriber<RedisSubscriber, StreamForm>;
218 type Copies = AddressedCopies;
219
220 delegates!(ConnectedRedisBroker, key);
221
222 async fn subscribe(
223 self,
224 connected: &ConnectedRedisBroker,
225 ) -> Result<Self::Subscriber, RedisError> {
226 let inner = connected.subscribe(self.into_descriptor()).await?;
227 let window = Window::new(
228 inner.round_form(),
229 inner.round_client(),
230 Mode::ATOMIC,
231 inner.key(),
232 prefetch(),
233 connected.window_owner()?,
234 );
235 Ok(PipelinedSubscriber::new(inner, window))
236 }
237}
238
239impl<Mode: WindowMode> SubscriptionSource<ConnectedRedisBroker> for Pipelined<RedisPubSub, Mode> {
240 type Subscriber = PipelinedSubscriber<ChannelReader, PubSubForm>;
241 type Copies = AddressedCopies;
242
243 delegates!(ConnectedRedisBroker, channel);
244
245 async fn subscribe(
246 self,
247 connected: &ConnectedRedisBroker,
248 ) -> Result<Self::Subscriber, RedisError> {
249 let channel = self.descriptor().channel().to_owned();
250 let inner = connected.open_pubsub(self.into_descriptor()).await?;
251 let window = Window::new(
254 PubSubForm,
255 inner.round_client(),
256 Mode::ATOMIC,
257 channel,
258 prefetch(),
259 connected.window_owner()?,
260 );
261 Ok(PipelinedSubscriber::new(ChannelReader(inner), window))
262 }
263}
264
265impl<Mode: WindowMode> SubscriptionSource<ConnectedRedisBroker>
268 for Pipelined<RedisPubSubPattern, Mode>
269{
270 type Subscriber = PipelinedSubscriber<ChannelReader, PubSubForm>;
271 type Copies = NamedCopies;
272
273 fn name(&self) -> &str {
274 self.descriptor().pattern()
275 }
276
277 async fn subscribe(
278 self,
279 connected: &ConnectedRedisBroker,
280 ) -> Result<Self::Subscriber, RedisError> {
281 let pattern = self.descriptor().pattern().to_owned();
282 let inner = connected
283 .open_pubsub_pattern(self.into_descriptor())
284 .await?;
285 let window = Window::new(
288 PubSubForm,
289 inner.round_client(),
290 Mode::ATOMIC,
291 pattern,
292 prefetch(),
293 connected.window_owner()?,
294 );
295 Ok(PipelinedSubscriber::new(ChannelReader(inner), window))
296 }
297
298 #[cfg(feature = "asyncapi")]
299 fn channel_bindings(&self) -> Bindings {
300 SubscriptionSource::<ConnectedRedisBroker>::channel_bindings(self.descriptor())
301 }
302}
303
304impl<Mode: WindowMode> SubscriptionSource<ConnectedRedisBroker> for Pipelined<RedisList, Mode> {
305 type Subscriber = PipelinedSubscriber<ListReader, ListForm>;
306 type Copies = AddressedCopies;
307
308 delegates!(ConnectedRedisBroker, key);
309
310 async fn subscribe(
311 self,
312 connected: &ConnectedRedisBroker,
313 ) -> Result<Self::Subscriber, RedisError> {
314 let wire = connected.open_list(self.into_descriptor()).await?;
315 let window = Window::new(
316 wire.round_form(),
317 wire.round_client(),
318 Mode::ATOMIC,
319 wire.key(),
320 prefetch(),
321 connected.window_owner()?,
322 );
323 Ok(PipelinedSubscriber::new(ListReader::new(wire), window))
324 }
325}
326
327addressed!(ConnectedRedisBroker, RedisStream);
328addressed!(ConnectedRedisBroker, RedisList);
329addressed!(ConnectedRedisBroker, RedisPubSub);