Skip to main content

simple_hyper_client/body/
shared.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 hyper::body::{Body, Buf, Frame, SizeHint};
8
9use std::cmp;
10use std::io;
11use std::pin::Pin;
12use std::sync::Arc;
13use std::task::{Context, Poll};
14
15/// This is an implementation of `hyper::body::Body` for use with HTTP
16/// `Request`s.
17///
18/// This can be constructed from `Arc<Vec<u8>>`, allowing the data to be
19/// shared. It also implements `Clone` and `AsRef<[u8]>`, and it provides a
20/// method to get its length and implements.
21#[derive(Clone)]
22pub struct SharedBody(Option<SharedBytes>);
23
24impl SharedBody {
25    /// Create an empty request body.
26    #[inline]
27    pub fn empty() -> Self {
28        Self::default()
29    }
30
31    /// Returns the length of the body in bytes.
32    pub fn len(&self) -> usize {
33        self.0.as_ref().map(SharedBytes::len).unwrap_or_default()
34    }
35}
36
37impl Default for SharedBody {
38    fn default() -> Self {
39        // Note: this is different from `Self(None)` because `Self(None)` would immediately
40        // return `false` for `is_end_stream()` while `Self(Some(SharedBytes::Static(&[])))`
41        // returns `true` for `is_end_stream()` until the first call to `poll_frame()`.
42        Self(Some(SharedBytes::Static(&[])))
43    }
44}
45
46impl From<Arc<Vec<u8>>> for SharedBody {
47    fn from(arc: Arc<Vec<u8>>) -> Self {
48        Self(Some(SharedBytes::Arc(arc)))
49    }
50}
51
52impl From<Vec<u8>> for SharedBody {
53    fn from(vec: Vec<u8>) -> Self {
54        Self(Some(SharedBytes::Arc(Arc::new(vec))))
55    }
56}
57
58impl From<String> for SharedBody {
59    fn from(s: String) -> Self {
60        Self(Some(SharedBytes::Arc(Arc::new(s.into_bytes()))))
61    }
62}
63
64impl From<&'static [u8]> for SharedBody {
65    fn from(slice: &'static [u8]) -> Self {
66        Self(Some(SharedBytes::Static(slice)))
67    }
68}
69
70impl From<&'static str> for SharedBody {
71    fn from(s: &'static str) -> Self {
72        Self(Some(SharedBytes::Static(s.as_bytes())))
73    }
74}
75
76impl AsRef<[u8]> for SharedBody {
77    fn as_ref(&self) -> &[u8] {
78        self.0.as_ref().map(SharedBytes::as_ref).unwrap_or(&[])
79    }
80}
81
82impl Body for SharedBody {
83    type Data = SharedBuf;
84    type Error = io::Error;
85
86    fn poll_frame(
87        self: Pin<&mut Self>,
88        _cx: &mut Context<'_>,
89    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
90        let opt = self
91            .get_mut()
92            .0
93            .take()
94            .map(|bytes| SharedBuf { bytes, pos: 0 })
95            .map(Frame::data)
96            .map(Ok);
97        Poll::Ready(opt)
98    }
99
100    fn is_end_stream(&self) -> bool {
101        self.0.is_none()
102    }
103
104    fn size_hint(&self) -> SizeHint {
105        let len = self.0.as_ref().map(SharedBytes::len).unwrap_or_default();
106        SizeHint::with_exact(len as u64)
107    }
108}
109
110pub struct SharedBuf {
111    bytes: SharedBytes,
112    pos: usize,
113}
114
115impl SharedBuf {
116    pub fn len(&self) -> usize {
117        self.bytes.len()
118    }
119}
120
121impl Buf for SharedBuf {
122    fn remaining(&self) -> usize {
123        self.len() - self.pos
124    }
125
126    fn chunk(&self) -> &[u8] {
127        match self.bytes {
128            SharedBytes::Arc(ref bytes) => &bytes[self.pos..],
129            SharedBytes::Static(ref bytes) => &bytes[self.pos..],
130        }
131    }
132
133    fn advance(&mut self, cnt: usize) {
134        self.pos = cmp::min(self.len(), self.pos + cnt);
135    }
136}
137
138#[derive(Clone)]
139enum SharedBytes {
140    Arc(Arc<Vec<u8>>),
141    Static(&'static [u8]),
142}
143
144impl SharedBytes {
145    fn len(&self) -> usize {
146        match self {
147            Self::Arc(ref bytes) => bytes.len(),
148            Self::Static(ref bytes) => bytes.len(),
149        }
150    }
151}
152
153impl AsRef<[u8]> for SharedBytes {
154    fn as_ref(&self) -> &[u8] {
155        match self {
156            Self::Arc(vec) => vec,
157            Self::Static(slice) => slice,
158        }
159    }
160}