utils/parser/
tinystr.rs

1use crate::parser::{Leaf, LeafResult, ParseError};
2use crate::str::{TinyStr, TinyStrInt, TinyStrLen};
3use std::num::NonZero;
4
5#[derive(Copy, Clone)]
6pub struct TinyStringParser<T: TinyStrInt> {
7    _phantom: std::marker::PhantomData<T>,
8    f: fn(&u8) -> bool,
9}
10impl<'i, T: TinyStrInt> Leaf<'i> for TinyStringParser<T> {
11    type Output = TinyStr<T>;
12
13    #[inline]
14    fn parse(&self, input: &'i [u8]) -> LeafResult<'i, Self::Output> {
15        let mut accumulator = T::Raw::default();
16        let mut len = 0;
17        while len < T::LEN
18            && let Some(&b) = input.get(len)
19            && (self.f)(&b)
20        {
21            accumulator = T::set_raw(accumulator, b, len);
22            len += 1;
23        }
24
25        if len == 0 {
26            return Err((ParseError::ExpectedAtLeastMatches(1, self.f), input));
27        }
28
29        if len == T::LEN
30            && let Some(b) = input.get(T::LEN)
31            && (self.f)(b)
32        {
33            return Err((
34                ParseError::ExpectedAtMostMatches(T::LEN, self.f),
35                &input[T::LEN..],
36            ));
37        }
38
39        match T::from_raw(accumulator) {
40            None => Err((ParseError::ExpectedAtLeastMatches(1, self.f), input)),
41            Some(v) => Ok((TinyStr::from_raw(v), &input[len..])),
42        }
43    }
44}
45
46/// [`Leaf`] parser for [`TinyStr`] strings between 1 and 2 bytes matching the provided function.
47///
48/// Similar to [`Parser::repeat_arrayvec`](crate::parser::Parser::repeat_arrayvec) if more than 2
49/// bytes match, it will return an error.
50///
51/// # Examples
52/// ```
53/// # use utils::parser::{self, Leaf};
54/// # use utils::str::TinyStr2;
55/// let parser = parser::tinystr2(u8::is_ascii_lowercase);
56/// assert_eq!(
57///     parser.parse(b"ab: 123"),
58///     Ok((TinyStr2::from_const(b"ab"), &b": 123"[..]))
59/// );
60/// assert!(parser.parse(b"abc: 123").is_err());
61/// assert!(parser.parse(b"ABC").is_err());
62/// ```
63#[inline]
64#[must_use]
65pub fn tinystr2(f: fn(&u8) -> bool) -> TinyStringParser<NonZero<u16>> {
66    TinyStringParser {
67        _phantom: std::marker::PhantomData,
68        f,
69    }
70}
71
72/// [`Leaf`] parser for [`TinyStr`] strings between 1 and 4 bytes matching the provided function.
73///
74/// Similar to [`Parser::repeat_arrayvec`](crate::parser::Parser::repeat_arrayvec) if more than 4
75/// bytes match, it will return an error.
76///
77/// # Examples
78/// ```
79/// # use utils::parser::{self, Leaf};
80/// # use utils::str::TinyStr4;
81/// let parser = parser::tinystr4(u8::is_ascii_lowercase);
82/// assert_eq!(
83///     parser.parse(b"abc: 123"),
84///     Ok((TinyStr4::from_const(b"abc"), &b": 123"[..]))
85/// );
86/// assert_eq!(
87///     parser.parse(b"abcd: 123"),
88///     Ok((TinyStr4::from_const(b"abcd"), &b": 123"[..]))
89/// );
90/// assert!(parser.parse(b"abcde: 123").is_err());
91/// assert!(parser.parse(b"ABC").is_err());
92/// ```
93#[inline]
94#[must_use]
95pub fn tinystr4(f: fn(&u8) -> bool) -> TinyStringParser<NonZero<u32>> {
96    TinyStringParser {
97        _phantom: std::marker::PhantomData,
98        f,
99    }
100}
101
102/// [`Leaf`] parser for [`TinyStr`] strings between 1 and 8 bytes matching the provided function.
103///
104/// Similar to [`Parser::repeat_arrayvec`](crate::parser::Parser::repeat_arrayvec) if more than 8
105/// bytes match, it will return an error.
106///
107/// # Examples
108/// ```
109/// # use utils::parser::{self, Leaf};
110/// # use utils::str::TinyStr8;
111/// let parser = parser::tinystr8(u8::is_ascii_lowercase);
112/// assert_eq!(
113///     parser.parse(b"abcde: 123"),
114///     Ok((TinyStr8::from_const(b"abcde"), &b": 123"[..]))
115/// );
116/// assert_eq!(
117///     parser.parse(b"abcdefgh: 123"),
118///     Ok((TinyStr8::from_const(b"abcdefgh"), &b": 123"[..]))
119/// );
120/// assert!(parser.parse(b"abcdefghi: 123").is_err());
121/// assert!(parser.parse(b"ABC").is_err());
122/// ```
123#[inline]
124#[must_use]
125pub fn tinystr8(f: fn(&u8) -> bool) -> TinyStringParser<NonZero<u64>> {
126    TinyStringParser {
127        _phantom: std::marker::PhantomData,
128        f,
129    }
130}
131
132#[derive(Copy, Clone)]
133pub struct TinyStringExact<const N: usize> {
134    f: fn(&u8) -> bool,
135}
136impl<'i, const N: usize> Leaf<'i> for TinyStringExact<N>
137where
138    (): TinyStrLen<N>,
139{
140    type Output = TinyStr<<() as TinyStrLen<N>>::Int>;
141
142    #[inline]
143    fn parse(&self, input: &'i [u8]) -> LeafResult<'i, Self::Output> {
144        let mut accumulator = <<() as TinyStrLen<N>>::Int as TinyStrInt>::Raw::default();
145
146        for i in 0..N {
147            if let Some(&b) = input.get(i)
148                && (self.f)(&b)
149            {
150                accumulator =
151                    <<() as TinyStrLen<N>>::Int as TinyStrInt>::set_raw(accumulator, b, i);
152            } else {
153                return Err((ParseError::ExpectedExactlyMatches(N, self.f), &input[i..]));
154            }
155        }
156
157        match <<() as TinyStrLen<N>>::Int as TinyStrInt>::from_raw(accumulator) {
158            None => Err((ParseError::ExpectedExactlyMatches(N, self.f), input)),
159            Some(v) => Ok((TinyStr::from_raw(v), &input[N..])),
160        }
161    }
162}
163
164/// [`Leaf`] parser for [`TinyStr`] strings exactly `N` long matching the provided function.
165///
166/// # Examples
167/// ```
168/// # use utils::parser::{self, Leaf};
169/// # use utils::str::TinyStr4;
170/// let parser = parser::tinystr::<3>(u8::is_ascii_lowercase);
171/// assert_eq!(
172///     parser.parse(b"abc: 123"),
173///     Ok((TinyStr4::from_const(b"abc"), &b": 123"[..]))
174/// );
175/// assert_eq!(
176///     parser.parse(b"abcd: 123"),
177///     Ok((TinyStr4::from_const(b"abc"), &b"d: 123"[..]))
178/// );
179/// assert!(parser.parse(b"ab: 123").is_err());
180/// assert!(parser.parse(b"ABC").is_err());
181/// ```
182#[inline]
183#[must_use]
184pub fn tinystr<const N: usize>(f: fn(&u8) -> bool) -> TinyStringExact<N>
185where
186    (): TinyStrLen<N>,
187{
188    TinyStringExact { f }
189}