ringbuf_rs/
lib.rs

1use std::num::NonZeroUsize;
2
3/// A data structure that uses a single, fixed-size buffer as if it were connected end-to-end
4pub struct RingBuf {
5    /// inner fixed-size memory block.
6    inner_block: Vec<u8>,
7    /// the read pointer offset.
8    read_offset: usize,
9    /// the write pointer offset.
10    write_offset: usize,
11}
12
13impl RingBuf {
14    /// Create a new `RingBuf` object with provided capacity.
15    ///
16    /// The provided `capacity` must be `NonZeroUsize`.
17    pub fn with_capacity(value: NonZeroUsize) -> Self {
18        Self {
19            inner_block: vec![0; value.get()],
20            read_offset: 0,
21            write_offset: 0,
22        }
23    }
24
25    /// Returns the number of bytes can be read.
26    pub fn remaining(&self) -> usize {
27        self.write_offset - self.read_offset
28    }
29
30    /// Returns the number of bytes that can be written from the current
31    /// position until the end of the buffer is reached.
32    pub fn remaining_mut(&self) -> usize {
33        self.read_offset + self.inner_block.len() - self.write_offset
34    }
35
36    /// Returns a mutable slice starting at the `write pointer`,
37    /// the length may shorter than [`remaining_mut`](Self::remaining_mut).
38    pub fn chunk_mut(&mut self) -> &mut [u8] {
39        let write_offset = self.write_offset % self.inner_block.len();
40
41        let mut write_len = self.remaining_mut();
42
43        if write_len > self.inner_block.len() - write_offset {
44            write_len = self.inner_block.len() - write_offset;
45        }
46
47        &mut self.inner_block[write_offset..write_offset + write_len]
48    }
49
50    /// Returns a immutable slice starting at the `read pointer`,
51    /// the length may shorter than [`remaining`](Self::remaining).
52    pub fn chunk(&self) -> &[u8] {
53        let read_offset = self.read_offset % self.inner_block.len();
54
55        let mut read_len = self.remaining();
56
57        if read_len > self.inner_block.len() - read_offset {
58            read_len = self.inner_block.len() - read_offset;
59        }
60
61        &self.inner_block[read_offset..read_offset + read_len]
62    }
63
64    /// Advance the innner write cursor of this `RingBuf`.
65    ///
66    /// if the `offset` value > `remaining_mut` will cause an panic.
67    pub fn advance_mut(&mut self, offset: usize) {
68        if offset > self.remaining_mut() {
69            panic!(
70                "advance out of bounds: the remaining mut len is {} but advancing by {}",
71                self.remaining_mut(),
72                offset
73            );
74        }
75
76        self.write_offset += offset;
77    }
78
79    /// Advance the innner read cursor of this `RingBuf`.
80    ///
81    /// if the `offset` value > `remaining` will cause an panic.
82    pub fn advance(&mut self, offset: usize) {
83        if offset > self.remaining() {
84            panic!(
85                "advance out of bounds: the remaining  len is {} but advancing by {}",
86                self.remaining(),
87                offset
88            );
89        }
90
91        self.read_offset += offset;
92    }
93
94    /// Write data into ring buf.
95    ///
96    /// Returns the number of written bytes.
97    /// the number of written bytes returned can be shorter than the length of the
98    /// input buffer when the ring buf doesn’t have enough capacity.
99    pub fn write(&mut self, mut buf: &[u8]) -> usize {
100        let mut write_len = 0;
101
102        while buf.len() > 0 && self.remaining_mut() > 0 {
103            let chunk_mut = self.chunk_mut();
104
105            if chunk_mut.len() >= buf.len() {
106                chunk_mut[..buf.len()].copy_from_slice(buf);
107                self.advance_mut(buf.len());
108                write_len += buf.len();
109
110                return write_len;
111            }
112
113            let advance = chunk_mut.len();
114
115            chunk_mut.copy_from_slice(&buf[..advance]);
116
117            write_len += advance;
118
119            // move write cursor
120            self.advance_mut(advance);
121
122            // split source buf to `advance` offset.
123            buf = &buf[advance..];
124        }
125
126        return write_len;
127    }
128
129    /// Read data from `RingBuf` and copy to provided mutable slice.
130    ///
131    /// Returns the number of read bytes.
132    pub fn read(&mut self, mut buf: &mut [u8]) -> usize {
133        let mut read_len = 0;
134
135        while buf.len() > 0 && self.remaining() > 0 {
136            let chunk = self.chunk();
137
138            if chunk.len() >= buf.len() {
139                buf.copy_from_slice(&chunk[..buf.len()]);
140
141                self.advance(buf.len());
142                read_len += buf.len();
143
144                return read_len;
145            }
146
147            let advance = chunk.len();
148
149            buf[..advance].copy_from_slice(chunk);
150
151            read_len += advance;
152
153            self.advance(advance);
154
155            buf = &mut buf[advance..];
156        }
157
158        return read_len;
159    }
160}
161
162#[cfg(test)]
163mod tests {
164    use super::*;
165
166    #[test]
167    fn test_ring_buf() {
168        let capacity = 1024;
169
170        let mut ring_buf = RingBuf::with_capacity(NonZeroUsize::new(1024).unwrap());
171
172        assert_eq!(ring_buf.remaining(), 0);
173        assert_eq!(ring_buf.remaining_mut(), capacity);
174
175        // write data out of range.
176
177        assert_eq!(ring_buf.write(&vec![1; capacity * 2]), ring_buf.remaining());
178
179        assert_eq!(ring_buf.remaining(), capacity);
180        assert_eq!(ring_buf.remaining_mut(), 0);
181
182        let mut buf = vec![0; capacity / 2];
183
184        assert_eq!(ring_buf.read(&mut buf), capacity / 2);
185
186        assert_eq!(buf, vec![1; capacity / 2]);
187
188        assert_eq!(ring_buf.write(&vec![2; capacity / 4]), capacity / 4);
189
190        let mut buf = vec![0; capacity / 2];
191
192        assert_eq!(ring_buf.read(&mut buf), capacity / 2);
193
194        assert_eq!(buf, vec![1; capacity / 2]);
195
196        let mut buf = vec![0; capacity / 8];
197
198        assert_eq!(ring_buf.read(&mut buf), capacity / 8);
199
200        assert_eq!(buf, vec![2; capacity / 8]);
201
202        assert_eq!(ring_buf.remaining_mut(), 7 * capacity / 8);
203
204        assert_eq!(ring_buf.write(&vec![3; capacity * 10]), 7 * capacity / 8);
205
206        assert_eq!(ring_buf.remaining_mut(), 0);
207
208        assert_eq!(ring_buf.remaining(), capacity);
209
210        let mut buf = vec![0; capacity / 8];
211
212        assert_eq!(ring_buf.read(&mut buf), capacity / 8);
213
214        assert_eq!(buf, vec![2; capacity / 8]);
215
216        assert_eq!(ring_buf.remaining_mut(), capacity / 8);
217
218        assert_eq!(ring_buf.remaining(), 7 * capacity / 8);
219
220        let mut buf = vec![0; capacity * 10];
221
222        assert_eq!(ring_buf.read(&mut buf), 7 * capacity / 8);
223
224        assert_eq!(buf[..7 * capacity / 8], vec![3; 7 * capacity / 8]);
225    }
226}