1use std::{cmp, ptr};
2
3#[derive(Debug,PartialEq,Clone)]
4pub(crate) struct Buffer {
5 memory: Vec<u8>,
6 capacity: usize,
7 position: usize,
8 end: usize
9}
10
11impl Buffer {
12 pub(crate) fn with_capacity(capacity: usize) -> Buffer {
13 Buffer {
14 memory: vec![0; capacity],
15 capacity,
16 position: 0,
17 end: 0
18 }
19 }
20
21 pub(crate) fn grow(&mut self, new_size: usize) -> bool {
22 if self.capacity >= new_size {
23 return false;
24 }
25
26 self.memory.resize(new_size, 0);
27 self.capacity = new_size;
28 true
29 }
30
31 pub(crate) fn available_data(&self) -> usize {
32 self.end - self.position
33 }
34
35 pub(crate) fn available_space(&self) -> usize {
36 self.capacity - self.end
37 }
38
39 pub(crate) fn consume(&mut self, count: usize) -> usize {
40 let cnt = cmp::min(count, self.available_data());
41 self.position += cnt;
42 cnt
43 }
44
45 pub(crate) fn fill(&mut self, count: usize) -> usize {
46 let cnt = cmp::min(count, self.available_space());
47 self.end += cnt;
48 cnt
49 }
50
51 pub(crate) fn data(&self) -> &[u8] {
52 &self.memory[self.position..self.end]
53 }
54
55 pub(crate) fn space(&mut self) -> &mut [u8] {
56 &mut self.memory[self.end..self.capacity]
57 }
58
59 pub(crate) fn shift(&mut self) {
60 let length = self.end - self.position;
61 unsafe {
62 ptr::copy((&self.memory[self.position..self.end]).as_ptr(), (&mut self.memory[..length]).as_mut_ptr(), length);
63 }
64 self.position = 0;
65 self.end = length;
66 }
67
68 pub(crate) fn shift_unless_available(&mut self, size: usize) {
69 if self.available_space() < size {
70 self.shift();
71 }
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78 use std::io::Write;
79
80 #[test]
81 fn fill_and_consume() {
82 let mut b = Buffer::with_capacity(10);
83 assert_eq!(b.available_data(), 0);
84 assert_eq!(b.available_space(), 10);
85 let res = b.space().write(&b"abcd"[..]).map(|size| { b.fill(size); size });
86 assert_eq!(res.ok(), Some(4));
87 assert_eq!(b.available_data(), 4);
88 assert_eq!(b.available_space(), 6);
89
90 assert_eq!(b.data(), &b"abcd"[..]);
91
92 b.consume(2);
93 assert_eq!(b.available_data(), 2);
94 assert_eq!(b.available_space(), 6);
95 assert_eq!(b.data(), &b"cd"[..]);
96
97 b.shift();
98 assert_eq!(b.available_data(), 2);
99 assert_eq!(b.available_space(), 8);
100 assert_eq!(b.data(), &b"cd"[..]);
101
102 assert_eq!(b.space().write(&b"efghijklmnop"[..]).map(|size| { b.fill(size); size }).ok(), Some(8));
103 assert_eq!(b.available_data(), 10);
104 assert_eq!(b.available_space(), 0);
105 assert_eq!(b.data(), &b"cdefghijkl"[..]);
106 b.shift();
107 assert_eq!(b.available_data(), 10);
108 assert_eq!(b.available_space(), 0);
109 assert_eq!(b.data(), &b"cdefghijkl"[..]);
110 }
111}