rustls/
vecbuf.rs

1use alloc::collections::VecDeque;
2use alloc::vec::Vec;
3use core::cmp;
4#[cfg(feature = "std")]
5use std::io;
6#[cfg(feature = "std")]
7use std::io::Read;
8
9#[cfg(feature = "std")]
10use crate::msgs::message::OutboundChunks;
11
12/// This is a byte buffer that is built from a vector
13/// of byte vectors.  This avoids extra copies when
14/// appending a new byte vector, at the expense of
15/// more complexity when reading out.
16pub(crate) struct ChunkVecBuffer {
17    chunks: VecDeque<Vec<u8>>,
18    limit: Option<usize>,
19}
20
21impl ChunkVecBuffer {
22    pub(crate) fn new(limit: Option<usize>) -> Self {
23        Self {
24            chunks: VecDeque::new(),
25            limit,
26        }
27    }
28
29    /// Sets the upper limit on how many bytes this
30    /// object can store.
31    ///
32    /// Setting a lower limit than the currently stored
33    /// data is not an error.
34    ///
35    /// A [`None`] limit is interpreted as no limit.
36    pub(crate) fn set_limit(&mut self, new_limit: Option<usize>) {
37        self.limit = new_limit;
38    }
39
40    /// If we're empty
41    pub(crate) fn is_empty(&self) -> bool {
42        self.chunks.is_empty()
43    }
44
45    /// How many bytes we're storing
46    pub(crate) fn len(&self) -> usize {
47        let mut len = 0;
48        for ch in &self.chunks {
49            len += ch.len();
50        }
51        len
52    }
53
54    /// For a proposed append of `len` bytes, how many
55    /// bytes should we actually append to adhere to the
56    /// currently set `limit`?
57    pub(crate) fn apply_limit(&self, len: usize) -> usize {
58        if let Some(limit) = self.limit {
59            let space = limit.saturating_sub(self.len());
60            cmp::min(len, space)
61        } else {
62            len
63        }
64    }
65
66    /// Take and append the given `bytes`.
67    pub(crate) fn append(&mut self, bytes: Vec<u8>) -> usize {
68        let len = bytes.len();
69
70        if !bytes.is_empty() {
71            self.chunks.push_back(bytes);
72        }
73
74        len
75    }
76
77    /// Take one of the chunks from this object.  This
78    /// function panics if the object `is_empty`.
79    pub(crate) fn pop(&mut self) -> Option<Vec<u8>> {
80        self.chunks.pop_front()
81    }
82
83    #[cfg(read_buf)]
84    /// Read data out of this object, writing it into `cursor`.
85    pub(crate) fn read_buf(&mut self, mut cursor: core::io::BorrowedCursor<'_>) -> io::Result<()> {
86        while !self.is_empty() && cursor.capacity() > 0 {
87            let chunk = self.chunks[0].as_slice();
88            let used = cmp::min(chunk.len(), cursor.capacity());
89            cursor.append(&chunk[..used]);
90            self.consume(used);
91        }
92
93        Ok(())
94    }
95}
96
97#[cfg(feature = "std")]
98impl ChunkVecBuffer {
99    pub(crate) fn is_full(&self) -> bool {
100        self.limit
101            .map(|limit| self.len() > limit)
102            .unwrap_or_default()
103    }
104
105    /// Append a copy of `bytes`, perhaps a prefix if
106    /// we're near the limit.
107    pub(crate) fn append_limited_copy(&mut self, payload: OutboundChunks<'_>) -> usize {
108        let take = self.apply_limit(payload.len());
109        self.append(payload.split_at(take).0.to_vec());
110        take
111    }
112
113    /// Read data out of this object, writing it into `buf`
114    /// and returning how many bytes were written there.
115    pub(crate) fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
116        let mut offs = 0;
117
118        while offs < buf.len() && !self.is_empty() {
119            let used = self.chunks[0]
120                .as_slice()
121                .read(&mut buf[offs..])?;
122
123            self.consume(used);
124            offs += used;
125        }
126
127        Ok(offs)
128    }
129
130    fn consume(&mut self, mut used: usize) {
131        while let Some(mut buf) = self.chunks.pop_front() {
132            if used < buf.len() {
133                buf.drain(..used);
134                self.chunks.push_front(buf);
135                break;
136            } else {
137                used -= buf.len();
138            }
139        }
140    }
141
142    /// Read data out of this object, passing it `wr`
143    pub(crate) fn write_to(&mut self, wr: &mut dyn io::Write) -> io::Result<usize> {
144        if self.is_empty() {
145            return Ok(0);
146        }
147
148        let mut bufs = [io::IoSlice::new(&[]); 64];
149        for (iov, chunk) in bufs.iter_mut().zip(self.chunks.iter()) {
150            *iov = io::IoSlice::new(chunk);
151        }
152        let len = cmp::min(bufs.len(), self.chunks.len());
153        let used = wr.write_vectored(&bufs[..len])?;
154        self.consume(used);
155        Ok(used)
156    }
157}
158
159#[cfg(all(test, feature = "std"))]
160mod tests {
161    use super::ChunkVecBuffer;
162
163    #[test]
164    fn short_append_copy_with_limit() {
165        let mut cvb = ChunkVecBuffer::new(Some(12));
166        assert_eq!(cvb.append_limited_copy(b"hello"[..].into()), 5);
167        assert_eq!(cvb.append_limited_copy(b"world"[..].into()), 5);
168        assert_eq!(cvb.append_limited_copy(b"hello"[..].into()), 2);
169        assert_eq!(cvb.append_limited_copy(b"world"[..].into()), 0);
170
171        let mut buf = [0u8; 12];
172        assert_eq!(cvb.read(&mut buf).unwrap(), 12);
173        assert_eq!(buf.to_vec(), b"helloworldhe".to_vec());
174    }
175
176    #[cfg(read_buf)]
177    #[test]
178    fn read_buf() {
179        use core::io::BorrowedBuf;
180        use core::mem::MaybeUninit;
181
182        {
183            let mut cvb = ChunkVecBuffer::new(None);
184            cvb.append(b"test ".to_vec());
185            cvb.append(b"fixture ".to_vec());
186            cvb.append(b"data".to_vec());
187
188            let mut buf = [MaybeUninit::<u8>::uninit(); 8];
189            let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into();
190            cvb.read_buf(buf.unfilled()).unwrap();
191            assert_eq!(buf.filled(), b"test fix");
192            buf.clear();
193            cvb.read_buf(buf.unfilled()).unwrap();
194            assert_eq!(buf.filled(), b"ture dat");
195            buf.clear();
196            cvb.read_buf(buf.unfilled()).unwrap();
197            assert_eq!(buf.filled(), b"a");
198        }
199
200        {
201            let mut cvb = ChunkVecBuffer::new(None);
202            cvb.append(b"short message".to_vec());
203
204            let mut buf = [MaybeUninit::<u8>::uninit(); 1024];
205            let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into();
206            cvb.read_buf(buf.unfilled()).unwrap();
207            assert_eq!(buf.filled(), b"short message");
208        }
209    }
210}