1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
use collections::slice::SlicePrelude;
use core::mem;
use core::str::StrPrelude;
use iobuf::Iobuf;
use impls::{RWIobuf, ROIobuf};
/// A ring buffer implemented with `Iobuf`s.
pub struct IORingbuf {
/// The contents of the window is space for input to be put into. Therefore,
/// initially full.
i_buf: RWIobuf<'static>,
/// The contents of the window are things needing to be output. Therefore,
/// initally empty.
o_buf: RWIobuf<'static>,
}
impl IORingbuf {
/// Creates a new ring buffer, with room for `cap` bytes.
pub fn new(cap: uint) -> IORingbuf {
let left_size = cap / 2;
let mut ret =
IORingbuf {
i_buf: RWIobuf::new(left_size),
o_buf: RWIobuf::new(cap - left_size),
};
ret.o_buf.flip_lo(); // start with an empty o_buf.
ret
}
/// Returns an Iobuf, whose window may be filled with new data. This acts as
/// the "push" operations for the ringbuf.
///
/// It is easy to get garbage data if using a clone of the returned Iobuf.
/// This is not memory-unsafe, but should be avoided.
#[inline(always)]
pub fn push_buf(&mut self) -> &mut RWIobuf<'static> {
&mut self.i_buf
}
/// Returns an Iobuf, whose window may be have data `consume`d out of it. This
/// acts as the "pop" operation for the ringbuf.
///
/// After emptying out the returned Iobuf, it is not necessarily true that
/// the ringbuf is empty. To truly empty out the ringbuf, you must pop
/// Iobufs in a loop until `is_empty` returns `true`.
///
/// It is easy to get garbage data if using a clone of the returned Iobuf.
/// This is not memory-unsafe, but should be avoided.
#[inline]
pub fn pop_buf(&mut self) -> &mut ROIobuf<'static> {
if self.o_buf.is_empty() {
self.i_buf.flip_lo();
self.o_buf.reset();
mem::swap(&mut self.i_buf, &mut self.o_buf);
}
// Clients should only be doing read-only operations into the iobuf, so
// return a ROIobuf.
unsafe { mem::transmute(&mut self.o_buf) }
}
/// `true` if there is no data to pop in the Iobuf.
#[inline]
pub fn is_empty(&self) -> bool {
self.i_buf.cap() == self.i_buf.len() && self.o_buf.is_empty()
}
/// `true` if there is no room for new data in the Iobuf.
#[inline(always)]
pub fn is_full(&self) -> bool {
self.i_buf.is_empty()
}
}