kawa/storage/
buffer.rs

1use std::{cmp::min, io, ptr};
2
3/// AsBuffer is the trait used by Buffer to oparate on an arbitrary buffer.
4/// This is to allow the user to use Kawa over any type as long as it exposes a continious slice
5/// of bytes. The previous solution directly used a slice of bytes but it introduces lifetimes.
6/// In this approach Buffer owns the underlying buffer.
7pub trait AsBuffer {
8    fn as_buffer(&self) -> &[u8];
9    fn as_mut_buffer(&mut self) -> &mut [u8];
10}
11
12/// Buffer is a pseudo ring buffer specifically designed to store data being parsed
13/// ```txt
14/// buffer        start   half     head  end   len
15/// v             v       v         v     v     v
16/// [             ████████:██████████░░░░░░     ]
17/// <-------------------------------------------> buffer()        | capacity()
18/// <------------------------------------->       used()          | end
19///                                        <----> space()         | available_space()
20///               <----------------------->       data()          | available_data()
21///                                  <---->       unparsed_data() |
22/// ```
23/// `head` must be comprised between `start` and `end` and delimit parsed data from unparsed data.
24/// The buffer is filled from `end` up to `buffer.len()`.
25/// Data is assumed to be processed from left to right.
26/// When data from the begining of the buffer can be discarded, `start` advances.
27/// When `start` overshoot half the length of the buffer, it means half the buffer is unsued.
28/// ```txt
29/// buffer             half  start  head  end   len
30/// v                     v  v      v     v     v
31/// [                     :  ████████░░░░░░     ]
32/// ```
33/// At that point the remaining data of the buffer should be shifted.
34/// Shifting the buffer memmoved the available data back at the begining of the buffer.
35/// ```txt
36/// buffer
37/// start   head  end     half                  len
38/// v       v     v       v                     v
39/// [████████░░░░░░       :                     ]
40/// ```
41/// It is also recommended to shift an empty buffer if `start` is not 0.
42/// ```txt
43/// buffer   start/end    half                  len
44/// v        v            v                     v
45/// [        |            :                     ]
46/// ```
47pub struct Buffer<T: AsBuffer> {
48    pub start: usize,
49    pub head: usize,
50    pub end: usize,
51    pub buffer: T,
52}
53
54impl<T: AsBuffer + Clone> Clone for Buffer<T> {
55    fn clone(&self) -> Self {
56        Self {
57            start: self.start,
58            head: self.head,
59            end: self.end,
60            buffer: self.buffer.clone(),
61        }
62    }
63}
64
65impl<T: AsBuffer> Buffer<T> {
66    pub fn new(buffer: T) -> Self {
67        Self {
68            start: 0,
69            head: 0,
70            end: 0,
71            buffer,
72        }
73    }
74
75    pub fn meter(&self, half: usize) -> String {
76        let size = half * 2 + 1;
77        let len = self.capacity();
78        (0..size + 2)
79            .map(|i| {
80                if i == 0 {
81                    '['
82                } else if i - 1 == half {
83                    ':'
84                } else if i - 1 < (self.start * size / len) {
85                    ' '
86                } else if i - 1 < (self.head * size / len) {
87                    '█'
88                } else if i - 1 < (self.end * size / len) {
89                    '░'
90                } else if i - 1 < size {
91                    ' '
92                } else {
93                    ']'
94                }
95            })
96            .collect()
97    }
98
99    pub fn available_data(&self) -> usize {
100        self.end - self.start
101    }
102
103    pub fn available_space(&self) -> usize {
104        self.capacity() - self.end
105    }
106
107    pub fn capacity(&self) -> usize {
108        self.buffer().len()
109    }
110
111    pub fn is_empty(&self) -> bool {
112        self.start == self.end
113    }
114
115    pub fn is_full(&self) -> bool {
116        self.end == self.capacity()
117    }
118
119    pub fn fill(&mut self, count: usize) -> usize {
120        let count = min(count, self.available_space());
121        self.end += count;
122        count
123    }
124
125    pub fn consume(&mut self, count: usize) -> usize {
126        let count = min(count, self.available_data());
127        self.start += count;
128        count
129    }
130
131    pub fn clear(&mut self) {
132        self.start = 0;
133        self.head = 0;
134        self.end = 0;
135    }
136
137    pub fn buffer(&self) -> &[u8] {
138        self.buffer.as_buffer()
139    }
140
141    pub fn mut_buffer(&mut self) -> &mut [u8] {
142        self.buffer.as_mut_buffer()
143    }
144
145    pub fn data(&self) -> &[u8] {
146        let range = self.start..self.end;
147        &self.buffer()[range]
148    }
149
150    pub fn unparsed_data(&self) -> &[u8] {
151        let range = self.head..self.end;
152        &self.buffer()[range]
153    }
154
155    pub fn space(&mut self) -> &mut [u8] {
156        let range = self.end..self.capacity();
157        &mut self.mut_buffer()[range]
158    }
159
160    pub fn used(&self) -> &[u8] {
161        let range = ..self.end;
162        &self.buffer()[range]
163    }
164
165    pub fn should_shift(&self) -> bool {
166        self.start > self.capacity() / 2 || (self.start > 0 && self.is_empty())
167    }
168
169    pub fn shift(&mut self) -> usize {
170        let start = self.start;
171        let end = self.end;
172        if start > 0 {
173            unsafe {
174                let len = end - start;
175                ptr::copy(
176                    self.buffer()[start..end].as_ptr(),
177                    self.mut_buffer()[..len].as_mut_ptr(),
178                    len,
179                );
180                self.start = 0;
181                self.head -= start;
182                self.end = len;
183            }
184        }
185        start
186    }
187}
188
189impl<T: AsBuffer> io::Write for Buffer<T> {
190    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
191        match self.space().write(buf) {
192            Ok(size) => {
193                self.fill(size);
194                Ok(size)
195            }
196            err => err,
197        }
198    }
199
200    fn flush(&mut self) -> io::Result<()> {
201        Ok(())
202    }
203}
204
205impl<T: AsBuffer> io::Read for Buffer<T> {
206    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
207        let len = min(self.available_data(), buf.len());
208        unsafe {
209            ptr::copy(
210                self.buffer()[self.start..self.start + len].as_ptr(),
211                buf.as_mut_ptr(),
212                len,
213            );
214            self.start += len;
215        }
216        Ok(len)
217    }
218}