diff --git a/circular-buffer/Cargo.lock b/circular-buffer/Cargo.lock new file mode 100644 index 000000000..b83dee78a --- /dev/null +++ b/circular-buffer/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "circular-buffer" +version = "0.0.0" + diff --git a/circular-buffer/Cargo.toml b/circular-buffer/Cargo.toml new file mode 100644 index 000000000..15eb6840b --- /dev/null +++ b/circular-buffer/Cargo.toml @@ -0,0 +1,3 @@ +[package] +name = "circular-buffer" +version = "0.0.0" diff --git a/circular-buffer/example.rs b/circular-buffer/example.rs new file mode 100644 index 000000000..38936421e --- /dev/null +++ b/circular-buffer/example.rs @@ -0,0 +1,69 @@ +#[derive(Debug, PartialEq)] +pub enum Error { + EmptyBuffer, + FullBuffer, +} + +pub struct CircularBuffer { + buffer: Vec, + size: usize, + start: usize, + end: usize, +} + +impl CircularBuffer { + // this circular buffer keeps an unallocated slot between the start and the end + // when the buffer is full. + pub fn new(size: usize) -> CircularBuffer { + let mut v = Vec::new(); + v.reserve(size + 1); + + // initialize the buffer + for _ in 0..(size + 1) { + v.push('0'); + } + + let buffer = CircularBuffer { + buffer: v, + size: size + 1, + start: 0, + end: 0 + }; + + buffer + } + + pub fn read(&mut self) -> Result { + if self.start == self.end { + return Err(Error::EmptyBuffer); + } + + let v = *self.buffer.get(self.start).unwrap(); + self.start = (self.start + 1) % self.size; + + Ok(v) + } + + pub fn write(&mut self, byte: char) -> Result<(), Error> { + if (self.end + 1) % self.size == self.start { + return Err(Error::FullBuffer); + } else { + self.buffer[self.end] = byte; + self.end = (self.end + 1) % self.size; + return Ok(()); + } + } + + pub fn overwrite(&mut self, byte: char) { + self.buffer[self.end] = byte; + self.end = (self.end + 1) % self.size; + if self.start == self.end { + self.start = (self.start + 1) % self.size; + } + } + + pub fn clear(&mut self) { + self.start = 0; + self.end = 0; + } +} diff --git a/circular-buffer/tests/circular-buffer.rs b/circular-buffer/tests/circular-buffer.rs new file mode 100644 index 000000000..fa6bdd3b6 --- /dev/null +++ b/circular-buffer/tests/circular-buffer.rs @@ -0,0 +1,90 @@ +extern crate circular_buffer; + +#[allow(unused_must_use)] +mod tests { + + use circular_buffer::{CircularBuffer, Error}; + + #[test] + fn error_on_read_empty_buffer() { + let mut buffer = CircularBuffer::new(1); + assert_eq!(Err(Error::EmptyBuffer), buffer.read()); + } + + #[test] + #[ignore] + fn write_and_read_back_item() { + let mut buffer = CircularBuffer::new(1); + buffer.write('1'); + assert_eq!('1', buffer.read().unwrap()); + assert_eq!(Err(Error::EmptyBuffer), buffer.read()); + } + + #[test] + #[ignore] + fn write_and_read_back_multiple_items() { + let mut buffer = CircularBuffer::new(2); + buffer.write('1'); + buffer.write('2'); + assert_eq!('1', buffer.read().unwrap()); + assert_eq!('2', buffer.read().unwrap()); + assert_eq!(Err(Error::EmptyBuffer), buffer.read()); + } + + #[test] + #[ignore] + fn alternate_write_and_read() { + let mut buffer = CircularBuffer::new(2); + buffer.write('1'); + assert_eq!('1', buffer.read().unwrap()); + buffer.write('2'); + assert_eq!('2', buffer.read().unwrap()); + } + + #[test] + #[ignore] + fn clear_buffer() { + let mut buffer = CircularBuffer::new(3); + buffer.write('1'); + buffer.write('2'); + buffer.write('3'); + buffer.clear(); + assert_eq!(Err(Error::EmptyBuffer), buffer.read()); + buffer.write('1'); + buffer.write('2'); + assert_eq!('1', buffer.read().unwrap()); + buffer.write('3'); + assert_eq!('2', buffer.read().unwrap()); + } + + #[test] + #[ignore] + fn full_buffer_error() { + let mut buffer = CircularBuffer::new(2); + buffer.write('1'); + buffer.write('2'); + assert_eq!(Err(Error::FullBuffer), buffer.write('3')); + } + + #[test] + #[ignore] + fn overwrite_item_in_non_full_buffer() { + let mut buffer = CircularBuffer::new(2); + buffer.write('1'); + buffer.overwrite('2'); + assert_eq!('1', buffer.read().unwrap()); + assert_eq!('2', buffer.read().unwrap()); + assert_eq!(Err(Error::EmptyBuffer), buffer.read()); + } + + #[test] + #[ignore] + fn overwrite_item_in_full_buffer() { + let mut buffer = CircularBuffer::new(2); + buffer.write('1'); + buffer.write('2'); + buffer.overwrite('A'); + assert_eq!('2', buffer.read().unwrap()); + assert_eq!('A', buffer.read().unwrap()); + } +} diff --git a/config.json b/config.json index e6fdaaae7..7d87f7a3b 100644 --- a/config.json +++ b/config.json @@ -27,7 +27,8 @@ "custom-set", "tournament", "rectangles", - "forth" + "forth", + "circular-buffer" ], "deprecated": [