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}