Skip to content

Commit

Permalink
Allow using arrays as input to alt (rust-bakery#1556)
Browse files Browse the repository at this point in the history
* Allow using arrays as input to `alt`

Now that min-const-generics is stabilized, it's possible
to (backwards-compatibly) write a version of `alt` that uses a const
array as input instead of being limited to only tuples - this allows us
to lift the 21-element limitation on tuples passed to `alt`.

---------

Co-authored-by: Geoffroy Couprie <[email protected]>
  • Loading branch information
glittershark and Geal committed Jul 30, 2023
1 parent 90d78d6 commit 9dffd60
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 3 deletions.
43 changes: 40 additions & 3 deletions src/branch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ use crate::internal::{Err, Mode, Parser};

/// Tests a list of parsers one by one until one succeeds.
///
/// It takes as argument a tuple of parsers. There is a maximum of 21
/// parsers. If you need more, it is possible to nest them in other `alt` calls,
/// like this: `alt(parser_a, alt(parser_b, parser_c))`
/// It takes as argument either a tuple or an array of parsers. If using a
/// tuple, there is a maximum of 21 parsers. If you need more, it is possible to
/// use an array.
///
/// ```rust
/// # use nom::error_position;
Expand Down Expand Up @@ -173,6 +173,43 @@ impl<Input, Output, Error: ParseError<Input>, A: Parser<Input, Output = Output,
}
}

impl<
const N: usize,
Input: Clone,
Output,
Error: ParseError<Input>,
A: Parser<Input, Output = Output, Error = Error>,
> Parser<Input> for Choice<[A; N]>
{
type Output = Output;
type Error = Error;

#[inline]
fn process<OM: crate::OutputMode>(
&mut self,
input: Input,
) -> crate::PResult<OM, Input, Self::Output, Self::Error> {
let mut error = None;

for branch in &mut self.parser {
match branch.process::<OM>(input.clone()) {
//branch.parse(input.clone()) {
Err(Err::Error(e)) => error = Some(e),
res => return res,
}
}

match error {
Some(e) => Err(Err::Error(OM::Error::map(e, |err| {
Error::append(input, ErrorKind::Alt, err)
}))),
None => Err(Err::Error(OM::Error::bind(|| {
Error::from_error_kind(input, ErrorKind::Alt)
}))),
}
}
}

macro_rules! permutation_trait(
(
$name1:ident $ty1:ident $item1:ident
Expand Down
16 changes: 16 additions & 0 deletions src/branch/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,22 @@ fn alt_incomplete() {
assert_eq!(alt1(a), Ok((&b"g"[..], &b"def"[..])));
}

#[test]
fn alt_array() {
fn alt1(i: &[u8]) -> IResult<&[u8], &[u8]> {
alt([tag("a"), tag("bc"), tag("def")]).parse(i)
}

let a = &b"a"[..];
assert_eq!(alt1(a), Ok((&b""[..], (&b"a"[..]))));

let bc = &b"bc"[..];
assert_eq!(alt1(bc), Ok((&b""[..], (&b"bc"[..]))));

let defg = &b"defg"[..];
assert_eq!(alt1(defg), Ok((&b"g"[..], (&b"def"[..]))));
}

#[test]
fn permutation_test() {
#[allow(clippy::type_complexity)]
Expand Down

0 comments on commit 9dffd60

Please sign in to comment.