rustrade_integration/stream/
exchange.rs1use crate::{Transformer, error::SocketError, protocol::StreamParser};
2use futures::Stream;
3use pin_project::pin_project;
4use std::{
5 collections::VecDeque,
6 marker::PhantomData,
7 pin::Pin,
8 task::{Context, Poll},
9};
10
11#[derive(Debug)]
16#[pin_project]
17pub struct ExchangeStream<Protocol, InnerStream, StreamTransformer>
18where
19 Protocol: StreamParser<StreamTransformer::Input>,
20 InnerStream: Stream,
21 StreamTransformer: Transformer,
22{
23 #[pin]
24 pub stream: InnerStream,
25 pub transformer: StreamTransformer,
26 pub buffer: VecDeque<Result<StreamTransformer::Output, StreamTransformer::Error>>,
27 pub protocol_marker: PhantomData<Protocol>,
28}
29
30impl<Protocol, InnerStream, StreamTransformer> Stream
31 for ExchangeStream<Protocol, InnerStream, StreamTransformer>
32where
33 Protocol: StreamParser<StreamTransformer::Input>,
34 InnerStream: Stream<Item = Result<Protocol::Message, Protocol::Error>> + Unpin,
35 StreamTransformer: Transformer,
36 StreamTransformer::Error: From<SocketError>,
37{
38 type Item = Result<StreamTransformer::Output, StreamTransformer::Error>;
39
40 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
41 loop {
42 if let Some(output) = self.buffer.pop_front() {
44 return Poll::Ready(Some(output));
45 }
46
47 let input = match self.as_mut().project().stream.poll_next(cx) {
49 Poll::Ready(Some(input)) => input,
50 Poll::Ready(None) => return Poll::Ready(None),
51 Poll::Pending => return Poll::Pending,
52 };
53
54 let exchange_message = match Protocol::parse(input) {
56 Some(Ok(exchange_message)) => exchange_message,
58
59 Some(Err(err)) => return Poll::Ready(Some(Err(err.into()))),
61
62 None => continue,
64 };
65
66 self.transformer
69 .transform(exchange_message)
70 .into_iter()
71 .for_each(
72 |output_result: Result<StreamTransformer::Output, StreamTransformer::Error>| {
73 self.buffer.push_back(output_result)
74 },
75 );
76 }
77 }
78}
79
80impl<Protocol, InnerStream, StreamTransformer>
81 ExchangeStream<Protocol, InnerStream, StreamTransformer>
82where
83 Protocol: StreamParser<StreamTransformer::Input>,
84 InnerStream: Stream,
85 StreamTransformer: Transformer,
86{
87 pub fn new(
88 stream: InnerStream,
89 transformer: StreamTransformer,
90 buffer: VecDeque<Result<StreamTransformer::Output, StreamTransformer::Error>>,
91 ) -> Self {
92 Self {
93 stream,
94 transformer,
95 buffer,
96 protocol_marker: PhantomData,
97 }
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use futures::StreamExt;
105
106 struct SkipZeroParser;
109
110 impl StreamParser<i32> for SkipZeroParser {
111 type Stream = futures::stream::Empty<i32>;
112 type Message = i32;
113 type Error = SocketError;
114
115 fn parse(input: Result<i32, SocketError>) -> Option<Result<i32, SocketError>> {
116 match input {
117 Ok(0) => None,
118 Ok(n) if n < 0 => Some(Err(SocketError::Sink)),
119 other => Some(other),
120 }
121 }
122 }
123
124 struct TwoOutputs;
126
127 impl Transformer for TwoOutputs {
128 type Error = SocketError;
129 type Input = i32;
130 type Output = i32;
131 type OutputIter = Vec<Result<i32, SocketError>>;
132
133 fn transform(&mut self, input: i32) -> Self::OutputIter {
134 vec![Ok(input), Ok(input * 10)]
135 }
136 }
137
138 #[tokio::test]
139 async fn exchange_stream_parses_skips_and_buffers_until_the_inner_stream_ends() {
140 let inner = futures::stream::iter([Ok(1), Ok(0), Ok(-1), Ok(2)]);
141 let stream =
142 ExchangeStream::<SkipZeroParser, _, _>::new(inner, TwoOutputs, VecDeque::new());
143
144 let outputs = stream
145 .map(|result| result.map_err(|error| error.to_string()))
146 .collect::<Vec<_>>()
147 .await;
148
149 assert_eq!(
150 outputs,
151 vec![
152 Ok(1),
153 Ok(10),
154 Err(SocketError::Sink.to_string()),
155 Ok(2),
156 Ok(20),
157 ]
158 );
159 }
160}