1use std::cmp;
2use std::collections::VecDeque;
3use std::io;
4use std::io::Read;
5
6pub(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 pub(crate) fn set_limit(&mut self, new_limit: Option<usize>) {
31 self.limit = new_limit;
32 }
33
34 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 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 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 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 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 pub(crate) fn pop(&mut self) -> Option<Vec<u8>> {
88 self.chunks.pop_front()
89 }
90
91 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 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 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}