//! 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)] pubstruct 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` pubfn with_capacity(capacity: usize) -> Buffer { letmut 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()` pubfn 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 pubfn grow(&mutself, new_size: usize) -> bool { ifself.capacity >= new_size { returnfalse;
}
/// returns true if there is no more data to read pubfn 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 pubfn consume(&mutself, count: usize) -> usize { let cnt = cmp::min(count, self.available_data()); self.position += cnt; ifself.position > self.capacity / 2 { //trace!("consume shift: pos {}, end {}", self.position, self.end); self.shift();
}
cnt
}
/// advances the position tracker /// /// This method is similar to `consume()` but will not move data /// to the beginning of the buffer pubfn consume_noshift(&mutself, 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 pubfn fill(&mutself, count: usize) -> usize { let cnt = cmp::min(count, self.available_space()); self.end += cnt; ifself.available_space() < self.available_data() + cnt { //trace!("fill shift: pos {}, end {}", self.position, self.end); self.shift();
}
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); /// ``` pubfn position(&self) -> usize { self.position
}
/// moves the position and end trackers to the beginning /// this function does not modify the data pubfn reset(&mutself) { self.position = 0; self.end = 0;
}
/// returns a slice with all the available data pubfn data(&self) -> &[u8] {
&self.memory[self.position..self.end]
}
/// returns a mutable slice with all the available space to /// write to pubfn space(&mutself) -> &mut[u8] {
&mutself.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 pubfn shift(&mutself) { ifself.position > 0 { unsafe { let length = self.end - self.position;
ptr::copy( (&self.memory[self.position..self.end]).as_ptr(), (&mutself.memory[..length]).as_mut_ptr(), length); self.position = 0; self.end = length;
}
}
}
//FIXME: this should probably be rewritten, and tested extensively #[doc(hidden)] pubfn delete_slice(&mutself, 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(),
(&mutself.memory[begin..next_end]).as_mut_ptr(), self.end - (begin+length)
); self.end = next_end;
}
Some(self.available_data())
}
//FIXME: this should probably be rewritten, and tested extensively #[doc(hidden)] pubfn replace_slice(&mutself, 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(), (&mutself.memory[begin..slice_end]).as_mut_ptr(), data_len);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.