Skip to main content

sozu_command_lib/buffer/
fixed.rs

1//! Fixed-capacity ring buffer (`Buffer`).
2//!
3//! Tracks `position` (read cursor), `end` (write cursor), and `capacity`
4//! over a `Vec<u8>` allocated once at construction.
5
6use std::{
7    cmp,
8    io::{self, Read, Write},
9};
10
11use poule::Reset;
12
13#[derive(Debug, PartialEq, Clone)]
14pub struct Buffer {
15    memory: Vec<u8>,
16    position: usize,
17    end: usize,
18}
19
20impl Buffer {
21    pub fn with_capacity(capacity: usize) -> Buffer {
22        Buffer {
23            memory: vec![0; capacity],
24            position: 0,
25            end: 0,
26        }
27    }
28
29    /*pub fn from_slice(sl: &[u8]) -> Buffer {
30      Buffer {
31        memory:   Vec::from(sl),
32        capacity: sl.len(),
33        position: 0,
34        end:      sl.len()
35      }
36      unimplemented!()
37    }
38      */
39
40    pub fn grow(&mut self, new_size: usize) -> bool {
41        if self.capacity() >= new_size {
42            return false;
43        }
44
45        /*
46        self.memory.resize(new_size, 0);
47        self.capacity = new_size;
48        true
49          */
50        unimplemented!()
51    }
52
53    pub fn available_data(&self) -> usize {
54        self.end - self.position
55    }
56
57    pub fn available_space(&self) -> usize {
58        self.capacity() - self.end
59    }
60
61    pub fn capacity(&self) -> usize {
62        self.memory.len()
63    }
64
65    pub fn empty(&self) -> bool {
66        self.position == self.end
67    }
68
69    pub fn consume(&mut self, count: usize) -> usize {
70        let cnt = cmp::min(count, self.available_data());
71        self.position += cnt;
72        if self.position > self.capacity() / 2 {
73            //trace!("consume shift: pos {}, end {}", self.position, self.end);
74            self.shift();
75        }
76        cnt
77    }
78
79    pub fn fill(&mut self, count: usize) -> usize {
80        let cnt = cmp::min(count, self.available_space());
81        self.end += cnt;
82        if self.available_space() < self.available_data() + cnt {
83            //trace!("fill shift: pos {}, end {}", self.position, self.end);
84            self.shift();
85        }
86
87        cnt
88    }
89
90    pub fn reset(&mut self) {
91        self.position = 0;
92        self.end = 0;
93    }
94
95    pub fn data(&self) -> &[u8] {
96        &self.memory[self.position..self.end]
97    }
98
99    pub fn space(&mut self) -> &mut [u8] {
100        &mut self.memory[self.end..]
101    }
102
103    pub fn shift(&mut self) {
104        if self.position > 0 {
105            let length = self.end - self.position;
106            self.memory.copy_within(self.position..self.end, 0);
107            self.position = 0;
108            self.end = length;
109        }
110    }
111
112    pub fn delete_slice(&mut self, start: usize, length: usize) -> Option<usize> {
113        let end = start.checked_add(length)?;
114        if end >= self.available_data() {
115            return None;
116        }
117
118        let begin = self.position + start;
119        let tail_start = begin + length;
120        self.memory.copy_within(tail_start..self.end, begin);
121        self.end -= length;
122        Some(self.available_data())
123    }
124
125    pub fn replace_slice(&mut self, data: &[u8], start: usize, length: usize) -> Option<usize> {
126        let data_len = data.len();
127        let replaced_end = start.checked_add(length)?;
128        if replaced_end > self.available_data() {
129            return None;
130        }
131
132        let begin = self.position + start;
133        let tail_start = begin + length;
134        let slice_end = begin + data_len;
135
136        match data_len.cmp(&length) {
137            cmp::Ordering::Less => {
138                self.memory[begin..slice_end].copy_from_slice(data);
139                self.memory.copy_within(tail_start..self.end, slice_end);
140                self.end -= length - data_len;
141            }
142            cmp::Ordering::Equal => {
143                self.memory[begin..slice_end].copy_from_slice(data);
144            }
145            cmp::Ordering::Greater => {
146                let new_end = self.end.checked_add(data_len - length)?;
147                if new_end > self.capacity() {
148                    return None;
149                }
150                self.memory.copy_within(tail_start..self.end, slice_end);
151                self.memory[begin..slice_end].copy_from_slice(data);
152                self.end = new_end;
153            }
154        }
155        Some(self.available_data())
156    }
157
158    pub fn insert_slice(&mut self, data: &[u8], start: usize) -> Option<usize> {
159        self.replace_slice(data, start, 0)
160    }
161}
162
163impl Write for Buffer {
164    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
165        match self.space().write(buf) {
166            Ok(size) => {
167                self.fill(size);
168                Ok(size)
169            }
170            err => err,
171        }
172    }
173
174    fn flush(&mut self) -> io::Result<()> {
175        Ok(())
176    }
177}
178
179impl Read for Buffer {
180    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
181        let len = cmp::min(self.available_data(), buf.len());
182        buf[..len].copy_from_slice(&self.memory[self.position..self.position + len]);
183        self.position += len;
184        Ok(len)
185    }
186}
187
188impl Reset for Buffer {
189    fn reset(&mut self) {
190        self.reset();
191    }
192}
193
194#[cfg(test)]
195mod tests {
196    use std::io::Write;
197
198    use super::*;
199
200    #[test]
201    fn fill_and_consume() {
202        let mut b = Buffer::with_capacity(10);
203        assert_eq!(b.available_data(), 0);
204        assert_eq!(b.available_space(), 10);
205        let res = b.write(&b"abcd"[..]);
206        assert_eq!(res.ok(), Some(4));
207        assert_eq!(b.available_data(), 4);
208        assert_eq!(b.available_space(), 6);
209
210        assert_eq!(b.data(), &b"abcd"[..]);
211
212        b.consume(2);
213        assert_eq!(b.available_data(), 2);
214        assert_eq!(b.available_space(), 6);
215        assert_eq!(b.data(), &b"cd"[..]);
216
217        b.shift();
218        assert_eq!(b.available_data(), 2);
219        assert_eq!(b.available_space(), 8);
220        assert_eq!(b.data(), &b"cd"[..]);
221
222        assert_eq!(b.write(&b"efghijklmnop"[..]).ok(), Some(8));
223        assert_eq!(b.available_data(), 10);
224        assert_eq!(b.available_space(), 0);
225        assert_eq!(b.data(), &b"cdefghijkl"[..]);
226        b.shift();
227        assert_eq!(b.available_data(), 10);
228        assert_eq!(b.available_space(), 0);
229        assert_eq!(b.data(), &b"cdefghijkl"[..]);
230    }
231
232    #[test]
233    fn delete() {
234        let mut b = Buffer::with_capacity(10);
235        let _ = b.write(&b"abcdefgh"[..]).expect("should write");
236        assert_eq!(b.available_data(), 8);
237        assert_eq!(b.available_space(), 2);
238
239        assert_eq!(b.delete_slice(2, 3), Some(5));
240        assert_eq!(b.available_data(), 5);
241        assert_eq!(b.available_space(), 5);
242        assert_eq!(b.data(), &b"abfgh"[..]);
243
244        assert_eq!(b.delete_slice(5, 2), None);
245        assert_eq!(b.delete_slice(4, 2), None);
246    }
247
248    #[test]
249    fn replace() {
250        let mut b = Buffer::with_capacity(10);
251        let _ = b.write(&b"abcdefgh"[..]).expect("should write");
252        assert_eq!(b.available_data(), 8);
253        assert_eq!(b.available_space(), 2);
254
255        assert_eq!(b.replace_slice(&b"ABC"[..], 2, 3), Some(8));
256        assert_eq!(b.available_data(), 8);
257        assert_eq!(b.available_space(), 2);
258        assert_eq!(b.data(), &b"abABCfgh"[..]);
259
260        assert_eq!(b.replace_slice(&b"XYZ"[..], 8, 3), None);
261        assert_eq!(b.replace_slice(&b"XYZ"[..], 6, 3), None);
262
263        assert_eq!(b.replace_slice(&b"XYZ"[..], 2, 4), Some(7));
264        assert_eq!(b.available_data(), 7);
265        assert_eq!(b.available_space(), 3);
266        assert_eq!(b.data(), &b"abXYZgh"[..]);
267
268        assert_eq!(b.replace_slice(&b"123"[..], 2, 2), Some(8));
269        assert_eq!(b.available_data(), 8);
270        assert_eq!(b.available_space(), 2);
271        assert_eq!(b.data(), &b"ab123Zgh"[..]);
272    }
273}