Skip to main content

anathema_store/
buffer.rs

1use std::ops::{Index, IndexMut, Range};
2
3#[derive(Debug, Default, Copy, Clone, PartialEq)]
4pub struct SliceIndex(u32);
5
6#[derive(Debug, Default, Copy, Clone)]
7/// Region access into a char buffer
8struct SessionKey {
9    start: u32,
10    end: u32,
11}
12
13impl SessionKey {
14    fn as_range(&self) -> Range<usize> {
15        self.start as usize..self.end as usize
16    }
17}
18
19#[derive(Debug)]
20pub struct Session<'a, T> {
21    buffer: &'a mut Buffer<T>,
22}
23
24impl<'a, T: Copy> Session<'a, T> {
25    /// Create and return a new session key from the current session.
26    /// This means the current session is now pointing to the end of the buffer.
27    #[must_use]
28    pub fn next_slice(&mut self) -> SliceIndex {
29        self.buffer.next_slice()
30    }
31
32    /// Insert a value into the buffer
33    pub fn insert(&mut self, pos: usize, value: T) {
34        self.buffer.insert(pos, value);
35    }
36
37    /// Reference to the last value in the buffer, regardless
38    /// of where the session is pointing.
39    pub fn last(&self) -> Option<&T> {
40        self.buffer.last()
41    }
42
43    /// Push a value to the buffer.
44    ///
45    /// # Panics
46    ///
47    /// This will panic if there is no slice keys in the buffer.
48    /// One can be created with `self.next_slice()`
49    pub fn push(&mut self, value: T) {
50        self.buffer.push(value)
51    }
52
53    /// Pop a value from the buffer.
54    /// This is fine as a session is always referring to the end of the
55    /// underlying buffer.
56    pub fn pop(&mut self) -> Option<T> {
57        self.buffer.pop()
58    }
59
60    /// Extend the buffer with the contents from the iterator
61    pub fn extend(&mut self, iter: impl IntoIterator<Item = T>) {
62        self.buffer.extend(iter);
63    }
64
65    /// Remove N elements from the end of the buffer
66    pub fn tail_drain(&mut self, size: u32) {
67        self.buffer.tail_drain(size);
68    }
69
70    /// Get a slice of data from the underlying buffer
71    pub fn slice(&self, index: SliceIndex) -> &[T] {
72        self.buffer.get(index)
73    }
74
75    /// Get a slice of mutable data from the underlying buffer
76    pub fn slice_mut(&mut self, index: SliceIndex) -> &mut [T] {
77        self.buffer.get_mut(index)
78    }
79
80    /// Length of the session buffer, not the total buffer
81    pub fn len(&self) -> u32 {
82        self.buffer.len()
83    }
84
85    /// It's empty?
86    pub fn is_empty(&self) -> bool {
87        self.len() == 0
88    }
89
90    /// See [`Buffer::truncate`]
91    pub fn truncate(&mut self, key: SliceIndex, index: usize) {
92        self.buffer.truncate(key, index);
93    }
94}
95
96impl<'a, T: Copy> Index<usize> for Session<'a, T> {
97    type Output = T;
98
99    fn index(&self, index: usize) -> &Self::Output {
100        self.buffer.buf.index(index)
101    }
102}
103
104impl<'a, T: Copy> IndexMut<usize> for Session<'a, T> {
105    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
106        self.buffer.buf.index_mut(index)
107    }
108}
109
110/// A buffer of copy values with a max size of `u32::MAX`.
111/// Make sure to interreact with the buffer through a session
112/// when writing and reading from the buffer:
113/// ```
114/// # use anathema_store::buffer::Buffer;
115/// let mut buffer = Buffer::empty();
116/// let mut session = buffer.new_session();
117/// let key = session.next_slice();
118///
119/// session.extend([1, 2, 3]);
120///
121/// assert_eq!(buffer.get(key), &[1, 2, 3]);
122/// ```
123///
124/// and use the `SliceIndex` to access the buffer.
125#[derive(Debug)]
126pub struct Buffer<T> {
127    buf: Vec<T>,
128    keys: Vec<SessionKey>,
129}
130
131impl<T: Copy> Buffer<T> {
132    /// Create an empty buffer.
133    pub fn empty() -> Self {
134        Self {
135            buf: Vec::new(),
136            keys: Vec::new(),
137        }
138    }
139
140    fn push(&mut self, value: T) {
141        assert!(!self.keys.is_empty(), "tried to push to a buffer without a slice key");
142        self.buf.push(value);
143        let buf_len = self.buf.len();
144        let index = self.keys.len() - 1;
145        self.keys[index].end = buf_len as u32;
146    }
147
148    fn pop(&mut self) -> Option<T> {
149        assert!(!self.keys.is_empty(), "tried to pop from a buffer without a slice key");
150        let index = self.keys.len() - 1;
151        let output = self.buf.pop();
152        if output.is_some() {
153            self.keys[index].end -= 1;
154        }
155        output
156    }
157
158    /// Insert a value into the buffer.
159    /// This will cause all the keys update after the
160    fn insert(&mut self, index: usize, value: T) {
161        assert!(index < u32::MAX as usize);
162
163        if self.buf.len() == index {
164            self.push(value);
165            return;
166        }
167
168        self.buf.insert(index, value);
169
170        // Find the slice key where the insert happens.
171        // Since the inserts are most likely happening
172        // at the end of the buffer, it makes sense to search
173        // backwards for the slice index and then subtract that
174        // position from the last index.
175        let last_key_index = self.keys.len() - 1;
176        let Some(key_index) = self
177            .keys
178            .iter_mut()
179            .rev()
180            .position(|key| key.as_range().contains(&index))
181            .map(|pos| last_key_index - pos)
182        else {
183            return;
184        };
185
186        // Increment the length of the slice key where
187        // the insert happened...
188        self.keys[key_index].end += 1;
189
190        // ... and offset all the subsequent keys by one
191        self.keys[key_index + 1..].iter_mut().for_each(|key| {
192            key.start += 1;
193            key.end += 1;
194        });
195    }
196
197    fn extend(&mut self, iter: impl IntoIterator<Item = T>) {
198        self.buf.extend(iter);
199        let buf_len = self.buf.len();
200
201        if !self.keys.is_empty() {
202            let index = self.keys.len() - 1;
203            self.keys[index].end = buf_len as u32;
204        }
205    }
206
207    /// Create a new session that can be converted into
208    /// a session key, with access to the underlying storage
209    /// written to by the session.
210    pub fn new_session(&mut self) -> Session<'_, T> {
211        Session { buffer: self }
212    }
213
214    fn next_slice(&mut self) -> SliceIndex {
215        let slice = SliceIndex(self.keys.len() as u32);
216        let len = self.buf.len() as u32;
217        let key = SessionKey { start: len, end: len };
218        self.keys.push(key);
219        slice
220    }
221
222    pub fn get(&self, index: SliceIndex) -> &[T] {
223        let key = self.keys[index.0 as usize];
224        &self.buf[key.as_range()]
225    }
226
227    pub fn get_mut(&mut self, index: SliceIndex) -> &mut [T] {
228        let key = self.keys[index.0 as usize];
229        &mut self.buf[key.as_range()]
230    }
231
232    /// Drain values from the end of the buffer,
233    /// regardless of which key it belongs to.
234    ///
235    /// This will update the last key in the buffer
236    ///
237    /// # Panics
238    ///
239    /// Panics if there are no keys in the buffer
240    pub fn tail_drain(&mut self, size: u32) {
241        assert!(!self.keys.is_empty());
242        let key_index = self.keys.len() - 1;
243        self.keys[key_index].end -= size;
244        let pos = self.len() - size;
245        let _ = self.buf.drain(pos as usize..);
246    }
247
248    /// Clear the entire buffer
249    pub fn clear(&mut self) {
250        self.buf.clear();
251        self.keys.clear();
252    }
253
254    /// Get a reference to the last value in the buffer
255    fn last(&self) -> Option<&T> {
256        self.buf.last()
257    }
258
259    fn len(&self) -> u32 {
260        self.buf.len() as u32
261    }
262
263    /// Truncate the storage.
264    /// This can only run on the last key, or else it would
265    /// damage the indices for the following keys.
266    fn truncate(&mut self, key: SliceIndex, index: usize) {
267        assert!(
268            !self.keys.is_empty(),
269            "tried to truncate from a buffer that contains zero slice keys"
270        );
271        let last_key_index = self.keys.len() - 1;
272        assert_eq!(key.0 as usize, last_key_index, "trying to truncate before the last key");
273
274        let slice = &mut self.keys[key.0 as usize];
275        let index = index + slice.start as usize;
276        self.buf.truncate(index);
277        slice.end = self.buf.len() as u32;
278    }
279}
280
281#[cfg(test)]
282mod test {
283    use super::*;
284
285    #[test]
286    fn two_sessions() {
287        let mut buffer = Buffer::empty();
288        let mut s1 = buffer.new_session();
289        let k1 = s1.next_slice();
290        s1.extend([1, 2, 3]);
291
292        let mut s2 = buffer.new_session();
293        let k2 = s2.next_slice();
294        s2.extend([10, 20, 30]);
295
296        let b1 = buffer.get(k1);
297        let b2 = buffer.get(k2);
298
299        assert_eq!(b1, &[1, 2, 3]);
300        assert_eq!(b2, &[10, 20, 30]);
301    }
302
303    #[test]
304    fn buffer_insert_via_session() {
305        let mut buffer = Buffer::<u8>::empty();
306        let mut session = buffer.new_session();
307        let k1 = session.next_slice();
308
309        session.extend([b'a', b'b']);
310
311        let k2 = session.next_slice();
312        session.insert(1, b'x');
313        session.push(b'z');
314
315        let output = buffer.get(k1);
316        assert_eq!(output, b"axb");
317
318        let output = buffer.get(k2);
319        assert_eq!(output, b"z");
320    }
321
322    #[test]
323    fn session_pop() {
324        let mut buffer = Buffer::<u8>::empty();
325        let mut session = buffer.new_session();
326        let k1 = session.next_slice();
327        session.push(0);
328        session.pop();
329
330        assert!(buffer.buf.is_empty());
331        assert!(buffer.get(k1).is_empty());
332    }
333
334    #[test]
335    fn clear_buffer() {
336        let mut buffer = Buffer::empty();
337        let mut session = buffer.new_session();
338        let _ = session.next_slice();
339        session.push(0);
340
341        assert_eq!(buffer.keys.len(), 1);
342        assert_eq!(buffer.buf.len(), 1);
343
344        buffer.clear();
345
346        assert!(buffer.keys.is_empty());
347        assert!(buffer.buf.is_empty());
348    }
349
350    #[test]
351    fn tail_drain() {
352        let mut buffer = Buffer::<u8>::empty();
353        let mut session = buffer.new_session();
354        let _k1 = session.next_slice();
355        session.extend(0..10);
356        session.tail_drain(3);
357
358        let key = buffer.keys[0];
359        assert_eq!(key.start, 0);
360        assert_eq!(key.end, 7);
361    }
362
363    #[test]
364    #[should_panic(expected = "tried to truncate from a buffer that contains zero slice keys")]
365    fn truncate_empty_buffer() {
366        let mut buffer = Buffer::<u8>::empty();
367        buffer.truncate(SliceIndex(0), 123);
368    }
369
370    #[test]
371    #[should_panic(expected = "trying to truncate before the last key")]
372    fn truncate_before_last_key() {
373        let mut buffer = Buffer::<u8>::empty();
374        let mut session = buffer.new_session();
375
376        let k1 = session.next_slice();
377        let _k2 = session.next_slice();
378        buffer.truncate(k1, 0);
379    }
380
381    #[test]
382    fn truncate() {
383        let mut buffer = Buffer::<u8>::empty();
384        let mut session = buffer.new_session();
385        let k1 = session.next_slice();
386        session.extend([1, 2, 3]);
387        session.truncate(k1, 2);
388        assert_eq!(&[1, 2], session.slice(k1));
389    }
390}