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, Default)]
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 From<Arc<Vec<u8>>> for SharedBody {
38    fn from(arc: Arc<Vec<u8>>) -> Self {
39        Self(Some(SharedBytes::Arc(arc)))
40    }
41}
42
43impl From<Vec<u8>> for SharedBody {
44    fn from(vec: Vec<u8>) -> Self {
45        Self(Some(SharedBytes::Arc(Arc::new(vec))))
46    }
47}
48
49impl From<String> for SharedBody {
50    fn from(s: String) -> Self {
51        Self(Some(SharedBytes::Arc(Arc::new(s.into_bytes()))))
52    }
53}
54
55impl From<&'static [u8]> for SharedBody {
56    fn from(slice: &'static [u8]) -> Self {
57        Self(Some(SharedBytes::Static(slice)))
58    }
59}
60
61impl From<&'static str> for SharedBody {
62    fn from(s: &'static str) -> Self {
63        Self(Some(SharedBytes::Static(s.as_bytes())))
64    }
65}
66
67impl AsRef<[u8]> for SharedBody {
68    fn as_ref(&self) -> &[u8] {
69        self.0.as_ref().map(SharedBytes::as_ref).unwrap_or(&[])
70    }
71}
72
73impl Body for SharedBody {
74    type Data = SharedBuf;
75    type Error = io::Error;
76
77    fn poll_frame(
78        self: Pin<&mut Self>,
79        _cx: &mut Context<'_>,
80    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
81        let opt = self
82            .get_mut()
83            .0
84            .take()
85            .map(|bytes| SharedBuf { bytes, pos: 0 })
86            .map(Frame::data)
87            .map(Ok);
88        Poll::Ready(opt)
89    }
90
91    fn is_end_stream(&self) -> bool {
92        self.0.is_none()
93    }
94
95    fn size_hint(&self) -> SizeHint {
96        let len = self.0.as_ref().map(SharedBytes::len).unwrap_or_default();
97        SizeHint::with_exact(len as u64)
98    }
99}
100
101pub struct SharedBuf {
102    bytes: SharedBytes,
103    pos: usize,
104}
105
106impl SharedBuf {
107    pub fn len(&self) -> usize {
108        self.bytes.len()
109    }
110}
111
112impl Buf for SharedBuf {
113    fn remaining(&self) -> usize {
114        self.len() - self.pos
115    }
116
117    fn chunk(&self) -> &[u8] {
118        match self.bytes {
119            SharedBytes::Arc(ref bytes) => &bytes[self.pos..],
120            SharedBytes::Static(ref bytes) => &bytes[self.pos..],
121        }
122    }
123
124    fn advance(&mut self, cnt: usize) {
125        self.pos = cmp::min(self.len(), self.pos + cnt);
126    }
127}
128
129#[derive(Clone)]
130enum SharedBytes {
131    Arc(Arc<Vec<u8>>),
132    Static(&'static [u8]),
133}
134
135impl SharedBytes {
136    fn len(&self) -> usize {
137        match self {
138            Self::Arc(ref bytes) => bytes.len(),
139            Self::Static(ref bytes) => bytes.len(),
140        }
141    }
142}
143
144impl AsRef<[u8]> for SharedBytes {
145    fn as_ref(&self) -> &[u8] {
146        match self {
147            Self::Arc(vec) => vec,
148            Self::Static(slice) => slice,
149        }
150    }
151}