Skip to main content

toe_beans/v4/message/
slicer.rs

1use log::trace;
2
3/// Takes a slice as input and divides it into smaller slices.
4/// This processes the slice from start to end by user-provided _len_ sized chunks.
5///
6/// For example `&[1, 2, 3, 4] --> &[1, 2] and &[3, 4]`.
7///
8/// Uses:
9/// - When you know the length to slice at runtime but not compile time.
10/// - When parsing formats within formats. For example,
11///   the DHCP format has an options field that contains TLV
12///   formatted options. See `options/options.rs`.
13#[derive(Debug)]
14pub struct Slicer<'de> {
15    input: &'de [u8],
16    input_index: usize,
17}
18
19impl<'de> Slicer<'de> {
20    /// Creates an instance of Slicer.
21    pub fn new(input: &'de [u8]) -> Self {
22        Slicer {
23            input,
24            input_index: 0,
25        }
26    }
27
28    /// Returns the next len number of bytes and changes the current position the same amount.
29    ///
30    /// Returns an Option instead of panicking. Use `slice_unchecked` if it is okay to panic.
31    #[inline]
32    pub fn slice(&mut self, len: usize) -> Option<&'de [u8]> {
33        trace!("slice");
34        let slice = self.input.get(self.input_index..self.input_index + len);
35
36        if slice.is_some() {
37            self.input_index += len;
38        }
39
40        slice
41    }
42
43    /// Returns the next len number of bytes and changes the current position the same amount.
44    ///
45    /// Can panic if slicing past array length. Use `slice` for no panic.
46    #[inline]
47    pub fn slice_unchecked(&mut self, len: usize) -> &'de [u8] {
48        trace!("slice_unchecked");
49        let slice = &self.input[self.input_index..self.input_index + len];
50        self.input_index += len;
51        slice
52    }
53
54    /// Returns the remaining bytes in the input and resets the current position to the start.
55    #[inline]
56    pub fn slice_remainder(&mut self) -> &'de [u8] {
57        trace!("slice_remainder");
58        let slice = &self.input[self.input_index..];
59        self.reset();
60        slice
61    }
62
63    /// Slicer keeps track of how many bytes have been sliced (the position from start).
64    /// This resets that internal state.
65    #[inline]
66    pub fn reset(&mut self) {
67        self.input_index = 0;
68    }
69}