1use core::{
2 pin::Pin,
3 task::{Context, Poll, ready},
4};
5
6use std::io;
7
8use bytes::Bytes;
9use http::HeaderMap;
10use http_body_alt::{Body, Frame, SizeHint};
11use pin_project_lite::pin_project;
12
13use super::error::CoderError;
14
15pin_project! {
16 #[derive(Default)]
18 pub struct Coder<S, C = FeaturedCode>{
19 #[pin]
20 body: S,
21 coder: C,
22 trailers: Option<HeaderMap>
23 }
24}
25
26impl<S, C> Coder<S, C>
27where
28 S: Body,
29 C: Code<S::Data>,
30 S::Data: AsRef<[u8]>,
31{
32 #[inline]
34 pub const fn new(body: S, coder: C) -> Self {
35 Self {
36 body,
37 coder,
38 trailers: None,
39 }
40 }
41
42 #[inline]
43 pub fn into_inner(self) -> S {
44 self.body
45 }
46}
47
48impl<S, C> Body for Coder<S, C>
49where
50 S: Body,
51 CoderError: From<S::Error>,
52 C: Code<S::Data>,
53{
54 type Data = C::Item;
55 type Error = CoderError;
56
57 fn poll_frame(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
58 let mut this = self.project();
59
60 while let Some(res) = ready!(this.body.as_mut().poll_frame(cx)) {
61 match res? {
62 Frame::Data(item) => {
63 if let Some(item) = this.coder.code(item)? {
64 return Poll::Ready(Some(Ok(Frame::Data(item))));
65 }
66 }
67 Frame::Trailers(trailers) => {
68 this.trailers.replace(trailers);
69 break;
70 }
71 }
72 }
73
74 match this.coder.code_eof()? {
75 Some(res) => Poll::Ready(Some(Ok(Frame::Data(res)))),
76 None => Poll::Ready(this.trailers.take().map(|trailsers| Ok(Frame::Trailers(trailsers)))),
77 }
78 }
79
80 fn is_end_stream(&self) -> bool {
81 self.coder.is_end_stream(&self.body) && self.trailers.is_none()
83 }
84
85 #[inline]
86 fn size_hint(&self) -> SizeHint {
87 self.coder.size_hint(&self.body)
89 }
90}
91
92pub trait Code<T>: Sized {
93 type Item;
94
95 fn code(&mut self, item: T) -> io::Result<Option<Self::Item>>;
96
97 fn code_eof(&mut self) -> io::Result<Option<Self::Item>>;
98
99 #[allow(unused_variables)]
103 #[inline]
104 fn is_end_stream(&self, body: &impl Body) -> bool {
105 false
106 }
107
108 #[allow(unused_variables)]
112 #[inline]
113 fn size_hint(&self, body: &impl Body) -> SizeHint {
114 SizeHint::default()
115 }
116}
117
118pub struct NoOpCode;
120
121impl<T> Code<T> for NoOpCode
122where
123 T: AsRef<[u8]> + 'static,
124{
125 type Item = Bytes;
126
127 fn code(&mut self, item: T) -> io::Result<Option<Self::Item>> {
128 Ok(Some(
129 try_downcast_to_bytes(item).unwrap_or_else(|item| Bytes::copy_from_slice(item.as_ref())),
130 ))
131 }
132
133 #[inline]
134 fn code_eof(&mut self) -> io::Result<Option<Self::Item>> {
135 Ok(None)
136 }
137
138 #[inline]
140 fn is_end_stream(&self, body: &impl Body) -> bool {
141 body.is_end_stream()
142 }
143
144 #[inline]
148 fn size_hint(&self, body: &impl Body) -> SizeHint {
149 body.size_hint()
150 }
151}
152
153pub enum FeaturedCode {
154 NoOp(NoOpCode),
155 #[cfg(feature = "br")]
156 DecodeBr(super::brotli::Decoder),
157 #[cfg(feature = "br")]
158 EncodeBr(super::brotli::Encoder),
159 #[cfg(feature = "gz")]
160 DecodeGz(super::gzip::Decoder),
161 #[cfg(feature = "gz")]
162 EncodeGz(super::gzip::Encoder),
163 #[cfg(feature = "de")]
164 DecodeDe(super::deflate::Decoder),
165 #[cfg(feature = "de")]
166 EncodeDe(super::deflate::Encoder),
167 #[cfg(feature = "zs")]
168 DecodeZs(super::zstandard::Decoder),
169 #[cfg(feature = "zs")]
170 EncodeZs(super::zstandard::Encoder),
171}
172
173impl Default for FeaturedCode {
174 fn default() -> Self {
175 Self::NoOp(NoOpCode)
176 }
177}
178
179impl<T> Code<T> for FeaturedCode
180where
181 T: AsRef<[u8]> + 'static,
182{
183 type Item = Bytes;
184
185 fn code(&mut self, item: T) -> io::Result<Option<Self::Item>> {
186 match self {
187 Self::NoOp(coder) => coder.code(item),
188 #[cfg(feature = "br")]
189 Self::DecodeBr(coder) => coder.code(item),
190 #[cfg(feature = "br")]
191 Self::EncodeBr(coder) => coder.code(item),
192 #[cfg(feature = "gz")]
193 Self::DecodeGz(coder) => coder.code(item),
194 #[cfg(feature = "gz")]
195 Self::EncodeGz(coder) => coder.code(item),
196 #[cfg(feature = "de")]
197 Self::DecodeDe(coder) => coder.code(item),
198 #[cfg(feature = "de")]
199 Self::EncodeDe(coder) => coder.code(item),
200 #[cfg(feature = "zs")]
201 Self::DecodeZs(coder) => coder.code(item),
202 #[cfg(feature = "zs")]
203 Self::EncodeZs(coder) => coder.code(item),
204 }
205 }
206
207 fn code_eof(&mut self) -> io::Result<Option<Self::Item>> {
208 match self {
209 Self::NoOp(coder) => <NoOpCode as Code<T>>::code_eof(coder),
210 #[cfg(feature = "br")]
211 Self::DecodeBr(coder) => <super::brotli::Decoder as Code<T>>::code_eof(coder),
212 #[cfg(feature = "br")]
213 Self::EncodeBr(coder) => <super::brotli::Encoder as Code<T>>::code_eof(coder),
214 #[cfg(feature = "gz")]
215 Self::DecodeGz(coder) => <super::gzip::Decoder as Code<T>>::code_eof(coder),
216 #[cfg(feature = "gz")]
217 Self::EncodeGz(coder) => <super::gzip::Encoder as Code<T>>::code_eof(coder),
218 #[cfg(feature = "de")]
219 Self::DecodeDe(coder) => <super::deflate::Decoder as Code<T>>::code_eof(coder),
220 #[cfg(feature = "de")]
221 Self::EncodeDe(coder) => <super::deflate::Encoder as Code<T>>::code_eof(coder),
222 #[cfg(feature = "zs")]
223 Self::DecodeZs(coder) => <super::zstandard::Decoder as Code<T>>::code_eof(coder),
224 #[cfg(feature = "zs")]
225 Self::EncodeZs(coder) => <super::zstandard::Encoder as Code<T>>::code_eof(coder),
226 }
227 }
228
229 fn is_end_stream(&self, body: &impl Body) -> bool {
230 match self {
231 Self::NoOp(coder) => <NoOpCode as Code<T>>::is_end_stream(coder, body),
232 #[cfg(feature = "br")]
233 Self::DecodeBr(coder) => <super::brotli::Decoder as Code<T>>::is_end_stream(coder, body),
234 #[cfg(feature = "br")]
235 Self::EncodeBr(coder) => <super::brotli::Encoder as Code<T>>::is_end_stream(coder, body),
236 #[cfg(feature = "gz")]
237 Self::DecodeGz(coder) => <super::gzip::Decoder as Code<T>>::is_end_stream(coder, body),
238 #[cfg(feature = "gz")]
239 Self::EncodeGz(coder) => <super::gzip::Encoder as Code<T>>::is_end_stream(coder, body),
240 #[cfg(feature = "de")]
241 Self::DecodeDe(coder) => <super::deflate::Decoder as Code<T>>::is_end_stream(coder, body),
242 #[cfg(feature = "de")]
243 Self::EncodeDe(coder) => <super::deflate::Encoder as Code<T>>::is_end_stream(coder, body),
244 #[cfg(feature = "zs")]
245 Self::DecodeZs(coder) => <super::zstandard::Decoder as Code<T>>::is_end_stream(coder, body),
246 #[cfg(feature = "zs")]
247 Self::EncodeZs(coder) => <super::zstandard::Encoder as Code<T>>::is_end_stream(coder, body),
248 }
249 }
250
251 fn size_hint(&self, body: &impl Body) -> SizeHint {
252 match self {
253 Self::NoOp(coder) => <NoOpCode as Code<T>>::size_hint(coder, body),
254 #[cfg(feature = "br")]
255 Self::DecodeBr(coder) => <super::brotli::Decoder as Code<T>>::size_hint(coder, body),
256 #[cfg(feature = "br")]
257 Self::EncodeBr(coder) => <super::brotli::Encoder as Code<T>>::size_hint(coder, body),
258 #[cfg(feature = "gz")]
259 Self::DecodeGz(coder) => <super::gzip::Decoder as Code<T>>::size_hint(coder, body),
260 #[cfg(feature = "gz")]
261 Self::EncodeGz(coder) => <super::gzip::Encoder as Code<T>>::size_hint(coder, body),
262 #[cfg(feature = "de")]
263 Self::DecodeDe(coder) => <super::deflate::Decoder as Code<T>>::size_hint(coder, body),
264 #[cfg(feature = "de")]
265 Self::EncodeDe(coder) => <super::deflate::Encoder as Code<T>>::size_hint(coder, body),
266 #[cfg(feature = "zs")]
267 Self::DecodeZs(coder) => <super::zstandard::Decoder as Code<T>>::size_hint(coder, body),
268 #[cfg(feature = "zs")]
269 Self::EncodeZs(coder) => <super::zstandard::Encoder as Code<T>>::size_hint(coder, body),
270 }
271 }
272}
273
274#[cfg(any(feature = "gz", feature = "de"))]
275macro_rules! code_impl {
276 ($coder: ident) => {
277 impl<T> crate::Code<T> for $coder<crate::writer::BytesMutWriter>
278 where
279 T: AsRef<[u8]>,
280 {
281 type Item = ::bytes::Bytes;
282
283 fn code(&mut self, item: T) -> ::std::io::Result<Option<Self::Item>> {
284 use ::std::io::Write;
285
286 self.write_all(item.as_ref())?;
287 let b = self.get_mut().take();
288 if !b.is_empty() { Ok(Some(b)) } else { Ok(None) }
289 }
290
291 fn code_eof(&mut self) -> ::std::io::Result<Option<Self::Item>> {
292 self.try_finish()?;
293 let b = self.get_mut().take();
294 if !b.is_empty() { Ok(Some(b)) } else { Ok(None) }
295 }
296 }
297 };
298}
299
300fn try_downcast_to_bytes<T: 'static>(item: T) -> Result<Bytes, T> {
301 use core::any::Any;
302
303 let item = &mut Some(item);
304 match (item as &mut dyn Any).downcast_mut::<Option<Bytes>>() {
305 Some(bytes) => Ok(bytes.take().unwrap()),
306 None => Err(item.take().unwrap()),
307 }
308}
309
310#[cfg(test)]
311mod test {
312 use super::*;
313
314 #[test]
315 fn downcast_bytes() {
316 let bytes = Bytes::new();
317 assert!(try_downcast_to_bytes(bytes).is_ok());
318 let bytes = Vec::<u8>::new();
319 assert!(try_downcast_to_bytes(bytes).is_err());
320 }
321}