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}