tz/parse/
utils.rs

1//! Some useful functions.
2
3use crate::error::parse::ParseDataError;
4
5/// Cursor type alias
6pub(super) type Cursor<'a> = &'a [u8];
7
8/// Read exactly `count` bytes and reduce remaining data
9pub(super) fn read_exact<'a>(cursor: &mut Cursor<'a>, count: usize) -> Result<&'a [u8], ParseDataError> {
10    match cursor.split_at_checked(count) {
11        Some((result, tail)) => {
12            *cursor = tail;
13            Ok(result)
14        }
15        None => Err(ParseDataError::UnexpectedEof),
16    }
17}
18
19/// Read exactly `N` bytes into an array and reduce remaining data
20pub(super) fn read_chunk_exact<'a, const N: usize>(cursor: &mut Cursor<'a>) -> Result<&'a [u8; N], ParseDataError> {
21    match cursor.split_first_chunk::<N>() {
22        Some((result, tail)) => {
23            *cursor = tail;
24            Ok(result)
25        }
26        None => Err(ParseDataError::UnexpectedEof),
27    }
28}
29
30/// Read bytes and compare them to the provided tag
31pub(super) fn read_tag(cursor: &mut Cursor<'_>, tag: &[u8]) -> Result<(), ParseDataError> {
32    if read_exact(cursor, tag.len())? == tag {
33        Ok(())
34    } else {
35        Err(ParseDataError::InvalidData)
36    }
37}
38
39/// Read bytes if the remaining data is prefixed by the provided tag
40pub(super) fn read_optional_tag(cursor: &mut Cursor<'_>, tag: &[u8]) -> Result<bool, ParseDataError> {
41    if cursor.starts_with(tag) {
42        read_exact(cursor, tag.len())?;
43        Ok(true)
44    } else {
45        Ok(false)
46    }
47}
48
49/// Read bytes as long as the provided predicate is true
50pub(super) fn read_while<'a, F: Fn(&u8) -> bool>(cursor: &mut Cursor<'a>, f: F) -> Result<&'a [u8], ParseDataError> {
51    read_exact(cursor, cursor.iter().position(|x| !f(x)).unwrap_or(cursor.len()))
52}
53
54/// Read bytes until the provided predicate is true
55pub(super) fn read_until<'a, F: Fn(&u8) -> bool>(cursor: &mut Cursor<'a>, f: F) -> Result<&'a [u8], ParseDataError> {
56    read_exact(cursor, cursor.iter().position(f).unwrap_or(cursor.len()))
57}