utils/parser/one_of.rs
1use crate::parser::then::Then2;
2use crate::parser::{ParseState, Parser, ParserResult};
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.
6#[doc(hidden)]
7pub trait ParserOneOfTuple<'i> {
8 type Output;
9 fn one_of(
10 &self,
11 input: &'i [u8],
12 state: &mut ParseState<'i>,
13 tail: bool,
14 ) -> ParserResult<'i, Self::Output>;
15}
16
17macro_rules! one_of_impl {
18 ($($l:ident: $n:tt),+) => {
19 impl<'i, A: Parser<'i>, $($l: Parser<'i, Output = A::Output>),+> ParserOneOfTuple<'i> for (A, $($l,)*) {
20 type Output = A::Output;
21
22 #[inline(always)]
23 fn one_of(
24 &self,
25 input: &'i [u8],
26 state: &mut ParseState<'i>,
27 tail: bool,
28 ) -> ParserResult<'i, Self::Output> {
29 let mut commit = false;
30 let token = match self.0.parse_ctx(input, state, &mut commit, tail) {
31 Ok(v) => return Ok(v),
32 Err(t) if commit => return Err(t),
33 Err(t) => t,
34 };
35
36 $(
37 let mut commit = false;
38 match self.$n.parse_ctx(input, state, &mut commit, tail) {
39 Ok(v) => return Ok(v),
40 Err(t) if commit => return Err(t),
41 Err(_) => {},
42 }
43 )+
44
45 Err(token)
46 }
47 }
48 };
49}
50
51one_of_impl! {B: 1}
52one_of_impl! {B: 1, C: 2}
53one_of_impl! {B: 1, C: 2, D: 3}
54one_of_impl! {B: 1, C: 2, D: 3, E: 4}
55one_of_impl! {B: 1, C: 2, D: 3, E: 4, F: 5}
56one_of_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6}
57one_of_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7}
58one_of_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7, I: 8}
59one_of_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7, I: 8, J: 9}
60one_of_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7, I: 8, J: 9, K: 10}
61one_of_impl! {B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7, I: 8, J: 9, K: 10, L: 11}
62
63#[derive(Copy, Clone)]
64pub struct OneOf<O> {
65 options: O,
66}
67impl<'i, O: ParserOneOfTuple<'i>> Parser<'i> for OneOf<O> {
68 type Output = O::Output;
69 type Then<T: Parser<'i>> = Then2<Self, T>;
70
71 #[inline]
72 fn parse_ctx(
73 &self,
74 input: &'i [u8],
75 state: &mut ParseState<'i>,
76 _: &mut bool,
77 tail: bool,
78 ) -> ParserResult<'i, Self::Output> {
79 self.options.one_of(input, state, tail)
80 }
81}
82
83/// [`Parser`] which tries a list of parsers in order until one succeeds.
84///
85/// If a parser commits, no further parsers are tried.
86///
87/// This is similar to [`Parser::or`] but supports a variable number of parsers.
88///
89/// Prefer [`parser::literal_map`](super::literal_map) if all the parsers are string literals.
90///
91/// # Examples
92/// ```
93/// # use utils::input::InputError;
94/// # use utils::parser::{self, ParseError, Parser};
95/// #[derive(Debug, PartialEq)]
96/// enum Value {
97/// Unsigned8(u8),
98/// Unsigned32(u32),
99/// Signed8(i8),
100/// Signed32(i32),
101/// }
102///
103/// let parser = parser::one_of((
104/// parser::u8().map(Value::Unsigned8),
105/// parser::u32().map(Value::Unsigned32),
106/// parser::i8().map(Value::Signed8),
107/// parser::i32().map(Value::Signed32),
108/// ));
109///
110/// assert_eq!(
111/// parser.parse_complete("31").unwrap(),
112/// Value::Unsigned8(31),
113/// );
114/// assert_eq!(
115/// parser.parse_complete("4294967295").unwrap(),
116/// Value::Unsigned32(4294967295),
117/// );
118/// assert_eq!(
119/// parser.parse_complete("-1").unwrap(),
120/// Value::Signed8(-1)
121/// );
122/// assert_eq!(
123/// parser.parse_complete("-2147483648").unwrap(),
124/// Value::Signed32(-2147483648)
125/// );
126///
127/// assert_eq!(
128/// parser.parse_complete("not a number").unwrap_err().into_source(),
129/// ParseError::Expected("unsigned integer")
130/// );
131/// assert_eq!(
132/// parser.parse_complete("-4294967295").unwrap_err().into_source(),
133/// ParseError::NumberTooSmall(-2147483648)
134/// );
135/// ```
136#[inline]
137#[must_use]
138pub fn one_of<'i, L: ParserOneOfTuple<'i>>(options: L) -> OneOf<L> {
139 OneOf { options }
140}