aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Geoffroy Couprie <geo.couprie@gmail.com>2017-05-08 12:04:14 +0200
committerLibravatar Geoffroy Couprie <geo.couprie@gmail.com>2017-05-08 12:05:34 +0200
commit1c411e1cc1b2820355f2c5a4d36fc8d1e754ccd0 (patch)
treea327bd037839d30939a3331b12fd089c9b97bf48
parent88b478e85fe2156e8506c223b5b8c3a35d866ee1 (diff)
downloadcircular-1c411e1cc1b2820355f2c5a4d36fc8d1e754ccd0.tar.gz
circular-1c411e1cc1b2820355f2c5a4d36fc8d1e754ccd0.tar.bz2
circular-1c411e1cc1b2820355f2c5a4d36fc8d1e754ccd0.zip
add documentation
-rw-r--r--src/lib.rs101
1 files changed, 97 insertions, 4 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 8025be5..8e13fae 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,16 +1,74 @@
+//! Circular, a stream abstraction designed for use with nom
+//!
+//! Circular provides a `Buffer` type that wraps a `Vec<u8>` with a position
+//! and end. Compared to a stream abstraction that would use `std::io::Read`,
+//! it separates the reading and consuming phases. `Read` is designed to write
+//! the data in a mutable slice and consume it from the stream as it does that.
+//!
+//! When used in streaming mode, nom will try to parse a slice, then tell you
+//! how much it consumed. So you don't know how much data was actually used
+//! until the parser returns. `Circular::Buffer` exposes a `data()` method
+//! that gives an immutable slice of all the currently readable data,
+//! and a `consume()` method to advance the position in the stream.
+//! The `space()` and `fill()` methods are the write counterparts to those methods.
+//!
+//! ```
+//! extern crate circular;
+//!
+//! use circular::Buffer;
+//! use std::io::Write;
+//!
+//! fn main() {
+//!
+//! // allocate a new Buffer
+//! 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);
+//!
+//! //the 4 bytes we wrote are immediately available and usable for parsing
+//! assert_eq!(b.data(), &b"abcd"[..]);
+//!
+//! // this will advance the position from 0 to 2. it does not modify the underlying Vec
+//! b.consume(2);
+//! assert_eq!(b.available_data(), 2);
+//! assert_eq!(b.available_space(), 6);
+//! assert_eq!(b.data(), &b"cd"[..]);
+//!
+//! // shift moves the available data at the beginning of the buffer.
+//! // the position is now 0
+//! b.shift();
+//! assert_eq!(b.available_data(), 2);
+//! assert_eq!(b.available_space(), 8);
+//! assert_eq!(b.data(), &b"cd"[..]);
+//! }
+//!
use std::{cmp, ptr};
use std::io::{self,Write,Read};
use std::iter::repeat;
+/// the Buffer contains the underlying memory and data positions
+///
+/// In all cases, `0 ≤ position ≤ end ≤ capacity` should be true
#[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
}
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));
@@ -22,15 +80,21 @@ impl Buffer {
}
}
- pub fn from_slice(sl: &[u8]) -> Buffer {
+ /// 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(sl),
- capacity: sl.len(),
+ memory: Vec::from(data),
+ capacity: data.len(),
position: 0,
- end: sl.len()
+ 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;
@@ -41,22 +105,31 @@ impl Buffer {
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;
@@ -67,6 +140,12 @@ impl Buffer {
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;
@@ -101,19 +180,27 @@ impl Buffer {
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 {
@@ -125,6 +212,8 @@ impl Buffer {
}
}
+ //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
@@ -143,6 +232,8 @@ impl Buffer {
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() ||
@@ -170,6 +261,8 @@ impl Buffer {
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() ||