Optimize decoder::Inner: Box all variants except PlainText
since these variants are just way too large: - Variant `Brotli` is 2752b - Variant `Gzip` is 320b - Variant `Deflate` is 240b - Variant `Pending` is 88b while variant `PlainText` is just 32b. Having a large variant would make `Response` and return type of `Response::bytes_stream` to be too large, which in turns adds extra copy. It would also means the generated async functions all have to be large, and since rust MIR/LLVM isn't good at optimizing out stack copies for async functions, it means more copies it going to occur for the generated futures. Also, rust MIR optimizer cannot inline generated futures, so any async fns that passes these types around would have to be huge. Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
@@ -43,29 +43,34 @@ pub(crate) struct Decoder {
|
||||
inner: Inner,
|
||||
}
|
||||
|
||||
type PeekableIoStream = Peekable<IoStream>;
|
||||
|
||||
#[cfg(any(feature = "gzip", feature = "brotli", feature = "deflate"))]
|
||||
type PeekableIoStreamReader = StreamReader<PeekableIoStream, Bytes>;
|
||||
|
||||
enum Inner {
|
||||
/// A `PlainText` decoder just returns the response content as is.
|
||||
PlainText(super::body::ImplStream),
|
||||
|
||||
/// A `Gzip` decoder will uncompress the gzipped response content before returning it.
|
||||
#[cfg(feature = "gzip")]
|
||||
Gzip(FramedRead<GzipDecoder<StreamReader<Peekable<IoStream>, Bytes>>, BytesCodec>),
|
||||
Gzip(Pin<Box<FramedRead<GzipDecoder<PeekableIoStreamReader>, BytesCodec>>>),
|
||||
|
||||
/// A `Brotli` decoder will uncompress the brotlied response content before returning it.
|
||||
#[cfg(feature = "brotli")]
|
||||
Brotli(FramedRead<BrotliDecoder<StreamReader<Peekable<IoStream>, Bytes>>, BytesCodec>),
|
||||
Brotli(Pin<Box<FramedRead<BrotliDecoder<PeekableIoStreamReader>, BytesCodec>>>),
|
||||
|
||||
/// A `Deflate` decoder will uncompress the deflated response content before returning it.
|
||||
#[cfg(feature = "deflate")]
|
||||
Deflate(FramedRead<ZlibDecoder<StreamReader<Peekable<IoStream>, Bytes>>, BytesCodec>),
|
||||
Deflate(Pin<Box<FramedRead<ZlibDecoder<PeekableIoStreamReader>, BytesCodec>>>),
|
||||
|
||||
/// A decoder that doesn't have a value yet.
|
||||
#[cfg(any(feature = "brotli", feature = "gzip", feature = "deflate"))]
|
||||
Pending(Pending),
|
||||
Pending(Pin<Box<Pending>>),
|
||||
}
|
||||
|
||||
/// A future attempt to poll the response body for EOF so we know whether to use gzip or not.
|
||||
struct Pending(Peekable<IoStream>, DecoderType);
|
||||
struct Pending(PeekableIoStream, DecoderType);
|
||||
|
||||
struct IoStream(super::body::ImplStream);
|
||||
|
||||
@@ -109,10 +114,10 @@ impl Decoder {
|
||||
use futures_util::StreamExt;
|
||||
|
||||
Decoder {
|
||||
inner: Inner::Pending(Pending(
|
||||
inner: Inner::Pending(Box::pin(Pending(
|
||||
IoStream(body.into_stream()).peekable(),
|
||||
DecoderType::Gzip,
|
||||
)),
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,10 +129,10 @@ impl Decoder {
|
||||
use futures_util::StreamExt;
|
||||
|
||||
Decoder {
|
||||
inner: Inner::Pending(Pending(
|
||||
inner: Inner::Pending(Box::pin(Pending(
|
||||
IoStream(body.into_stream()).peekable(),
|
||||
DecoderType::Brotli,
|
||||
)),
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,10 +144,10 @@ impl Decoder {
|
||||
use futures_util::StreamExt;
|
||||
|
||||
Decoder {
|
||||
inner: Inner::Pending(Pending(
|
||||
inner: Inner::Pending(Box::pin(Pending(
|
||||
IoStream(body.into_stream()).peekable(),
|
||||
DecoderType::Deflate,
|
||||
)),
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,37 +223,35 @@ impl Stream for Decoder {
|
||||
Inner::Pending(ref mut future) => match Pin::new(future).poll(cx) {
|
||||
Poll::Ready(Ok(inner)) => {
|
||||
self.inner = inner;
|
||||
return self.poll_next(cx);
|
||||
self.poll_next(cx)
|
||||
}
|
||||
Poll::Ready(Err(e)) => {
|
||||
return Poll::Ready(Some(Err(crate::error::decode_io(e))));
|
||||
}
|
||||
Poll::Pending => return Poll::Pending,
|
||||
Poll::Ready(Err(e)) => Poll::Ready(Some(Err(crate::error::decode_io(e)))),
|
||||
Poll::Pending => Poll::Pending,
|
||||
},
|
||||
Inner::PlainText(ref mut body) => Pin::new(body).poll_next(cx),
|
||||
#[cfg(feature = "gzip")]
|
||||
Inner::Gzip(ref mut decoder) => {
|
||||
return match futures_core::ready!(Pin::new(decoder).poll_next(cx)) {
|
||||
match futures_core::ready!(Pin::new(decoder).poll_next(cx)) {
|
||||
Some(Ok(bytes)) => Poll::Ready(Some(Ok(bytes.freeze()))),
|
||||
Some(Err(err)) => Poll::Ready(Some(Err(crate::error::decode_io(err)))),
|
||||
None => Poll::Ready(None),
|
||||
};
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "brotli")]
|
||||
Inner::Brotli(ref mut decoder) => {
|
||||
return match futures_core::ready!(Pin::new(decoder).poll_next(cx)) {
|
||||
match futures_core::ready!(Pin::new(decoder).poll_next(cx)) {
|
||||
Some(Ok(bytes)) => Poll::Ready(Some(Ok(bytes.freeze()))),
|
||||
Some(Err(err)) => Poll::Ready(Some(Err(crate::error::decode_io(err)))),
|
||||
None => Poll::Ready(None),
|
||||
};
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "deflate")]
|
||||
Inner::Deflate(ref mut decoder) => {
|
||||
return match futures_core::ready!(Pin::new(decoder).poll_next(cx)) {
|
||||
match futures_core::ready!(Pin::new(decoder).poll_next(cx)) {
|
||||
Some(Ok(bytes)) => Poll::Ready(Some(Ok(bytes.freeze()))),
|
||||
Some(Err(err)) => Poll::Ready(Some(Err(crate::error::decode_io(err)))),
|
||||
None => Poll::Ready(None),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -310,20 +313,20 @@ impl Future for Pending {
|
||||
|
||||
match self.1 {
|
||||
#[cfg(feature = "brotli")]
|
||||
DecoderType::Brotli => Poll::Ready(Ok(Inner::Brotli(FramedRead::new(
|
||||
DecoderType::Brotli => Poll::Ready(Ok(Inner::Brotli(Box::pin(FramedRead::new(
|
||||
BrotliDecoder::new(StreamReader::new(_body)),
|
||||
BytesCodec::new(),
|
||||
)))),
|
||||
))))),
|
||||
#[cfg(feature = "gzip")]
|
||||
DecoderType::Gzip => Poll::Ready(Ok(Inner::Gzip(FramedRead::new(
|
||||
DecoderType::Gzip => Poll::Ready(Ok(Inner::Gzip(Box::pin(FramedRead::new(
|
||||
GzipDecoder::new(StreamReader::new(_body)),
|
||||
BytesCodec::new(),
|
||||
)))),
|
||||
))))),
|
||||
#[cfg(feature = "deflate")]
|
||||
DecoderType::Deflate => Poll::Ready(Ok(Inner::Deflate(FramedRead::new(
|
||||
DecoderType::Deflate => Poll::Ready(Ok(Inner::Deflate(Box::pin(FramedRead::new(
|
||||
ZlibDecoder::new(StreamReader::new(_body)),
|
||||
BytesCodec::new(),
|
||||
)))),
|
||||
))))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user