wip: body typeid full data

This commit is contained in:
Sean McArthur
2019-08-29 10:02:47 -07:00
parent 62a96c077b
commit 3c6f7999cd
3 changed files with 40 additions and 1 deletions

View File

@@ -285,6 +285,14 @@ impl Body {
}
}
}
pub(super) fn take_full_data(&mut self) -> Option<Chunk> {
if let Kind::Once(ref mut chunk) = self.kind {
chunk.take()
} else {
None
}
}
}
impl Default for Body {

View File

@@ -14,6 +14,7 @@
//! and returned by hyper as a "receive stream" (so, for server requests and
//! client responses). It is also a decent default implementation if you don't
//! have very custom needs of your send streams.
pub use self::body::{Body, Sender};
pub use self::chunk::Chunk;
pub use self::payload::Payload;
@@ -22,6 +23,27 @@ mod body;
mod chunk;
mod payload;
/// An optimization to try to take a full body if immediately available.
///
/// This is currently limited to *only* `hyper::Body`s.
pub(crate) fn take_full_data<T: Payload + 'static>(body: &mut T) -> Option<T::Data> {
use std::any::{Any, TypeId};
// This static type check can be optimized at compile-time.
if TypeId::of::<T>() == TypeId::of::<Body>() {
let mut full = (body as &mut dyn Any)
.downcast_mut::<Body>()
.expect("must be Body")
.take_full_data();
(&mut full as &mut dyn Any)
.downcast_mut::<Option<T::Data>>()
.expect("must be T::Data")
.take()
} else {
None
}
}
// The full_data API is not stable, so these types are to try to prevent
// users from being able to:
//

View File

@@ -248,7 +248,16 @@ where
return Poll::Ready(Ok(()));
} else if self.body_rx.is_none() && self.conn.can_write_head() && self.dispatch.should_poll() {
if let Some(msg) = ready!(self.dispatch.poll_msg(cx)) {
let (head, body) = msg.map_err(crate::Error::new_user_service)?;
let (head, mut body) = msg.map_err(crate::Error::new_user_service)?;
// Check if the body knows its full data immediately.
//
// If so, we can skip a bit of bookkeeping that streaming
// bodies need to do.
if let Some(full) = crate::body::take_full_data(&mut body) {
self.conn.write_full_msg(head, full);
return Poll::Ready(Ok(()));
}
let body_type = if body.is_end_stream() {
self.body_rx.set(None);