1use crate::error::StreamError;
10use crate::format::{DecodeOptions, FrameParser, ItemEncoder};
11use bytes::{Bytes, BytesMut};
12use futures::stream::{Stream, StreamExt};
13use tokio_util::codec::{Decoder, FramedRead};
14use tokio_util::io::StreamReader;
15
16enum Phase {
23 Prologue,
24 Items,
25 Epilogue,
26 Done,
27}
28
29struct EncodeState<S, ENC> {
30 inner: S,
31 encoder: ENC,
32 index: u64,
33 phase: Phase,
34}
35
36pub fn encode_stream<'b, S, T, ENC>(
45 stream: S,
46 encoder: ENC,
47) -> impl Stream<Item = Result<Bytes, StreamError>> + Send + 'b
48where
49 S: Stream<Item = Result<T, StreamError>> + Send + Unpin + 'b,
50 T: Send + 'b,
51 ENC: ItemEncoder<T> + Send + 'b,
52{
53 let state = EncodeState {
54 inner: stream,
55 encoder,
56 index: 0,
57 phase: Phase::Prologue,
58 };
59
60 futures::stream::unfold(state, |mut st| async move {
61 loop {
62 match st.phase {
63 Phase::Prologue => {
64 let mut buf = BytesMut::new();
65 match st.encoder.prologue(&mut buf) {
66 Err(e) => {
67 st.phase = Phase::Done;
68 return Some((Err(e), st));
69 }
70 Ok(()) => {
71 st.phase = Phase::Items;
72 if !buf.is_empty() {
73 return Some((Ok(buf.freeze()), st));
74 }
75 }
76 }
77 }
78 Phase::Items => match st.inner.next().await {
79 Some(Ok(item)) => {
80 let mut buf = BytesMut::new();
81 let index = st.index;
82 match st.encoder.encode(&item, index, &mut buf) {
83 Err(e) => {
84 st.phase = Phase::Done;
85 return Some((Err(e), st));
86 }
87 Ok(()) => {
88 st.index += 1;
89 if !buf.is_empty() {
90 return Some((Ok(buf.freeze()), st));
91 }
92 }
93 }
94 }
95 Some(Err(e)) => {
98 st.phase = Phase::Done;
99 return Some((Err(e), st));
100 }
101 None => st.phase = Phase::Epilogue,
102 },
103 Phase::Epilogue => {
104 let mut buf = BytesMut::new();
105 let result = st.encoder.epilogue(&mut buf);
106 st.phase = Phase::Done;
107 match result {
108 Err(e) => return Some((Err(e), st)),
109 Ok(()) => {
110 if !buf.is_empty() {
111 return Some((Ok(buf.freeze()), st));
112 }
113 }
114 }
115 }
116 Phase::Done => return None,
117 }
118 }
119 })
120 .fuse()
123}
124
125pub fn decode_stream<'b, S, F, D, P, T>(
138 stream: S,
139 framer: D,
140 parser: P,
141 options: &DecodeOptions,
142) -> impl Stream<Item = Result<T, StreamError>> + Send + 'b
143where
144 S: Stream<Item = Result<Bytes, std::io::Error>> + Send + 'b,
145 D: Decoder<Item = F, Error = StreamError> + Send + 'b,
146 P: FrameParser<F, T> + Send + 'b,
147 F: 'b,
148{
149 let reader = StreamReader::new(Box::pin(stream));
150 FramedRead::with_capacity(reader, framer, options.buf_capacity).map(
151 move |framed| match framed {
152 Ok(frame) => parser.parse(frame),
153 Err(err) => Err(err),
154 },
155 )
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161 use crate::error::StreamErrorKind;
162
163 struct Bracketed {
165 fail_at: Option<u64>,
166 }
167
168 impl ItemEncoder<u32> for Bracketed {
169 fn prologue(&mut self, buf: &mut BytesMut) -> Result<(), StreamError> {
170 buf.extend_from_slice(b"[");
171 Ok(())
172 }
173
174 fn encode(
175 &mut self,
176 item: &u32,
177 index: u64,
178 buf: &mut BytesMut,
179 ) -> Result<(), StreamError> {
180 if self.fail_at == Some(index) {
181 return Err(StreamError::new(
182 StreamErrorKind::CodecError,
183 None,
184 Some("boom".into()),
185 ));
186 }
187 if index != 0 {
188 buf.extend_from_slice(b",");
189 }
190 buf.extend_from_slice(item.to_string().as_bytes());
191 Ok(())
192 }
193
194 fn epilogue(&mut self, buf: &mut BytesMut) -> Result<(), StreamError> {
195 buf.extend_from_slice(b"]");
196 Ok(())
197 }
198 }
199
200 async fn collect(s: impl Stream<Item = Result<Bytes, StreamError>>) -> (Vec<u8>, usize) {
201 let items: Vec<_> = Box::pin(s).collect().await;
202 let errors = items.iter().filter(|i| i.is_err()).count();
203 let mut out = Vec::new();
204 for i in items.into_iter().flatten() {
205 out.extend_from_slice(&i);
206 }
207 (out, errors)
208 }
209
210 #[tokio::test]
211 async fn encodes_prologue_items_and_epilogue() {
212 let source = futures::stream::iter(vec![Ok(1u32), Ok(2), Ok(3)]);
213 let (bytes, errors) = collect(encode_stream(source, Bracketed { fail_at: None })).await;
214 assert_eq!(String::from_utf8(bytes).unwrap(), "[1,2,3]");
215 assert_eq!(errors, 0);
216 }
217
218 #[tokio::test]
219 async fn empty_source_still_brackets() {
220 let source = futures::stream::iter(Vec::<Result<u32, StreamError>>::new());
221 let (bytes, _) = collect(encode_stream(source, Bracketed { fail_at: None })).await;
222 assert_eq!(String::from_utf8(bytes).unwrap(), "[]");
223 }
224
225 #[tokio::test]
228 async fn encoder_error_suppresses_the_epilogue() {
229 let source = futures::stream::iter(vec![Ok(1u32), Ok(2), Ok(3)]);
230 let (bytes, errors) = collect(encode_stream(source, Bracketed { fail_at: Some(1) })).await;
231 assert_eq!(String::from_utf8(bytes).unwrap(), "[1");
232 assert_eq!(errors, 1);
233 }
234
235 #[tokio::test]
236 async fn source_error_is_forwarded_and_suppresses_the_epilogue() {
237 let source = futures::stream::iter(vec![
238 Ok(1u32),
239 Err(StreamError::new(
240 StreamErrorKind::InputOutputError,
241 None,
242 None,
243 )),
244 ]);
245 let (bytes, errors) = collect(encode_stream(source, Bracketed { fail_at: None })).await;
246 assert_eq!(String::from_utf8(bytes).unwrap(), "[1");
247 assert_eq!(errors, 1);
248 }
249
250 #[tokio::test]
254 async fn polling_after_completion_yields_none() {
255 let source = futures::stream::iter(vec![Ok(1u32), Ok(2)]);
256 let mut stream = Box::pin(encode_stream(source, Bracketed { fail_at: None }));
257 while stream.next().await.is_some() {}
258 assert!(stream.next().await.is_none());
259 assert!(stream.next().await.is_none());
260 }
261
262 #[tokio::test]
265 async fn polling_after_an_error_yields_none() {
266 let source = futures::stream::iter(vec![Ok(1u32), Ok(2), Ok(3)]);
267 let mut stream = Box::pin(encode_stream(source, Bracketed { fail_at: Some(1) }));
268 while stream.next().await.is_some() {}
269 assert!(stream.next().await.is_none());
270 assert!(stream.next().await.is_none());
271 }
272}