tlspuffin/tls/rustls/
vecbuf.rs1use std::collections::VecDeque;
2use std::io::Read;
3use std::{cmp, io};
4
5pub struct ChunkVecBuffer {
10 chunks: VecDeque<Vec<u8>>,
11 limit: Option<usize>,
12}
13
14impl ChunkVecBuffer {
15 pub fn new(limit: Option<usize>) -> Self {
16 Self {
17 chunks: VecDeque::new(),
18 limit,
19 }
20 }
21
22 pub fn set_limit(&mut self, new_limit: Option<usize>) {
30 self.limit = new_limit;
31 }
32
33 pub fn is_empty(&self) -> bool {
35 self.chunks.is_empty()
36 }
37
38 pub fn len(&self) -> usize {
40 let mut len = 0;
41 for ch in &self.chunks {
42 len += ch.len();
43 }
44 len
45 }
46
47 pub fn apply_limit(&self, len: usize) -> usize {
51 if let Some(limit) = self.limit {
52 let space = limit.saturating_sub(self.len());
53 cmp::min(len, space)
54 } else {
55 len
56 }
57 }
58
59 pub fn append_limited_copy(&mut self, bytes: &[u8]) -> usize {
62 let take = self.apply_limit(bytes.len());
63 self.append(bytes[..take].to_vec());
64 take
65 }
66
67 pub fn append(&mut self, bytes: Vec<u8>) -> usize {
69 let len = bytes.len();
70
71 if !bytes.is_empty() {
72 self.chunks.push_back(bytes);
73 }
74
75 len
76 }
77
78 pub fn pop(&mut self) -> Option<Vec<u8>> {
81 self.chunks.pop_front()
82 }
83
84 pub fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
87 let mut offs = 0;
88
89 while offs < buf.len() && !self.is_empty() {
90 let used = self.chunks[0].as_slice().read(&mut buf[offs..])?;
91
92 self.consume(used);
93 offs += used;
94 }
95
96 Ok(offs)
97 }
98
99 fn consume(&mut self, mut used: usize) {
100 while let Some(mut buf) = self.chunks.pop_front() {
101 if used < buf.len() {
102 self.chunks.push_front(buf.split_off(used));
103 break;
104 } else {
105 used -= buf.len();
106 }
107 }
108 }
109
110 pub fn write_to(&mut self, wr: &mut dyn io::Write) -> io::Result<usize> {
112 if self.is_empty() {
113 return Ok(0);
114 }
115
116 let mut bufs = [io::IoSlice::new(&[]); 64];
117 for (iov, chunk) in bufs.iter_mut().zip(self.chunks.iter()) {
118 *iov = io::IoSlice::new(chunk);
119 }
120 let len = cmp::min(bufs.len(), self.chunks.len());
121 let used = wr.write_vectored(&bufs[..len])?;
122 self.consume(used);
123 Ok(used)
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::ChunkVecBuffer;
130
131 #[test_log::test]
132 fn short_append_copy_with_limit() {
133 let mut cvb = ChunkVecBuffer::new(Some(12));
134 assert_eq!(cvb.append_limited_copy(b"hello"), 5);
135 assert_eq!(cvb.append_limited_copy(b"world"), 5);
136 assert_eq!(cvb.append_limited_copy(b"hello"), 2);
137 assert_eq!(cvb.append_limited_copy(b"world"), 0);
138
139 let mut buf = [0u8; 12];
140 assert_eq!(cvb.read(&mut buf).unwrap(), 12);
141 assert_eq!(buf.to_vec(), b"helloworldhe".to_vec());
142 }
143}