simple_hyper_client/
shared_body.rs

1/* Copyright (c) Fortanix, Inc.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7use headers::HeaderMap;
8use hyper::body::{Buf, HttpBody};
9
10use std::pin::Pin;
11use std::sync::Arc;
12use std::task::{Context, Poll};
13use std::{cmp, io};
14
15/// This is an alternative to `hyper::Body` for use with HTTP `Request`s
16///
17/// This can be constructed from `Arc<Vec<u8>>` while `hyper::Body` cannot.
18/// Additionally this type provides a method to get its length.
19pub struct SharedBody(Option<InnerBuf>);
20
21enum InnerBuf {
22    Arc(Arc<Vec<u8>>),
23    Static(&'static [u8]),
24}
25
26impl AsRef<[u8]> for SharedBody {
27    fn as_ref(&self) -> &[u8] {
28        match self.0.as_ref() {
29            Some(InnerBuf::Arc(vec)) => vec,
30            Some(InnerBuf::Static(slice)) => slice,
31            None => &[],
32        }
33    }
34}
35
36impl SharedBody {
37    pub fn len(&self) -> usize {
38        match self.0.as_ref() {
39            Some(InnerBuf::Arc(vec)) => vec.len(),
40            Some(InnerBuf::Static(slice)) => slice.len(),
41            None => 0,
42        }
43    }
44
45    pub fn empty() -> Self {
46        SharedBody(None)
47    }
48}
49
50impl Default for SharedBody {
51    /// Returns `SharedBody::empty()`.
52    #[inline]
53    fn default() -> Self {
54        SharedBody::empty()
55    }
56}
57
58impl From<Arc<Vec<u8>>> for SharedBody {
59    fn from(arc: Arc<Vec<u8>>) -> Self {
60        SharedBody(Some(InnerBuf::Arc(arc)))
61    }
62}
63
64impl From<Vec<u8>> for SharedBody {
65    fn from(vec: Vec<u8>) -> Self {
66        SharedBody(Some(InnerBuf::Arc(Arc::new(vec))))
67    }
68}
69
70impl From<String> for SharedBody {
71    fn from(s: String) -> Self {
72        SharedBody(Some(InnerBuf::Arc(Arc::new(s.into_bytes()))))
73    }
74}
75
76impl From<&'static [u8]> for SharedBody {
77    fn from(slice: &'static [u8]) -> Self {
78        SharedBody(Some(InnerBuf::Static(slice)))
79    }
80}
81
82impl From<&'static str> for SharedBody {
83    fn from(s: &'static str) -> Self {
84        SharedBody(Some(InnerBuf::Static(s.as_bytes())))
85    }
86}
87
88impl HttpBody for SharedBody {
89    type Data = SharedBuf;
90    type Error = io::Error;
91
92    fn poll_data(
93        self: Pin<&mut Self>,
94        _cx: &mut Context<'_>,
95    ) -> Poll<Option<Result<Self::Data, Self::Error>>> {
96        let opt = self
97            .get_mut()
98            .0
99            .take()
100            .map(|bytes| SharedBuf { bytes, pos: 0 })
101            .map(Ok);
102        Poll::Ready(opt)
103    }
104
105    fn poll_trailers(
106        self: Pin<&mut Self>,
107        _cx: &mut Context<'_>,
108    ) -> Poll<Result<Option<HeaderMap>, Self::Error>> {
109        Poll::Ready(Ok(None))
110    }
111}
112
113pub struct SharedBuf {
114    bytes: InnerBuf,
115    pos: usize,
116}
117
118impl SharedBuf {
119    fn len(&self) -> usize {
120        match self.bytes {
121            InnerBuf::Arc(ref bytes) => bytes.len(),
122            InnerBuf::Static(ref bytes) => bytes.len(),
123        }
124    }
125}
126
127impl Buf for SharedBuf {
128    fn remaining(&self) -> usize {
129        self.len() - self.pos
130    }
131
132    fn chunk(&self) -> &[u8] {
133        match self.bytes {
134            InnerBuf::Arc(ref bytes) => &bytes[self.pos..],
135            InnerBuf::Static(ref bytes) => &bytes[self.pos..],
136        }
137    }
138
139    fn advance(&mut self, cnt: usize) {
140        self.pos = cmp::min(self.len(), self.pos + cnt);
141    }
142}