#![forbid(unsafe_code)]
use std::cmp::min;
use std::io::{Error, ErrorKind, Read, Result, Write};
macro_rules! check_valid {
($self:ident) => {
debug_assert!($self.read_pos < $self.data.len());
debug_assert!($self.write_pos < $self.data.len());
}
}
pub struct RingBuf {
data: Box<[u8]>,
read_pos: usize,
write_pos: usize
}
impl RingBuf {
pub fn with_capacity(capacity: usize) -> Self {
vec!(0; capacity + 1).into_boxed_slice().into()
}
pub fn capacity(&self) -> usize {
check_valid!(self);
self.data.len() - 1
}
pub fn clear(&mut self) {
check_valid!(self);
self.read_pos = 0;
self.write_pos = 0;
}
pub fn len(&self) -> usize {
check_valid!(self);
if self.read_pos > self.write_pos {
self.data.len() - self.read_pos + self.write_pos
}
else {
self.write_pos - self.read_pos
}
}
pub fn is_empty(&self) -> bool {
check_valid!(self);
self.read_pos == self.write_pos
}
pub fn advance_read_pos(&mut self, count: usize) -> Result<()> {
check_valid!(self);
if count > self.len() {
return Err(Error::new(ErrorKind::InvalidInput, "Can't seek past write pos."));
}
self.read_pos += count;
if self.read_pos >= self.data.len() {
self.read_pos -= self.data.len();
}
Ok(())
}
pub fn peek(&self, buf: &mut [u8]) -> Result<usize> {
check_valid!(self);
let to_read = min(self.len(), buf.len());
let bytes_until_end = self.data.len() - self.read_pos;
if bytes_until_end <= to_read {
buf[..bytes_until_end].copy_from_slice(&self.data[self.read_pos..]);
buf[bytes_until_end..to_read].copy_from_slice(&self.data[..to_read - bytes_until_end]);
}
else {
buf[..to_read].copy_from_slice(&self.data[self.read_pos..self.read_pos + to_read]);
}
Ok(to_read)
}
}
impl From<Box<[u8]>> for RingBuf {
fn from(s: Box<[u8]>) -> Self {
RingBuf {
data: s,
read_pos: 0,
write_pos: 0
}
}
}
impl From<Vec<u8>> for RingBuf {
fn from(mut s: Vec<u8>) -> Self {
s.push(0);
let write_pos = s.len() - 1;
RingBuf {
data: s.into_boxed_slice(),
read_pos: 0,
write_pos
}
}
}
impl Read for RingBuf {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
check_valid!(self);
let bytes_read = self.peek(buf)?;
self.advance_read_pos(bytes_read)?;
Ok(bytes_read)
}
}
impl Write for RingBuf {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
check_valid!(self);
let to_write = min(self.capacity() - self.len(), buf.len());
let bytes_until_end = self.data.len() - self.write_pos;
if bytes_until_end <= to_write {
self.data[self.write_pos..].copy_from_slice(&buf[..bytes_until_end]);
self.data[..to_write - bytes_until_end].copy_from_slice(&buf[bytes_until_end..to_write]);
self.write_pos = to_write - bytes_until_end;
}
else {
self.data[self.write_pos..self.write_pos + to_write].copy_from_slice(&buf[..to_write]);
self.write_pos += to_write;
}
Ok(to_write)
}
fn flush(&mut self) -> Result<()> {
check_valid!(self);
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::io::{Read, Write};
use crate::RingBuf;
#[test]
fn ringbuf_with_capacity() {
let rb = RingBuf::with_capacity(4);
assert_eq!(rb.capacity(), 4);
assert_eq!(rb.len(), 0);
assert!(rb.is_empty());
}
#[test]
fn ringbuf_from_vec() {
let mut rb: RingBuf = vec![5, 4, 3, 2, 1].into();
assert_eq!(rb.capacity(), 5);
assert_eq!(rb.len(), 5);
assert!(!rb.is_empty());
let mut buf = [0u8; 10];
assert_eq!(rb.peek(&mut buf).unwrap(), 5);
assert_eq!(buf, [5, 4, 3, 2, 1, 0, 0, 0, 0, 0]);
assert_eq!(rb.capacity(), 5);
assert_eq!(rb.len(), 5);
assert!(!rb.is_empty());
buf = [0u8; 10];
assert_eq!(rb.read(&mut buf).unwrap(), 5);
assert_eq!(buf, [5, 4, 3, 2, 1, 0, 0, 0, 0, 0]);
assert_eq!(rb.capacity(), 5);
assert_eq!(rb.len(), 0);
assert!(rb.is_empty());
buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
assert_eq!(rb.write(&buf).unwrap(), 5);
assert_eq!(rb.capacity(), 5);
assert_eq!(rb.len(), 5);
assert!(!rb.is_empty());
buf = [0u8; 10];
assert_eq!(rb.read(&mut buf).unwrap(), 5);
assert_eq!(buf, [0, 1, 2, 3, 4, 0, 0, 0, 0, 0]);
assert_eq!(rb.capacity(), 5);
assert_eq!(rb.len(), 0);
assert!(rb.is_empty());
}
#[test]
fn ringbuf_wrapped_read_write() {
let mut rb = RingBuf::with_capacity(5);
assert_eq!(rb.capacity(), 5);
assert_eq!(rb.len(), 0);
assert!(rb.is_empty());
let mut buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
assert_eq!(rb.write(&mut buf).unwrap(), 5);
assert_eq!(rb.capacity(), 5);
assert_eq!(rb.len(), 5);
assert!(!rb.is_empty());
let mut buf = [0u8; 3];
assert_eq!(rb.peek(&mut buf).unwrap(), 3);
assert_eq!(buf, [0, 1, 2]);
assert_eq!(rb.capacity(), 5);
assert_eq!(rb.len(), 5);
assert!(!rb.is_empty());
buf = [0u8; 3];
assert_eq!(rb.read(&mut buf).unwrap(), 3);
assert_eq!(buf, [0, 1, 2]);
assert_eq!(rb.capacity(), 5);
assert_eq!(rb.len(), 2);
assert!(!rb.is_empty());
let mut buf = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
assert_eq!(rb.write(&mut buf).unwrap(), 3);
assert_eq!(rb.capacity(), 5);
assert_eq!(rb.len(), 5);
assert!(!rb.is_empty());
buf = [0u8; 10];
assert_eq!(rb.peek(&mut buf).unwrap(), 5);
assert_eq!(buf, [3, 4, 9, 8, 7, 0, 0, 0, 0, 0]);
assert_eq!(rb.capacity(), 5);
assert_eq!(rb.len(), 5);
assert!(!rb.is_empty());
buf = [0u8; 10];
assert_eq!(rb.read(&mut buf).unwrap(), 5);
assert_eq!(buf, [3, 4, 9, 8, 7, 0, 0, 0, 0, 0]);
assert_eq!(rb.capacity(), 5);
assert_eq!(rb.len(), 0);
assert!(rb.is_empty());
}
#[test]
fn ringbuf_clear() {
let mut rb: RingBuf = vec![5, 4, 3, 2, 1].into();
assert_eq!(rb.capacity(), 5);
assert_eq!(rb.len(), 5);
assert!(!rb.is_empty());
rb.clear();
assert_eq!(rb.capacity(), 5);
assert_eq!(rb.len(), 0);
assert!(rb.is_empty());
}
#[test]
fn ringbuf_peek_read_empty() {
let mut rb = RingBuf::with_capacity(10);
let mut buf = [0u8; 10];
assert_eq!(rb.peek(&mut buf).unwrap(), 0);
assert_eq!(rb.read(&mut buf).unwrap(), 0);
}
#[test]
fn ringbuf_peek_read_0_len_buf() {
let mut rb: RingBuf = vec![0, 1, 2].into();
let mut buf = [0u8; 0];
assert_eq!(rb.peek(&mut buf).unwrap(), 0);
assert_eq!(rb.read(&mut buf).unwrap(), 0);
}
#[test]
fn ringbuf_read_write_larger_then_capacity() {
let mut rb = RingBuf::with_capacity(5);
assert_eq!(rb.write(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).unwrap(), 5);
let mut buf = [0u8; 10];
assert_eq!(rb.read(&mut buf).unwrap(), 5);
assert_eq!(buf, [1, 2, 3, 4, 5, 0, 0, 0, 0, 0]);
assert_eq!(rb.write(&[6, 7, 8, 9, 10, 11, 12, 13, 14, 15]).unwrap(), 5);
assert_eq!(rb.read(&mut buf).unwrap(), 5);
assert_eq!(buf, [6, 7, 8, 9, 10, 0, 0, 0, 0, 0]);
assert_eq!(rb.len(), 0);
assert!(rb.is_empty());
}
#[test]
fn ringbuf_read_write_buf_end() {
let mut rb = RingBuf::with_capacity(5);
assert_eq!(rb.write(&[1]).unwrap(), 1);
let mut buf = [0u8; 10];
assert_eq!(rb.read(&mut buf).unwrap(), 1);
assert_eq!(buf, [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
assert_eq!(rb.write(&[0, 1, 2, 3, 4]).unwrap(), 5);
assert_eq!(rb.read(&mut buf).unwrap(), 5);
assert_eq!(buf, [0, 1, 2, 3, 4, 0, 0, 0, 0, 0]);
assert_eq!(rb.read_pos, 0);
assert_eq!(rb.write_pos, 0);
assert_eq!(rb.len(), 0);
assert!(rb.is_empty());
}
}