circular/
lib.rs

1//! Circular, a stream abstraction designed for use with nom
2//!
3//! Circular provides a `Buffer` type that wraps a `Vec<u8>` with a position
4//! and end. Compared to a stream abstraction that would use `std::io::Read`,
5//! it separates the reading and consuming phases. `Read` is designed to write
6//! the data in a mutable slice and consume it from the stream as it does that.
7//!
8//! When used in streaming mode, nom will try to parse a slice, then tell you
9//! how much it consumed. So you don't know how much data was actually used
10//! until the parser returns. `Circular::Buffer` exposes a `data()` method
11//! that gives an immutable slice of all the currently readable data,
12//! and a `consume()` method to advance the position in the stream.
13//! The `space()` and `fill()` methods are the write counterparts to those methods.
14//!
15//! ```
16//! extern crate circular;
17//!
18//! use circular::Buffer;
19//! use std::io::Write;
20//!
21//! fn main() {
22//!
23//!   // allocate a new Buffer
24//!   let mut b = Buffer::with_capacity(10);
25//!   assert_eq!(b.available_data(), 0);
26//!   assert_eq!(b.available_space(), 10);
27//!
28//!   let res = b.write(&b"abcd"[..]);
29//!   assert_eq!(res.ok(), Some(4));
30//!   assert_eq!(b.available_data(), 4);
31//!   assert_eq!(b.available_space(), 6);
32//!
33//!   //the 4 bytes we wrote are immediately available and usable for parsing
34//!   assert_eq!(b.data(), &b"abcd"[..]);
35//!
36//!   // this will advance the position from 0 to 2. it does not modify the underlying Vec
37//!   b.consume(2);
38//!   assert_eq!(b.available_data(), 2);
39//!   assert_eq!(b.available_space(), 6);
40//!   assert_eq!(b.data(), &b"cd"[..]);
41//!
42//!   // shift moves the available data at the beginning of the buffer.
43//!   // the position is now 0
44//!   b.shift();
45//!   assert_eq!(b.available_data(), 2);
46//!   assert_eq!(b.available_space(), 8);
47//!   assert_eq!(b.data(), &b"cd"[..]);
48//! }
49//!
50use std::{cmp, ptr};
51use std::io::{self,Write,Read};
52use std::iter::repeat;
53
54/// the Buffer contains the underlying memory and data positions
55///
56/// In all cases, `0 ≤ position ≤ end ≤ capacity` should be true
57#[derive(Debug,PartialEq,Clone)]
58pub struct Buffer {
59  /// the Vec containing the data
60  memory:   Vec<u8>,
61  /// the current capacity of the Buffer
62  capacity: usize,
63  /// the current beginning of the available data
64  position: usize,
65  /// the current end of the available data
66  /// and beginning of the available space
67  end:      usize
68}
69
70impl Buffer {
71  /// allocates a new buffer of maximum size `capacity`
72  pub fn with_capacity(capacity: usize) -> Buffer {
73    let mut v = Vec::with_capacity(capacity);
74    v.extend(repeat(0).take(capacity));
75    Buffer {
76      memory:   v,
77      capacity: capacity,
78      position: 0,
79      end:      0
80    }
81  }
82
83  /// allocates a new buffer containing the slice `data`
84  ///
85  /// the buffer starts full, its available data size is exactly `data.len()`
86  pub fn from_slice(data: &[u8]) -> Buffer {
87    Buffer {
88      memory:   Vec::from(data),
89      capacity: data.len(),
90      position: 0,
91      end:      data.len()
92    }
93  }
94
95  /// increases the size of the buffer
96  ///
97  /// this does nothing if the buffer is already large enough
98  pub fn grow(&mut self, new_size: usize) -> bool {
99    if self.capacity >= new_size {
100      return false;
101    }
102
103    self.memory.resize(new_size, 0);
104    self.capacity = new_size;
105    true
106  }
107
108  /// returns how much data can be read from the buffer
109  pub fn available_data(&self) -> usize {
110    self.end - self.position
111  }
112
113  /// returns how much free space is available to write to
114  pub fn available_space(&self) -> usize {
115    self.capacity - self.end
116  }
117
118  /// returns the underlying vector's size
119  pub fn capacity(&self) -> usize {
120    self.capacity
121  }
122
123  /// returns true if there is no more data to read
124  pub fn empty(&self) -> bool {
125    self.position == self.end
126  }
127
128  /// advances the position tracker
129  ///
130  /// if the position gets past the buffer's half,
131  /// this will call `shift()` to move the remaining data
132  /// to the beginning of the buffer
133  pub fn consume(&mut self, count: usize) -> usize {
134    let cnt        = cmp::min(count, self.available_data());
135    self.position += cnt;
136    if self.position > self.capacity / 2 {
137      //trace!("consume shift: pos {}, end {}", self.position, self.end);
138      self.shift();
139    }
140    cnt
141  }
142
143  /// advances the position tracker
144  ///
145  /// This method is similar to `consume()` but will not move data
146  /// to the beginning of the buffer
147  pub fn consume_noshift(&mut self, count: usize) -> usize {
148    let cnt        = cmp::min(count, self.available_data());
149    self.position += cnt;
150    cnt
151  }
152
153  /// after having written data to the buffer, use this function
154  /// to indicate how many bytes were written
155  ///
156  /// if there is not enough available space, this function can call
157  /// `shift()` to move the remaining data to the beginning of the
158  /// buffer
159  pub fn fill(&mut self, count: usize) -> usize {
160    let cnt   = cmp::min(count, self.available_space());
161    self.end += cnt;
162    if self.available_space() < self.available_data() + cnt {
163      //trace!("fill shift: pos {}, end {}", self.position, self.end);
164      self.shift();
165    }
166
167    cnt
168  }
169
170  /// Get the current position
171  ///
172  /// # Examples
173  /// ```
174  /// use circular::Buffer;
175  /// use std::io::{Read,Write};
176  ///
177  /// let mut output = [0;5];
178  ///
179  /// let mut b = Buffer::with_capacity(10);
180  ///
181  /// let res = b.write(&b"abcdefgh"[..]);
182  ///
183  /// b.read(&mut output);
184  ///
185  /// // Position must be 5
186  /// assert_eq!(b.position(), 5);
187  /// assert_eq!(b.available_data(), 3);
188  /// ```
189  pub fn position(&self) -> usize {
190      self.position
191  }
192
193  /// moves the position and end trackers to the beginning
194  /// this function does not modify the data
195  pub fn reset(&mut self) {
196    self.position = 0;
197    self.end      = 0;
198  }
199
200  /// returns a slice with all the available data
201  pub fn data(&self) -> &[u8] {
202    &self.memory[self.position..self.end]
203  }
204
205  /// returns a mutable slice with all the available space to
206  /// write to
207  pub fn space(&mut self) -> &mut[u8] {
208    &mut self.memory[self.end..self.capacity]
209  }
210
211  /// moves the data at the beginning of the buffer
212  ///
213  /// if the position was more than 0, it is now 0
214  pub fn shift(&mut self) {
215    if self.position > 0 {
216      unsafe {
217        let length = self.end - self.position;
218        ptr::copy( (&self.memory[self.position..self.end]).as_ptr(), (&mut self.memory[..length]).as_mut_ptr(), length);
219        self.position = 0;
220        self.end      = length;
221      }
222    }
223  }
224
225  //FIXME: this should probably be rewritten, and tested extensively
226  #[doc(hidden)]
227  pub fn delete_slice(&mut self, start: usize, length: usize) -> Option<usize> {
228    if start + length >= self.available_data() {
229      return None
230    }
231
232    unsafe {
233      let begin    = self.position + start;
234      let next_end = self.end - length;
235      ptr::copy(
236        (&self.memory[begin+length..self.end]).as_ptr(),
237        (&mut self.memory[begin..next_end]).as_mut_ptr(),
238        self.end - (begin+length)
239      );
240      self.end = next_end;
241    }
242    Some(self.available_data())
243  }
244
245  //FIXME: this should probably be rewritten, and tested extensively
246  #[doc(hidden)]
247  pub fn replace_slice(&mut self, data: &[u8], start: usize, length: usize) -> Option<usize> {
248    let data_len = data.len();
249    if start + length > self.available_data() ||
250      self.position + start + data_len > self.capacity {
251      return None
252    }
253
254    unsafe {
255      let begin     = self.position + start;
256      let slice_end = begin + data_len;
257      // we reduced the data size
258      if data_len < length {
259        ptr::copy(data.as_ptr(), (&mut self.memory[begin..slice_end]).as_mut_ptr(), data_len);
260
261        ptr::copy((&self.memory[start+length..self.end]).as_ptr(), (&mut self.memory[slice_end..]).as_mut_ptr(), self.end - (start + length));
262        self.end = self.end - (length - data_len);
263
264      // we put more data in the buffer
265      } else {
266        ptr::copy((&self.memory[start+length..self.end]).as_ptr(), (&mut self.memory[start+data_len..]).as_mut_ptr(), self.end - (start + length));
267        ptr::copy(data.as_ptr(), (&mut self.memory[begin..slice_end]).as_mut_ptr(), data_len);
268        self.end = self.end + data_len - length;
269      }
270    }
271    Some(self.available_data())
272  }
273
274  //FIXME: this should probably be rewritten, and tested extensively
275  #[doc(hidden)]
276  pub fn insert_slice(&mut self, data: &[u8], start: usize) -> Option<usize> {
277    let data_len = data.len();
278    if start > self.available_data() ||
279      self.position + self.end + data_len > self.capacity {
280      return None
281    }
282
283    unsafe {
284      let begin     = self.position + start;
285      let slice_end = begin + data_len;
286      ptr::copy((&self.memory[start..self.end]).as_ptr(), (&mut self.memory[start+data_len..]).as_mut_ptr(), self.end - start);
287      ptr::copy(data.as_ptr(), (&mut self.memory[begin..slice_end]).as_mut_ptr(), data_len);
288      self.end = self.end + data_len;
289    }
290    Some(self.available_data())
291  }
292}
293
294impl Write for Buffer {
295  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
296    match self.space().write(buf) {
297      Ok(size) => { self.fill(size); Ok(size) },
298      err      => err
299    }
300  }
301
302  fn flush(&mut self) -> io::Result<()> {
303    Ok(())
304  }
305}
306
307impl Read for Buffer {
308  fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
309    let len = cmp::min(self.available_data(), buf.len());
310    unsafe {
311      ptr::copy((&self.memory[self.position..self.position+len]).as_ptr(), buf.as_mut_ptr(), len);
312      self.position += len;
313    }
314    Ok(len)
315  }
316}
317
318#[cfg(test)]
319mod tests {
320  use super::*;
321  use std::io::Write;
322
323  #[test]
324  fn fill_and_consume() {
325    let mut b = Buffer::with_capacity(10);
326    assert_eq!(b.available_data(), 0);
327    assert_eq!(b.available_space(), 10);
328    let res = b.write(&b"abcd"[..]);
329    assert_eq!(res.ok(), Some(4));
330    assert_eq!(b.available_data(), 4);
331    assert_eq!(b.available_space(), 6);
332
333    assert_eq!(b.data(), &b"abcd"[..]);
334
335    b.consume(2);
336    assert_eq!(b.available_data(), 2);
337    assert_eq!(b.available_space(), 6);
338    assert_eq!(b.data(), &b"cd"[..]);
339
340    b.shift();
341    assert_eq!(b.available_data(), 2);
342    assert_eq!(b.available_space(), 8);
343    assert_eq!(b.data(), &b"cd"[..]);
344
345    assert_eq!(b.write(&b"efghijklmnop"[..]).ok(), Some(8));
346    assert_eq!(b.available_data(), 10);
347    assert_eq!(b.available_space(), 0);
348    assert_eq!(b.data(), &b"cdefghijkl"[..]);
349    b.shift();
350    assert_eq!(b.available_data(), 10);
351    assert_eq!(b.available_space(), 0);
352    assert_eq!(b.data(), &b"cdefghijkl"[..]);
353  }
354
355  #[test]
356  fn delete() {
357    let mut b = Buffer::with_capacity(10);
358    let _ = b.write(&b"abcdefgh"[..]);
359    assert_eq!(b.available_data(), 8);
360    assert_eq!(b.available_space(), 2);
361
362    assert_eq!(b.delete_slice(2, 3), Some(5));
363    assert_eq!(b.available_data(), 5);
364    assert_eq!(b.available_space(), 5);
365    assert_eq!(b.data(), &b"abfgh"[..]);
366
367    assert_eq!(b.delete_slice(5, 2), None);
368    assert_eq!(b.delete_slice(4, 2), None);
369  }
370
371  #[test]
372  fn replace() {
373    let mut b = Buffer::with_capacity(10);
374    let _ = b.write(&b"abcdefgh"[..]);
375    assert_eq!(b.available_data(), 8);
376    assert_eq!(b.available_space(), 2);
377
378    assert_eq!(b.replace_slice(&b"ABC"[..], 2, 3), Some(8));
379    assert_eq!(b.available_data(), 8);
380    assert_eq!(b.available_space(), 2);
381    assert_eq!(b.data(), &b"abABCfgh"[..]);
382
383    assert_eq!(b.replace_slice(&b"XYZ"[..], 8, 3), None);
384    assert_eq!(b.replace_slice(&b"XYZ"[..], 6, 3), None);
385
386    assert_eq!(b.replace_slice(&b"XYZ"[..], 2, 4), Some(7));
387    assert_eq!(b.available_data(), 7);
388    assert_eq!(b.available_space(), 3);
389    assert_eq!(b.data(), &b"abXYZgh"[..]);
390
391    assert_eq!(b.replace_slice(&b"123"[..], 2, 2), Some(8));
392    assert_eq!(b.available_data(), 8);
393    assert_eq!(b.available_space(), 2);
394    assert_eq!(b.data(), &b"ab123Zgh"[..]);
395  }
396
397  use std::str;
398  #[test]
399  fn set_position() {
400    let mut output = [0;5];
401    let mut b = Buffer::with_capacity(10);
402    let _ = b.write(&b"abcdefgh"[..]);
403    let _ = b.read(&mut output);
404    assert_eq!(b.available_data(), 3);
405    println!("{:?}", b.position());
406  }
407
408  #[test]
409  fn consume_without_shift() {
410    let mut b = Buffer::with_capacity(10);
411    let _ = b.write(&b"abcdefgh"[..]);
412    b.consume_noshift(6);
413    assert_eq!(b.position(), 6);
414  }
415}