1use std::cmp;
2use std::collections::VecDeque;
3use std::io;
4use std::io::Read;
5
6pub struct ChunkVecBuffer {
11 chunks: VecDeque<Vec<u8>>,
12 limit: usize,
13}
14
15impl ChunkVecBuffer {
16 pub fn new() -> ChunkVecBuffer {
17 ChunkVecBuffer {
18 chunks: VecDeque::new(),
19 limit: 0,
20 }
21 }
22
23 pub fn set_limit(&mut self, new_limit: usize) {
31 self.limit = new_limit;
32 }
33
34 pub fn is_empty(&self) -> bool {
36 self.chunks.is_empty()
37 }
38
39 pub fn len(&self) -> usize {
41 let mut len = 0;
42 for ch in &self.chunks {
43 len += ch.len();
44 }
45 len
46 }
47
48 pub fn apply_limit(&self, len: usize) -> usize {
52 if self.limit == 0 {
53 len
54 } else {
55 let space = self.limit.saturating_sub(self.len());
56 cmp::min(len, space)
57 }
58 }
59
60 pub fn append_limited_copy(&mut self, bytes: &[u8]) -> usize {
63 let take = self.apply_limit(bytes.len());
64 self.append(bytes[..take].to_vec());
65 take
66 }
67
68 pub fn append(&mut self, bytes: Vec<u8>) -> usize {
70 let len = bytes.len();
71
72 if !bytes.is_empty() {
73 self.chunks.push_back(bytes);
74 }
75
76 len
77 }
78
79 pub fn take_one(&mut self) -> Vec<u8> {
82 self.chunks.pop_front().unwrap()
83 }
84
85 pub fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
88 let mut offs = 0;
89
90 while offs < buf.len() && !self.is_empty() {
91 let used = self.chunks[0]
92 .as_slice()
93 .read(&mut buf[offs..])?;
94
95 self.consume(used);
96 offs += used;
97 }
98
99 Ok(offs)
100 }
101
102 fn consume(&mut self, mut used: usize) {
103 while used > 0 && !self.is_empty() {
104 if used >= self.chunks[0].len() {
105 used -= self.chunks[0].len();
106 self.take_one();
107 } else {
108 self.chunks[0] = self.chunks[0].split_off(used);
109 used = 0;
110 }
111 }
112 }
113
114 pub fn write_to(&mut self, wr: &mut dyn io::Write) -> io::Result<usize> {
116 if self.is_empty() {
117 return Ok(0);
118 }
119
120 let used = wr.write_vectored(
121 &self
122 .chunks
123 .iter()
124 .map(|ch| io::IoSlice::new(ch))
125 .collect::<Vec<io::IoSlice>>(),
126 )?;
127 self.consume(used);
128 Ok(used)
129 }
130}
131
132#[cfg(test)]
133mod test {
134 use super::ChunkVecBuffer;
135
136 #[test]
137 fn short_append_copy_with_limit() {
138 let mut cvb = ChunkVecBuffer::new();
139 cvb.set_limit(12);
140 assert_eq!(cvb.append_limited_copy(b"hello"), 5);
141 assert_eq!(cvb.append_limited_copy(b"world"), 5);
142 assert_eq!(cvb.append_limited_copy(b"hello"), 2);
143 assert_eq!(cvb.append_limited_copy(b"world"), 0);
144
145 let mut buf = [0u8; 12];
146 assert_eq!(cvb.read(&mut buf).unwrap(), 12);
147 assert_eq!(buf.to_vec(), b"helloworldhe".to_vec());
148 }
149}