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