use std::num::NonZeroUsize;
pub struct RingBuf {
inner_block: Vec<u8>,
read_offset: usize,
write_offset: usize,
}
impl RingBuf {
pub fn with_capacity(value: NonZeroUsize) -> Self {
Self {
inner_block: vec![0; value.get()],
read_offset: 0,
write_offset: 0,
}
}
pub fn remaining(&self) -> usize {
self.write_offset - self.read_offset
}
pub fn remaining_mut(&self) -> usize {
self.read_offset + self.inner_block.len() - self.write_offset
}
pub fn chunk_mut(&mut self) -> &mut [u8] {
let write_offset = self.write_offset % self.inner_block.len();
let mut write_len = self.remaining_mut();
if write_len > self.inner_block.len() - write_offset {
write_len = self.inner_block.len() - write_offset;
}
&mut self.inner_block[write_offset..write_offset + write_len]
}
pub fn chunk(&self) -> &[u8] {
let read_offset = self.read_offset % self.inner_block.len();
let mut read_len = self.remaining();
if read_len > self.inner_block.len() - read_offset {
read_len = self.inner_block.len() - read_offset;
}
&self.inner_block[read_offset..read_offset + read_len]
}
pub fn advance_mut(&mut self, offset: usize) {
if offset > self.remaining_mut() {
panic!(
"advance out of bounds: the remaining mut len is {} but advancing by {}",
self.remaining_mut(),
offset
);
}
self.write_offset += offset;
}
pub fn advance(&mut self, offset: usize) {
if offset > self.remaining() {
panic!(
"advance out of bounds: the remaining len is {} but advancing by {}",
self.remaining(),
offset
);
}
self.read_offset += offset;
}
pub fn write(&mut self, mut buf: &[u8]) -> usize {
let mut write_len = 0;
while buf.len() > 0 && self.remaining_mut() > 0 {
let chunk_mut = self.chunk_mut();
if chunk_mut.len() >= buf.len() {
chunk_mut[..buf.len()].copy_from_slice(buf);
self.advance_mut(buf.len());
write_len += buf.len();
return write_len;
}
let advance = chunk_mut.len();
chunk_mut.copy_from_slice(&buf[..advance]);
write_len += advance;
self.advance_mut(advance);
buf = &buf[advance..];
}
return write_len;
}
pub fn read(&mut self, mut buf: &mut [u8]) -> usize {
let mut read_len = 0;
while buf.len() > 0 && self.remaining() > 0 {
let chunk = self.chunk();
if chunk.len() >= buf.len() {
buf.copy_from_slice(&chunk[..buf.len()]);
self.advance(buf.len());
read_len += buf.len();
return read_len;
}
let advance = chunk.len();
buf[..advance].copy_from_slice(chunk);
read_len += advance;
self.advance(advance);
buf = &mut buf[advance..];
}
return read_len;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ring_buf() {
let capacity = 1024;
let mut ring_buf = RingBuf::with_capacity(NonZeroUsize::new(1024).unwrap());
assert_eq!(ring_buf.remaining(), 0);
assert_eq!(ring_buf.remaining_mut(), capacity);
assert_eq!(ring_buf.write(&vec![1; capacity * 2]), ring_buf.remaining());
assert_eq!(ring_buf.remaining(), capacity);
assert_eq!(ring_buf.remaining_mut(), 0);
let mut buf = vec![0; capacity / 2];
assert_eq!(ring_buf.read(&mut buf), capacity / 2);
assert_eq!(buf, vec![1; capacity / 2]);
assert_eq!(ring_buf.write(&vec![2; capacity / 4]), capacity / 4);
let mut buf = vec![0; capacity / 2];
assert_eq!(ring_buf.read(&mut buf), capacity / 2);
assert_eq!(buf, vec![1; capacity / 2]);
let mut buf = vec![0; capacity / 8];
assert_eq!(ring_buf.read(&mut buf), capacity / 8);
assert_eq!(buf, vec![2; capacity / 8]);
assert_eq!(ring_buf.remaining_mut(), 7 * capacity / 8);
assert_eq!(ring_buf.write(&vec![3; capacity * 10]), 7 * capacity / 8);
assert_eq!(ring_buf.remaining_mut(), 0);
assert_eq!(ring_buf.remaining(), capacity);
let mut buf = vec![0; capacity / 8];
assert_eq!(ring_buf.read(&mut buf), capacity / 8);
assert_eq!(buf, vec![2; capacity / 8]);
assert_eq!(ring_buf.remaining_mut(), capacity / 8);
assert_eq!(ring_buf.remaining(), 7 * capacity / 8);
let mut buf = vec![0; capacity * 10];
assert_eq!(ring_buf.read(&mut buf), 7 * capacity / 8);
assert_eq!(buf[..7 * capacity / 8], vec![3; 7 * capacity / 8]);
}
}