utils/parser/
one_of.rs

1use crate::parser::then::Then2;
2use crate::parser::{ParseResult, Parser};
3
4/// Use a second trait to force usage of the [`one_of`] method, preventing tuples from being used as
5/// parsers directly, which could be confusing.
6pub trait ParserOneOfTuple<'i> {
7    type Output;
8    fn one_of(&self, input: &'i [u8]) -> ParseResult<'i, Self::Output>;
9}
10
11macro_rules! one_of_impl {
12    ($($l:ident: $n:tt),+) => {
13        impl<'i, A: Parser<'i>, $($l: Parser<'i, Output = A::Output>),+> ParserOneOfTuple<'i> for (A, $($l,)*) {
14            type Output = A::Output;
15
16            #[inline(always)]
17            fn one_of(&self, input: &'i [u8]) -> ParseResult<'i, Self::Output> {
18                let mut err = match self.0.parse(input) {
19                    Ok(v) => return Ok(v),
20                    Err(err) => err,
21                };
22
23                $(match self.$n.parse(input) {
24                    Ok(v) => return Ok(v),
25                    Err(this_err) => {
26                        if this_err.1.len() < err.1.len() {
27                            err = this_err;
28                        }
29                    }
30                })+
31
32                Err(err)
33            }
34        }
35    };
36}
37
38one_of_impl! {B: 1}
39one_of_impl! {B: 1, C: 2}
40one_of_impl! {B: 1, C: 2, D: 3}
41one_of_impl! {B: 1, C: 2, D: 3, E: 4}
42one_of_impl! {B: 1, C: 2, D: 3, E: 4, F: 5}
43one_of_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6}
44one_of_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7}
45one_of_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7, I: 8}
46one_of_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7, I: 8, J: 9}
47one_of_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7, I: 8, J: 9, K: 10}
48one_of_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7, I: 8, J: 9, K: 10, L: 11}
49
50#[derive(Copy, Clone)]
51pub struct OneOf<O> {
52    options: O,
53}
54impl<'i, O: ParserOneOfTuple<'i>> Parser<'i> for OneOf<O> {
55    type Output = O::Output;
56    type Then<T: Parser<'i>> = Then2<Self, T>;
57
58    #[inline]
59    fn parse(&self, input: &'i [u8]) -> ParseResult<'i, Self::Output> {
60        self.options.one_of(input)
61    }
62}
63
64/// Attempt to parse using a list of parsers.
65///
66/// Similar to [`Parser::or`], each parser will be tried in order until one succeeds. If no parsers
67/// succeed, the error from the parser furthest into the input is returned.
68///
69/// Prefer [`parser::literal_map`](super::literal_map) if all the parsers are string literals.
70///
71/// # Examples
72/// ```
73/// # use utils::input::InputError;
74/// # use utils::parser::{self, ParseError, Parser};
75/// #[derive(Debug, PartialEq)]
76/// enum Value {
77///     Unsigned8(u8),
78///     Unsigned32(u32),
79///     Signed8(i8),
80///     Signed32(i32),
81/// }
82///
83/// let parser = parser::one_of((
84///     parser::u8().map(Value::Unsigned8),
85///     parser::u32().map(Value::Unsigned32),
86///     parser::i8().map(Value::Signed8),
87///     parser::i32().map(Value::Signed32),
88/// ));
89///
90/// assert_eq!(
91///     parser.parse_complete("31").unwrap(),
92///     Value::Unsigned8(31),
93/// );
94/// assert_eq!(
95///     parser.parse_complete("4294967295").unwrap(),
96///     Value::Unsigned32(4294967295),
97/// );
98/// assert_eq!(
99///     parser.parse_complete("-1").unwrap(),
100///     Value::Signed8(-1)
101/// );
102/// assert_eq!(
103///     parser.parse_complete("-2147483648").unwrap(),
104///     Value::Signed32(-2147483648)
105/// );
106///
107/// assert_eq!(
108///     parser.parse(b"not a number").unwrap_err().0,
109///     ParseError::Expected("unsigned integer")
110/// );
111/// assert_eq!(
112///     parser.parse(b"-4294967295").unwrap_err().0,
113///     ParseError::NumberTooSmall(-2147483648)
114/// );
115/// ```
116pub fn one_of<'i, L: ParserOneOfTuple<'i>>(options: L) -> OneOf<L> {
117    OneOf { options }
118}