From 9835e2ae736235810b4ea1c162ca5e65c547e770 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 18 May 2024 04:49:50 +0200 Subject: Merging upstream version 1.71.1+dfsg1. Signed-off-by: Daniel Baumann --- vendor/winnow/src/combinator/mod.rs | 1471 +++++++++++++++++++++++++++++++++ vendor/winnow/src/combinator/tests.rs | 319 +++++++ 2 files changed, 1790 insertions(+) create mode 100644 vendor/winnow/src/combinator/mod.rs create mode 100644 vendor/winnow/src/combinator/tests.rs (limited to 'vendor/winnow/src/combinator') diff --git a/vendor/winnow/src/combinator/mod.rs b/vendor/winnow/src/combinator/mod.rs new file mode 100644 index 000000000..4276b06d3 --- /dev/null +++ b/vendor/winnow/src/combinator/mod.rs @@ -0,0 +1,1471 @@ +//! # List of parsers and combinators +//! +//! **Note**: this list is meant to provide a nicer way to find a parser than reading through the documentation on docs.rs. Function combinators are organized in module so they are a bit easier to find. +//! +//! ## Basic elements +//! +//! Those are used to recognize the lowest level elements of your grammar, like, "here is a dot", or "here is an big endian integer". +//! +//! | combinator | usage | input | output | comment | +//! |---|---|---|---|---| +//! | [`one_of`][crate::bytes::one_of] | `one_of("abc")` | `"abc"` | `Ok(("bc", 'a'))` |Matches one of the provided characters (works with non ASCII characters too)| +//! | [`none_of`][crate::bytes::none_of] | `none_of("abc")` | `"xyab"` | `Ok(("yab", 'x'))` |Matches anything but the provided characters| +//! | [`tag`][crate::bytes::tag] | `"hello"` | `"hello world"` | `Ok((" world", "hello"))` |Recognizes a specific suite of characters or bytes| +//! | [`tag_no_case`][crate::bytes::tag_no_case] | `tag_no_case("hello")` | `"HeLLo World"` | `Ok((" World", "HeLLo"))` |Case insensitive comparison. Note that case insensitive comparison is not well defined for unicode, and that you might have bad surprises| +//! | [`take`][crate::bytes::take] | `take(4)` | `"hello"` | `Ok(("o", "hell"))` |Takes a specific number of bytes or characters| +//! | [`take_while0`][crate::bytes::take_while0] | `take_while0(is_alphabetic)` | `"abc123"` | `Ok(("123", "abc"))` |Returns the longest list of bytes for which the provided pattern matches. `take_while1` does the same, but must return at least one character| +//! | [`take_till0`][crate::bytes::take_till0] | `take_till0(is_alphabetic)` | `"123abc"` | `Ok(("abc", "123"))` |Returns the longest list of bytes or characters until the provided pattern matches. `take_till1` does the same, but must return at least one character. This is the reverse behaviour from `take_while0`: `take_till(f)` is equivalent to `take_while0(\|c\| !f(c))`| +//! | [`take_until0`][crate::bytes::take_until0] | `take_until0("world")` | `"Hello world"` | `Ok(("world", "Hello "))` |Returns the longest list of bytes or characters until the provided tag is found. `take_until1` does the same, but must return at least one character| +//! +//! ## Choice combinators +//! +//! | combinator | usage | input | output | comment | +//! |---|---|---|---|---| +//! | [`alt`][crate::branch::alt] | `alt(("ab", "cd"))` | `"cdef"` | `Ok(("ef", "cd"))` |Try a list of parsers and return the result of the first successful one| +//! | [`dispatch`][crate::branch::dispatch] | \- | \- | \- | `match` for parsers | +//! | [`permutation`][crate::branch::permutation] | `permutation(("ab", "cd", "12"))` | `"cd12abc"` | `Ok(("c", ("ab", "cd", "12"))` |Succeeds when all its child parser have succeeded, whatever the order| +//! +//! ## Sequence combinators +//! +//! | combinator | usage | input | output | comment | +//! |---|---|---|---|---| +//! | [`(...)` (tuples)][crate::Parser] | `("ab", "XY", take(1))` | `"abXYZ!"` | `Ok(("!", ("ab", "XY", "Z")))` |Chains parsers and assemble the sub results in a tuple. You can use as many child parsers as you can put elements in a tuple| +//! | [`delimited`][crate::sequence::delimited] | `delimited(char('('), take(2), char(')'))` | `"(ab)cd"` | `Ok(("cd", "ab"))` || +//! | [`preceded`][crate::sequence::preceded] | `preceded("ab", "XY")` | `"abXYZ"` | `Ok(("Z", "XY"))` || +//! | [`terminated`][crate::sequence::terminated] | `terminated("ab", "XY")` | `"abXYZ"` | `Ok(("Z", "ab"))` || +//! | [`separated_pair`][crate::sequence::separated_pair] | `separated_pair("hello", char(','), "world")` | `"hello,world!"` | `Ok(("!", ("hello", "world")))` || +//! +//! ## Applying a parser multiple times +//! +//! | combinator | usage | input | output | comment | +//! |---|---|---|---|---| +//! | [`count`][crate::multi::count] | `count(take(2), 3)` | `"abcdefgh"` | `Ok(("gh", vec!["ab", "cd", "ef"]))` |Applies the child parser a specified number of times| +//! | [`many0`][crate::multi::many0] | `many0("ab")` | `"abababc"` | `Ok(("c", vec!["ab", "ab", "ab"]))` |Applies the parser 0 or more times and returns the list of results in a Vec. `many1` does the same operation but must return at least one element| +//! | [`many_m_n`][crate::multi::many_m_n] | `many_m_n(1, 3, "ab")` | `"ababc"` | `Ok(("c", vec!["ab", "ab"]))` |Applies the parser between m and n times (n included) and returns the list of results in a Vec| +//! | [`many_till0`][crate::multi::many_till0] | `many_till0(tag( "ab" ), tag( "ef" ))` | `"ababefg"` | `Ok(("g", (vec!["ab", "ab"], "ef")))` |Applies the first parser until the second applies. Returns a tuple containing the list of results from the first in a Vec and the result of the second| +//! | [`separated0`][crate::multi::separated0] | `separated0("ab", ",")` | `"ab,ab,ab."` | `Ok((".", vec!["ab", "ab", "ab"]))` |`separated1` works like `separated0` but must returns at least one element| +//! | [`fold_many0`][crate::multi::fold_many0] | `fold_many0(be_u8, \|\| 0, \|acc, item\| acc + item)` | `[1, 2, 3]` | `Ok(([], 6))` |Applies the parser 0 or more times and folds the list of return values. The `fold_many1` version must apply the child parser at least one time| +//! | [`fold_many_m_n`][crate::multi::fold_many_m_n] | `fold_many_m_n(1, 2, be_u8, \|\| 0, \|acc, item\| acc + item)` | `[1, 2, 3]` | `Ok(([3], 3))` |Applies the parser between m and n times (n included) and folds the list of return value| +//! | [`length_count`][crate::multi::length_count] | `length_count(number, "ab")` | `"2ababab"` | `Ok(("ab", vec!["ab", "ab"]))` |Gets a number from the first parser, then applies the second parser that many times| +//! +//! ## Partial related +//! +//! - [`eof`][eof]: Returns its input if it is at the end of input data +//! - [`Parser::complete_err`]: Replaces an `Incomplete` returned by the child parser with an `Backtrack` +//! +//! ## Modifiers +//! +//! - [`cond`][cond]: Conditional combinator. Wraps another parser and calls it if the condition is met +//! - [`Parser::flat_map`][crate::Parser::flat_map]: method to map a new parser from the output of the first parser, then apply that parser over the rest of the input +//! - [`Parser::value`][crate::Parser::value]: method to replace the result of a parser +//! - [`Parser::map`][crate::Parser::map]: method to map a function on the result of a parser +//! - [`Parser::and_then`][crate::Parser::and_then]: Applies a second parser over the output of the first one +//! - [`Parser::verify_map`][Parser::verify_map]: Maps a function returning an `Option` on the output of a parser +//! - [`Parser::map_res`][Parser::map_res]: Maps a function returning a `Result` on the output of a parser +//! - [`Parser::parse_to`][crate::Parser::parse_to]: Apply [`std::str::FromStr`] to the output of the parser +//! - [`not`][not]: Returns a result only if the embedded parser returns `Backtrack` or `Incomplete`. Does not consume the input +//! - [`opt`][opt]: Make the underlying parser optional +//! - [`peek`][peek]: Returns a result without consuming the input +//! - [`Parser::recognize`][Parser::recognize]: If the child parser was successful, return the consumed input as the produced value +//! - [`Parser::with_recognized`][Parser::with_recognized]: If the child parser was successful, return a tuple of the consumed input and the produced output. +//! - [`Parser::span`][Parser::span]: If the child parser was successful, return the location of the consumed input as the produced value +//! - [`Parser::with_span`][Parser::with_span]: If the child parser was successful, return a tuple of the location of the consumed input and the produced output. +//! - [`Parser::verify`]: Returns the result of the child parser if it satisfies a verification function +//! +//! ## Error management and debugging +//! +//! - [`cut_err`]: Commit the parse result, disallowing alternative parsers from being attempted +//! - [`backtrack_err`]: Attemmpts a parse, allowing alternative parsers to be attempted despite +//! use of `cut_err` +//! - [`Parser::context`]: Add context to the error if the parser fails +//! - [`trace`][crate::trace::trace]: Print the parse state with the `debug` feature flag +//! - [`todo()`]: Placeholder parser +//! +//! ## Remaining combinators +//! +//! - [`success`][success]: Returns a value without consuming any input, always succeeds +//! - [`fail`][fail]: Inversion of `success`. Always fails. +//! - [`Parser::by_ref`]: Allow moving `&mut impl Parser` into other parsers +//! +//! ## Text parsing +//! +//! - [`any`][crate::bytes::any]: Matches one token +//! - [`tab`][crate::character::tab]: Matches a tab character `\t` +//! - [`crlf`][crate::character::crlf]: Recognizes the string `\r\n` +//! - [`line_ending`][crate::character::line_ending]: Recognizes an end of line (both `\n` and `\r\n`) +//! - [`newline`][crate::character::newline]: Matches a newline character `\n` +//! - [`not_line_ending`][crate::character::not_line_ending]: Recognizes a string of any char except `\r` or `\n` +//! - [`rest`][rest]: Return the remaining input +//! +//! - [`alpha0`][crate::character::alpha0]: Recognizes zero or more lowercase and uppercase alphabetic characters: `[a-zA-Z]`. [`alpha1`][crate::character::alpha1] does the same but returns at least one character +//! - [`alphanumeric0`][crate::character::alphanumeric0]: Recognizes zero or more numerical and alphabetic characters: `[0-9a-zA-Z]`. [`alphanumeric1`][crate::character::alphanumeric1] does the same but returns at least one character +//! - [`space0`][crate::character::space0]: Recognizes zero or more spaces and tabs. [`space1`][crate::character::space1] does the same but returns at least one character +//! - [`multispace0`][crate::character::multispace0]: Recognizes zero or more spaces, tabs, carriage returns and line feeds. [`multispace1`][crate::character::multispace1] does the same but returns at least one character +//! - [`digit0`][crate::character::digit0]: Recognizes zero or more numerical characters: `[0-9]`. [`digit1`][crate::character::digit1] does the same but returns at least one character +//! - [`hex_digit0`][crate::character::hex_digit0]: Recognizes zero or more hexadecimal numerical characters: `[0-9A-Fa-f]`. [`hex_digit1`][crate::character::hex_digit1] does the same but returns at least one character +//! - [`oct_digit0`][crate::character::oct_digit0]: Recognizes zero or more octal characters: `[0-7]`. [`oct_digit1`][crate::character::oct_digit1] does the same but returns at least one character +//! +//! - [`float`][crate::character::float]: Parse a floating point number in a byte string +//! - [`dec_int`][crate::character::dec_uint]: Decode a variable-width, decimal signed integer +//! - [`dec_uint`][crate::character::dec_uint]: Decode a variable-width, decimal unsigned integer +//! - [`hex_uint`][crate::character::hex_uint]: Decode a variable-width, hexadecimal integer +//! +//! - [`escaped`][crate::character::escaped]: Matches a byte string with escaped characters +//! - [`escaped_transform`][crate::character::escaped_transform]: Matches a byte string with escaped characters, and returns a new string with the escaped characters replaced +//! +//! ### Character test functions +//! +//! Use these functions with a combinator like `take_while0`: +//! +//! - [`AsChar::is_alpha`][crate::stream::AsChar::is_alpha]: Tests if byte is ASCII alphabetic: `[A-Za-z]` +//! - [`AsChar::is_alphanum`][crate::stream::AsChar::is_alphanum]: Tests if byte is ASCII alphanumeric: `[A-Za-z0-9]` +//! - [`AsChar::is_dec_digit`][crate::stream::AsChar::is_dec_digit]: Tests if byte is ASCII digit: `[0-9]` +//! - [`AsChar::is_hex_digit`][crate::stream::AsChar::is_hex_digit]: Tests if byte is ASCII hex digit: `[0-9A-Fa-f]` +//! - [`AsChar::is_oct_digit`][crate::stream::AsChar::is_oct_digit]: Tests if byte is ASCII octal digit: `[0-7]` +//! - [`AsChar::is_space`][crate::stream::AsChar::is_space]: Tests if byte is ASCII space or tab: `[ \t]` +//! - [`AsChar::is_newline`][crate::stream::AsChar::is_newline]: Tests if byte is ASCII newline: `[\n]` +//! +//! ## Binary format parsing +//! +//! - [`length_data`][crate::multi::length_data]: Gets a number from the first parser, then takes a subslice of the input of that size, and returns that subslice +//! - [`length_value`][crate::multi::length_value]: Gets a number from the first parser, takes a subslice of the input of that size, then applies the second parser on that subslice. If the second parser returns `Incomplete`, `length_value` will return an error +//! +//! ### Integers +//! +//! Parsing integers from binary formats can be done in two ways: With parser functions, or combinators with configurable endianness. +//! +//! - **configurable endianness:** [`i16`][crate::number::i16], [`i32`][crate::number::i32], +//! [`i64`][crate::number::i64], [`u16`][crate::number::u16], [`u32`][crate::number::u32], +//! [`u64`][crate::number::u64] are combinators that take as argument a +//! [`winnow::number::Endianness`][crate::number::Endianness], like this: `i16(endianness)`. If the +//! parameter is `winnow::number::Endianness::Big`, parse a big endian `i16` integer, otherwise a +//! little endian `i16` integer. +//! - **fixed endianness**: The functions are prefixed by `be_` for big endian numbers, and by `le_` for little endian numbers, and the suffix is the type they parse to. As an example, `be_u32` parses a big endian unsigned integer stored in 32 bits. +//! - [`be_f32`][crate::number::be_f32], [`be_f64`][crate::number::be_f64]: Big endian floating point numbers +//! - [`le_f32`][crate::number::le_f32], [`le_f64`][crate::number::le_f64]: Little endian floating point numbers +//! - [`be_i8`][crate::number::be_i8], [`be_i16`][crate::number::be_i16], [`be_i24`][crate::number::be_i24], [`be_i32`][crate::number::be_i32], [`be_i64`][crate::number::be_i64], [`be_i128`][crate::number::be_i128]: Big endian signed integers +//! - [`be_u8`][crate::number::be_u8], [`be_u16`][crate::number::be_u16], [`be_u24`][crate::number::be_u24], [`be_u32`][crate::number::be_u32], [`be_u64`][crate::number::be_u64], [`be_u128`][crate::number::be_u128]: Big endian unsigned integers +//! - [`le_i8`][crate::number::le_i8], [`le_i16`][crate::number::le_i16], [`le_i24`][crate::number::le_i24], [`le_i32`][crate::number::le_i32], [`le_i64`][crate::number::le_i64], [`le_i128`][crate::number::le_i128]: Little endian signed integers +//! - [`le_u8`][crate::number::le_u8], [`le_u16`][crate::number::le_u16], [`le_u24`][crate::number::le_u24], [`le_u32`][crate::number::le_u32], [`le_u64`][crate::number::le_u64], [`le_u128`][crate::number::le_u128]: Little endian unsigned integers +//! +//! ### Bit stream parsing +//! +//! - [`bits`][crate::bits::bits]: Transforms the current input type (byte slice `&[u8]`) to a bit stream on which bit specific parsers and more general combinators can be applied +//! - [`bytes`][crate::bits::bytes]: Transforms its bits stream input back into a byte slice for the underlying parser +//! - [`take`][crate::bits::take]: Take a set number of its +//! - [`tag`][crate::bits::tag]: Check if a set number of bis matches a pattern +//! - [`bool`][crate::bits::bool]: Match any one bit + +use crate::error::{ContextError, ErrMode, ErrorKind, FromExternalError, Needed, ParseError}; +use crate::lib::std::borrow::Borrow; +use crate::lib::std::ops::Range; +use crate::stream::{Location, Stream}; +use crate::stream::{Offset, StreamIsPartial}; +use crate::trace::trace; +use crate::trace::trace_result; +use crate::*; + +#[cfg(test)] +mod tests; + +/// Return the remaining input. +/// +/// # Example +/// +/// ```rust +/// # use winnow::error::ErrorKind; +/// # use winnow::error::Error; +/// use winnow::combinator::rest; +/// assert_eq!(rest::<_,Error<_>>("abc"), Ok(("", "abc"))); +/// assert_eq!(rest::<_,Error<_>>(""), Ok(("", ""))); +/// ``` +#[inline] +pub fn rest>(input: I) -> IResult::Slice, E> +where + I: Stream, +{ + trace("rest", move |input: I| { + Ok(input.next_slice(input.eof_offset())) + }) + .parse_next(input) +} + +/// Return the length of the remaining input. +/// +/// Note: this does not advance the [`Stream`] +/// +/// # Example +/// +/// ```rust +/// # use winnow::error::ErrorKind; +/// # use winnow::error::Error; +/// use winnow::combinator::rest_len; +/// assert_eq!(rest_len::<_,Error<_>>("abc"), Ok(("abc", 3))); +/// assert_eq!(rest_len::<_,Error<_>>(""), Ok(("", 0))); +/// ``` +#[inline] +pub fn rest_len>(input: I) -> IResult +where + I: Stream, +{ + trace("rest_len", move |input: I| { + let len = input.eof_offset(); + Ok((input, len)) + }) + .parse_next(input) +} + +/// Implementation of [`Parser::by_ref`][Parser::by_ref] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct ByRef<'p, P> { + p: &'p mut P, +} + +impl<'p, P> ByRef<'p, P> { + pub(crate) fn new(p: &'p mut P) -> Self { + Self { p } + } +} + +impl<'p, I, O, E, P: Parser> Parser for ByRef<'p, P> { + fn parse_next(&mut self, i: I) -> IResult { + self.p.parse_next(i) + } +} + +/// Implementation of [`Parser::map`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct Map +where + F: Parser, + G: Fn(O) -> O2, +{ + parser: F, + map: G, + i: core::marker::PhantomData, + o: core::marker::PhantomData, + o2: core::marker::PhantomData, + e: core::marker::PhantomData, +} + +impl Map +where + F: Parser, + G: Fn(O) -> O2, +{ + pub(crate) fn new(parser: F, map: G) -> Self { + Self { + parser, + map, + i: Default::default(), + o: Default::default(), + o2: Default::default(), + e: Default::default(), + } + } +} + +impl Parser for Map +where + F: Parser, + G: Fn(O) -> O2, +{ + fn parse_next(&mut self, i: I) -> IResult { + match self.parser.parse_next(i) { + Err(e) => Err(e), + Ok((i, o)) => Ok((i, (self.map)(o))), + } + } +} + +/// Implementation of [`Parser::map_res`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct MapRes +where + F: Parser, + G: FnMut(O) -> Result, + I: Clone, + E: FromExternalError, +{ + parser: F, + map: G, + i: core::marker::PhantomData, + o: core::marker::PhantomData, + o2: core::marker::PhantomData, + e: core::marker::PhantomData, + e2: core::marker::PhantomData, +} + +impl MapRes +where + F: Parser, + G: FnMut(O) -> Result, + I: Clone, + E: FromExternalError, +{ + pub(crate) fn new(parser: F, map: G) -> Self { + Self { + parser, + map, + i: Default::default(), + o: Default::default(), + o2: Default::default(), + e: Default::default(), + e2: Default::default(), + } + } +} + +impl Parser for MapRes +where + F: Parser, + G: FnMut(O) -> Result, + I: Clone, + E: FromExternalError, +{ + fn parse_next(&mut self, input: I) -> IResult { + let i = input.clone(); + let (input, o) = self.parser.parse_next(input)?; + let res = match (self.map)(o) { + Ok(o2) => Ok((input, o2)), + Err(e) => Err(ErrMode::from_external_error(i, ErrorKind::Verify, e)), + }; + trace_result("verify", &res); + res + } +} + +/// Implementation of [`Parser::verify_map`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct VerifyMap +where + F: Parser, + G: FnMut(O) -> Option, + I: Clone, + E: ParseError, +{ + parser: F, + map: G, + i: core::marker::PhantomData, + o: core::marker::PhantomData, + o2: core::marker::PhantomData, + e: core::marker::PhantomData, +} + +impl VerifyMap +where + F: Parser, + G: FnMut(O) -> Option, + I: Clone, + E: ParseError, +{ + pub(crate) fn new(parser: F, map: G) -> Self { + Self { + parser, + map, + i: Default::default(), + o: Default::default(), + o2: Default::default(), + e: Default::default(), + } + } +} + +impl Parser for VerifyMap +where + F: Parser, + G: FnMut(O) -> Option, + I: Clone, + E: ParseError, +{ + fn parse_next(&mut self, input: I) -> IResult { + let i = input.clone(); + let (input, o) = self.parser.parse_next(input)?; + let res = match (self.map)(o) { + Some(o2) => Ok((input, o2)), + None => Err(ErrMode::from_error_kind(i, ErrorKind::Verify)), + }; + trace_result("verify", &res); + res + } +} + +/// Implementation of [`Parser::and_then`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct AndThen +where + F: Parser, + G: Parser, + O: StreamIsPartial, +{ + outer: F, + inner: G, + i: core::marker::PhantomData, + o: core::marker::PhantomData, + o2: core::marker::PhantomData, + e: core::marker::PhantomData, +} + +impl AndThen +where + F: Parser, + G: Parser, + O: StreamIsPartial, +{ + pub(crate) fn new(outer: F, inner: G) -> Self { + Self { + outer, + inner, + i: Default::default(), + o: Default::default(), + o2: Default::default(), + e: Default::default(), + } + } +} + +impl Parser for AndThen +where + F: Parser, + G: Parser, + O: StreamIsPartial, +{ + fn parse_next(&mut self, i: I) -> IResult { + let (i, mut o) = self.outer.parse_next(i)?; + let _ = o.complete(); + let (_, o2) = self.inner.parse_next(o)?; + Ok((i, o2)) + } +} + +/// Implementation of [`Parser::parse_to`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct ParseTo +where + P: Parser, + I: Stream, + O: crate::stream::ParseSlice, + E: ParseError, +{ + p: P, + i: core::marker::PhantomData, + o: core::marker::PhantomData, + o2: core::marker::PhantomData, + e: core::marker::PhantomData, +} + +impl ParseTo +where + P: Parser, + I: Stream, + O: crate::stream::ParseSlice, + E: ParseError, +{ + pub(crate) fn new(p: P) -> Self { + Self { + p, + i: Default::default(), + o: Default::default(), + o2: Default::default(), + e: Default::default(), + } + } +} + +impl Parser for ParseTo +where + P: Parser, + I: Stream, + O: crate::stream::ParseSlice, + E: ParseError, +{ + fn parse_next(&mut self, i: I) -> IResult { + let input = i.clone(); + let (i, o) = self.p.parse_next(i)?; + + let res = o + .parse_slice() + .ok_or_else(|| ErrMode::from_error_kind(input, ErrorKind::Verify)); + trace_result("verify", &res); + Ok((i, res?)) + } +} + +/// Implementation of [`Parser::flat_map`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct FlatMap +where + F: Parser, + G: FnMut(O) -> H, + H: Parser, +{ + f: F, + g: G, + h: core::marker::PhantomData, + i: core::marker::PhantomData, + o: core::marker::PhantomData, + o2: core::marker::PhantomData, + e: core::marker::PhantomData, +} + +impl FlatMap +where + F: Parser, + G: FnMut(O) -> H, + H: Parser, +{ + pub(crate) fn new(f: F, g: G) -> Self { + Self { + f, + g, + h: Default::default(), + i: Default::default(), + o: Default::default(), + o2: Default::default(), + e: Default::default(), + } + } +} + +impl Parser for FlatMap +where + F: Parser, + G: FnMut(O) -> H, + H: Parser, +{ + fn parse_next(&mut self, i: I) -> IResult { + let (i, o) = self.f.parse_next(i)?; + (self.g)(o).parse_next(i) + } +} + +/// Apply a [`Parser`], producing `None` on [`ErrMode::Backtrack`]. +/// +/// To chain an error up, see [`cut_err`]. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error}; +/// # use winnow::prelude::*; +/// use winnow::combinator::opt; +/// use winnow::character::alpha1; +/// # fn main() { +/// +/// fn parser(i: &str) -> IResult<&str, Option<&str>> { +/// opt(alpha1).parse_next(i) +/// } +/// +/// assert_eq!(parser("abcd;"), Ok((";", Some("abcd")))); +/// assert_eq!(parser("123;"), Ok(("123;", None))); +/// # } +/// ``` +pub fn opt, F>(mut f: F) -> impl Parser, E> +where + F: Parser, +{ + trace("opt", move |input: I| { + let i = input.clone(); + match f.parse_next(input) { + Ok((i, o)) => Ok((i, Some(o))), + Err(ErrMode::Backtrack(_)) => Ok((i, None)), + Err(e) => Err(e), + } + }) +} + +/// Calls the parser if the condition is met. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult}; +/// # use winnow::prelude::*; +/// use winnow::combinator::cond; +/// use winnow::character::alpha1; +/// # fn main() { +/// +/// fn parser(b: bool, i: &str) -> IResult<&str, Option<&str>> { +/// cond(b, alpha1).parse_next(i) +/// } +/// +/// assert_eq!(parser(true, "abcd;"), Ok((";", Some("abcd")))); +/// assert_eq!(parser(false, "abcd;"), Ok(("abcd;", None))); +/// assert_eq!(parser(true, "123;"), Err(ErrMode::Backtrack(Error::new("123;", ErrorKind::Slice)))); +/// assert_eq!(parser(false, "123;"), Ok(("123;", None))); +/// # } +/// ``` +pub fn cond, F>(b: bool, mut f: F) -> impl Parser, E> +where + I: Stream, + F: Parser, +{ + trace("cond", move |input: I| { + if b { + match f.parse_next(input) { + Ok((i, o)) => Ok((i, Some(o))), + Err(e) => Err(e), + } + } else { + Ok((input, None)) + } + }) +} + +/// Tries to apply its parser without consuming the input. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult}; +/// # use winnow::prelude::*; +/// use winnow::combinator::peek; +/// use winnow::character::alpha1; +/// # fn main() { +/// +/// let mut parser = peek(alpha1); +/// +/// assert_eq!(parser.parse_next("abcd;"), Ok(("abcd;", "abcd"))); +/// assert_eq!(parser.parse_next("123;"), Err(ErrMode::Backtrack(Error::new("123;", ErrorKind::Slice)))); +/// # } +/// ``` +#[doc(alias = "look_ahead")] +#[doc(alias = "rewind")] +pub fn peek, F>(mut f: F) -> impl Parser +where + F: Parser, +{ + trace("peek", move |input: I| { + let i = input.clone(); + match f.parse_next(input) { + Ok((_, o)) => Ok((i, o)), + Err(e) => Err(e), + } + }) +} + +/// Match the end of the [`Stream`] +/// +/// Otherwise, it will error. +/// +/// # Example +/// +/// ```rust +/// # use std::str; +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error}; +/// # use winnow::combinator::eof; +/// # use winnow::prelude::*; +/// +/// let mut parser = eof; +/// assert_eq!(parser.parse_next("abc"), Err(ErrMode::Backtrack(Error::new("abc", ErrorKind::Eof)))); +/// assert_eq!(parser.parse_next(""), Ok(("", ""))); +/// ``` +#[doc(alias = "end")] +#[doc(alias = "eoi")] +pub fn eof>(input: I) -> IResult::Slice, E> +where + I: Stream, +{ + trace("eof", move |input: I| { + if input.eof_offset() == 0 { + Ok(input.next_slice(0)) + } else { + Err(ErrMode::from_error_kind(input, ErrorKind::Eof)) + } + }) + .parse_next(input) +} + +/// Implementation of [`Parser::complete_err`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct CompleteErr { + f: F, +} + +impl CompleteErr { + pub(crate) fn new(f: F) -> Self { + Self { f } + } +} + +impl Parser for CompleteErr +where + I: Stream, + F: Parser, + E: ParseError, +{ + fn parse_next(&mut self, input: I) -> IResult { + trace("complete_err", |input: I| { + let i = input.clone(); + match (self.f).parse_next(input) { + Err(ErrMode::Incomplete(_)) => { + Err(ErrMode::from_error_kind(i, ErrorKind::Complete)) + } + rest => rest, + } + }) + .parse_next(input) + } +} + +/// Implementation of [`Parser::verify`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct Verify +where + F: Parser, + G: Fn(&O2) -> bool, + I: Clone, + O: Borrow, + O2: ?Sized, + E: ParseError, +{ + parser: F, + filter: G, + i: core::marker::PhantomData, + o: core::marker::PhantomData, + o2: core::marker::PhantomData, + e: core::marker::PhantomData, +} + +impl Verify +where + F: Parser, + G: Fn(&O2) -> bool, + I: Clone, + O: Borrow, + O2: ?Sized, + E: ParseError, +{ + pub(crate) fn new(parser: F, filter: G) -> Self { + Self { + parser, + filter, + i: Default::default(), + o: Default::default(), + o2: Default::default(), + e: Default::default(), + } + } +} + +impl Parser for Verify +where + F: Parser, + G: Fn(&O2) -> bool, + I: Clone, + O: Borrow, + O2: ?Sized, + E: ParseError, +{ + fn parse_next(&mut self, input: I) -> IResult { + let i = input.clone(); + let (input, o) = self.parser.parse_next(input)?; + + let res = if (self.filter)(o.borrow()) { + Ok((input, o)) + } else { + Err(ErrMode::from_error_kind(i, ErrorKind::Verify)) + }; + trace_result("verify", &res); + res + } +} + +/// Implementation of [`Parser::value`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct Value +where + F: Parser, + O2: Clone, +{ + parser: F, + val: O2, + i: core::marker::PhantomData, + o: core::marker::PhantomData, + e: core::marker::PhantomData, +} + +impl Value +where + F: Parser, + O2: Clone, +{ + pub(crate) fn new(parser: F, val: O2) -> Self { + Self { + parser, + val, + i: Default::default(), + o: Default::default(), + e: Default::default(), + } + } +} + +impl Parser for Value +where + F: Parser, + O2: Clone, +{ + fn parse_next(&mut self, input: I) -> IResult { + (self.parser) + .parse_next(input) + .map(|(i, _)| (i, self.val.clone())) + } +} + +/// Implementation of [`Parser::void`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct Void +where + F: Parser, +{ + parser: F, + i: core::marker::PhantomData, + o: core::marker::PhantomData, + e: core::marker::PhantomData, +} + +impl Void +where + F: Parser, +{ + pub(crate) fn new(parser: F) -> Self { + Self { + parser, + i: Default::default(), + o: Default::default(), + e: Default::default(), + } + } +} + +impl Parser for Void +where + F: Parser, +{ + fn parse_next(&mut self, input: I) -> IResult { + (self.parser).parse_next(input).map(|(i, _)| (i, ())) + } +} + +/// Succeeds if the child parser returns an error. +/// +/// **Note:** This does not advance the [`Stream`] +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult}; +/// # use winnow::prelude::*; +/// use winnow::combinator::not; +/// use winnow::character::alpha1; +/// # fn main() { +/// +/// let mut parser = not(alpha1); +/// +/// assert_eq!(parser.parse_next("123"), Ok(("123", ()))); +/// assert_eq!(parser.parse_next("abcd"), Err(ErrMode::Backtrack(Error::new("abcd", ErrorKind::Not)))); +/// # } +/// ``` +pub fn not, F>(mut parser: F) -> impl Parser +where + F: Parser, +{ + trace("not", move |input: I| { + let i = input.clone(); + match parser.parse_next(input) { + Ok(_) => Err(ErrMode::from_error_kind(i, ErrorKind::Not)), + Err(ErrMode::Backtrack(_)) => Ok((i, ())), + Err(e) => Err(e), + } + }) +} + +/// Implementation of [`Parser::recognize`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct Recognize +where + F: Parser, + I: Stream + Offset, +{ + parser: F, + i: core::marker::PhantomData, + o: core::marker::PhantomData, + e: core::marker::PhantomData, +} + +impl Recognize +where + F: Parser, + I: Stream + Offset, +{ + pub(crate) fn new(parser: F) -> Self { + Self { + parser, + i: Default::default(), + o: Default::default(), + e: Default::default(), + } + } +} + +impl Parser::Slice, E> for Recognize +where + F: Parser, + I: Stream + Offset, +{ + fn parse_next(&mut self, input: I) -> IResult::Slice, E> { + let i = input.clone(); + match (self.parser).parse_next(i) { + Ok((i, _)) => { + let offset = input.offset_to(&i); + Ok(input.next_slice(offset)) + } + Err(e) => Err(e), + } + } +} + +/// Implementation of [`Parser::with_recognized`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct WithRecognized +where + F: Parser, + I: Stream + Offset, +{ + parser: F, + i: core::marker::PhantomData, + o: core::marker::PhantomData, + e: core::marker::PhantomData, +} + +impl WithRecognized +where + F: Parser, + I: Stream + Offset, +{ + pub(crate) fn new(parser: F) -> Self { + Self { + parser, + i: Default::default(), + o: Default::default(), + e: Default::default(), + } + } +} + +impl Parser::Slice), E> for WithRecognized +where + F: Parser, + I: Stream + Offset, +{ + fn parse_next(&mut self, input: I) -> IResult::Slice), E> { + let i = input.clone(); + match (self.parser).parse_next(i) { + Ok((remaining, result)) => { + let offset = input.offset_to(&remaining); + let (remaining, recognized) = input.next_slice(offset); + Ok((remaining, (result, recognized))) + } + Err(e) => Err(e), + } + } +} + +/// Implementation of [`Parser::span`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct Span +where + F: Parser, + I: Clone + Location, +{ + parser: F, + i: core::marker::PhantomData, + o: core::marker::PhantomData, + e: core::marker::PhantomData, +} + +impl Span +where + F: Parser, + I: Clone + Location, +{ + pub(crate) fn new(parser: F) -> Self { + Self { + parser, + i: Default::default(), + o: Default::default(), + e: Default::default(), + } + } +} + +impl Parser, E> for Span +where + F: Parser, + I: Clone + Location, +{ + fn parse_next(&mut self, input: I) -> IResult, E> { + let start = input.location(); + self.parser.parse_next(input).map(move |(remaining, _)| { + let end = remaining.location(); + (remaining, (start..end)) + }) + } +} + +/// Implementation of [`Parser::with_span`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct WithSpan +where + F: Parser, + I: Clone + Location, +{ + parser: F, + i: core::marker::PhantomData, + o: core::marker::PhantomData, + e: core::marker::PhantomData, +} + +impl WithSpan +where + F: Parser, + I: Clone + Location, +{ + pub(crate) fn new(parser: F) -> Self { + Self { + parser, + i: Default::default(), + o: Default::default(), + e: Default::default(), + } + } +} + +impl Parser), E> for WithSpan +where + F: Parser, + I: Clone + Location, +{ + fn parse_next(&mut self, input: I) -> IResult), E> { + let start = input.location(); + self.parser + .parse_next(input) + .map(move |(remaining, output)| { + let end = remaining.location(); + (remaining, (output, (start..end))) + }) + } +} + +/// Transforms an [`ErrMode::Backtrack`] (recoverable) to [`ErrMode::Cut`] (unrecoverable) +/// +/// This commits the parse result, preventing alternative branch paths like with +/// [`winnow::branch::alt`][crate::branch::alt]. +/// +/// # Example +/// +/// Without `cut_err`: +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error}; +/// # use winnow::bytes::one_of; +/// # use winnow::character::digit1; +/// # use winnow::combinator::rest; +/// # use winnow::branch::alt; +/// # use winnow::sequence::preceded; +/// # use winnow::prelude::*; +/// # fn main() { +/// +/// fn parser(input: &str) -> IResult<&str, &str> { +/// alt(( +/// preceded(one_of("+-"), digit1), +/// rest +/// )).parse_next(input) +/// } +/// +/// assert_eq!(parser("+10 ab"), Ok((" ab", "10"))); +/// assert_eq!(parser("ab"), Ok(("", "ab"))); +/// assert_eq!(parser("+"), Ok(("", "+"))); +/// # } +/// ``` +/// +/// With `cut_err`: +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error}; +/// # use winnow::prelude::*; +/// # use winnow::bytes::one_of; +/// # use winnow::character::digit1; +/// # use winnow::combinator::rest; +/// # use winnow::branch::alt; +/// # use winnow::sequence::preceded; +/// use winnow::combinator::cut_err; +/// # fn main() { +/// +/// fn parser(input: &str) -> IResult<&str, &str> { +/// alt(( +/// preceded(one_of("+-"), cut_err(digit1)), +/// rest +/// )).parse_next(input) +/// } +/// +/// assert_eq!(parser("+10 ab"), Ok((" ab", "10"))); +/// assert_eq!(parser("ab"), Ok(("", "ab"))); +/// assert_eq!(parser("+"), Err(ErrMode::Cut(Error { input: "", kind: ErrorKind::Slice }))); +/// # } +/// ``` +pub fn cut_err, F>(mut parser: F) -> impl Parser +where + I: Stream, + F: Parser, +{ + trace("cut_err", move |input: I| { + parser.parse_next(input).map_err(|e| e.cut()) + }) +} + +/// Transforms an [`ErrMode::Cut`] (unrecoverable) to [`ErrMode::Backtrack`] (recoverable) +/// +/// This attempts the parse, allowing other parsers to be tried on failure, like with +/// [`winnow::branch::alt`][crate::branch::alt]. +pub fn backtrack_err, F>(mut parser: F) -> impl Parser +where + I: Stream, + F: Parser, +{ + trace("backtrack_err", move |input: I| { + parser.parse_next(input).map_err(|e| e.backtrack()) + }) +} + +/// A placeholder for a not-yet-implemented [`Parser`] +/// +/// This is analogous to the [`todo!`] macro and helps with prototyping. +/// +/// # Panic +/// +/// This will panic when parsing +/// +/// # Example +/// +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::combinator::todo; +/// +/// fn parser(input: &str) -> IResult<&str, u64> { +/// todo(input) +/// } +/// ``` +#[track_caller] +pub fn todo(input: I) -> IResult +where + I: Stream, +{ + #![allow(clippy::todo)] + trace("todo", move |_input: I| todo!("unimplemented parse")).parse_next(input) +} + +/// Implementation of [`Parser::output_into`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct OutputInto +where + F: Parser, + O: Into, +{ + parser: F, + i: core::marker::PhantomData, + o: core::marker::PhantomData, + o2: core::marker::PhantomData, + e: core::marker::PhantomData, +} + +impl OutputInto +where + F: Parser, + O: Into, +{ + pub(crate) fn new(parser: F) -> Self { + Self { + parser, + i: Default::default(), + o: Default::default(), + o2: Default::default(), + e: Default::default(), + } + } +} + +impl Parser for OutputInto +where + F: Parser, + O: Into, +{ + fn parse_next(&mut self, i: I) -> IResult { + match self.parser.parse_next(i) { + Ok((i, o)) => Ok((i, o.into())), + Err(err) => Err(err), + } + } +} + +/// Implementation of [`Parser::err_into`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct ErrInto +where + F: Parser, + E: Into, +{ + parser: F, + i: core::marker::PhantomData, + o: core::marker::PhantomData, + e: core::marker::PhantomData, + e2: core::marker::PhantomData, +} + +impl ErrInto +where + F: Parser, + E: Into, +{ + pub(crate) fn new(parser: F) -> Self { + Self { + parser, + i: Default::default(), + o: Default::default(), + e: Default::default(), + e2: Default::default(), + } + } +} + +impl Parser for ErrInto +where + F: Parser, + E: Into, +{ + fn parse_next(&mut self, i: I) -> IResult { + match self.parser.parse_next(i) { + Ok(ok) => Ok(ok), + Err(ErrMode::Backtrack(e)) => Err(ErrMode::Backtrack(e.into())), + Err(ErrMode::Cut(e)) => Err(ErrMode::Cut(e.into())), + Err(ErrMode::Incomplete(e)) => Err(ErrMode::Incomplete(e)), + } + } +} + +/// Creates an iterator from input data and a parser. +/// +/// Call the iterator's [`ParserIterator::finish`] method to get the remaining input if successful, +/// or the error value if we encountered an error. +/// +/// On [`ErrMode::Backtrack`], iteration will stop. To instead chain an error up, see [`cut_err`]. +/// +/// # Example +/// +/// ```rust +/// use winnow::{combinator::iterator, IResult, bytes::tag, character::alpha1, sequence::terminated}; +/// use std::collections::HashMap; +/// +/// let data = "abc|defg|hijkl|mnopqr|123"; +/// let mut it = iterator(data, terminated(alpha1, "|")); +/// +/// let parsed = it.map(|v| (v, v.len())).collect::>(); +/// let res: IResult<_,_> = it.finish(); +/// +/// assert_eq!(parsed, [("abc", 3usize), ("defg", 4), ("hijkl", 5), ("mnopqr", 6)].iter().cloned().collect()); +/// assert_eq!(res, Ok(("123", ()))); +/// ``` +pub fn iterator(input: I, parser: F) -> ParserIterator +where + F: Parser, + I: Stream, + E: ParseError, +{ + ParserIterator { + parser, + input, + state: Some(State::Running), + o: Default::default(), + } +} + +/// Main structure associated to [`iterator`]. +pub struct ParserIterator +where + F: Parser, + I: Stream, +{ + parser: F, + input: I, + state: Option>, + o: core::marker::PhantomData, +} + +impl ParserIterator +where + F: Parser, + I: Stream, +{ + /// Returns the remaining input if parsing was successful, or the error if we encountered an error. + pub fn finish(mut self) -> IResult { + match self.state.take().unwrap() { + State::Running | State::Done => Ok((self.input, ())), + State::Failure(e) => Err(ErrMode::Cut(e)), + State::Incomplete(i) => Err(ErrMode::Incomplete(i)), + } + } +} + +impl<'a, F, I, O, E> core::iter::Iterator for &'a mut ParserIterator +where + F: Parser, + I: Stream, +{ + type Item = O; + + fn next(&mut self) -> Option { + if let State::Running = self.state.take().unwrap() { + let input = self.input.clone(); + + match self.parser.parse_next(input) { + Ok((i, o)) => { + self.input = i; + self.state = Some(State::Running); + Some(o) + } + Err(ErrMode::Backtrack(_)) => { + self.state = Some(State::Done); + None + } + Err(ErrMode::Cut(e)) => { + self.state = Some(State::Failure(e)); + None + } + Err(ErrMode::Incomplete(i)) => { + self.state = Some(State::Incomplete(i)); + None + } + } + } else { + None + } + } +} + +enum State { + Running, + Done, + Failure(E), + Incomplete(Needed), +} + +/// Always succeeds with given value without consuming any input. +/// +/// For example, it can be used as the last alternative in `alt` to +/// specify the default case. +/// +/// **Note:** This never advances the [`Stream`] +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error}; +/// # use winnow::prelude::*; +/// use winnow::branch::alt; +/// use winnow::combinator::success; +/// +/// let mut parser = success::<_,_,Error<_>>(10); +/// assert_eq!(parser.parse_next("xyz"), Ok(("xyz", 10))); +/// +/// fn sign(input: &str) -> IResult<&str, isize> { +/// alt(( +/// '-'.value(-1), +/// '+'.value(1), +/// success::<_,_,Error<_>>(1) +/// )).parse_next(input) +/// } +/// assert_eq!(sign("+10"), Ok(("10", 1))); +/// assert_eq!(sign("-10"), Ok(("10", -1))); +/// assert_eq!(sign("10"), Ok(("10", 1))); +/// ``` +#[doc(alias = "value")] +#[doc(alias = "empty")] +pub fn success>(val: O) -> impl Parser { + trace("success", move |input: I| Ok((input, val.clone()))) +} + +/// A parser which always fails. +/// +/// For example, it can be used as the last alternative in `alt` to +/// control the error message given. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult}; +/// use winnow::combinator::fail; +/// +/// let s = "string"; +/// assert_eq!(fail::<_, &str, _>(s), Err(ErrMode::Backtrack(Error::new(s, ErrorKind::Fail)))); +/// ``` +#[doc(alias = "unexpected")] +pub fn fail>(i: I) -> IResult { + trace("fail", |i| { + Err(ErrMode::from_error_kind(i, ErrorKind::Fail)) + }) + .parse_next(i) +} + +/// Implementation of [`Parser::context`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct Context +where + F: Parser, + I: Stream, + E: ContextError, + C: Clone + crate::lib::std::fmt::Debug, +{ + parser: F, + context: C, + i: core::marker::PhantomData, + o: core::marker::PhantomData, + e: core::marker::PhantomData, +} + +impl Context +where + F: Parser, + I: Stream, + E: ContextError, + C: Clone + crate::lib::std::fmt::Debug, +{ + pub(crate) fn new(parser: F, context: C) -> Self { + Self { + parser, + context, + i: Default::default(), + o: Default::default(), + e: Default::default(), + } + } +} + +impl Parser for Context +where + F: Parser, + I: Stream, + E: ContextError, + C: Clone + crate::lib::std::fmt::Debug, +{ + fn parse_next(&mut self, i: I) -> IResult { + #[cfg(feature = "debug")] + let name = format!("context={:?}", self.context); + #[cfg(not(feature = "debug"))] + let name = "context"; + trace(name, move |i: I| { + (self.parser) + .parse_next(i.clone()) + .map_err(|err| err.map(|err| err.add_context(i, self.context.clone()))) + }) + .parse_next(i) + } +} diff --git a/vendor/winnow/src/combinator/tests.rs b/vendor/winnow/src/combinator/tests.rs new file mode 100644 index 000000000..4286286ae --- /dev/null +++ b/vendor/winnow/src/combinator/tests.rs @@ -0,0 +1,319 @@ +use super::*; + +use crate::bytes::take; +use crate::error::ErrMode; +use crate::error::Error; +use crate::error::ErrorKind; +use crate::error::Needed; +use crate::error::ParseError; +use crate::multi::count; +use crate::number::u16; +use crate::number::u8; +use crate::number::Endianness; +use crate::IResult; +use crate::Parser; +use crate::Partial; + +macro_rules! assert_parse( + ($left: expr, $right: expr) => { + let res: $crate::IResult<_, _, Error<_>> = $left; + assert_eq!(res, $right); + }; +); + +#[test] +fn eof_on_slices() { + let not_over: &[u8] = &b"Hello, world!"[..]; + let is_over: &[u8] = &b""[..]; + + let res_not_over = eof(not_over); + assert_parse!( + res_not_over, + Err(ErrMode::Backtrack(error_position!( + not_over, + ErrorKind::Eof + ))) + ); + + let res_over = eof(is_over); + assert_parse!(res_over, Ok((is_over, is_over))); +} + +#[test] +fn eof_on_strs() { + let not_over: &str = "Hello, world!"; + let is_over: &str = ""; + + let res_not_over = eof(not_over); + assert_parse!( + res_not_over, + Err(ErrMode::Backtrack(error_position!( + not_over, + ErrorKind::Eof + ))) + ); + + let res_over = eof(is_over); + assert_parse!(res_over, Ok((is_over, is_over))); +} + +#[test] +fn rest_on_slices() { + let input: &[u8] = &b"Hello, world!"[..]; + let empty: &[u8] = &b""[..]; + assert_parse!(rest(input), Ok((empty, input))); +} + +#[test] +fn rest_on_strs() { + let input: &str = "Hello, world!"; + let empty: &str = ""; + assert_parse!(rest(input), Ok((empty, input))); +} + +#[test] +fn rest_len_on_slices() { + let input: &[u8] = &b"Hello, world!"[..]; + assert_parse!(rest_len(input), Ok((input, input.len()))); +} + +use crate::lib::std::convert::From; +impl From for CustomError { + fn from(_: u32) -> Self { + CustomError + } +} + +impl ParseError for CustomError { + fn from_error_kind(_: I, _: ErrorKind) -> Self { + CustomError + } + + fn append(self, _: I, _: ErrorKind) -> Self { + CustomError + } +} + +struct CustomError; +#[allow(dead_code)] +fn custom_error(input: &[u8]) -> IResult<&[u8], &[u8], CustomError> { + //fix_error!(input, CustomError<_>, alphanumeric) + crate::character::alphanumeric1(input) +} + +#[test] +fn test_parser_flat_map() { + let input: &[u8] = &[3, 100, 101, 102, 103, 104][..]; + assert_parse!( + u8.flat_map(take).parse_next(input), + Ok((&[103, 104][..], &[100, 101, 102][..])) + ); +} + +#[allow(dead_code)] +fn test_closure_compiles_195(input: &[u8]) -> IResult<&[u8], ()> { + u8.flat_map(|num| count(u16(Endianness::Big), num as usize)) + .parse_next(input) +} + +#[test] +fn test_parser_verify_map() { + let input: &[u8] = &[50][..]; + assert_parse!( + u8.verify_map(|u| if u < 20 { Some(u) } else { None }) + .parse_next(input), + Err(ErrMode::Backtrack(Error { + input: &[50][..], + kind: ErrorKind::Verify + })) + ); + assert_parse!( + u8.verify_map(|u| if u > 20 { Some(u) } else { None }) + .parse_next(input), + Ok((&[][..], 50)) + ); +} + +#[test] +fn test_parser_map_parser() { + let input: &[u8] = &[100, 101, 102, 103, 104][..]; + assert_parse!( + take(4usize).and_then(take(2usize)).parse_next(input), + Ok((&[104][..], &[100, 101][..])) + ); +} + +#[test] +#[cfg(feature = "std")] +fn test_parser_into() { + use crate::bytes::take; + use crate::error::Error; + + let mut parser = take::<_, _, Error<_>>(3u8).output_into(); + let result: IResult<&[u8], Vec> = parser.parse_next(&b"abcdefg"[..]); + + assert_eq!(result, Ok((&b"defg"[..], vec![97, 98, 99]))); +} + +#[test] +fn opt_test() { + fn opt_abcd(i: Partial<&[u8]>) -> IResult, Option<&[u8]>> { + opt("abcd").parse_next(i) + } + + let a = &b"abcdef"[..]; + let b = &b"bcdefg"[..]; + let c = &b"ab"[..]; + assert_eq!( + opt_abcd(Partial::new(a)), + Ok((Partial::new(&b"ef"[..]), Some(&b"abcd"[..]))) + ); + assert_eq!( + opt_abcd(Partial::new(b)), + Ok((Partial::new(&b"bcdefg"[..]), None)) + ); + assert_eq!( + opt_abcd(Partial::new(c)), + Err(ErrMode::Incomplete(Needed::new(2))) + ); +} + +#[test] +fn peek_test() { + fn peek_tag(i: Partial<&[u8]>) -> IResult, &[u8]> { + peek("abcd").parse_next(i) + } + + assert_eq!( + peek_tag(Partial::new(&b"abcdef"[..])), + Ok((Partial::new(&b"abcdef"[..]), &b"abcd"[..])) + ); + assert_eq!( + peek_tag(Partial::new(&b"ab"[..])), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_eq!( + peek_tag(Partial::new(&b"xxx"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxx"[..]), + ErrorKind::Tag + ))) + ); +} + +#[test] +fn not_test() { + fn not_aaa(i: Partial<&[u8]>) -> IResult, ()> { + not("aaa").parse_next(i) + } + + assert_eq!( + not_aaa(Partial::new(&b"aaa"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"aaa"[..]), + ErrorKind::Not + ))) + ); + assert_eq!( + not_aaa(Partial::new(&b"aa"[..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + not_aaa(Partial::new(&b"abcd"[..])), + Ok((Partial::new(&b"abcd"[..]), ())) + ); +} + +#[test] +fn test_parser_verify() { + use crate::bytes::take; + + fn test(i: Partial<&[u8]>) -> IResult, &[u8]> { + take(5u8) + .verify(|slice: &[u8]| slice[0] == b'a') + .parse_next(i) + } + assert_eq!( + test(Partial::new(&b"bcd"[..])), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_eq!( + test(Partial::new(&b"bcdefg"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"bcdefg"[..]), + ErrorKind::Verify + ))) + ); + assert_eq!( + test(Partial::new(&b"abcdefg"[..])), + Ok((Partial::new(&b"fg"[..]), &b"abcde"[..])) + ); +} + +#[test] +#[allow(unused)] +fn test_parser_verify_ref() { + use crate::bytes::take; + + let mut parser1 = take(3u8).verify(|s: &[u8]| s == &b"abc"[..]); + + assert_eq!( + parser1.parse_next(&b"abcd"[..]), + Ok((&b"d"[..], &b"abc"[..])) + ); + assert_eq!( + parser1.parse_next(&b"defg"[..]), + Err(ErrMode::Backtrack(Error { + input: &b"defg"[..], + kind: ErrorKind::Verify + })) + ); + + fn parser2(i: &[u8]) -> IResult<&[u8], u32> { + crate::number::be_u32 + .verify(|val: &u32| *val < 3) + .parse_next(i) + } +} + +#[test] +#[cfg(feature = "alloc")] +fn test_parser_verify_alloc() { + use crate::bytes::take; + let mut parser1 = take(3u8) + .map(|s: &[u8]| s.to_vec()) + .verify(|s: &[u8]| s == &b"abc"[..]); + + assert_eq!( + parser1.parse_next(&b"abcd"[..]), + Ok((&b"d"[..], b"abc".to_vec())) + ); + assert_eq!( + parser1.parse_next(&b"defg"[..]), + Err(ErrMode::Backtrack(Error { + input: &b"defg"[..], + kind: ErrorKind::Verify + })) + ); +} + +#[test] +fn fail_test() { + let a = "string"; + let b = "another string"; + + assert_eq!( + fail::<_, &str, _>(a), + Err(ErrMode::Backtrack(Error { + input: a, + kind: ErrorKind::Fail + })) + ); + assert_eq!( + fail::<_, &str, _>(b), + Err(ErrMode::Backtrack(Error { + input: b, + kind: ErrorKind::Fail + })) + ); +} -- cgit v1.2.3