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 ParserList {
7    type Output<'i>;
8    fn parse<'i>(&self, input: &'i [u8]) -> ParseResult<'i, Self::Output<'i>>;
9}
10
11macro_rules! parserlist_impl {
12    ($($l:ident: $n:tt),+) => {
13        impl<A: Parser, $($l: for<'i> Parser<Output<'i> = A::Output<'i>>),+> ParserList for (A, $($l,)*) {
14            type Output<'i> = A::Output<'i>;
15
16            #[inline(always)]
17            fn parse<'i>(&self, input: &'i [u8]) -> ParseResult<'i, Self::Output<'i>> {
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
38parserlist_impl! {B: 1}
39parserlist_impl! {B: 1, C: 2}
40parserlist_impl! {B: 1, C: 2, D: 3}
41parserlist_impl! {B: 1, C: 2, D: 3, E: 4}
42parserlist_impl! {B: 1, C: 2, D: 3, E: 4, F: 5}
43parserlist_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6}
44parserlist_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7}
45parserlist_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7, I: 8}
46parserlist_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7, I: 8, J: 9}
47parserlist_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7, I: 8, J: 9, K: 10}
48parserlist_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<L> {
52    list: L,
53}
54impl<L: ParserList> Parser for OneOf<L> {
55    type Output<'i> = L::Output<'i>;
56    type Then<T: Parser> = Then2<Self, T>;
57
58    #[inline]
59    fn parse<'i>(&self, input: &'i [u8]) -> ParseResult<'i, Self::Output<'i>> {
60        self.list.parse(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<L: ParserList>(options: L) -> OneOf<L> {
117    OneOf { list: options }
118}