finchers_core/input/
body.rs

1use bytes::Bytes;
2use error::HttpError;
3use http::StatusCode;
4use poll::{Poll, PollResult};
5use std::fmt;
6use std::ops::Deref;
7
8#[cfg(feature = "hyper")]
9use futures::Stream;
10#[cfg(feature = "hyper")]
11use hyper;
12
13/// An asyncrhonous stream to receive the chunks of incoming request body.
14pub struct RequestBody {
15    kind: RequestBodyKind,
16}
17
18enum RequestBodyKind {
19    Empty,
20    Once(Option<Bytes>),
21    #[cfg(feature = "hyper")]
22    Hyper(hyper::Body),
23}
24
25impl fmt::Debug for RequestBody {
26    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27        use self::RequestBodyKind::*;
28        match self.kind {
29            Empty => f.debug_tuple("Empty").finish(),
30            Once(..) => f.debug_tuple("Once").finish(),
31            #[cfg(feature = "hyper")]
32            Hyper(..) => f.debug_tuple("Hyper").finish(),
33        }
34    }
35}
36
37impl RequestBody {
38    /// Create an instance of empty `RequestBody`.
39    pub fn empty() -> RequestBody {
40        RequestBody {
41            kind: RequestBodyKind::Empty,
42        }
43    }
44
45    /// Create an instance of `RequestBody` from a chunk of bytes.
46    pub fn once<T>(body: T) -> RequestBody
47    where
48        T: Into<Bytes>,
49    {
50        RequestBody {
51            kind: RequestBodyKind::Once(Some(body.into())),
52        }
53    }
54
55    /// Create an instance of `RequestBody` from `hyper::Body`.
56    #[cfg(feature = "hyper")]
57    pub fn from_hyp(body: hyper::Body) -> RequestBody {
58        RequestBody {
59            kind: RequestBodyKind::Hyper(body),
60        }
61    }
62
63    /// Poll an element of `Chunk`.
64    // FIXME: make adapt to the signature of futures2 or std's Async
65    pub fn poll_data(&mut self) -> PollResult<Option<Data>, PollDataError> {
66        use self::RequestBodyKind::*;
67        match self.kind {
68            Empty => Poll::Ready(Ok(None)),
69            Once(ref mut chunk) => Poll::Ready(Ok(chunk.take().map(Data::new))),
70            #[cfg(feature = "hyper")]
71            Hyper(ref mut body) => body.poll()
72                .map(|async| async.map(|chunk_opt| chunk_opt.map(Data::from_hyp)))
73                .map_err(PollDataError::Hyper)
74                .into(),
75        }
76    }
77}
78
79/// A chunk of bytes in the incoming message body.
80#[derive(Debug)]
81pub struct Data(ChunkType);
82
83#[derive(Debug)]
84enum ChunkType {
85    Shared(Bytes),
86    #[cfg(feature = "hyper")]
87    Hyper(hyper::Chunk),
88}
89
90impl Data {
91    #[allow(missing_docs)]
92    pub fn new<T>(chunk: T) -> Data
93    where
94        T: Into<Bytes>,
95    {
96        Data(ChunkType::Shared(chunk.into()))
97    }
98
99    #[allow(missing_docs)]
100    #[cfg(feature = "hyper")]
101    pub fn from_hyp(chunk: hyper::Chunk) -> Data {
102        Data(ChunkType::Hyper(chunk))
103    }
104}
105
106impl AsRef<[u8]> for Data {
107    fn as_ref(&self) -> &[u8] {
108        match self.0 {
109            ChunkType::Shared(ref b) => b.as_ref(),
110            #[cfg(feature = "hyper")]
111            ChunkType::Hyper(ref c) => c.as_ref(),
112        }
113    }
114}
115
116impl Deref for Data {
117    type Target = [u8];
118
119    fn deref(&self) -> &Self::Target {
120        self.as_ref()
121    }
122}
123
124/// An error type which will returned at receiving the message body.
125#[derive(Debug, Fail)]
126pub enum PollDataError {
127    #[allow(missing_docs)]
128    #[cfg(feature = "hyper")]
129    #[fail(display = "during receiving the chunk")]
130    Hyper(hyper::Error),
131
132    #[doc(hidden)]
133    #[fail(display = "dummy for derivation of Fail")]
134    __Dummy(()),
135}
136
137impl HttpError for PollDataError {
138    fn status_code(&self) -> StatusCode {
139        StatusCode::INTERNAL_SERVER_ERROR
140    }
141}