rotating_buffer/
lib.rs

1#![no_std]
2
3/*!
4# Rotating Buffer
5
6… is a small helper data structure that allows a stack-allocated buffer to be
7reused while keeping data that couldn't be handled immediately.
8
9## Example
10
11```rust
12use rotating_buffer::*;
13let mut buf = RotatingBuffer::<u8, 4>::new();
14
15buf.get_append_only().copy_from_slice(&[1, 2, 3, 4]);
16buf.add_len(4);
17assert_eq!(&[1, 2, 3, 4], buf.as_slice());
18
19buf.rotate_right_and_resize_at(3);
20assert_eq!(&[4], buf.as_slice());
21
22assert_eq!(3, buf.get_append_only().len());
23buf.get_append_only().copy_from_slice(&[5, 6, 7]);
24buf.add_len(3);
25assert_eq!(&[4, 5, 6, 7], buf.as_slice());
26
27buf.rotate_right_and_resize_at(4);
28assert_eq!(buf.as_slice().len(), 0);
29```
30
31For a more in depth example please see `examples/read_to_eof.rs`.
32
33Inspired by a pairing session at [Recurse Center](https://www.recurse.com/) 👩‍💻🐙
34*/
35
36#[derive(Debug, Clone, Copy)]
37pub struct RotatingBuffer<T: Default + Copy, const S: usize> {
38    inner_length: usize,
39    pub inner: [T; S],
40}
41
42impl<T: Default + Copy, const S: usize> RotatingBuffer<T, S> {
43    pub fn new() -> RotatingBuffer<T, S> {
44        RotatingBuffer {
45            inner: [T::default(); S],
46            inner_length: 0,
47        }
48    }
49
50    /// Extracts slice with the length of the buffer's internally tracked size
51    ///
52    /// # Example
53    ///
54    /// ```rust
55    /// # use rotating_buffer::*;
56    /// let mut buf = RotatingBuffer::<u128, 20>::new();
57    /// assert_eq!(buf.as_slice().len(), 0);
58    ///
59    /// buf.add_len(15);
60    /// assert_eq!(buf.as_slice().len(), 15);
61    /// ```
62    pub fn as_slice(&self) -> &[T] {
63        &self.inner[..self.inner_length]
64    }
65
66    /// Returns a mutable slice with the length of the currently "unused" allocation of the buffer
67    ///
68    /// # Example
69    ///
70    /// ```rust
71    /// # use rotating_buffer::*;
72    /// let mut buf = RotatingBuffer::<u8, 5>::new();
73    /// buf.add_len(3);
74    ///
75    /// assert_eq!(buf.get_append_only().len(), 2);
76    /// buf.get_append_only()[0] = 50;
77    /// assert_eq!(buf.inner, [0, 0, 0, 50, 0]);
78    /// ```
79    pub fn get_append_only(&mut self) -> &mut [T] {
80        &mut self.inner[self.inner_length..]
81    }
82
83    /// Returns `true` if the buffer's internal size is 0
84    pub fn is_empty(&self) -> bool {
85        self.inner_length == 0
86    }
87
88    /// Returns internally tracked length
89    pub fn len(&self) -> usize {
90        self.inner_length
91    }
92
93    /// Returns the capacity of this buffer
94    pub fn capacity(&self) -> usize {
95        S
96    }
97
98    /// Manually set the internal size of the buffer
99    ///
100    /// # Panics
101    ///
102    /// Panics if the new size is bigger than its capacity
103    pub fn resize(&mut self, new_len: usize) {
104        assert!(new_len <= S);
105        self.inner_length = new_len;
106    }
107
108    /// Add to the current internal length of the buffer
109    ///
110    /// # Example
111    ///
112    /// ```rust
113    /// # use rotating_buffer::*;
114    /// let mut buf = RotatingBuffer::<u8, 5>::new();
115    /// assert_eq!(buf.len(), 0);
116    ///
117    /// buf.add_len(3);
118    /// assert_eq!(buf.len(), 3);
119    /// buf.add_len(1);
120    /// assert_eq!(buf.len(), 4);
121    /// ```
122    pub fn add_len(&mut self, new_len: usize) -> usize {
123        self.resize(self.inner_length + new_len);
124        self.inner_length
125    }
126
127    /// Rotates the buffer contents in place (see `core::slice::rotate_right`) and subsequently
128    /// changes the buffer's internal length to however much was rotated
129    ///
130    /// # Example
131    ///
132    /// ```rust
133    /// # use rotating_buffer::*;
134    /// let mut buf = RotatingBuffer::<bool, 5>::new();
135    /// buf.get_append_only()[3] = true;
136    /// buf.add_len(5);
137    ///
138    /// buf.rotate_right_and_resize(2);
139    /// assert_eq!(buf.as_slice()[0], true);
140    /// assert_eq!(buf.len(), 2);
141    /// ```
142    pub fn rotate_right_and_resize(&mut self, k: usize) {
143        self.inner[..self.inner_length].rotate_right(k);
144        self.inner_length = k;
145    }
146
147    /// Rotate and resize buffer by supplying an index rather than a length
148    ///
149    /// # Example
150    ///
151    /// ```rust
152    /// # use rotating_buffer::*;
153    /// let mut buf = RotatingBuffer::<bool, 5>::new();
154    /// buf.get_append_only()[3] = true;
155    /// buf.add_len(5);
156    ///
157    /// buf.rotate_right_and_resize_at(3);
158    /// assert_eq!(buf.as_slice()[0], true);
159    /// assert_eq!(buf.len(), 2);
160    /// ```
161    pub fn rotate_right_and_resize_at(&mut self, index: usize) {
162        self.rotate_right_and_resize(self.inner_length - index);
163    }
164}
165
166/// Maybe just to allow `RotatingBuffer<RotatingBuffer<T, S>, S>` 😄
167///
168/// # Example
169///
170/// ```rust
171/// # use rotating_buffer::*;
172/// let mut buf = RotatingBuffer::<RotatingBuffer<u8, 10>, 5>::new();
173/// buf.add_len(2);
174/// let slice = buf.as_slice();
175/// assert_eq!(slice[0].inner, slice[1].inner);
176/// ```
177///
178/// But why!
179impl<T: Default + Copy, const S: usize> Default for RotatingBuffer<T, S> {
180    fn default() -> Self {
181        Self::new()
182    }
183}