Skip to main content

sozu_command_lib/buffer/
growable.rs

1//! Growable ring buffer (`Buffer`).
2//!
3//! Same `position` / `end` / `capacity` discipline as `fixed.rs` but
4//! grows the backing `Vec<u8>` on demand up to a configured cap. Shift /
5//! insert / replace operations use overlapping-safe `std::ptr::copy`
6//! (NOT `copy_nonoverlapping`) with bounds checked against
7//! `self.capacity()`.
8
9use std::{
10    cmp,
11    io::{self, Read, Write},
12    ptr,
13};
14
15use pool::Reset;
16
17#[derive(Debug, PartialEq, Eq, Clone)]
18pub struct Buffer {
19    memory: Vec<u8>,
20    capacity: usize,
21    position: usize,
22    end: usize,
23}
24
25impl Buffer {
26    pub fn with_capacity(capacity: usize) -> Buffer {
27        Buffer {
28            memory: vec![0; capacity],
29            capacity,
30            position: 0,
31            end: 0,
32        }
33    }
34
35    pub fn from_slice(sl: &[u8]) -> Buffer {
36        Buffer {
37            memory: Vec::from(sl),
38            capacity: sl.len(),
39            position: 0,
40            end: sl.len(),
41        }
42    }
43
44    pub fn grow(&mut self, new_size: usize) -> bool {
45        if self.capacity >= new_size {
46            return false;
47        }
48
49        self.memory.resize(new_size, 0);
50        self.capacity = new_size;
51        true
52    }
53
54    /// Shrink the buffer to target_size, preserving any pending data.
55    /// If pending data exceeds target_size, the buffer is not shrunk.
56    pub fn shrink(&mut self, target_size: usize) -> bool {
57        if target_size >= self.capacity {
58            return false;
59        }
60        self.shift();
61        if self.end > target_size {
62            return false;
63        }
64        self.memory.truncate(target_size);
65        self.memory.shrink_to_fit();
66        self.capacity = target_size;
67        true
68    }
69
70    pub fn available_data(&self) -> usize {
71        self.end - self.position
72    }
73
74    pub fn available_space(&self) -> usize {
75        self.capacity - self.end
76    }
77
78    pub fn capacity(&self) -> usize {
79        self.capacity
80    }
81
82    pub fn empty(&self) -> bool {
83        self.position == self.end
84    }
85
86    pub fn consume(&mut self, count: usize) -> usize {
87        let cnt = cmp::min(count, self.available_data());
88        self.position += cnt;
89        if self.position > self.capacity / 2 {
90            //trace!("consume shift: pos {}, end {}", self.position, self.end);
91            self.shift();
92        }
93        cnt
94    }
95
96    /// displaces the end pointer to the right
97    pub fn fill(&mut self, count: usize) -> usize {
98        let cnt = cmp::min(count, self.available_space());
99        self.end += cnt;
100        if self.available_space() < self.available_data() + cnt {
101            //trace!("fill shift: pos {}, end {}", self.position, self.end);
102            self.shift();
103        }
104
105        cnt
106    }
107
108    pub fn reset(&mut self) {
109        self.position = 0;
110        self.end = 0;
111    }
112
113    pub fn data(&self) -> &[u8] {
114        &self.memory[self.position..self.end]
115    }
116
117    pub fn space(&mut self) -> &mut [u8] {
118        &mut self.memory[self.end..self.capacity]
119    }
120
121    pub fn shift(&mut self) {
122        if self.position > 0 {
123            // SAFETY: src and dst point into `self.memory` (same
124            // allocation); the slice indexing above bounds-checks both
125            // ranges (`position..end` and `..length`) against the live
126            // buffer length. `ptr::copy` is overlap-safe.
127            unsafe {
128                let length = self.end - self.position;
129                ptr::copy(
130                    self.memory[self.position..self.end].as_ptr(),
131                    self.memory[..length].as_mut_ptr(),
132                    length,
133                );
134                self.position = 0;
135                self.end = length;
136            }
137        }
138    }
139
140    pub fn delete_slice(&mut self, start: usize, length: usize) -> Option<usize> {
141        if start + length >= self.available_data() {
142            return None;
143        }
144
145        // SAFETY: src and dst point into `self.memory` (same allocation).
146        // The early-return above guarantees `start + length < available_data`,
147        // and slice indexing bounds-checks both `begin+length..end` and
148        // `begin..next_end` against the live buffer length. `ptr::copy` is
149        // overlap-safe.
150        unsafe {
151            let begin = self.position + start;
152            let next_end = self.end - length;
153            ptr::copy(
154                self.memory[begin + length..self.end].as_ptr(),
155                self.memory[begin..next_end].as_mut_ptr(),
156                self.end - (begin + length),
157            );
158            self.end = next_end;
159        }
160        Some(self.available_data())
161    }
162
163    pub fn replace_slice(&mut self, data: &[u8], start: usize, length: usize) -> Option<usize> {
164        let data_len = data.len();
165        if start + length > self.available_data()
166            || self.position + start + data_len > self.capacity
167        {
168            return None;
169        }
170
171        // SAFETY: every `ptr::copy` below moves bytes inside `self.memory`
172        // (same allocation) or copies from the caller's `data` slice into
173        // it. The two early-return checks above bound the affected ranges
174        // against `available_data()` and `self.capacity`, and each slice
175        // indexing site is bounds-checked. `ptr::copy` is overlap-safe.
176        unsafe {
177            let begin = self.position + start;
178            let slice_end = begin + data_len;
179            // we reduced the data size
180            if data_len < length {
181                ptr::copy(
182                    data.as_ptr(),
183                    self.memory[begin..slice_end].as_mut_ptr(),
184                    data_len,
185                );
186
187                ptr::copy(
188                    self.memory[start + length..self.end].as_ptr(),
189                    self.memory[slice_end..].as_mut_ptr(),
190                    self.end - (start + length),
191                );
192                self.end -= length - data_len;
193
194            // we put more data in the buffer
195            } else {
196                ptr::copy(
197                    self.memory[start + length..self.end].as_ptr(),
198                    self.memory[start + data_len..].as_mut_ptr(),
199                    self.end - (start + length),
200                );
201                ptr::copy(
202                    data.as_ptr(),
203                    self.memory[begin..slice_end].as_mut_ptr(),
204                    data_len,
205                );
206                self.end += data_len - length;
207            }
208        }
209        Some(self.available_data())
210    }
211
212    pub fn insert_slice(&mut self, data: &[u8], start: usize) -> Option<usize> {
213        let data_len = data.len();
214        if start > self.available_data() || self.position + self.end + data_len > self.capacity {
215            return None;
216        }
217
218        // SAFETY: both `ptr::copy` calls touch `self.memory` (same
219        // allocation) or copy from `data` into it. The early-return checks
220        // bound `start <= available_data` and the resulting tail
221        // `position + end + data_len <= capacity`, and each slice indexing
222        // site is bounds-checked. `ptr::copy` is overlap-safe.
223        unsafe {
224            let begin = self.position + start;
225            let slice_end = begin + data_len;
226            ptr::copy(
227                self.memory[start..self.end].as_ptr(),
228                self.memory[start + data_len..].as_mut_ptr(),
229                self.end - start,
230            );
231            ptr::copy(
232                data.as_ptr(),
233                self.memory[begin..slice_end].as_mut_ptr(),
234                data_len,
235            );
236            self.end += data_len;
237        }
238        Some(self.available_data())
239    }
240}
241
242impl Write for Buffer {
243    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
244        match self.space().write(buf) {
245            Ok(size) => {
246                self.fill(size);
247                Ok(size)
248            }
249            err => err,
250        }
251    }
252
253    fn flush(&mut self) -> io::Result<()> {
254        Ok(())
255    }
256}
257
258impl Read for Buffer {
259    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
260        let len = cmp::min(self.available_data(), buf.len());
261        // SAFETY: `len = min(available_data, buf.len())`, so the source
262        // range `position..position+len` lies inside `self.memory` and the
263        // destination `buf[..len]` fits the caller's `&mut [u8]`. The two
264        // slices are in different allocations; `ptr::copy` is overlap-safe
265        // regardless.
266        unsafe {
267            ptr::copy(
268                self.memory[self.position..self.position + len].as_ptr(),
269                buf.as_mut_ptr(),
270                len,
271            );
272            self.position += len;
273        }
274        Ok(len)
275    }
276}
277
278impl Reset for Buffer {
279    fn reset(&mut self) {
280        self.reset();
281    }
282}
283
284#[cfg(test)]
285mod tests {
286    use std::io::Write;
287
288    use super::*;
289
290    #[test]
291    fn fill_and_consume() {
292        let mut b = Buffer::with_capacity(10);
293        assert_eq!(b.available_data(), 0);
294        assert_eq!(b.available_space(), 10);
295        let res = b.write(&b"abcd"[..]);
296        assert_eq!(res.ok(), Some(4));
297        assert_eq!(b.available_data(), 4);
298        assert_eq!(b.available_space(), 6);
299
300        assert_eq!(b.data(), &b"abcd"[..]);
301
302        b.consume(2);
303        assert_eq!(b.available_data(), 2);
304        assert_eq!(b.available_space(), 6);
305        assert_eq!(b.data(), &b"cd"[..]);
306
307        b.shift();
308        assert_eq!(b.available_data(), 2);
309        assert_eq!(b.available_space(), 8);
310        assert_eq!(b.data(), &b"cd"[..]);
311
312        assert_eq!(b.write(&b"efghijklmnop"[..]).ok(), Some(8));
313        assert_eq!(b.available_data(), 10);
314        assert_eq!(b.available_space(), 0);
315        assert_eq!(b.data(), &b"cdefghijkl"[..]);
316        b.shift();
317        assert_eq!(b.available_data(), 10);
318        assert_eq!(b.available_space(), 0);
319        assert_eq!(b.data(), &b"cdefghijkl"[..]);
320    }
321
322    #[test]
323    fn delete() {
324        let mut b = Buffer::with_capacity(10);
325        let _ = b.write(&b"abcdefgh"[..]).expect("should write");
326        assert_eq!(b.available_data(), 8);
327        assert_eq!(b.available_space(), 2);
328
329        assert_eq!(b.delete_slice(2, 3), Some(5));
330        assert_eq!(b.available_data(), 5);
331        assert_eq!(b.available_space(), 5);
332        assert_eq!(b.data(), &b"abfgh"[..]);
333
334        assert_eq!(b.delete_slice(5, 2), None);
335        assert_eq!(b.delete_slice(4, 2), None);
336    }
337
338    #[test]
339    fn replace() {
340        let mut b = Buffer::with_capacity(10);
341        let _ = b.write(&b"abcdefgh"[..]).expect("should write");
342        assert_eq!(b.available_data(), 8);
343        assert_eq!(b.available_space(), 2);
344
345        assert_eq!(b.replace_slice(&b"ABC"[..], 2, 3), Some(8));
346        assert_eq!(b.available_data(), 8);
347        assert_eq!(b.available_space(), 2);
348        assert_eq!(b.data(), &b"abABCfgh"[..]);
349
350        assert_eq!(b.replace_slice(&b"XYZ"[..], 8, 3), None);
351        assert_eq!(b.replace_slice(&b"XYZ"[..], 6, 3), None);
352
353        assert_eq!(b.replace_slice(&b"XYZ"[..], 2, 4), Some(7));
354        assert_eq!(b.available_data(), 7);
355        assert_eq!(b.available_space(), 3);
356        assert_eq!(b.data(), &b"abXYZgh"[..]);
357
358        assert_eq!(b.replace_slice(&b"123"[..], 2, 2), Some(8));
359        assert_eq!(b.available_data(), 8);
360        assert_eq!(b.available_space(), 2);
361        assert_eq!(b.data(), &b"ab123Zgh"[..]);
362    }
363}