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}