rustls/
vecbuf.rs

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