expand documentation on new messagebody methods

This commit is contained in:
Rob Ede 2021-12-09 12:43:40 +00:00
parent 99ce36cb2f
commit 5a43fd2df1
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
4 changed files with 44 additions and 18 deletions

View File

@ -18,6 +18,7 @@
* `Request::take_conn_data()`. [#2491]
* `Request::take_req_data()`. [#2487]
* `impl Clone` for `RequestHead`. [#2487]
* New methods on `MessageBody` trait, `is_complete_body` and `take_complete_body`, both with default implementations, for optimisations on body types that are done in exactly one poll/chunk. [#2497]
### Changed
* Rename `body::BoxBody::{from_body => new}`. [#2468]
@ -45,6 +46,7 @@
[#2487]: https://github.com/actix/actix-web/pull/2487
[#2488]: https://github.com/actix/actix-web/pull/2488
[#2491]: https://github.com/actix/actix-web/pull/2491
[#2497]: https://github.com/actix/actix-web/pull/2497
## 3.0.0-beta.14 - 2021-11-30

View File

@ -53,14 +53,10 @@ impl MessageBody for BoxBody {
}
fn is_complete_body(&self) -> bool {
let a = self.0.is_complete_body();
eprintln!("BoxBody is complete?: {}", a);
a
self.0.is_complete_body()
}
fn take_complete_body(&mut self) -> Bytes {
eprintln!("taking box body contents");
debug_assert!(
self.is_complete_body(),
"boxed type does not allow taking complete body; caller should make sure to \

View File

@ -25,18 +25,52 @@ pub trait MessageBody {
fn size(&self) -> BodySize;
/// Attempt to pull out the next chunk of body bytes.
// TODO: expand documentation
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Bytes, Self::Error>>>;
/// Returns true if entire body bytes chunk is obtainable in one call to `poll_next`.
///
/// This method's implementation should agree with [`take_complete_body`] and should always be
/// checked before taking the body.
///
/// The default implementation returns `false.
///
/// [`take_complete_body`]: MessageBody::take_complete_body
fn is_complete_body(&self) -> bool {
false
}
/// Returns the complete chunk of body bytes.
///
/// Implementors of this method should note the following:
/// - It is acceptable to skip the omit checks of [`is_complete_body`]. The responsibility of
/// performing this check is delegated to the caller.
/// - If the result of [`is_complete_body`] is conditional, that condition should be given
/// equivalent attention here.
/// - A second call call to [`take_complete_body`] should return an empty `Bytes` or panic.
/// - A call to [`poll_next`] after calling [`take_complete_body`] should return `None` unless
/// the chunk is guaranteed to be empty.
///
/// # Panics
/// With a correct implementation, panics if called without first checking [`is_complete_body`].
///
/// [`is_complete_body`]: MessageBody::is_complete_body
/// [`take_complete_body`]: MessageBody::take_complete_body
/// [`poll_next`]: MessageBody::poll_next
fn take_complete_body(&mut self) -> Bytes {
assert!(
self.is_complete_body(),
"type ({}) allows taking complete body but did not provide an implementation \
of `take_complete_body`",
std::any::type_name::<Self>()
);
unimplemented!(
"type ({}) allows taking complete body but did not provide an implementation",
"type ({}) does not allow taking complete body; caller should make sure to \
check `is_complete_body` first",
std::any::type_name::<Self>()
);
}
@ -86,10 +120,12 @@ mod foreign_impls {
Poll::Ready(None)
}
#[inline]
fn is_complete_body(&self) -> bool {
true
}
#[inline]
fn take_complete_body(&mut self) -> Bytes {
Bytes::new()
}
@ -114,10 +150,12 @@ mod foreign_impls {
Pin::new(self.get_mut().as_mut()).poll_next(cx)
}
#[inline]
fn is_complete_body(&self) -> bool {
self.as_ref().is_complete_body()
}
#[inline]
fn take_complete_body(&mut self) -> Bytes {
self.as_mut().take_complete_body()
}
@ -142,10 +180,12 @@ mod foreign_impls {
self.as_mut().poll_next(cx)
}
#[inline]
fn is_complete_body(&self) -> bool {
self.as_ref().is_complete_body()
}
#[inline]
fn take_complete_body(&mut self) -> Bytes {
debug_assert!(
self.is_complete_body(),

View File

@ -65,24 +65,16 @@ impl<B: MessageBody> Encoder<B> {
return Self::none();
}
eprintln!("body type: {}", std::any::type_name::<B>());
let body = if body.is_complete_body() {
eprintln!("reducing allocation");
let body = body.take_complete_body();
EncoderBody::Full { body }
} else {
eprintln!("using stream type");
EncoderBody::Stream { body }
};
if can_encode {
eprintln!("I CAN ENCODE WOO");
// Modify response body only if encoder is set
if let Some(enc) = ContentEncoder::encoder(encoding) {
eprintln!("AND i have an encoder - lucky day");
update_head(encoding, head);
return Encoder {
@ -92,12 +84,8 @@ impl<B: MessageBody> Encoder<B> {
eof: false,
};
}
eprintln!("but i DONT have an encoder :(");
}
eprintln!("rip, no compression for you");
Encoder {
body,
encoder: None,