aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml1
-rw-r--r--src/lib.rs700
2 files changed, 377 insertions, 324 deletions
diff --git a/Cargo.toml b/Cargo.toml
index ef3c8cc..f151682 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,3 +17,4 @@ include = [
]
[dependencies]
+bytes = "1.8.0"
diff --git a/src/lib.rs b/src/lib.rs
index 1b0e13d..9371ee3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -47,369 +47,421 @@
//! assert_eq!(b.data(), &b"cd"[..]);
//! }
//!
-use std::{cmp, ptr};
-use std::io::{self,Write,Read};
+use std::io::{self, Read, Write};
use std::iter::repeat;
+use std::{cmp, ptr};
+
+extern crate bytes;
+use bytes::BufMut;
/// the Buffer contains the underlying memory and data positions
///
/// In all cases, `0 ≤ position ≤ end ≤ capacity` should be true
-#[derive(Debug,PartialEq,Clone)]
+#[derive(Debug, PartialEq, Clone)]
pub struct Buffer {
- /// the Vec containing the data
- memory: Vec<u8>,
- /// the current capacity of the Buffer
- capacity: usize,
- /// the current beginning of the available data
- position: usize,
- /// the current end of the available data
- /// and beginning of the available space
- end: usize
+ /// the Vec containing the data
+ memory: Vec<u8>,
+ /// the current capacity of the Buffer
+ capacity: usize,
+ /// the current beginning of the available data
+ position: usize,
+ /// the current end of the available data
+ /// and beginning of the available space
+ end: usize,
}
impl Buffer {
- /// allocates a new buffer of maximum size `capacity`
- pub fn with_capacity(capacity: usize) -> Buffer {
- let mut v = Vec::with_capacity(capacity);
- v.extend(repeat(0).take(capacity));
- Buffer {
- memory: v,
- capacity: capacity,
- position: 0,
- end: 0
+ /// allocates a new buffer of maximum size `capacity`
+ pub fn with_capacity(capacity: usize) -> Buffer {
+ let mut v = Vec::with_capacity(capacity);
+ v.extend(repeat(0).take(capacity));
+ Buffer {
+ memory: v,
+ capacity: capacity,
+ position: 0,
+ end: 0,
+ }
+ }
+
+ /// allocates a new buffer containing the slice `data`
+ ///
+ /// the buffer starts full, its available data size is exactly `data.len()`
+ pub fn from_slice(data: &[u8]) -> Buffer {
+ Buffer {
+ memory: Vec::from(data),
+ capacity: data.len(),
+ position: 0,
+ end: data.len(),
+ }
+ }
+
+ /// increases the size of the buffer
+ ///
+ /// this does nothing if the buffer is already large enough
+ pub fn grow(&mut self, new_size: usize) -> bool {
+ if self.capacity >= new_size {
+ return false;
+ }
+
+ self.memory.resize(new_size, 0);
+ self.capacity = new_size;
+ true
+ }
+
+ /// returns how much data can be read from the buffer
+ pub fn available_data(&self) -> usize {
+ self.end - self.position
+ }
+
+ /// returns how much free space is available to write to
+ pub fn available_space(&self) -> usize {
+ self.capacity - self.end
+ }
+
+ /// returns the underlying vector's size
+ pub fn capacity(&self) -> usize {
+ self.capacity
+ }
+
+ /// returns true if there is no more data to read
+ pub fn empty(&self) -> bool {
+ self.position == self.end
}
- }
-
- /// allocates a new buffer containing the slice `data`
- ///
- /// the buffer starts full, its available data size is exactly `data.len()`
- pub fn from_slice(data: &[u8]) -> Buffer {
- Buffer {
- memory: Vec::from(data),
- capacity: data.len(),
- position: 0,
- end: data.len()
+
+ /// advances the position tracker
+ ///
+ /// if the position gets past the buffer's half,
+ /// this will call `shift()` to move the remaining data
+ /// to the beginning of the buffer
+ pub fn consume(&mut self, count: usize) -> usize {
+ let cnt = cmp::min(count, self.available_data());
+ self.position += cnt;
+ if self.position > self.capacity / 2 {
+ //trace!("consume shift: pos {}, end {}", self.position, self.end);
+ self.shift();
+ }
+ cnt
}
- }
-
- /// increases the size of the buffer
- ///
- /// this does nothing if the buffer is already large enough
- pub fn grow(&mut self, new_size: usize) -> bool {
- if self.capacity >= new_size {
- return false;
+
+ /// advances the position tracker
+ ///
+ /// This method is similar to `consume()` but will not move data
+ /// to the beginning of the buffer
+ pub fn consume_noshift(&mut self, count: usize) -> usize {
+ let cnt = cmp::min(count, self.available_data());
+ self.position += cnt;
+ cnt
}
- self.memory.resize(new_size, 0);
- self.capacity = new_size;
- true
- }
-
- /// returns how much data can be read from the buffer
- pub fn available_data(&self) -> usize {
- self.end - self.position
- }
-
- /// returns how much free space is available to write to
- pub fn available_space(&self) -> usize {
- self.capacity - self.end
- }
-
- /// returns the underlying vector's size
- pub fn capacity(&self) -> usize {
- self.capacity
- }
-
- /// returns true if there is no more data to read
- pub fn empty(&self) -> bool {
- self.position == self.end
- }
-
- /// advances the position tracker
- ///
- /// if the position gets past the buffer's half,
- /// this will call `shift()` to move the remaining data
- /// to the beginning of the buffer
- pub fn consume(&mut self, count: usize) -> usize {
- let cnt = cmp::min(count, self.available_data());
- self.position += cnt;
- if self.position > self.capacity / 2 {
- //trace!("consume shift: pos {}, end {}", self.position, self.end);
- self.shift();
+ /// after having written data to the buffer, use this function
+ /// to indicate how many bytes were written
+ ///
+ /// if there is not enough available space, this function can call
+ /// `shift()` to move the remaining data to the beginning of the
+ /// buffer
+ pub fn fill(&mut self, count: usize) -> usize {
+ let cnt = cmp::min(count, self.available_space());
+ self.end += cnt;
+ if self.available_space() < self.available_data() + cnt {
+ //trace!("fill shift: pos {}, end {}", self.position, self.end);
+ self.shift();
+ }
+
+ cnt
}
- cnt
- }
-
- /// advances the position tracker
- ///
- /// This method is similar to `consume()` but will not move data
- /// to the beginning of the buffer
- pub fn consume_noshift(&mut self, count: usize) -> usize {
- let cnt = cmp::min(count, self.available_data());
- self.position += cnt;
- cnt
- }
-
- /// after having written data to the buffer, use this function
- /// to indicate how many bytes were written
- ///
- /// if there is not enough available space, this function can call
- /// `shift()` to move the remaining data to the beginning of the
- /// buffer
- pub fn fill(&mut self, count: usize) -> usize {
- let cnt = cmp::min(count, self.available_space());
- self.end += cnt;
- if self.available_space() < self.available_data() + cnt {
- //trace!("fill shift: pos {}, end {}", self.position, self.end);
- self.shift();
+
+ /// Get the current position
+ ///
+ /// # Examples
+ /// ```
+ /// use circular::Buffer;
+ /// use std::io::{Read,Write};
+ ///
+ /// let mut output = [0;5];
+ ///
+ /// let mut b = Buffer::with_capacity(10);
+ ///
+ /// let res = b.write(&b"abcdefgh"[..]);
+ ///
+ /// b.read(&mut output);
+ ///
+ /// // Position must be 5
+ /// assert_eq!(b.position(), 5);
+ /// assert_eq!(b.available_data(), 3);
+ /// ```
+ pub fn position(&self) -> usize {
+ self.position
}
- cnt
- }
-
- /// Get the current position
- ///
- /// # Examples
- /// ```
- /// use circular::Buffer;
- /// use std::io::{Read,Write};
- ///
- /// let mut output = [0;5];
- ///
- /// let mut b = Buffer::with_capacity(10);
- ///
- /// let res = b.write(&b"abcdefgh"[..]);
- ///
- /// b.read(&mut output);
- ///
- /// // Position must be 5
- /// assert_eq!(b.position(), 5);
- /// assert_eq!(b.available_data(), 3);
- /// ```
- pub fn position(&self) -> usize {
- self.position
- }
-
- /// moves the position and end trackers to the beginning
- /// this function does not modify the data
- pub fn reset(&mut self) {
- self.position = 0;
- self.end = 0;
- }
-
- /// returns a slice with all the available data
- pub fn data(&self) -> &[u8] {
- &self.memory[self.position..self.end]
- }
-
- /// returns a mutable slice with all the available space to
- /// write to
- pub fn space(&mut self) -> &mut[u8] {
- &mut self.memory[self.end..self.capacity]
- }
-
- /// moves the data at the beginning of the buffer
- ///
- /// if the position was more than 0, it is now 0
- pub fn shift(&mut self) {
- if self.position > 0 {
- unsafe {
- let length = self.end - self.position;
- ptr::copy( (&self.memory[self.position..self.end]).as_ptr(), (&mut self.memory[..length]).as_mut_ptr(), length);
+ /// moves the position and end trackers to the beginning
+ /// this function does not modify the data
+ pub fn reset(&mut self) {
self.position = 0;
- self.end = length;
- }
+ self.end = 0;
}
- }
- //FIXME: this should probably be rewritten, and tested extensively
- #[doc(hidden)]
- pub fn delete_slice(&mut self, start: usize, length: usize) -> Option<usize> {
- if start + length >= self.available_data() {
- return None
+ /// returns a slice with all the available data
+ pub fn data(&self) -> &[u8] {
+ &self.memory[self.position..self.end]
}
- unsafe {
- let begin = self.position + start;
- let next_end = self.end - length;
- ptr::copy(
- (&self.memory[begin+length..self.end]).as_ptr(),
- (&mut self.memory[begin..next_end]).as_mut_ptr(),
- self.end - (begin+length)
- );
- self.end = next_end;
+ /// returns a mutable slice with all the available space to
+ /// write to
+ pub fn space(&mut self) -> &mut [u8] {
+ &mut self.memory[self.end..self.capacity]
}
- Some(self.available_data())
- }
-
- //FIXME: this should probably be rewritten, and tested extensively
- #[doc(hidden)]
- pub fn replace_slice(&mut self, data: &[u8], start: usize, length: usize) -> Option<usize> {
- let data_len = data.len();
- if start + length > self.available_data() ||
- self.position + start + data_len > self.capacity {
- return None
+
+ /// moves the data at the beginning of the buffer
+ ///
+ /// if the position was more than 0, it is now 0
+ pub fn shift(&mut self) {
+ if self.position > 0 {
+ unsafe {
+ let length = self.end - self.position;
+ ptr::copy(
+ (&self.memory[self.position..self.end]).as_ptr(),
+ (&mut self.memory[..length]).as_mut_ptr(),
+ length,
+ );
+ self.position = 0;
+ self.end = length;
+ }
+ }
}
- unsafe {
- let begin = self.position + start;
- let slice_end = begin + data_len;
- // we reduced the data size
- if data_len < length {
- ptr::copy(data.as_ptr(), (&mut self.memory[begin..slice_end]).as_mut_ptr(), data_len);
-
- ptr::copy((&self.memory[start+length..self.end]).as_ptr(), (&mut self.memory[slice_end..]).as_mut_ptr(), self.end - (start + length));
- self.end = self.end - (length - data_len);
-
- // we put more data in the buffer
- } else {
- ptr::copy((&self.memory[start+length..self.end]).as_ptr(), (&mut self.memory[start+data_len..]).as_mut_ptr(), self.end - (start + length));
- ptr::copy(data.as_ptr(), (&mut self.memory[begin..slice_end]).as_mut_ptr(), data_len);
- self.end = self.end + data_len - length;
- }
+ //FIXME: this should probably be rewritten, and tested extensively
+ #[doc(hidden)]
+ pub fn delete_slice(&mut self, start: usize, length: usize) -> Option<usize> {
+ if start + length >= self.available_data() {
+ return None;
+ }
+
+ unsafe {
+ let begin = self.position + start;
+ let next_end = self.end - length;
+ ptr::copy(
+ (&self.memory[begin + length..self.end]).as_ptr(),
+ (&mut self.memory[begin..next_end]).as_mut_ptr(),
+ self.end - (begin + length),
+ );
+ self.end = next_end;
+ }
+ Some(self.available_data())
}
- Some(self.available_data())
- }
-
- //FIXME: this should probably be rewritten, and tested extensively
- #[doc(hidden)]
- pub fn insert_slice(&mut self, data: &[u8], start: usize) -> Option<usize> {
- let data_len = data.len();
- if start > self.available_data() ||
- self.position + self.end + data_len > self.capacity {
- return None
+
+ //FIXME: this should probably be rewritten, and tested extensively
+ #[doc(hidden)]
+ pub fn replace_slice(&mut self, data: &[u8], start: usize, length: usize) -> Option<usize> {
+ let data_len = data.len();
+ if start + length > self.available_data()
+ || self.position + start + data_len > self.capacity
+ {
+ return None;
+ }
+
+ unsafe {
+ let begin = self.position + start;
+ let slice_end = begin + data_len;
+ // we reduced the data size
+ if data_len < length {
+ ptr::copy(
+ data.as_ptr(),
+ (&mut self.memory[begin..slice_end]).as_mut_ptr(),
+ data_len,
+ );
+
+ ptr::copy(
+ (&self.memory[start + length..self.end]).as_ptr(),
+ (&mut self.memory[slice_end..]).as_mut_ptr(),
+ self.end - (start + length),
+ );
+ self.end = self.end - (length - data_len);
+
+ // we put more data in the buffer
+ } else {
+ ptr::copy(
+ (&self.memory[start + length..self.end]).as_ptr(),
+ (&mut self.memory[start + data_len..]).as_mut_ptr(),
+ self.end - (start + length),
+ );
+ ptr::copy(
+ data.as_ptr(),
+ (&mut self.memory[begin..slice_end]).as_mut_ptr(),
+ data_len,
+ );
+ self.end = self.end + data_len - length;
+ }
+ }
+ Some(self.available_data())
}
- unsafe {
- let begin = self.position + start;
- let slice_end = begin + data_len;
- ptr::copy((&self.memory[start..self.end]).as_ptr(), (&mut self.memory[start+data_len..]).as_mut_ptr(), self.end - start);
- ptr::copy(data.as_ptr(), (&mut self.memory[begin..slice_end]).as_mut_ptr(), data_len);
- self.end = self.end + data_len;
+ //FIXME: this should probably be rewritten, and tested extensively
+ #[doc(hidden)]
+ pub fn insert_slice(&mut self, data: &[u8], start: usize) -> Option<usize> {
+ let data_len = data.len();
+ if start > self.available_data() || self.position + self.end + data_len > self.capacity {
+ return None;
+ }
+
+ unsafe {
+ let begin = self.position + start;
+ let slice_end = begin + data_len;
+ ptr::copy(
+ (&self.memory[start..self.end]).as_ptr(),
+ (&mut self.memory[start + data_len..]).as_mut_ptr(),
+ self.end - start,
+ );
+ ptr::copy(
+ data.as_ptr(),
+ (&mut self.memory[begin..slice_end]).as_mut_ptr(),
+ data_len,
+ );
+ self.end = self.end + data_len;
+ }
+ Some(self.available_data())
}
- Some(self.available_data())
- }
}
impl Write for Buffer {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- match self.space().write(buf) {
- Ok(size) => { self.fill(size); Ok(size) },
- err => err
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ match self.space().write(buf) {
+ Ok(size) => {
+ self.fill(size);
+ Ok(size)
+ }
+ err => err,
+ }
}
- }
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
}
impl Read for Buffer {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- let len = cmp::min(self.available_data(), buf.len());
- unsafe {
- ptr::copy((&self.memory[self.position..self.position+len]).as_ptr(), buf.as_mut_ptr(), len);
- self.position += len;
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ let len = cmp::min(self.available_data(), buf.len());
+ unsafe {
+ ptr::copy(
+ (&self.memory[self.position..self.position + len]).as_ptr(),
+ buf.as_mut_ptr(),
+ len,
+ );
+ self.position += len;
+ }
+ Ok(len)
+ }
+}
+
+unsafe impl BufMut for Buffer {
+ fn remaining_mut(&self) -> usize {
+ self.available_space()
+ }
+
+ unsafe fn advance_mut(&mut self, cnt: usize) {
+ self.fill(cnt);
+ }
+
+ fn chunk_mut(&mut self) -> &mut bytes::buf::UninitSlice {
+ self.space().into()
}
- Ok(len)
- }
}
#[cfg(test)]
mod tests {
- use super::*;
- use std::io::Write;
-
- #[test]
- fn fill_and_consume() {
- let mut b = Buffer::with_capacity(10);
- assert_eq!(b.available_data(), 0);
- assert_eq!(b.available_space(), 10);
- let res = b.write(&b"abcd"[..]);
- assert_eq!(res.ok(), Some(4));
- assert_eq!(b.available_data(), 4);
- assert_eq!(b.available_space(), 6);
-
- assert_eq!(b.data(), &b"abcd"[..]);
-
- b.consume(2);
- assert_eq!(b.available_data(), 2);
- assert_eq!(b.available_space(), 6);
- assert_eq!(b.data(), &b"cd"[..]);
-
- b.shift();
- assert_eq!(b.available_data(), 2);
- assert_eq!(b.available_space(), 8);
- assert_eq!(b.data(), &b"cd"[..]);
-
- assert_eq!(b.write(&b"efghijklmnop"[..]).ok(), Some(8));
- assert_eq!(b.available_data(), 10);
- assert_eq!(b.available_space(), 0);
- assert_eq!(b.data(), &b"cdefghijkl"[..]);
- b.shift();
- assert_eq!(b.available_data(), 10);
- assert_eq!(b.available_space(), 0);
- assert_eq!(b.data(), &b"cdefghijkl"[..]);
- }
-
- #[test]
- fn delete() {
- let mut b = Buffer::with_capacity(10);
- let _ = b.write(&b"abcdefgh"[..]);
- assert_eq!(b.available_data(), 8);
- assert_eq!(b.available_space(), 2);
-
- assert_eq!(b.delete_slice(2, 3), Some(5));
- assert_eq!(b.available_data(), 5);
- assert_eq!(b.available_space(), 5);
- assert_eq!(b.data(), &b"abfgh"[..]);
-
- assert_eq!(b.delete_slice(5, 2), None);
- assert_eq!(b.delete_slice(4, 2), None);
- }
-
- #[test]
- fn replace() {
- let mut b = Buffer::with_capacity(10);
- let _ = b.write(&b"abcdefgh"[..]);
- assert_eq!(b.available_data(), 8);
- assert_eq!(b.available_space(), 2);
-
- assert_eq!(b.replace_slice(&b"ABC"[..], 2, 3), Some(8));
- assert_eq!(b.available_data(), 8);
- assert_eq!(b.available_space(), 2);
- assert_eq!(b.data(), &b"abABCfgh"[..]);
-
- assert_eq!(b.replace_slice(&b"XYZ"[..], 8, 3), None);
- assert_eq!(b.replace_slice(&b"XYZ"[..], 6, 3), None);
-
- assert_eq!(b.replace_slice(&b"XYZ"[..], 2, 4), Some(7));
- assert_eq!(b.available_data(), 7);
- assert_eq!(b.available_space(), 3);
- assert_eq!(b.data(), &b"abXYZgh"[..]);
-
- assert_eq!(b.replace_slice(&b"123"[..], 2, 2), Some(8));
- assert_eq!(b.available_data(), 8);
- assert_eq!(b.available_space(), 2);
- assert_eq!(b.data(), &b"ab123Zgh"[..]);
- }
-
- use std::str;
- #[test]
- fn set_position() {
- let mut output = [0;5];
- let mut b = Buffer::with_capacity(10);
- let _ = b.write(&b"abcdefgh"[..]);
- let _ = b.read(&mut output);
- assert_eq!(b.available_data(), 3);
- println!("{:?}", b.position());
- }
-
- #[test]
- fn consume_without_shift() {
- let mut b = Buffer::with_capacity(10);
- let _ = b.write(&b"abcdefgh"[..]);
- b.consume_noshift(6);
- assert_eq!(b.position(), 6);
- }
+ use super::*;
+ use std::io::Write;
+
+ #[test]
+ fn fill_and_consume() {
+ let mut b = Buffer::with_capacity(10);
+ assert_eq!(b.available_data(), 0);
+ assert_eq!(b.available_space(), 10);
+ let res = b.write(&b"abcd"[..]);
+ assert_eq!(res.ok(), Some(4));
+ assert_eq!(b.available_data(), 4);
+ assert_eq!(b.available_space(), 6);
+
+ assert_eq!(b.data(), &b"abcd"[..]);
+
+ b.consume(2);
+ assert_eq!(b.available_data(), 2);
+ assert_eq!(b.available_space(), 6);
+ assert_eq!(b.data(), &b"cd"[..]);
+
+ b.shift();
+ assert_eq!(b.available_data(), 2);
+ assert_eq!(b.available_space(), 8);
+ assert_eq!(b.data(), &b"cd"[..]);
+
+ assert_eq!(b.write(&b"efghijklmnop"[..]).ok(), Some(8));
+ assert_eq!(b.available_data(), 10);
+ assert_eq!(b.available_space(), 0);
+ assert_eq!(b.data(), &b"cdefghijkl"[..]);
+ b.shift();
+ assert_eq!(b.available_data(), 10);
+ assert_eq!(b.available_space(), 0);
+ assert_eq!(b.data(), &b"cdefghijkl"[..]);
+ }
+
+ #[test]
+ fn delete() {
+ let mut b = Buffer::with_capacity(10);
+ let _ = b.write(&b"abcdefgh"[..]);
+ assert_eq!(b.available_data(), 8);
+ assert_eq!(b.available_space(), 2);
+
+ assert_eq!(b.delete_slice(2, 3), Some(5));
+ assert_eq!(b.available_data(), 5);
+ assert_eq!(b.available_space(), 5);
+ assert_eq!(b.data(), &b"abfgh"[..]);
+
+ assert_eq!(b.delete_slice(5, 2), None);
+ assert_eq!(b.delete_slice(4, 2), None);
+ }
+
+ #[test]
+ fn replace() {
+ let mut b = Buffer::with_capacity(10);
+ let _ = b.write(&b"abcdefgh"[..]);
+ assert_eq!(b.available_data(), 8);
+ assert_eq!(b.available_space(), 2);
+
+ assert_eq!(b.replace_slice(&b"ABC"[..], 2, 3), Some(8));
+ assert_eq!(b.available_data(), 8);
+ assert_eq!(b.available_space(), 2);
+ assert_eq!(b.data(), &b"abABCfgh"[..]);
+
+ assert_eq!(b.replace_slice(&b"XYZ"[..], 8, 3), None);
+ assert_eq!(b.replace_slice(&b"XYZ"[..], 6, 3), None);
+
+ assert_eq!(b.replace_slice(&b"XYZ"[..], 2, 4), Some(7));
+ assert_eq!(b.available_data(), 7);
+ assert_eq!(b.available_space(), 3);
+ assert_eq!(b.data(), &b"abXYZgh"[..]);
+
+ assert_eq!(b.replace_slice(&b"123"[..], 2, 2), Some(8));
+ assert_eq!(b.available_data(), 8);
+ assert_eq!(b.available_space(), 2);
+ assert_eq!(b.data(), &b"ab123Zgh"[..]);
+ }
+
+ use std::str;
+ #[test]
+ fn set_position() {
+ let mut output = [0; 5];
+ let mut b = Buffer::with_capacity(10);
+ let _ = b.write(&b"abcdefgh"[..]);
+ let _ = b.read(&mut output);
+ assert_eq!(b.available_data(), 3);
+ println!("{:?}", b.position());
+ }
+
+ #[test]
+ fn consume_without_shift() {
+ let mut b = Buffer::with_capacity(10);
+ let _ = b.write(&b"abcdefgh"[..]);
+ b.consume_noshift(6);
+ assert_eq!(b.position(), 6);
+ }
}