tz/utils/
types.rs

1//! Some useful types.
2
3use std::io::{Error, ErrorKind};
4
5/// A `Cursor` contains a slice of a buffer and a read count.
6#[derive(Debug, Eq, PartialEq)]
7pub struct Cursor<'a> {
8    /// Slice representing the remaining data to be read
9    remaining: &'a [u8],
10    /// Number of already read bytes
11    read_count: usize,
12}
13
14impl<'a> Cursor<'a> {
15    /// Construct a new `Cursor` from remaining data
16    pub fn new(remaining: &'a [u8]) -> Self {
17        Self { remaining, read_count: 0 }
18    }
19
20    /// Returns remaining data
21    pub fn remaining(&self) -> &'a [u8] {
22        self.remaining
23    }
24
25    /// Returns `true` if data is remaining
26    pub fn is_empty(&self) -> bool {
27        self.remaining.is_empty()
28    }
29
30    /// Read exactly `count` bytes, reducing remaining data and incrementing read count
31    pub fn read_exact(&mut self, count: usize) -> Result<&'a [u8], Error> {
32        match (self.remaining.get(..count), self.remaining.get(count..)) {
33            (Some(result), Some(remaining)) => {
34                self.remaining = remaining;
35                self.read_count += count;
36                Ok(result)
37            }
38            _ => Err(Error::from(ErrorKind::UnexpectedEof)),
39        }
40    }
41
42    /// Read bytes and compare them to the provided tag
43    pub fn read_tag(&mut self, tag: &[u8]) -> Result<(), Error> {
44        if self.read_exact(tag.len())? == tag {
45            Ok(())
46        } else {
47            Err(Error::from(ErrorKind::InvalidData))
48        }
49    }
50
51    /// Read bytes if the remaining data is prefixed by the provided tag
52    pub fn read_optional_tag(&mut self, tag: &[u8]) -> Result<bool, Error> {
53        if self.remaining.starts_with(tag) {
54            self.read_exact(tag.len())?;
55            Ok(true)
56        } else {
57            Ok(false)
58        }
59    }
60
61    /// Read bytes as long as the provided predicate is true
62    pub fn read_while<F: Fn(&u8) -> bool>(&mut self, f: F) -> Result<&'a [u8], Error> {
63        match self.remaining.iter().position(|x| !f(x)) {
64            None => self.read_exact(self.remaining.len()),
65            Some(position) => self.read_exact(position),
66        }
67    }
68
69    /// Read bytes until the provided predicate is true
70    pub fn read_until<F: Fn(&u8) -> bool>(&mut self, f: F) -> Result<&'a [u8], Error> {
71        match self.remaining.iter().position(f) {
72            None => self.read_exact(self.remaining.len()),
73            Some(position) => self.read_exact(position),
74        }
75    }
76}