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>(
41 stream: S,
42 encoder: ENC,
43) -> impl Stream<Item = Result<Bytes, StreamError>> + Send + 'b
44where
45 S: Stream<Item = Result<T, StreamError>> + Send + Unpin + 'b,
46 T: Send + 'b,
47 ENC: ItemEncoder<T> + Send + 'b,
48{
49 let state = EncodeState {
50 inner: stream,
51 encoder,
52 index: 0,
53 phase: Phase::Prologue,
54 };
55
56 futures::stream::unfold(state, |mut st| async move {
57 loop {
58 match st.phase {
59 Phase::Prologue => {
60 let mut buf = BytesMut::new();
61 match st.encoder.prologue(&mut buf) {
62 Err(e) => {
63 st.phase = Phase::Done;
64 return Some((Err(e), st));
65 }
66 Ok(()) => {
67 st.phase = Phase::Items;
68 if !buf.is_empty() {
69 return Some((Ok(buf.freeze()), st));
70 }
71 }
72 }
73 }
74 Phase::Items => match st.inner.next().await {
75 Some(Ok(item)) => {
76 let mut buf = BytesMut::new();
77 let index = st.index;
78 match st.encoder.encode(&item, index, &mut buf) {
79 Err(e) => {
80 st.phase = Phase::Done;
81 return Some((Err(e), st));
82 }
83 Ok(()) => {
84 st.index += 1;
85 if !buf.is_empty() {
86 return Some((Ok(buf.freeze()), st));
87 }
88 }
89 }
90 }
91 Some(Err(e)) => {
94 st.phase = Phase::Done;
95 return Some((Err(e), st));
96 }
97 None => st.phase = Phase::Epilogue,
98 },
99 Phase::Epilogue => {
100 let mut buf = BytesMut::new();
101 let result = st.encoder.epilogue(&mut buf);
102 st.phase = Phase::Done;
103 match result {
104 Err(e) => return Some((Err(e), st)),
105 Ok(()) => {
106 if !buf.is_empty() {
107 return Some((Ok(buf.freeze()), st));
108 }
109 }
110 }
111 }
112 Phase::Done => return None,
113 }
114 }
115 })
116}
117
118pub fn decode_stream<'b, S, F, D, P, T>(
131 stream: S,
132 framer: D,
133 parser: P,
134 options: &DecodeOptions,
135) -> impl Stream<Item = Result<T, StreamError>> + Send + 'b
136where
137 S: Stream<Item = Result<Bytes, std::io::Error>> + Send + 'b,
138 D: Decoder<Item = F, Error = StreamError> + Send + 'b,
139 P: FrameParser<F, T> + Send + 'b,
140 F: 'b,
141{
142 let reader = StreamReader::new(Box::pin(stream));
143 FramedRead::with_capacity(reader, framer, options.buf_capacity).map(
144 move |framed| match framed {
145 Ok(frame) => parser.parse(frame),
146 Err(err) => Err(err),
147 },
148 )
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154 use crate::error::StreamErrorKind;
155
156 struct Bracketed {
158 fail_at: Option<u64>,
159 }
160
161 impl ItemEncoder<u32> for Bracketed {
162 fn prologue(&mut self, buf: &mut BytesMut) -> Result<(), StreamError> {
163 buf.extend_from_slice(b"[");
164 Ok(())
165 }
166
167 fn encode(
168 &mut self,
169 item: &u32,
170 index: u64,
171 buf: &mut BytesMut,
172 ) -> Result<(), StreamError> {
173 if self.fail_at == Some(index) {
174 return Err(StreamError::new(
175 StreamErrorKind::CodecError,
176 None,
177 Some("boom".into()),
178 ));
179 }
180 if index != 0 {
181 buf.extend_from_slice(b",");
182 }
183 buf.extend_from_slice(item.to_string().as_bytes());
184 Ok(())
185 }
186
187 fn epilogue(&mut self, buf: &mut BytesMut) -> Result<(), StreamError> {
188 buf.extend_from_slice(b"]");
189 Ok(())
190 }
191 }
192
193 async fn collect(s: impl Stream<Item = Result<Bytes, StreamError>>) -> (Vec<u8>, usize) {
194 let items: Vec<_> = Box::pin(s).collect().await;
195 let errors = items.iter().filter(|i| i.is_err()).count();
196 let mut out = Vec::new();
197 for i in items.into_iter().flatten() {
198 out.extend_from_slice(&i);
199 }
200 (out, errors)
201 }
202
203 #[tokio::test]
204 async fn encodes_prologue_items_and_epilogue() {
205 let source = futures::stream::iter(vec![Ok(1u32), Ok(2), Ok(3)]);
206 let (bytes, errors) = collect(encode_stream(source, Bracketed { fail_at: None })).await;
207 assert_eq!(String::from_utf8(bytes).unwrap(), "[1,2,3]");
208 assert_eq!(errors, 0);
209 }
210
211 #[tokio::test]
212 async fn empty_source_still_brackets() {
213 let source = futures::stream::iter(Vec::<Result<u32, StreamError>>::new());
214 let (bytes, _) = collect(encode_stream(source, Bracketed { fail_at: None })).await;
215 assert_eq!(String::from_utf8(bytes).unwrap(), "[]");
216 }
217
218 #[tokio::test]
221 async fn encoder_error_suppresses_the_epilogue() {
222 let source = futures::stream::iter(vec![Ok(1u32), Ok(2), Ok(3)]);
223 let (bytes, errors) = collect(encode_stream(source, Bracketed { fail_at: Some(1) })).await;
224 assert_eq!(String::from_utf8(bytes).unwrap(), "[1");
225 assert_eq!(errors, 1);
226 }
227
228 #[tokio::test]
229 async fn source_error_is_forwarded_and_suppresses_the_epilogue() {
230 let source = futures::stream::iter(vec![
231 Ok(1u32),
232 Err(StreamError::new(
233 StreamErrorKind::InputOutputError,
234 None,
235 None,
236 )),
237 ]);
238 let (bytes, errors) = collect(encode_stream(source, Bracketed { fail_at: None })).await;
239 assert_eq!(String::from_utf8(bytes).unwrap(), "[1");
240 assert_eq!(errors, 1);
241 }
242}