incpa_byte/bufmgr.rs
1use incpa::state::{Outcome, ParserState};
2
3/// Manage the buffering necessary for driving [ByteParser](crate::ByteParser) in an i/o agnostic manner
4#[derive(Debug, Default)]
5pub struct BufferManager {
6 buffer: Vec<u8>,
7 rstart: usize,
8}
9
10impl BufferManager {
11 /// Construct a [BufferManager] with `cap` byte size initially.
12 pub fn with_initial_size(cap: usize) -> Self {
13 BufferManager {
14 buffer: vec![0; cap],
15 rstart: 0,
16 }
17 }
18
19 /// Get a writable byte slice for inserting new data
20 pub fn get_write_slice(&mut self) -> &mut [u8] {
21 if self.rstart == self.buffer.len() {
22 // The parser is using the entire buffer for storage, so let's grow for new input:
23 self.buffer
24 .resize(std::cmp::max(self.buffer.len() * 2, 1 << 12), 0);
25 }
26 &mut self.buffer[self.rstart..]
27 }
28
29 /// Process newly inserted data
30 ///
31 /// # Diagram
32 ///
33 /// ```text
34 /// rstart-+ +-end
35 /// | _readcnt_ |
36 /// v/ \v
37 /// +-----------+-----------+--------+
38 /// buffer | prev-kept | new | uninit |
39 /// +-----------+----+------+--------+
40 /// rslice | consumed | kept |
41 /// +------+---------+------+--------+
42 /// rotate | kept | uninit |
43 /// +------+-------------------------+
44 /// ```
45 pub fn process_write<P, E>(
46 &mut self,
47 parser: P,
48 readcnt: usize,
49 ) -> Result<Outcome<P, P::Output>, E>
50 where
51 P: ParserState<[u8]>,
52 E: From<P::Error>,
53 {
54 use Outcome::Parsed;
55 use incpa::state::Update;
56
57 let end = self.rstart + readcnt;
58 let rslice = &self.buffer[..end];
59
60 if readcnt == 0 {
61 let output = parser.end_input(rslice)?;
62 Ok(Parsed(output))
63 } else {
64 let Update { consumed, outcome } = parser.feed(rslice)?;
65
66 self.buffer.rotate_left(consumed);
67 self.rstart = end - consumed;
68
69 Ok(outcome)
70 }
71 }
72}