refactor(body): separate body, payload, and chunk into their own internal mods
This commit is contained in:
		| @@ -1,127 +1,19 @@ | ||||
| //! Streaming bodies for Requests and Responses
 | ||||
| //!
 | ||||
| //! For both [Clients](::client) and [Servers](::server), requests and
 | ||||
| //! responses use streaming bodies, instead of complete buffering. This
 | ||||
| //! allows applications to not use memory they don't need, and allows exerting
 | ||||
| //! back-pressure on connections by only reading when asked.
 | ||||
| //!
 | ||||
| //! There are two pieces to this in hyper:
 | ||||
| //!
 | ||||
| //! - The [`Payload`](Payload) trait the describes all possible bodies. hyper
 | ||||
| //!   allows any body type that implements `Payload`, allowing applications to
 | ||||
| //!   have fine-grained control over their streaming.
 | ||||
| //! - The [`Body`](Body) concrete type, which is an implementation of `Payload`,
 | ||||
| //!  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.
 | ||||
| use std::borrow::Cow; | ||||
| use std::fmt; | ||||
| 
 | ||||
| use bytes::{Buf, Bytes}; | ||||
| use bytes::Bytes; | ||||
| use futures::{Async, Future, Poll, Stream}; | ||||
| use futures::sync::{mpsc, oneshot}; | ||||
| use h2; | ||||
| use http::HeaderMap; | ||||
| 
 | ||||
| use common::Never; | ||||
| pub use chunk::Chunk; | ||||
| use super::{Chunk, Payload}; | ||||
| use super::internal::{FullDataArg, FullDataRet}; | ||||
| 
 | ||||
| use self::internal::{FullDataArg, FullDataRet}; | ||||
| 
 | ||||
| type BodySender = mpsc::Sender<Result<Chunk, ::Error>>; | ||||
| 
 | ||||
| 
 | ||||
| /// This trait represents a streaming body of a `Request` or `Response`.
 | ||||
| ///
 | ||||
| /// The built-in implementation of this trait is [`Body`](Body), in case you
 | ||||
| /// don't need to customize a send stream for your own application.
 | ||||
| pub trait Payload: Send + 'static { | ||||
|     /// A buffer of bytes representing a single chunk of a body.
 | ||||
|     type Data: Buf + Send; | ||||
| 
 | ||||
|     /// The error type of this stream.
 | ||||
|     type Error: Into<Box<::std::error::Error + Send + Sync>>; | ||||
| 
 | ||||
|     /// Poll for a `Data` buffer.
 | ||||
|     ///
 | ||||
|     /// Similar to `Stream::poll_next`, this yields `Some(Data)` until
 | ||||
|     /// the body ends, when it yields `None`.
 | ||||
|     fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error>; | ||||
| 
 | ||||
|     /// Poll for an optional **single** `HeaderMap` of trailers.
 | ||||
|     ///
 | ||||
|     /// This should **only** be called after `poll_data` has ended.
 | ||||
|     ///
 | ||||
|     /// Note: Trailers aren't currently used for HTTP/1, only for HTTP/2.
 | ||||
|     fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, Self::Error> { | ||||
|         Ok(Async::Ready(None)) | ||||
|     } | ||||
| 
 | ||||
|     /// A hint that the `Body` is complete, and doesn't need to be polled more.
 | ||||
|     ///
 | ||||
|     /// This can be useful to determine if the there is any body or trailers
 | ||||
|     /// without having to poll. An empty `Body` could return `true` and hyper
 | ||||
|     /// would be able to know that only the headers need to be sent. Or, it can
 | ||||
|     /// also be checked after each `poll_data` call, to allow hyper to try to
 | ||||
|     /// end the underlying stream with the last chunk, instead of needing to
 | ||||
|     /// send an extra `DATA` frame just to mark the stream as finished.
 | ||||
|     ///
 | ||||
|     /// As a hint, it is used to try to optimize, and thus is OK for a default
 | ||||
|     /// implementation to return `false`.
 | ||||
|     fn is_end_stream(&self) -> bool { | ||||
|         false | ||||
|     } | ||||
| 
 | ||||
|     /// Return a length of the total bytes that will be streamed, if known.
 | ||||
|     ///
 | ||||
|     /// If an exact size of bytes is known, this would allow hyper to send a
 | ||||
|     /// `Content-Length` header automatically, not needing to fall back to
 | ||||
|     /// `Transfer-Encoding: chunked`.
 | ||||
|     ///
 | ||||
|     /// This does not need to be kept updated after polls, it will only be
 | ||||
|     /// called once to create the headers.
 | ||||
|     fn content_length(&self) -> Option<u64> { | ||||
|         None | ||||
|     } | ||||
| 
 | ||||
|     // This API is unstable, and is impossible to use outside of hyper. Some
 | ||||
|     // form of it may become stable in a later version.
 | ||||
|     //
 | ||||
|     // The only thing a user *could* do is reference the method, but DON'T
 | ||||
|     // DO THAT! :)
 | ||||
|     #[doc(hidden)] | ||||
|     fn __hyper_full_data(&mut self, FullDataArg) -> FullDataRet<Self::Data> { | ||||
|         FullDataRet(None) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<E: Payload> Payload for Box<E> { | ||||
|     type Data = E::Data; | ||||
|     type Error = E::Error; | ||||
| 
 | ||||
|     fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error> { | ||||
|         (**self).poll_data() | ||||
|     } | ||||
| 
 | ||||
|     fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, Self::Error> { | ||||
|         (**self).poll_trailers() | ||||
|     } | ||||
| 
 | ||||
|     fn is_end_stream(&self) -> bool { | ||||
|         (**self).is_end_stream() | ||||
|     } | ||||
| 
 | ||||
|     fn content_length(&self) -> Option<u64> { | ||||
|         (**self).content_length() | ||||
|     } | ||||
| 
 | ||||
|     #[doc(hidden)] | ||||
|     fn __hyper_full_data(&mut self, arg: FullDataArg) -> FullDataRet<Self::Data> { | ||||
|         (**self).__hyper_full_data(arg) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /// A stream of `Chunk`s, used when receiving bodies.
 | ||||
| ///
 | ||||
| /// A good default `Payload` to use in many applications.
 | ||||
| @@ -496,35 +388,8 @@ impl From<Cow<'static, str>> for Body { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // The full_data API is not stable, so these types are to try to prevent
 | ||||
| // users from being able to:
 | ||||
| //
 | ||||
| // - Implment `__hyper_full_data` on their own Payloads.
 | ||||
| // - Call `__hyper_full_data` on any Payload.
 | ||||
| //
 | ||||
| // That's because to implement it, they need to name these types, and
 | ||||
| // they can't because they aren't exported. And to call it, they would
 | ||||
| // need to create one of these values, which they also can't.
 | ||||
| pub(crate) mod internal { | ||||
|     #[allow(missing_debug_implementations)] | ||||
|     pub struct FullDataArg(pub(crate) ()); | ||||
|     #[allow(missing_debug_implementations)] | ||||
|     pub struct FullDataRet<B>(pub(crate) Option<B>); | ||||
| } | ||||
| 
 | ||||
| fn _assert_send_sync() { | ||||
|     fn _assert_send<T: Send>() {} | ||||
|     fn _assert_sync<T: Sync>() {} | ||||
| 
 | ||||
|     _assert_send::<Body>(); | ||||
|     _assert_send::<Chunk>(); | ||||
|     _assert_sync::<Chunk>(); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn test_body_stream_concat() { | ||||
|     use futures::{Stream, Future}; | ||||
| 
 | ||||
|     let body = Body::from("hello world"); | ||||
| 
 | ||||
|     let total = body | ||||
							
								
								
									
										49
									
								
								src/body/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/body/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| //! Streaming bodies for Requests and Responses | ||||
| //! | ||||
| //! For both [Clients](::client) and [Servers](::server), requests and | ||||
| //! responses use streaming bodies, instead of complete buffering. This | ||||
| //! allows applications to not use memory they don't need, and allows exerting | ||||
| //! back-pressure on connections by only reading when asked. | ||||
| //! | ||||
| //! There are two pieces to this in hyper: | ||||
| //! | ||||
| //! - The [`Payload`](Payload) trait the describes all possible bodies. hyper | ||||
| //!   allows any body type that implements `Payload`, allowing applications to | ||||
| //!   have fine-grained control over their streaming. | ||||
| //! - The [`Body`](Body) concrete type, which is an implementation of `Payload`, | ||||
| //!  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; | ||||
|  | ||||
| mod body; | ||||
| mod chunk; | ||||
| mod payload; | ||||
|  | ||||
| // The full_data API is not stable, so these types are to try to prevent | ||||
| // users from being able to: | ||||
| // | ||||
| // - Implment `__hyper_full_data` on their own Payloads. | ||||
| // - Call `__hyper_full_data` on any Payload. | ||||
| // | ||||
| // That's because to implement it, they need to name these types, and | ||||
| // they can't because they aren't exported. And to call it, they would | ||||
| // need to create one of these values, which they also can't. | ||||
| pub(crate) mod internal { | ||||
|     #[allow(missing_debug_implementations)] | ||||
|     pub struct FullDataArg(pub(crate) ()); | ||||
|     #[allow(missing_debug_implementations)] | ||||
|     pub struct FullDataRet<B>(pub(crate) Option<B>); | ||||
| } | ||||
|  | ||||
| fn _assert_send_sync() { | ||||
|     fn _assert_send<T: Send>() {} | ||||
|     fn _assert_sync<T: Sync>() {} | ||||
|  | ||||
|     _assert_send::<Body>(); | ||||
|     _assert_send::<Chunk>(); | ||||
|     _assert_sync::<Chunk>(); | ||||
| } | ||||
|  | ||||
							
								
								
									
										97
									
								
								src/body/payload.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								src/body/payload.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| use bytes::Buf; | ||||
| use futures::{Async, Poll}; | ||||
| use http::HeaderMap; | ||||
|  | ||||
| use super::internal::{FullDataArg, FullDataRet}; | ||||
|  | ||||
| /// This trait represents a streaming body of a `Request` or `Response`. | ||||
| /// | ||||
| /// The built-in implementation of this trait is [`Body`](Body), in case you | ||||
| /// don't need to customize a send stream for your own application. | ||||
| pub trait Payload: Send + 'static { | ||||
|     /// A buffer of bytes representing a single chunk of a body. | ||||
|     type Data: Buf + Send; | ||||
|  | ||||
|     /// The error type of this stream. | ||||
|     type Error: Into<Box<::std::error::Error + Send + Sync>>; | ||||
|  | ||||
|     /// Poll for a `Data` buffer. | ||||
|     /// | ||||
|     /// Similar to `Stream::poll_next`, this yields `Some(Data)` until | ||||
|     /// the body ends, when it yields `None`. | ||||
|     fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error>; | ||||
|  | ||||
|     /// Poll for an optional **single** `HeaderMap` of trailers. | ||||
|     /// | ||||
|     /// This should **only** be called after `poll_data` has ended. | ||||
|     /// | ||||
|     /// Note: Trailers aren't currently used for HTTP/1, only for HTTP/2. | ||||
|     fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, Self::Error> { | ||||
|         Ok(Async::Ready(None)) | ||||
|     } | ||||
|  | ||||
|     /// A hint that the `Body` is complete, and doesn't need to be polled more. | ||||
|     /// | ||||
|     /// This can be useful to determine if the there is any body or trailers | ||||
|     /// without having to poll. An empty `Body` could return `true` and hyper | ||||
|     /// would be able to know that only the headers need to be sent. Or, it can | ||||
|     /// also be checked after each `poll_data` call, to allow hyper to try to | ||||
|     /// end the underlying stream with the last chunk, instead of needing to | ||||
|     /// send an extra `DATA` frame just to mark the stream as finished. | ||||
|     /// | ||||
|     /// As a hint, it is used to try to optimize, and thus is OK for a default | ||||
|     /// implementation to return `false`. | ||||
|     fn is_end_stream(&self) -> bool { | ||||
|         false | ||||
|     } | ||||
|  | ||||
|     /// Return a length of the total bytes that will be streamed, if known. | ||||
|     /// | ||||
|     /// If an exact size of bytes is known, this would allow hyper to send a | ||||
|     /// `Content-Length` header automatically, not needing to fall back to | ||||
|     /// `Transfer-Encoding: chunked`. | ||||
|     /// | ||||
|     /// This does not need to be kept updated after polls, it will only be | ||||
|     /// called once to create the headers. | ||||
|     fn content_length(&self) -> Option<u64> { | ||||
|         None | ||||
|     } | ||||
|  | ||||
|     // This API is unstable, and is impossible to use outside of hyper. Some | ||||
|     // form of it may become stable in a later version. | ||||
|     // | ||||
|     // The only thing a user *could* do is reference the method, but DON'T | ||||
|     // DO THAT! :) | ||||
|     #[doc(hidden)] | ||||
|     fn __hyper_full_data(&mut self, FullDataArg) -> FullDataRet<Self::Data> { | ||||
|         FullDataRet(None) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<E: Payload> Payload for Box<E> { | ||||
|     type Data = E::Data; | ||||
|     type Error = E::Error; | ||||
|  | ||||
|     fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error> { | ||||
|         (**self).poll_data() | ||||
|     } | ||||
|  | ||||
|     fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, Self::Error> { | ||||
|         (**self).poll_trailers() | ||||
|     } | ||||
|  | ||||
|     fn is_end_stream(&self) -> bool { | ||||
|         (**self).is_end_stream() | ||||
|     } | ||||
|  | ||||
|     fn content_length(&self) -> Option<u64> { | ||||
|         (**self).content_length() | ||||
|     } | ||||
|  | ||||
|     #[doc(hidden)] | ||||
|     fn __hyper_full_data(&mut self, arg: FullDataArg) -> FullDataRet<Self::Data> { | ||||
|         (**self).__hyper_full_data(arg) | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -57,7 +57,6 @@ mod common; | ||||
| #[cfg(test)] | ||||
| mod mock; | ||||
| pub mod body; | ||||
| mod chunk; | ||||
| pub mod client; | ||||
| pub mod error; | ||||
| mod headers; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user