From dc0db358abe19481e475e10c32149b53370f1a1c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 30 May 2024 05:57:31 +0200 Subject: Merging upstream version 1.72.1+dfsg1. Signed-off-by: Daniel Baumann --- vendor/winnow/src/_topic/language.rs | 101 +- vendor/winnow/src/_topic/mod.rs | 3 + vendor/winnow/src/_topic/partial.rs | 6 +- vendor/winnow/src/_topic/performance.rs | 54 + vendor/winnow/src/_topic/stream.rs | 2 +- vendor/winnow/src/_tutorial/chapter_2.rs | 26 +- vendor/winnow/src/_tutorial/chapter_3.rs | 48 +- vendor/winnow/src/_tutorial/chapter_4.rs | 26 +- vendor/winnow/src/_tutorial/chapter_5.rs | 86 +- vendor/winnow/src/_tutorial/chapter_6.rs | 26 +- vendor/winnow/src/_tutorial/chapter_7.rs | 22 +- vendor/winnow/src/ascii/mod.rs | 1783 +++++++++++++++++++++ vendor/winnow/src/ascii/tests.rs | 1496 ++++++++++++++++++ vendor/winnow/src/binary/bits/mod.rs | 342 ++++ vendor/winnow/src/binary/bits/tests.rs | 190 +++ vendor/winnow/src/binary/mod.rs | 2550 ++++++++++++++++++++++++++++++ vendor/winnow/src/binary/tests.rs | 1214 ++++++++++++++ vendor/winnow/src/bits.rs | 71 + vendor/winnow/src/bits/mod.rs | 383 ----- vendor/winnow/src/bits/tests.rs | 190 --- vendor/winnow/src/branch.rs | 10 + vendor/winnow/src/branch/mod.rs | 275 ---- vendor/winnow/src/branch/tests.rs | 180 --- vendor/winnow/src/bytes.rs | 26 + vendor/winnow/src/bytes/mod.rs | 1167 -------------- vendor/winnow/src/bytes/tests.rs | 701 -------- vendor/winnow/src/character.rs | 342 ++++ vendor/winnow/src/character/mod.rs | 1808 --------------------- vendor/winnow/src/character/tests.rs | 1496 ------------------ vendor/winnow/src/combinator/branch.rs | 268 ++++ vendor/winnow/src/combinator/core.rs | 490 ++++++ vendor/winnow/src/combinator/mod.rs | 1441 +---------------- vendor/winnow/src/combinator/multi.rs | 987 ++++++++++++ vendor/winnow/src/combinator/parser.rs | 827 ++++++++++ vendor/winnow/src/combinator/sequence.rs | 164 ++ vendor/winnow/src/combinator/tests.rs | 972 +++++++++++- vendor/winnow/src/error.rs | 19 +- vendor/winnow/src/lib.rs | 9 +- vendor/winnow/src/macros.rs | 8 +- vendor/winnow/src/multi.rs | 124 ++ vendor/winnow/src/multi/mod.rs | 1065 ------------- vendor/winnow/src/multi/tests.rs | 743 --------- vendor/winnow/src/number.rs | 509 ++++++ vendor/winnow/src/number/mod.rs | 2388 ---------------------------- vendor/winnow/src/number/tests.rs | 1058 ------------- vendor/winnow/src/parser.rs | 124 +- vendor/winnow/src/sequence.rs | 9 + vendor/winnow/src/sequence/mod.rs | 169 -- vendor/winnow/src/sequence/tests.rs | 211 --- vendor/winnow/src/stream/mod.rs | 158 +- vendor/winnow/src/token/mod.rs | 1009 ++++++++++++ vendor/winnow/src/token/tests.rs | 700 ++++++++ vendor/winnow/src/trace/internals.rs | 128 +- vendor/winnow/src/trace/mod.rs | 5 +- 54 files changed, 14643 insertions(+), 13566 deletions(-) create mode 100644 vendor/winnow/src/_topic/performance.rs create mode 100644 vendor/winnow/src/ascii/mod.rs create mode 100644 vendor/winnow/src/ascii/tests.rs create mode 100644 vendor/winnow/src/binary/bits/mod.rs create mode 100644 vendor/winnow/src/binary/bits/tests.rs create mode 100644 vendor/winnow/src/binary/mod.rs create mode 100644 vendor/winnow/src/binary/tests.rs create mode 100644 vendor/winnow/src/bits.rs delete mode 100644 vendor/winnow/src/bits/mod.rs delete mode 100644 vendor/winnow/src/bits/tests.rs create mode 100644 vendor/winnow/src/branch.rs delete mode 100644 vendor/winnow/src/branch/mod.rs delete mode 100644 vendor/winnow/src/branch/tests.rs create mode 100644 vendor/winnow/src/bytes.rs delete mode 100644 vendor/winnow/src/bytes/mod.rs delete mode 100644 vendor/winnow/src/bytes/tests.rs create mode 100644 vendor/winnow/src/character.rs delete mode 100644 vendor/winnow/src/character/mod.rs delete mode 100644 vendor/winnow/src/character/tests.rs create mode 100644 vendor/winnow/src/combinator/branch.rs create mode 100644 vendor/winnow/src/combinator/core.rs create mode 100644 vendor/winnow/src/combinator/multi.rs create mode 100644 vendor/winnow/src/combinator/parser.rs create mode 100644 vendor/winnow/src/combinator/sequence.rs create mode 100644 vendor/winnow/src/multi.rs delete mode 100644 vendor/winnow/src/multi/mod.rs delete mode 100644 vendor/winnow/src/multi/tests.rs create mode 100644 vendor/winnow/src/number.rs delete mode 100644 vendor/winnow/src/number/mod.rs delete mode 100644 vendor/winnow/src/number/tests.rs create mode 100644 vendor/winnow/src/sequence.rs delete mode 100644 vendor/winnow/src/sequence/mod.rs delete mode 100644 vendor/winnow/src/sequence/tests.rs create mode 100644 vendor/winnow/src/token/mod.rs create mode 100644 vendor/winnow/src/token/tests.rs (limited to 'vendor/winnow/src') diff --git a/vendor/winnow/src/_topic/language.rs b/vendor/winnow/src/_topic/language.rs index d257c0b18..245bab4c7 100644 --- a/vendor/winnow/src/_topic/language.rs +++ b/vendor/winnow/src/_topic/language.rs @@ -28,8 +28,8 @@ //! use winnow::prelude::*; //! use winnow::{ //! error::ParseError, -//! sequence::delimited, -//! character::multispace0, +//! combinator::delimited, +//! ascii::multispace0, //! }; //! //! /// A combinator that takes a parser `inner` and produces a parser that also consumes both leading and @@ -62,7 +62,7 @@ //! use winnow::prelude::*; //! use winnow::{ //! error::ParseError, -//! bytes::take_till1, +//! token::take_till1, //! }; //! //! pub fn peol_comment<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, (), E> @@ -82,7 +82,7 @@ //! use winnow::prelude::*; //! use winnow::{ //! error::ParseError, -//! bytes::{tag, take_until0}, +//! token::{tag, take_until0}, //! }; //! //! pub fn pinline_comment<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, (), E> { @@ -107,14 +107,14 @@ //! use winnow::prelude::*; //! use winnow::{ //! stream::AsChar, -//! bytes::take_while0, -//! bytes::one_of, +//! token::take_while, +//! token::one_of, //! }; //! //! pub fn identifier(input: &str) -> IResult<&str, &str> { //! ( //! one_of(|c: char| c.is_alpha() || c == '_'), -//! take_while0(|c: char| c.is_alphanum() || c == '_') +//! take_while(0.., |c: char| c.is_alphanum() || c == '_') //! ) //! .recognize() //! .parse_next(input) @@ -122,8 +122,8 @@ //! ``` //! //! Let's say we apply this to the identifier `hello_world123abc`. The first element of the tuple -//! would uses [`one_of`][crate::bytes::one_of] which would recognize `h`. The tuple ensures that -//! `ello_world123abc` will be piped to the next [`take_while0`][crate::bytes::take_while0] parser, +//! would uses [`one_of`][crate::token::one_of] which would recognize `h`. The tuple ensures that +//! `ello_world123abc` will be piped to the next [`take_while`][crate::token::take_while] parser, //! which recognizes every remaining character. However, the tuple returns a tuple of the results //! of its sub-parsers. The [`recognize`][crate::Parser::recognize] parser produces a `&str` of the //! input text that was parsed, which in this case is the entire `&str` `hello_world123abc`. @@ -146,9 +146,6 @@ //! string slice to an integer value is slightly simpler. You can also strip the `_` from the string //! slice that is returned, which is demonstrated in the second hexadecimal number parser. //! -//! If you wish to limit the number of digits in a valid integer literal, replace `many1` with -//! `many_m_n` in the recipes. -//! //! #### Hexadecimal //! //! The parser outputs the string slice of the digits without the leading `0x`/`0X`. @@ -156,18 +153,18 @@ //! ```rust //! use winnow::prelude::*; //! use winnow::{ -//! branch::alt, -//! multi::{many0, many1}, -//! sequence::{preceded, terminated}, -//! bytes::one_of, -//! bytes::tag, +//! combinator::alt, +//! combinator::{repeat}, +//! combinator::{preceded, terminated}, +//! token::one_of, +//! token::tag, //! }; //! //! fn hexadecimal(input: &str) -> IResult<&str, &str> { // <'a, E: ParseError<&'a str>> //! preceded( //! alt(("0x", "0X")), -//! many1( -//! terminated(one_of("0123456789abcdefABCDEF"), many0('_').map(|()| ())) +//! repeat(1.., +//! terminated(one_of("0123456789abcdefABCDEF"), repeat(0.., '_').map(|()| ())) //! ).map(|()| ()).recognize() //! ).parse_next(input) //! } @@ -178,20 +175,20 @@ //! ```rust //! use winnow::prelude::*; //! use winnow::{ -//! branch::alt, -//! multi::{many0, many1}, -//! sequence::{preceded, terminated}, -//! bytes::one_of, -//! bytes::tag, +//! combinator::alt, +//! combinator::{repeat}, +//! combinator::{preceded, terminated}, +//! token::one_of, +//! token::tag, //! }; //! //! fn hexadecimal_value(input: &str) -> IResult<&str, i64> { //! preceded( //! alt(("0x", "0X")), -//! many1( -//! terminated(one_of("0123456789abcdefABCDEF"), many0('_').map(|()| ())) +//! repeat(1.., +//! terminated(one_of("0123456789abcdefABCDEF"), repeat(0.., '_').map(|()| ())) //! ).map(|()| ()).recognize() -//! ).map_res( +//! ).try_map( //! |out: &str| i64::from_str_radix(&str::replace(&out, "_", ""), 16) //! ).parse_next(input) //! } @@ -202,18 +199,18 @@ //! ```rust //! use winnow::prelude::*; //! use winnow::{ -//! branch::alt, -//! multi::{many0, many1}, -//! sequence::{preceded, terminated}, -//! bytes::one_of, -//! bytes::tag, +//! combinator::alt, +//! combinator::{repeat}, +//! combinator::{preceded, terminated}, +//! token::one_of, +//! token::tag, //! }; //! //! fn octal(input: &str) -> IResult<&str, &str> { //! preceded( //! alt(("0o", "0O")), -//! many1( -//! terminated(one_of("01234567"), many0('_').map(|()| ())) +//! repeat(1.., +//! terminated(one_of("01234567"), repeat(0.., '_').map(|()| ())) //! ).map(|()| ()).recognize() //! ).parse_next(input) //! } @@ -224,18 +221,18 @@ //! ```rust //! use winnow::prelude::*; //! use winnow::{ -//! branch::alt, -//! multi::{many0, many1}, -//! sequence::{preceded, terminated}, -//! bytes::one_of, -//! bytes::tag, +//! combinator::alt, +//! combinator::{repeat}, +//! combinator::{preceded, terminated}, +//! token::one_of, +//! token::tag, //! }; //! //! fn binary(input: &str) -> IResult<&str, &str> { //! preceded( //! alt(("0b", "0B")), -//! many1( -//! terminated(one_of("01"), many0('_').map(|()| ())) +//! repeat(1.., +//! terminated(one_of("01"), repeat(0.., '_').map(|()| ())) //! ).map(|()| ()).recognize() //! ).parse_next(input) //! } @@ -247,14 +244,14 @@ //! use winnow::prelude::*; //! use winnow::{ //! IResult, -//! multi::{many0, many1}, -//! sequence::terminated, -//! bytes::one_of, +//! combinator::{repeat}, +//! combinator::terminated, +//! token::one_of, //! }; //! //! fn decimal(input: &str) -> IResult<&str, &str> { -//! many1( -//! terminated(one_of("0123456789"), many0('_').map(|()| ())) +//! repeat(1.., +//! terminated(one_of("0123456789"), repeat(0.., '_').map(|()| ())) //! ).map(|()| ()) //! .recognize() //! .parse_next(input) @@ -268,11 +265,11 @@ //! ```rust //! use winnow::prelude::*; //! use winnow::{ -//! branch::alt, -//! multi::{many0, many1}, +//! combinator::alt, +//! combinator::{repeat}, //! combinator::opt, -//! sequence::{preceded, terminated}, -//! bytes::one_of, +//! combinator::{preceded, terminated}, +//! token::one_of, //! }; //! //! fn float(input: &str) -> IResult<&str, &str> { @@ -308,8 +305,8 @@ //! } //! //! fn decimal(input: &str) -> IResult<&str, &str> { -//! many1( -//! terminated(one_of("0123456789"), many0('_').map(|()| ())) +//! repeat(1.., +//! terminated(one_of("0123456789"), repeat(0.., '_').map(|()| ())) //! ). //! map(|()| ()) //! .recognize() diff --git a/vendor/winnow/src/_topic/mod.rs b/vendor/winnow/src/_topic/mod.rs index 76687277a..72c8145fe 100644 --- a/vendor/winnow/src/_topic/mod.rs +++ b/vendor/winnow/src/_topic/mod.rs @@ -12,6 +12,7 @@ //! - [HTTP][http] //! - Special Topics: //! - [Implementing `FromStr`][fromstr] +//! - [Performance][performance] //! - [Parsing Partial Input][partial] //! - [Custom stream][stream] //! - [Custom errors][error] @@ -19,6 +20,7 @@ //! See also parsers written with `winnow`: //! //! - [`toml_edit`](https://crates.io/crates/toml_edit) +//! - [`hcl-edit`](https://crates.io/crates/hcl-edit) pub mod arithmetic; pub mod error; @@ -28,6 +30,7 @@ pub mod ini; pub mod json; pub mod language; pub mod partial; +pub mod performance; pub mod s_expression; pub mod stream; pub mod why; diff --git a/vendor/winnow/src/_topic/partial.rs b/vendor/winnow/src/_topic/partial.rs index 263d7f127..19895d35a 100644 --- a/vendor/winnow/src/_topic/partial.rs +++ b/vendor/winnow/src/_topic/partial.rs @@ -21,7 +21,7 @@ //! Caveats: //! - `winnow` takes the approach of re-parsing from scratch. Chunks should be relatively small to //! prevent the re-parsing overhead from dominating. -//! - Parsers like [`many0`] do not know when an `eof` is from insufficient data or the end of the +//! - Parsers like [`repeat`] do not know when an `eof` is from insufficient data or the end of the //! stream, causing them to always report [`Incomplete`]. //! //! # Example @@ -38,9 +38,9 @@ #![allow(unused_imports)] // Used for intra-doc links +use crate::binary::length_value; +use crate::combinator::repeat; use crate::error::ErrMode::Incomplete; use crate::error::Needed; -use crate::multi::length_value; -use crate::multi::many0; use crate::stream::Partial; use crate::stream::StreamIsPartial; diff --git a/vendor/winnow/src/_topic/performance.rs b/vendor/winnow/src/_topic/performance.rs new file mode 100644 index 000000000..fac12da4c --- /dev/null +++ b/vendor/winnow/src/_topic/performance.rs @@ -0,0 +1,54 @@ +//! # Performance +//! +//! ## Runtime Performance +//! +//! See also the general Rust [Performance Book](https://nnethercote.github.io/perf-book/) +//! +//! Tips +//! - When enough cases of an [`alt`] have unique prefixes, prefer [`dispatch`] +//! - When parsing text, try to parse is as bytes (`u8`) rather than `char`s ([`BStr`] can make +//! debugging easier) +//! - Find simplified subsets of the grammar to parse, falling back to the full grammar when it +//! doesn't work. For example, when parsing json strings, parse them without support for escapes, +//! falling back to escape support if it fails. +//! - Watch for large return types. A surprising place these can show up is when chaining parsers +//! with a tuple. +//! +//! ## Built-time Performance +//! +//! Returning complex types as `impl Trait` can negatively impact build times. This can hit in +//! surprising cases like: +//! ```rust +//! # use winnow::prelude::*; +//! fn foo() -> impl Parser +//! # where +//! # I: winnow::stream::Stream, +//! # I: winnow::stream::StreamIsPartial, +//! # E: winnow::error::ParseError, +//! { +//! // ...some chained combinators... +//! # winnow::token::any +//! } +//! ``` +//! +//! Instead, wrap the combinators in a closure to simplify the type: +//! ```rust +//! # use winnow::prelude::*; +//! fn foo() -> impl Parser +//! # where +//! # I: winnow::stream::Stream, +//! # I: winnow::stream::StreamIsPartial, +//! # E: winnow::error::ParseError, +//! { +//! move |input: I| { +//! // ...some chained combinators... +//! # winnow::token::any +//! .parse_next(input) +//! } +//! } +//! ``` + +#![allow(unused_imports)] +use crate::combinator::alt; +use crate::combinator::dispatch; +use crate::stream::BStr; diff --git a/vendor/winnow/src/_topic/stream.rs b/vendor/winnow/src/_topic/stream.rs index 92841eda2..7455e185b 100644 --- a/vendor/winnow/src/_topic/stream.rs +++ b/vendor/winnow/src/_topic/stream.rs @@ -17,7 +17,7 @@ //! //! ```rust //! # use winnow::prelude::*; -//! # use winnow::bytes::tag; +//! # use winnow::token::tag; //! # type MyStream<'i> = &'i str; //! # type Output<'i> = &'i str; //! fn parser(i: MyStream<'_>) -> IResult, Output<'_>> { diff --git a/vendor/winnow/src/_tutorial/chapter_2.rs b/vendor/winnow/src/_tutorial/chapter_2.rs index a7f9ea9e7..49b61f3f4 100644 --- a/vendor/winnow/src/_tutorial/chapter_2.rs +++ b/vendor/winnow/src/_tutorial/chapter_2.rs @@ -61,7 +61,7 @@ //! ```rust //! # use winnow::Parser; //! # use winnow::IResult; -//! use winnow::bytes::one_of; +//! use winnow::token::one_of; //! //! fn parse_digits(input: &str) -> IResult<&str, char> { //! one_of("0123456789abcdefgABCDEFG").parse_next(input) @@ -87,7 +87,7 @@ //! > list: &'static str //! > ) -> impl Parser<&'i str, char, Error<&'i str>> { //! > // ... -//! > # winnow::bytes::one_of(list) +//! > # winnow::token::one_of(list) //! > } //! > ``` //! > If you have not programmed in a language where functions are values, the type signature of the @@ -97,18 +97,18 @@ //! > configurable or stateful parsers. //! //! Some of character classes are common enough that a named parser is provided, like with: -//! - [`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` -//! - [`tab`][crate::character::tab]: Matches a tab character `\t` +//! - [`line_ending`][crate::ascii::line_ending]: Recognizes an end of line (both `\n` and `\r\n`) +//! - [`newline`][crate::ascii::newline]: Matches a newline character `\n` +//! - [`tab`][crate::ascii::tab]: Matches a tab character `\t` //! -//! You can then capture sequences of these characters with parsers like [`take_while1`]. +//! You can then capture sequences of these characters with parsers like [`take_while`]. //! ```rust //! # use winnow::Parser; //! # use winnow::IResult; -//! use winnow::bytes::take_while1; +//! use winnow::token::take_while; //! //! fn parse_digits(input: &str) -> IResult<&str, &str> { -//! take_while1("0123456789abcdefgABCDEFG").parse_next(input) +//! take_while(1.., "0123456789abcdefgABCDEFG").parse_next(input) //! } //! //! fn main() { @@ -126,7 +126,7 @@ //! ```rust //! # use winnow::Parser; //! # use winnow::IResult; -//! use winnow::character::hex_digit1; +//! use winnow::ascii::hex_digit1; //! //! fn parse_digits(input: &str) -> IResult<&str, &str> { //! hex_digit1.parse_next(input) @@ -144,11 +144,11 @@ //! ``` #![allow(unused_imports)] -use crate::bytes::one_of; -use crate::bytes::tag; -use crate::bytes::take_while1; -use crate::character::hex_digit1; +use crate::ascii::hex_digit1; use crate::stream::ContainsToken; +use crate::token::one_of; +use crate::token::tag; +use crate::token::take_while; use crate::Parser; use std::ops::RangeInclusive; diff --git a/vendor/winnow/src/_tutorial/chapter_3.rs b/vendor/winnow/src/_tutorial/chapter_3.rs index 29c5db457..8d307e324 100644 --- a/vendor/winnow/src/_tutorial/chapter_3.rs +++ b/vendor/winnow/src/_tutorial/chapter_3.rs @@ -10,7 +10,7 @@ //! Now that we can create more interesting parsers, we can sequence them together, like: //! //! ```rust -//! # use winnow::bytes::take_while1; +//! # use winnow::token::take_while; //! # use winnow::Parser; //! # use winnow::IResult; //! # @@ -19,7 +19,7 @@ //! } //! //! fn parse_digits(input: &str) -> IResult<&str, &str> { -//! take_while1(( +//! take_while(1.., ( //! ('0'..='9'), //! ('A'..='F'), //! ('a'..='f'), @@ -40,7 +40,7 @@ //! //! To sequence these together, you can just put them in a tuple: //! ```rust -//! # use winnow::bytes::take_while1; +//! # use winnow::token::take_while; //! # use winnow::Parser; //! # use winnow::IResult; //! # @@ -49,7 +49,7 @@ //! # } //! # //! # fn parse_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # ('A'..='F'), //! # ('a'..='f'), @@ -75,17 +75,17 @@ //! Frequently, you won't care about the tag and you can instead use one of the provided combinators, //! like [`preceded`]: //! ```rust -//! # use winnow::bytes::take_while1; +//! # use winnow::token::take_while; //! # use winnow::Parser; //! # use winnow::IResult; -//! use winnow::sequence::preceded; +//! use winnow::combinator::preceded; //! //! # fn parse_prefix(input: &str) -> IResult<&str, &str> { //! # "0x".parse_next(input) //! # } //! # //! # fn parse_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # ('A'..='F'), //! # ('a'..='f'), @@ -120,8 +120,8 @@ //! ```rust //! # use winnow::IResult; //! # use winnow::Parser; -//! # use winnow::bytes::take_while1; -//! use winnow::branch::alt; +//! # use winnow::token::take_while; +//! use winnow::combinator::alt; //! //! fn parse_digits(input: &str) -> IResult<&str, (&str, &str)> { //! alt(( @@ -134,25 +134,25 @@ //! //! // ... //! # fn parse_bin_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_oct_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_dec_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # )).parse_next(input) //! # } //! # //! # fn parse_hex_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # ('A'..='F'), //! # ('a'..='f'), @@ -174,14 +174,14 @@ //! //! Sometimes a giant if/else-if ladder can be slow and you'd rather have a `match` statement for //! branches of your parser that have unique prefixes. In this case, you can use the -//! [`dispatch`][crate::branch::dispatch] macro: +//! [`dispatch`][crate::combinator::dispatch] macro: //! //! ```rust //! # use winnow::IResult; //! # use winnow::Parser; -//! # use winnow::bytes::take_while1; -//! use winnow::branch::dispatch; -//! use winnow::bytes::take; +//! # use winnow::token::take_while; +//! use winnow::combinator::dispatch; +//! use winnow::token::take; //! use winnow::combinator::fail; //! //! fn parse_digits(input: &str) -> IResult<&str, &str> { @@ -196,25 +196,25 @@ //! //! // ... //! # fn parse_bin_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_oct_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_dec_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # )).parse_next(input) //! # } //! # //! # fn parse_hex_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # ('A'..='F'), //! # ('a'..='f'), @@ -234,9 +234,9 @@ //! ``` #![allow(unused_imports)] -use crate::branch::alt; -use crate::branch::dispatch; -use crate::sequence::preceded; +use crate::combinator::alt; +use crate::combinator::dispatch; +use crate::combinator::preceded; pub use super::chapter_2 as previous; pub use super::chapter_4 as next; diff --git a/vendor/winnow/src/_tutorial/chapter_4.rs b/vendor/winnow/src/_tutorial/chapter_4.rs index 5d19a05bc..315d185ba 100644 --- a/vendor/winnow/src/_tutorial/chapter_4.rs +++ b/vendor/winnow/src/_tutorial/chapter_4.rs @@ -22,7 +22,7 @@ //! ```rust //! # use winnow::Parser; //! # use winnow::IResult; -//! # use winnow::character::digit1; +//! # use winnow::ascii::digit1; //! # //! fn parse_digits(input: &str) -> IResult<&str, usize> { //! digit1 @@ -41,47 +41,47 @@ //! } //! ``` //! -//! `Parser::parse_to` is just a convenient form of [`Parser::map_res`] which we can use to handle +//! `Parser::parse_to` is just a convenient form of [`Parser::try_map`] which we can use to handle //! all radices of numbers: //! ```rust //! # use winnow::IResult; //! # use winnow::Parser; -//! # use winnow::bytes::take_while1; -//! use winnow::branch::dispatch; -//! use winnow::bytes::take; +//! # use winnow::token::take_while; +//! use winnow::combinator::dispatch; +//! use winnow::token::take; //! use winnow::combinator::fail; //! //! fn parse_digits(input: &str) -> IResult<&str, usize> { //! dispatch!(take(2usize); -//! "0b" => parse_bin_digits.map_res(|s| usize::from_str_radix(s, 2)), -//! "0o" => parse_oct_digits.map_res(|s| usize::from_str_radix(s, 8)), -//! "0d" => parse_dec_digits.map_res(|s| usize::from_str_radix(s, 10)), -//! "0x" => parse_hex_digits.map_res(|s| usize::from_str_radix(s, 16)), +//! "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)), +//! "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)), +//! "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)), +//! "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)), //! _ => fail, //! ).parse_next(input) //! } //! //! // ... //! # fn parse_bin_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_oct_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_dec_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # )).parse_next(input) //! # } //! # //! # fn parse_hex_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # ('A'..='F'), //! # ('a'..='f'), diff --git a/vendor/winnow/src/_tutorial/chapter_5.rs b/vendor/winnow/src/_tutorial/chapter_5.rs index b703bcf5c..3a4be4b32 100644 --- a/vendor/winnow/src/_tutorial/chapter_5.rs +++ b/vendor/winnow/src/_tutorial/chapter_5.rs @@ -1,55 +1,55 @@ //! # Chapter 5: Repetition //! //! In [`chapter_3`], we covered how to sequence different parsers into a tuple but sometimes you need to run a -//! single parser many times into a [`Vec`]. +//! single parser multiple times, collecting the result into a [`Vec`]. //! -//! Let's take our `parse_digits` and collect a list of them with [`many0`]: +//! Let's take our `parse_digits` and collect a list of them with [`repeat`]: //! ```rust //! # use winnow::IResult; //! # use winnow::Parser; -//! # use winnow::bytes::take_while1; -//! # use winnow::branch::dispatch; -//! # use winnow::bytes::take; +//! # use winnow::token::take_while; +//! # use winnow::combinator::dispatch; +//! # use winnow::token::take; //! # use winnow::combinator::fail; //! use winnow::combinator::opt; -//! use winnow::multi::many0; -//! use winnow::sequence::terminated; +//! use winnow::combinator::repeat; +//! use winnow::combinator::terminated; //! //! fn parse_list(input: &str) -> IResult<&str, Vec> { -//! many0(terminated(parse_digits, opt(','))).parse_next(input) +//! repeat(0.., terminated(parse_digits, opt(','))).parse_next(input) //! } //! //! // ... //! # fn parse_digits(input: &str) -> IResult<&str, usize> { //! # dispatch!(take(2usize); -//! # "0b" => parse_bin_digits.map_res(|s| usize::from_str_radix(s, 2)), -//! # "0o" => parse_oct_digits.map_res(|s| usize::from_str_radix(s, 8)), -//! # "0d" => parse_dec_digits.map_res(|s| usize::from_str_radix(s, 10)), -//! # "0x" => parse_hex_digits.map_res(|s| usize::from_str_radix(s, 16)), +//! # "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)), +//! # "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)), +//! # "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)), +//! # "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)), //! # _ => fail, //! # ).parse_next(input) //! # } //! # //! # fn parse_bin_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_oct_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_dec_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # )).parse_next(input) //! # } //! # //! # fn parse_hex_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # ('A'..='F'), //! # ('a'..='f'), @@ -73,11 +73,11 @@ //! ```rust //! # use winnow::IResult; //! # use winnow::Parser; -//! # use winnow::bytes::take_while1; -//! # use winnow::branch::dispatch; -//! # use winnow::bytes::take; +//! # use winnow::token::take_while; +//! # use winnow::combinator::dispatch; +//! # use winnow::token::take; //! # use winnow::combinator::fail; -//! use winnow::multi::separated0; +//! use winnow::combinator::separated0; //! //! fn parse_list(input: &str) -> IResult<&str, Vec> { //! separated0(parse_digits, ",").parse_next(input) @@ -86,34 +86,34 @@ //! // ... //! # fn parse_digits(input: &str) -> IResult<&str, usize> { //! # dispatch!(take(2usize); -//! # "0b" => parse_bin_digits.map_res(|s| usize::from_str_radix(s, 2)), -//! # "0o" => parse_oct_digits.map_res(|s| usize::from_str_radix(s, 8)), -//! # "0d" => parse_dec_digits.map_res(|s| usize::from_str_radix(s, 10)), -//! # "0x" => parse_hex_digits.map_res(|s| usize::from_str_radix(s, 16)), +//! # "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)), +//! # "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)), +//! # "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)), +//! # "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)), //! # _ => fail, //! # ).parse_next(input) //! # } //! # //! # fn parse_bin_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_oct_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_dec_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # )).parse_next(input) //! # } //! # //! # fn parse_hex_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # ('A'..='F'), //! # ('a'..='f'), @@ -132,17 +132,17 @@ //! } //! ``` //! -//! If you look closely at [`many0`], it isn't collecting directly into a [`Vec`] but +//! If you look closely at [`repeat`], it isn't collecting directly into a [`Vec`] but //! [`Accumulate`] to gather the results. This let's us make more complex parsers than we did in //! [`chapter_2`] by accumulating the results into a `()` and [`recognize`][Parser::recognize]-ing the captured input: //! ```rust //! # use winnow::IResult; //! # use winnow::Parser; -//! # use winnow::bytes::take_while1; -//! # use winnow::branch::dispatch; -//! # use winnow::bytes::take; +//! # use winnow::token::take_while; +//! # use winnow::combinator::dispatch; +//! # use winnow::token::take; //! # use winnow::combinator::fail; -//! # use winnow::multi::separated0; +//! # use winnow::combinator::separated0; //! # //! fn recognize_list(input: &str) -> IResult<&str, &str> { //! parse_list.recognize().parse_next(input) @@ -155,34 +155,34 @@ //! // ... //! # fn parse_digits(input: &str) -> IResult<&str, usize> { //! # dispatch!(take(2usize); -//! # "0b" => parse_bin_digits.map_res(|s| usize::from_str_radix(s, 2)), -//! # "0o" => parse_oct_digits.map_res(|s| usize::from_str_radix(s, 8)), -//! # "0d" => parse_dec_digits.map_res(|s| usize::from_str_radix(s, 10)), -//! # "0x" => parse_hex_digits.map_res(|s| usize::from_str_radix(s, 16)), +//! # "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)), +//! # "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)), +//! # "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)), +//! # "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)), //! # _ => fail, //! # ).parse_next(input) //! # } //! # //! # fn parse_bin_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_oct_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_dec_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # )).parse_next(input) //! # } //! # //! # fn parse_hex_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # ('A'..='F'), //! # ('a'..='f'), @@ -204,8 +204,8 @@ #![allow(unused_imports)] use super::chapter_2; use super::chapter_3; -use crate::multi::many0; -use crate::multi::separated0; +use crate::combinator::repeat; +use crate::combinator::separated0; use crate::stream::Accumulate; use crate::Parser; use std::vec::Vec; diff --git a/vendor/winnow/src/_tutorial/chapter_6.rs b/vendor/winnow/src/_tutorial/chapter_6.rs index 74169429d..268e38a31 100644 --- a/vendor/winnow/src/_tutorial/chapter_6.rs +++ b/vendor/winnow/src/_tutorial/chapter_6.rs @@ -14,8 +14,8 @@ //! ```rust //! # use winnow::IResult; //! # use winnow::Parser; -//! # use winnow::bytes::take_while1; -//! # use winnow::branch::alt; +//! # use winnow::token::take_while; +//! # use winnow::combinator::alt; //! use winnow::error::VerboseError; //! //! fn parse_digits(input: &str) -> IResult<&str, (&str, &str), VerboseError<&str>> { @@ -29,25 +29,25 @@ //! //! // ... //! # fn parse_bin_digits(input: &str) -> IResult<&str, &str, VerboseError<&str>> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_oct_digits(input: &str) -> IResult<&str, &str, VerboseError<&str>> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_dec_digits(input: &str) -> IResult<&str, &str, VerboseError<&str>> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # )).parse_next(input) //! # } //! # //! # fn parse_hex_digits(input: &str) -> IResult<&str, &str, VerboseError<&str>> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # ('A'..='F'), //! # ('a'..='f'), @@ -89,8 +89,8 @@ //! ```rust //! # use winnow::IResult; //! # use winnow::Parser; -//! # use winnow::bytes::take_while1; -//! # use winnow::branch::alt; +//! # use winnow::token::take_while; +//! # use winnow::combinator::alt; //! # use winnow::error::VerboseError; //! use winnow::combinator::cut_err; //! @@ -105,25 +105,25 @@ //! //! // ... //! # fn parse_bin_digits(input: &str) -> IResult<&str, &str, VerboseError<&str>> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_oct_digits(input: &str) -> IResult<&str, &str, VerboseError<&str>> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_dec_digits(input: &str) -> IResult<&str, &str, VerboseError<&str>> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # )).parse_next(input) //! # } //! # //! # fn parse_hex_digits(input: &str) -> IResult<&str, &str, VerboseError<&str>> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # ('A'..='F'), //! # ('a'..='f'), @@ -145,7 +145,7 @@ #![allow(unused_imports)] use super::chapter_1; use super::chapter_3; -use crate::branch::alt; +use crate::combinator::alt; use crate::combinator::cut_err; use crate::error::ErrMode; use crate::error::Error; diff --git a/vendor/winnow/src/_tutorial/chapter_7.rs b/vendor/winnow/src/_tutorial/chapter_7.rs index 8c27cb5ad..c20607c36 100644 --- a/vendor/winnow/src/_tutorial/chapter_7.rs +++ b/vendor/winnow/src/_tutorial/chapter_7.rs @@ -27,9 +27,9 @@ //! winnow provides some helpers for this: //! ```rust //! # use winnow::IResult; -//! # use winnow::bytes::take_while1; -//! # use winnow::branch::dispatch; -//! # use winnow::bytes::take; +//! # use winnow::token::take_while; +//! # use winnow::combinator::dispatch; +//! # use winnow::token::take; //! # use winnow::combinator::fail; //! use winnow::Parser; //! use winnow::error::Error; @@ -51,34 +51,34 @@ //! // ... //! # fn parse_digits(input: &str) -> IResult<&str, usize> { //! # dispatch!(take(2usize); -//! # "0b" => parse_bin_digits.map_res(|s| usize::from_str_radix(s, 2)), -//! # "0o" => parse_oct_digits.map_res(|s| usize::from_str_radix(s, 8)), -//! # "0d" => parse_dec_digits.map_res(|s| usize::from_str_radix(s, 10)), -//! # "0x" => parse_hex_digits.map_res(|s| usize::from_str_radix(s, 16)), +//! # "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)), +//! # "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)), +//! # "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)), +//! # "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)), //! # _ => fail, //! # ).parse_next(input) //! # } //! # //! # fn parse_bin_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_oct_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='7'), //! # )).parse_next(input) //! # } //! # //! # fn parse_dec_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # )).parse_next(input) //! # } //! # //! # fn parse_hex_digits(input: &str) -> IResult<&str, &str> { -//! # take_while1(( +//! # take_while(1.., ( //! # ('0'..='9'), //! # ('A'..='F'), //! # ('a'..='f'), diff --git a/vendor/winnow/src/ascii/mod.rs b/vendor/winnow/src/ascii/mod.rs new file mode 100644 index 000000000..4ada7c00b --- /dev/null +++ b/vendor/winnow/src/ascii/mod.rs @@ -0,0 +1,1783 @@ +//! Character specific parsers and combinators +//! +//! Functions recognizing specific characters + +#[cfg(test)] +mod tests; + +use crate::lib::std::ops::{Add, Shl}; + +use crate::combinator::alt; +use crate::token::one_of; + +use crate::combinator::cut_err; +use crate::combinator::opt; +use crate::error::ParseError; +use crate::error::{ErrMode, ErrorKind, Needed}; +use crate::stream::ContainsToken; +use crate::stream::{AsBStr, AsChar, Offset, ParseSlice, Stream, StreamIsPartial}; +use crate::stream::{Compare, CompareResult}; +use crate::token::take_while; +use crate::trace::trace; +use crate::IResult; +use crate::Parser; + +/// Recognizes the string "\r\n". +/// +/// *Complete version*: Will return an error if there's not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult}; +/// # use winnow::ascii::crlf; +/// fn parser(input: &str) -> IResult<&str, &str> { +/// crlf(input) +/// } +/// +/// assert_eq!(parser("\r\nc"), Ok(("c", "\r\n"))); +/// assert_eq!(parser("ab\r\nc"), Err(ErrMode::Backtrack(Error::new("ab\r\nc", ErrorKind::Tag)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::crlf; +/// assert_eq!(crlf::<_, Error<_>>(Partial::new("\r\nc")), Ok((Partial::new("c"), "\r\n"))); +/// assert_eq!(crlf::<_, Error<_>>(Partial::new("ab\r\nc")), Err(ErrMode::Backtrack(Error::new(Partial::new("ab\r\nc"), ErrorKind::Tag)))); +/// assert_eq!(crlf::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(2)))); +/// ``` +#[inline(always)] +pub fn crlf>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + I: Compare<&'static str>, +{ + trace("crlf", move |input: I| "\r\n".parse_next(input)).parse_next(input) +} + +/// Recognizes a string of any char except '\r\n' or '\n'. +/// +/// *Complete version*: Will return an error if there's not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; +/// # use winnow::ascii::not_line_ending; +/// fn parser(input: &str) -> IResult<&str, &str> { +/// not_line_ending(input) +/// } +/// +/// assert_eq!(parser("ab\r\nc"), Ok(("\r\nc", "ab"))); +/// assert_eq!(parser("ab\nc"), Ok(("\nc", "ab"))); +/// assert_eq!(parser("abc"), Ok(("", "abc"))); +/// assert_eq!(parser(""), Ok(("", ""))); +/// assert_eq!(parser("a\rb\nc"), Err(ErrMode::Backtrack(Error { input: "a\rb\nc", kind: ErrorKind::Tag }))); +/// assert_eq!(parser("a\rbc"), Err(ErrMode::Backtrack(Error { input: "a\rbc", kind: ErrorKind::Tag }))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::not_line_ending; +/// assert_eq!(not_line_ending::<_, Error<_>>(Partial::new("ab\r\nc")), Ok((Partial::new("\r\nc"), "ab"))); +/// assert_eq!(not_line_ending::<_, Error<_>>(Partial::new("abc")), Err(ErrMode::Incomplete(Needed::Unknown))); +/// assert_eq!(not_line_ending::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::Unknown))); +/// assert_eq!(not_line_ending::<_, Error<_>>(Partial::new("a\rb\nc")), Err(ErrMode::Backtrack(Error::new(Partial::new("a\rb\nc"), ErrorKind::Tag )))); +/// assert_eq!(not_line_ending::<_, Error<_>>(Partial::new("a\rbc")), Err(ErrMode::Backtrack(Error::new(Partial::new("a\rbc"), ErrorKind::Tag )))); +/// ``` +#[inline(always)] +pub fn not_line_ending>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream + AsBStr, + I: Compare<&'static str>, + ::Token: AsChar, +{ + trace("not_line_ending", move |input: I| { + if ::is_partial_supported() { + not_line_ending_::<_, _, true>(input) + } else { + not_line_ending_::<_, _, false>(input) + } + }) + .parse_next(input) +} + +fn not_line_ending_, const PARTIAL: bool>( + input: I, +) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream + AsBStr, + I: Compare<&'static str>, + ::Token: AsChar, +{ + match input.offset_for(|item| { + let c = item.as_char(); + c == '\r' || c == '\n' + }) { + None if PARTIAL && input.is_partial() => Err(ErrMode::Incomplete(Needed::Unknown)), + None => Ok(input.next_slice(input.eof_offset())), + Some(offset) => { + let (new_input, res) = input.next_slice(offset); + let bytes = new_input.as_bstr(); + let nth = bytes[0]; + if nth == b'\r' { + let comp = new_input.compare("\r\n"); + match comp { + //FIXME: calculate the right index + CompareResult::Ok => {} + CompareResult::Incomplete if PARTIAL && input.is_partial() => { + return Err(ErrMode::Incomplete(Needed::Unknown)); + } + CompareResult::Incomplete | CompareResult::Error => { + let e: ErrorKind = ErrorKind::Tag; + return Err(ErrMode::from_error_kind(input, e)); + } + } + } + Ok((new_input, res)) + } + } +} + +/// Recognizes an end of line (both '\n' and '\r\n'). +/// +/// *Complete version*: Will return an error if there's not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; +/// # use winnow::ascii::line_ending; +/// fn parser(input: &str) -> IResult<&str, &str> { +/// line_ending(input) +/// } +/// +/// assert_eq!(parser("\r\nc"), Ok(("c", "\r\n"))); +/// assert_eq!(parser("ab\r\nc"), Err(ErrMode::Backtrack(Error::new("ab\r\nc", ErrorKind::Tag)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::line_ending; +/// assert_eq!(line_ending::<_, Error<_>>(Partial::new("\r\nc")), Ok((Partial::new("c"), "\r\n"))); +/// assert_eq!(line_ending::<_, Error<_>>(Partial::new("ab\r\nc")), Err(ErrMode::Backtrack(Error::new(Partial::new("ab\r\nc"), ErrorKind::Tag)))); +/// assert_eq!(line_ending::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn line_ending>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + I: Compare<&'static str>, +{ + trace("line_ending", move |input: I| { + alt(("\n", "\r\n")).parse_next(input) + }) + .parse_next(input) +} + +/// Matches a newline character '\n'. +/// +/// *Complete version*: Will return an error if there's not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; +/// # use winnow::ascii::newline; +/// fn parser(input: &str) -> IResult<&str, char> { +/// newline(input) +/// } +/// +/// assert_eq!(parser("\nc"), Ok(("c", '\n'))); +/// assert_eq!(parser("\r\nc"), Err(ErrMode::Backtrack(Error::new("\r\nc", ErrorKind::Verify)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Token)))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::newline; +/// assert_eq!(newline::<_, Error<_>>(Partial::new("\nc")), Ok((Partial::new("c"), '\n'))); +/// assert_eq!(newline::<_, Error<_>>(Partial::new("\r\nc")), Err(ErrMode::Backtrack(Error::new(Partial::new("\r\nc"), ErrorKind::Verify)))); +/// assert_eq!(newline::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn newline>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar + Copy, +{ + trace("newline", move |input: I| { + '\n'.map(|c: ::Token| c.as_char()) + .parse_next(input) + }) + .parse_next(input) +} + +/// Matches a tab character '\t'. +/// +/// *Complete version*: Will return an error if there's not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; +/// # use winnow::ascii::tab; +/// fn parser(input: &str) -> IResult<&str, char> { +/// tab(input) +/// } +/// +/// assert_eq!(parser("\tc"), Ok(("c", '\t'))); +/// assert_eq!(parser("\r\nc"), Err(ErrMode::Backtrack(Error::new("\r\nc", ErrorKind::Verify)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Token)))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::tab; +/// assert_eq!(tab::<_, Error<_>>(Partial::new("\tc")), Ok((Partial::new("c"), '\t'))); +/// assert_eq!(tab::<_, Error<_>>(Partial::new("\r\nc")), Err(ErrMode::Backtrack(Error::new(Partial::new("\r\nc"), ErrorKind::Verify)))); +/// assert_eq!(tab::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn tab>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar + Copy, +{ + trace("tab", move |input: I| { + '\t'.map(|c: ::Token| c.as_char()) + .parse_next(input) + }) + .parse_next(input) +} + +/// Recognizes zero or more lowercase and uppercase ASCII alphabetic characters: a-z, A-Z +/// +/// *Complete version*: Will return the whole input if no terminating token is found (a non +/// alphabetic character). +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, +/// or if no terminating token is found (a non alphabetic character). +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::ascii::alpha0; +/// fn parser(input: &str) -> IResult<&str, &str> { +/// alpha0(input) +/// } +/// +/// assert_eq!(parser("ab1c"), Ok(("1c", "ab"))); +/// assert_eq!(parser("1c"), Ok(("1c", ""))); +/// assert_eq!(parser(""), Ok(("", ""))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::alpha0; +/// assert_eq!(alpha0::<_, Error<_>>(Partial::new("ab1c")), Ok((Partial::new("1c"), "ab"))); +/// assert_eq!(alpha0::<_, Error<_>>(Partial::new("1c")), Ok((Partial::new("1c"), ""))); +/// assert_eq!(alpha0::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn alpha0>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + trace("alpha0", move |input: I| { + take_while(0.., |c: ::Token| c.is_alpha()).parse_next(input) + }) + .parse_next(input) +} + +/// Recognizes one or more lowercase and uppercase ASCII alphabetic characters: a-z, A-Z +/// +/// *Complete version*: Will return an error if there's not enough input data, +/// or the whole input if no terminating token is found (a non alphabetic character). +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, +/// or if no terminating token is found (a non alphabetic character). +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; +/// # use winnow::ascii::alpha1; +/// fn parser(input: &str) -> IResult<&str, &str> { +/// alpha1(input) +/// } +/// +/// assert_eq!(parser("aB1c"), Ok(("1c", "aB"))); +/// assert_eq!(parser("1c"), Err(ErrMode::Backtrack(Error::new("1c", ErrorKind::Slice)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::alpha1; +/// assert_eq!(alpha1::<_, Error<_>>(Partial::new("aB1c")), Ok((Partial::new("1c"), "aB"))); +/// assert_eq!(alpha1::<_, Error<_>>(Partial::new("1c")), Err(ErrMode::Backtrack(Error::new(Partial::new("1c"), ErrorKind::Slice)))); +/// assert_eq!(alpha1::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn alpha1>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + trace("alpha1", move |input: I| { + take_while(1.., |c: ::Token| c.is_alpha()).parse_next(input) + }) + .parse_next(input) +} + +/// Recognizes zero or more ASCII numerical characters: 0-9 +/// +/// *Complete version*: Will return an error if there's not enough input data, +/// or the whole input if no terminating token is found (a non digit character). +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, +/// or if no terminating token is found (a non digit character). +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::ascii::digit0; +/// fn parser(input: &str) -> IResult<&str, &str> { +/// digit0(input) +/// } +/// +/// assert_eq!(parser("21c"), Ok(("c", "21"))); +/// assert_eq!(parser("21"), Ok(("", "21"))); +/// assert_eq!(parser("a21c"), Ok(("a21c", ""))); +/// assert_eq!(parser(""), Ok(("", ""))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::digit0; +/// assert_eq!(digit0::<_, Error<_>>(Partial::new("21c")), Ok((Partial::new("c"), "21"))); +/// assert_eq!(digit0::<_, Error<_>>(Partial::new("a21c")), Ok((Partial::new("a21c"), ""))); +/// assert_eq!(digit0::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn digit0>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + trace("digit0", move |input: I| { + take_while(0.., |c: ::Token| c.is_dec_digit()).parse_next(input) + }) + .parse_next(input) +} + +/// Recognizes one or more ASCII numerical characters: 0-9 +/// +/// *Complete version*: Will return an error if there's not enough input data, +/// or the whole input if no terminating token is found (a non digit character). +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, +/// or if no terminating token is found (a non digit character). +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; +/// # use winnow::ascii::digit1; +/// fn parser(input: &str) -> IResult<&str, &str> { +/// digit1(input) +/// } +/// +/// assert_eq!(parser("21c"), Ok(("c", "21"))); +/// assert_eq!(parser("c1"), Err(ErrMode::Backtrack(Error::new("c1", ErrorKind::Slice)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::digit1; +/// assert_eq!(digit1::<_, Error<_>>(Partial::new("21c")), Ok((Partial::new("c"), "21"))); +/// assert_eq!(digit1::<_, Error<_>>(Partial::new("c1")), Err(ErrMode::Backtrack(Error::new(Partial::new("c1"), ErrorKind::Slice)))); +/// assert_eq!(digit1::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +/// +/// ## Parsing an integer +/// +/// You can use `digit1` in combination with [`Parser::try_map`][crate::Parser::try_map] to parse an integer: +/// +/// ``` +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed, Parser}; +/// # use winnow::ascii::digit1; +/// fn parser(input: &str) -> IResult<&str, u32> { +/// digit1.try_map(str::parse).parse_next(input) +/// } +/// +/// assert_eq!(parser("416"), Ok(("", 416))); +/// assert_eq!(parser("12b"), Ok(("b", 12))); +/// assert!(parser("b").is_err()); +/// ``` +#[inline(always)] +pub fn digit1>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + trace("digit1", move |input: I| { + take_while(1.., |c: ::Token| c.is_dec_digit()).parse_next(input) + }) + .parse_next(input) +} + +/// Recognizes zero or more ASCII hexadecimal numerical characters: 0-9, A-F, a-f +/// +/// *Complete version*: Will return the whole input if no terminating token is found (a non hexadecimal digit character). +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, +/// or if no terminating token is found (a non hexadecimal digit character). +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::ascii::hex_digit0; +/// fn parser(input: &str) -> IResult<&str, &str> { +/// hex_digit0(input) +/// } +/// +/// assert_eq!(parser("21cZ"), Ok(("Z", "21c"))); +/// assert_eq!(parser("Z21c"), Ok(("Z21c", ""))); +/// assert_eq!(parser(""), Ok(("", ""))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::hex_digit0; +/// assert_eq!(hex_digit0::<_, Error<_>>(Partial::new("21cZ")), Ok((Partial::new("Z"), "21c"))); +/// assert_eq!(hex_digit0::<_, Error<_>>(Partial::new("Z21c")), Ok((Partial::new("Z21c"), ""))); +/// assert_eq!(hex_digit0::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn hex_digit0>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + trace("hex_digit0", move |input: I| { + take_while(0.., |c: ::Token| c.is_hex_digit()).parse_next(input) + }) + .parse_next(input) +} + +/// Recognizes one or more ASCII hexadecimal numerical characters: 0-9, A-F, a-f +/// +/// *Complete version*: Will return an error if there's not enough input data, +/// or the whole input if no terminating token is found (a non hexadecimal digit character). +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, +/// or if no terminating token is found (a non hexadecimal digit character). +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; +/// # use winnow::ascii::hex_digit1; +/// fn parser(input: &str) -> IResult<&str, &str> { +/// hex_digit1(input) +/// } +/// +/// assert_eq!(parser("21cZ"), Ok(("Z", "21c"))); +/// assert_eq!(parser("H2"), Err(ErrMode::Backtrack(Error::new("H2", ErrorKind::Slice)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::hex_digit1; +/// assert_eq!(hex_digit1::<_, Error<_>>(Partial::new("21cZ")), Ok((Partial::new("Z"), "21c"))); +/// assert_eq!(hex_digit1::<_, Error<_>>(Partial::new("H2")), Err(ErrMode::Backtrack(Error::new(Partial::new("H2"), ErrorKind::Slice)))); +/// assert_eq!(hex_digit1::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn hex_digit1>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + trace("hex_digit1", move |input: I| { + take_while(1.., |c: ::Token| c.is_hex_digit()).parse_next(input) + }) + .parse_next(input) +} + +/// Recognizes zero or more octal characters: 0-7 +/// +/// *Complete version*: Will return the whole input if no terminating token is found (a non octal +/// digit character). +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, +/// or if no terminating token is found (a non octal digit character). +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::ascii::oct_digit0; +/// fn parser(input: &str) -> IResult<&str, &str> { +/// oct_digit0(input) +/// } +/// +/// assert_eq!(parser("21cZ"), Ok(("cZ", "21"))); +/// assert_eq!(parser("Z21c"), Ok(("Z21c", ""))); +/// assert_eq!(parser(""), Ok(("", ""))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::oct_digit0; +/// assert_eq!(oct_digit0::<_, Error<_>>(Partial::new("21cZ")), Ok((Partial::new("cZ"), "21"))); +/// assert_eq!(oct_digit0::<_, Error<_>>(Partial::new("Z21c")), Ok((Partial::new("Z21c"), ""))); +/// assert_eq!(oct_digit0::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn oct_digit0>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + trace("oct_digit0", move |input: I| { + take_while(0.., |c: ::Token| c.is_oct_digit()).parse_next(input) + }) + .parse_next(input) +} + +/// Recognizes one or more octal characters: 0-7 +/// +/// *Complete version*: Will return an error if there's not enough input data, +/// or the whole input if no terminating token is found (a non octal digit character). +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, +/// or if no terminating token is found (a non octal digit character). +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; +/// # use winnow::ascii::oct_digit1; +/// fn parser(input: &str) -> IResult<&str, &str> { +/// oct_digit1(input) +/// } +/// +/// assert_eq!(parser("21cZ"), Ok(("cZ", "21"))); +/// assert_eq!(parser("H2"), Err(ErrMode::Backtrack(Error::new("H2", ErrorKind::Slice)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::oct_digit1; +/// assert_eq!(oct_digit1::<_, Error<_>>(Partial::new("21cZ")), Ok((Partial::new("cZ"), "21"))); +/// assert_eq!(oct_digit1::<_, Error<_>>(Partial::new("H2")), Err(ErrMode::Backtrack(Error::new(Partial::new("H2"), ErrorKind::Slice)))); +/// assert_eq!(oct_digit1::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn oct_digit1>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + trace("oct_digit0", move |input: I| { + take_while(1.., |c: ::Token| c.is_oct_digit()).parse_next(input) + }) + .parse_next(input) +} + +/// Recognizes zero or more ASCII numerical and alphabetic characters: 0-9, a-z, A-Z +/// +/// *Complete version*: Will return the whole input if no terminating token is found (a non +/// alphanumerical character). +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, +/// or if no terminating token is found (a non alphanumerical character). +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::ascii::alphanumeric0; +/// fn parser(input: &str) -> IResult<&str, &str> { +/// alphanumeric0(input) +/// } +/// +/// assert_eq!(parser("21cZ%1"), Ok(("%1", "21cZ"))); +/// assert_eq!(parser("&Z21c"), Ok(("&Z21c", ""))); +/// assert_eq!(parser(""), Ok(("", ""))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::alphanumeric0; +/// assert_eq!(alphanumeric0::<_, Error<_>>(Partial::new("21cZ%1")), Ok((Partial::new("%1"), "21cZ"))); +/// assert_eq!(alphanumeric0::<_, Error<_>>(Partial::new("&Z21c")), Ok((Partial::new("&Z21c"), ""))); +/// assert_eq!(alphanumeric0::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn alphanumeric0>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + trace("alphanumeric0", move |input: I| { + take_while(0.., |c: ::Token| c.is_alphanum()).parse_next(input) + }) + .parse_next(input) +} + +/// Recognizes one or more ASCII numerical and alphabetic characters: 0-9, a-z, A-Z +/// +/// *Complete version*: Will return an error if there's not enough input data, +/// or the whole input if no terminating token is found (a non alphanumerical character). +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, +/// or if no terminating token is found (a non alphanumerical character). +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; +/// # use winnow::ascii::alphanumeric1; +/// fn parser(input: &str) -> IResult<&str, &str> { +/// alphanumeric1(input) +/// } +/// +/// assert_eq!(parser("21cZ%1"), Ok(("%1", "21cZ"))); +/// assert_eq!(parser("&H2"), Err(ErrMode::Backtrack(Error::new("&H2", ErrorKind::Slice)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::alphanumeric1; +/// assert_eq!(alphanumeric1::<_, Error<_>>(Partial::new("21cZ%1")), Ok((Partial::new("%1"), "21cZ"))); +/// assert_eq!(alphanumeric1::<_, Error<_>>(Partial::new("&H2")), Err(ErrMode::Backtrack(Error::new(Partial::new("&H2"), ErrorKind::Slice)))); +/// assert_eq!(alphanumeric1::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn alphanumeric1>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + trace("alphanumeric1", move |input: I| { + take_while(1.., |c: ::Token| c.is_alphanum()).parse_next(input) + }) + .parse_next(input) +} + +/// Recognizes zero or more spaces and tabs. +/// +/// *Complete version*: Will return the whole input if no terminating token is found (a non space +/// character). +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, +/// or if no terminating token is found (a non space character). +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::space0; +/// assert_eq!(space0::<_, Error<_>>(Partial::new(" \t21c")), Ok((Partial::new("21c"), " \t"))); +/// assert_eq!(space0::<_, Error<_>>(Partial::new("Z21c")), Ok((Partial::new("Z21c"), ""))); +/// assert_eq!(space0::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn space0>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar + Copy, +{ + trace("space0", move |input: I| { + take_while(0.., |c: ::Token| { + let ch = c.as_char(); + matches!(ch, ' ' | '\t') + }) + .parse_next(input) + }) + .parse_next(input) +} + +/// Recognizes one or more spaces and tabs. +/// +/// *Complete version*: Will return an error if there's not enough input data, +/// or the whole input if no terminating token is found (a non space character). +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, +/// or if no terminating token is found (a non space character). +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; +/// # use winnow::ascii::space1; +/// fn parser(input: &str) -> IResult<&str, &str> { +/// space1(input) +/// } +/// +/// assert_eq!(parser(" \t21c"), Ok(("21c", " \t"))); +/// assert_eq!(parser("H2"), Err(ErrMode::Backtrack(Error::new("H2", ErrorKind::Slice)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::space1; +/// assert_eq!(space1::<_, Error<_>>(Partial::new(" \t21c")), Ok((Partial::new("21c"), " \t"))); +/// assert_eq!(space1::<_, Error<_>>(Partial::new("H2")), Err(ErrMode::Backtrack(Error::new(Partial::new("H2"), ErrorKind::Slice)))); +/// assert_eq!(space1::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn space1>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar + Copy, +{ + trace("space1", move |input: I| { + take_while(1.., |c: ::Token| { + let ch = c.as_char(); + matches!(ch, ' ' | '\t') + }) + .parse_next(input) + }) + .parse_next(input) +} + +/// Recognizes zero or more spaces, tabs, carriage returns and line feeds. +/// +/// *Complete version*: will return the whole input if no terminating token is found (a non space +/// character). +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, +/// or if no terminating token is found (a non space character). +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::ascii::multispace0; +/// fn parser(input: &str) -> IResult<&str, &str> { +/// multispace0(input) +/// } +/// +/// assert_eq!(parser(" \t\n\r21c"), Ok(("21c", " \t\n\r"))); +/// assert_eq!(parser("Z21c"), Ok(("Z21c", ""))); +/// assert_eq!(parser(""), Ok(("", ""))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::multispace0; +/// assert_eq!(multispace0::<_, Error<_>>(Partial::new(" \t\n\r21c")), Ok((Partial::new("21c"), " \t\n\r"))); +/// assert_eq!(multispace0::<_, Error<_>>(Partial::new("Z21c")), Ok((Partial::new("Z21c"), ""))); +/// assert_eq!(multispace0::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn multispace0>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar + Copy, +{ + trace("multispace0", move |input: I| { + take_while(0.., |c: ::Token| { + let ch = c.as_char(); + matches!(ch, ' ' | '\t' | '\r' | '\n') + }) + .parse_next(input) + }) + .parse_next(input) +} + +/// Recognizes one or more spaces, tabs, carriage returns and line feeds. +/// +/// *Complete version*: will return an error if there's not enough input data, +/// or the whole input if no terminating token is found (a non space character). +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, +/// or if no terminating token is found (a non space character). +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; +/// # use winnow::ascii::multispace1; +/// fn parser(input: &str) -> IResult<&str, &str> { +/// multispace1(input) +/// } +/// +/// assert_eq!(parser(" \t\n\r21c"), Ok(("21c", " \t\n\r"))); +/// assert_eq!(parser("H2"), Err(ErrMode::Backtrack(Error::new("H2", ErrorKind::Slice)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::ascii::multispace1; +/// assert_eq!(multispace1::<_, Error<_>>(Partial::new(" \t\n\r21c")), Ok((Partial::new("21c"), " \t\n\r"))); +/// assert_eq!(multispace1::<_, Error<_>>(Partial::new("H2")), Err(ErrMode::Backtrack(Error::new(Partial::new("H2"), ErrorKind::Slice)))); +/// assert_eq!(multispace1::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn multispace1>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar + Copy, +{ + trace("multispace1", move |input: I| { + take_while(1.., |c: ::Token| { + let ch = c.as_char(); + matches!(ch, ' ' | '\t' | '\r' | '\n') + }) + .parse_next(input) + }) + .parse_next(input) +} + +/// Decode a decimal unsigned integer +/// +/// *Complete version*: can parse until the end of input. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. +#[doc(alias = "u8")] +#[doc(alias = "u16")] +#[doc(alias = "u32")] +#[doc(alias = "u64")] +#[doc(alias = "u128")] +pub fn dec_uint>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar + Copy, + O: Uint, +{ + trace("dec_uint", move |input: I| { + if input.eof_offset() == 0 { + if ::is_partial_supported() && input.is_partial() { + return Err(ErrMode::Incomplete(Needed::new(1))); + } else { + return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); + } + } + + let mut value = O::default(); + for (offset, c) in input.iter_offsets() { + match c.as_char().to_digit(10) { + Some(d) => match value.checked_mul(10, sealed::SealedMarker).and_then(|v| { + let d = d as u8; + v.checked_add(d, sealed::SealedMarker) + }) { + None => return Err(ErrMode::from_error_kind(input, ErrorKind::Verify)), + Some(v) => value = v, + }, + None => { + if offset == 0 { + return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); + } else { + return Ok((input.next_slice(offset).0, value)); + } + } + } + } + + if ::is_partial_supported() && input.is_partial() { + Err(ErrMode::Incomplete(Needed::new(1))) + } else { + Ok((input.next_slice(input.eof_offset()).0, value)) + } + }) + .parse_next(input) +} + +/// Metadata for parsing unsigned integers, see [`dec_uint`] +pub trait Uint: Default { + #[doc(hidden)] + fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option; + #[doc(hidden)] + fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option; +} + +impl Uint for u8 { + fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_mul(by as Self) + } + fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_add(by as Self) + } +} + +impl Uint for u16 { + fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_mul(by as Self) + } + fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_add(by as Self) + } +} + +impl Uint for u32 { + fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_mul(by as Self) + } + fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_add(by as Self) + } +} + +impl Uint for u64 { + fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_mul(by as Self) + } + fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_add(by as Self) + } +} + +impl Uint for u128 { + fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_mul(by as Self) + } + fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_add(by as Self) + } +} + +impl Uint for i8 { + fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_mul(by as Self) + } + fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_add(by as Self) + } +} + +impl Uint for i16 { + fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_mul(by as Self) + } + fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_add(by as Self) + } +} + +impl Uint for i32 { + fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_mul(by as Self) + } + fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_add(by as Self) + } +} + +impl Uint for i64 { + fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_mul(by as Self) + } + fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_add(by as Self) + } +} + +impl Uint for i128 { + fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_mul(by as Self) + } + fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_add(by as Self) + } +} + +/// Decode a decimal signed integer +/// +/// *Complete version*: can parse until the end of input. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. +#[doc(alias = "i8")] +#[doc(alias = "i16")] +#[doc(alias = "i32")] +#[doc(alias = "i64")] +#[doc(alias = "i128")] +pub fn dec_int>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar + Copy, + O: Int, +{ + trace("dec_int", move |input: I| { + fn sign(token: impl AsChar) -> bool { + let token = token.as_char(); + token == '+' || token == '-' + } + let (input, sign) = opt(crate::token::one_of(sign).map(AsChar::as_char)) + .map(|c| c != Some('-')) + .parse_next(input)?; + + if input.eof_offset() == 0 { + if ::is_partial_supported() && input.is_partial() { + return Err(ErrMode::Incomplete(Needed::new(1))); + } else { + return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); + } + } + + let mut value = O::default(); + for (offset, c) in input.iter_offsets() { + match c.as_char().to_digit(10) { + Some(d) => match value.checked_mul(10, sealed::SealedMarker).and_then(|v| { + let d = d as u8; + if sign { + v.checked_add(d, sealed::SealedMarker) + } else { + v.checked_sub(d, sealed::SealedMarker) + } + }) { + None => return Err(ErrMode::from_error_kind(input, ErrorKind::Verify)), + Some(v) => value = v, + }, + None => { + if offset == 0 { + return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); + } else { + return Ok((input.next_slice(offset).0, value)); + } + } + } + } + + if ::is_partial_supported() && input.is_partial() { + Err(ErrMode::Incomplete(Needed::new(1))) + } else { + Ok((input.next_slice(input.eof_offset()).0, value)) + } + }) + .parse_next(input) +} + +/// Metadata for parsing signed integers, see [`dec_int`] +pub trait Int: Uint { + #[doc(hidden)] + fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option; +} + +impl Int for i8 { + fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_sub(by as Self) + } +} + +impl Int for i16 { + fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_sub(by as Self) + } +} + +impl Int for i32 { + fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_sub(by as Self) + } +} + +impl Int for i64 { + fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_sub(by as Self) + } +} + +impl Int for i128 { + fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option { + self.checked_sub(by as Self) + } +} + +/// Decode a variable-width hexadecimal integer. +/// +/// *Complete version*: Will parse until the end of input if it has fewer characters than the type +/// supports. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if end-of-input +/// is hit before a hard boundary (non-hex character, more characters than supported). +/// +/// # Example +/// +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error}; +/// use winnow::ascii::hex_uint; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], u32> { +/// hex_uint(s) +/// } +/// +/// assert_eq!(parser(&b"01AE"[..]), Ok((&b""[..], 0x01AE))); +/// assert_eq!(parser(&b"abc"[..]), Ok((&b""[..], 0x0ABC))); +/// assert_eq!(parser(&b"ggg"[..]), Err(ErrMode::Backtrack(Error::new(&b"ggg"[..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::Partial; +/// use winnow::ascii::hex_uint; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, u32> { +/// hex_uint(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"01AE;"[..])), Ok((Partial::new(&b";"[..]), 0x01AE))); +/// assert_eq!(parser(Partial::new(&b"abc"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(parser(Partial::new(&b"ggg"[..])), Err(ErrMode::Backtrack(Error::new(Partial::new(&b"ggg"[..]), ErrorKind::Slice)))); +/// ``` +#[inline] +pub fn hex_uint>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + O: HexUint, + ::Token: AsChar, + ::Slice: AsBStr, +{ + trace("hex_uint", move |input: I| { + let invalid_offset = input + .offset_for(|c| { + let c = c.as_char(); + !"0123456789abcdefABCDEF".contains(c) + }) + .unwrap_or_else(|| input.eof_offset()); + let max_nibbles = O::max_nibbles(sealed::SealedMarker); + let max_offset = input.offset_at(max_nibbles); + let offset = match max_offset { + Ok(max_offset) => { + if max_offset < invalid_offset { + // Overflow + return Err(ErrMode::from_error_kind(input, ErrorKind::Verify)); + } else { + invalid_offset + } + } + Err(_) => { + if ::is_partial_supported() + && input.is_partial() + && invalid_offset == input.eof_offset() + { + // Only the next byte is guaranteed required + return Err(ErrMode::Incomplete(Needed::new(1))); + } else { + invalid_offset + } + } + }; + if offset == 0 { + // Must be at least one digit + return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); + } + let (remaining, parsed) = input.next_slice(offset); + + let mut res = O::default(); + for c in parsed.as_bstr() { + let nibble = *c as char; + let nibble = nibble.to_digit(16).unwrap_or(0) as u8; + let nibble = O::from(nibble); + res = (res << O::from(4)) + nibble; + } + + Ok((remaining, res)) + }) + .parse_next(input) +} + +/// Metadata for parsing hex numbers, see [`hex_uint`] +pub trait HexUint: + Default + Shl + Add + From +{ + #[doc(hidden)] + fn max_nibbles(_: sealed::SealedMarker) -> usize; +} + +impl HexUint for u8 { + #[inline(always)] + fn max_nibbles(_: sealed::SealedMarker) -> usize { + 2 + } +} + +impl HexUint for u16 { + #[inline(always)] + fn max_nibbles(_: sealed::SealedMarker) -> usize { + 4 + } +} + +impl HexUint for u32 { + #[inline(always)] + fn max_nibbles(_: sealed::SealedMarker) -> usize { + 8 + } +} + +impl HexUint for u64 { + #[inline(always)] + fn max_nibbles(_: sealed::SealedMarker) -> usize { + 16 + } +} + +impl HexUint for u128 { + #[inline(always)] + fn max_nibbles(_: sealed::SealedMarker) -> usize { + 32 + } +} + +/// Recognizes floating point number in text format and returns a f32 or f64. +/// +/// *Complete version*: Can parse until the end of input. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::error::Needed::Size; +/// use winnow::ascii::float; +/// +/// fn parser(s: &str) -> IResult<&str, f64> { +/// float(s) +/// } +/// +/// assert_eq!(parser("11e-1"), Ok(("", 1.1))); +/// assert_eq!(parser("123E-02"), Ok(("", 1.23))); +/// assert_eq!(parser("123K-01"), Ok(("K-01", 123.0))); +/// assert_eq!(parser("abc"), Err(ErrMode::Backtrack(Error::new("abc", ErrorKind::Tag)))); +/// ``` +/// +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::error::Needed::Size; +/// # use winnow::Partial; +/// use winnow::ascii::float; +/// +/// fn parser(s: Partial<&str>) -> IResult, f64> { +/// float(s) +/// } +/// +/// assert_eq!(parser(Partial::new("11e-1 ")), Ok((Partial::new(" "), 1.1))); +/// assert_eq!(parser(Partial::new("11e-1")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(parser(Partial::new("123E-02")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(parser(Partial::new("123K-01")), Ok((Partial::new("K-01"), 123.0))); +/// assert_eq!(parser(Partial::new("abc")), Err(ErrMode::Backtrack(Error::new(Partial::new("abc"), ErrorKind::Tag)))); +/// ``` +#[inline(always)] +#[doc(alias = "f32")] +#[doc(alias = "double")] +pub fn float>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + I: Offset + Compare<&'static str>, + ::Slice: ParseSlice, + ::Token: AsChar + Copy, + ::IterOffsets: Clone, + I: AsBStr, + &'static str: ContainsToken<::Token>, +{ + trace("float", move |input: I| { + let (i, s) = recognize_float_or_exceptions(input)?; + match s.parse_slice() { + Some(f) => Ok((i, f)), + None => Err(ErrMode::from_error_kind(i, ErrorKind::Verify)), + } + }) + .parse_next(input) +} + +fn recognize_float_or_exceptions>( + input: I, +) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + I: Offset + Compare<&'static str>, + ::Token: AsChar + Copy, + ::IterOffsets: Clone, + I: AsBStr, + &'static str: ContainsToken<::Token>, +{ + alt(( + recognize_float, + crate::token::tag_no_case("nan"), + crate::token::tag_no_case("inf"), + crate::token::tag_no_case("infinity"), + )) + .parse_next(input) +} + +fn recognize_float>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + I: Offset + Compare<&'static str>, + ::Token: AsChar + Copy, + ::IterOffsets: Clone, + I: AsBStr, + &'static str: ContainsToken<::Token>, +{ + ( + opt(one_of("+-")), + alt(( + (digit1, opt(('.', opt(digit1)))).map(|_| ()), + ('.', digit1).map(|_| ()), + )), + opt((one_of("eE"), opt(one_of("+-")), cut_err(digit1))), + ) + .recognize() + .parse_next(input) +} + +/// Matches a byte string with escaped characters. +/// +/// * The first argument matches the normal characters (it must not accept the control character) +/// * The second argument is the control character (like `\` in most languages) +/// * The third argument matches the escaped characters +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed, IResult}; +/// # use winnow::ascii::digit1; +/// # use winnow::prelude::*; +/// use winnow::ascii::escaped; +/// use winnow::token::one_of; +/// +/// fn esc(s: &str) -> IResult<&str, &str> { +/// escaped(digit1, '\\', one_of(r#""n\"#)).parse_next(s) +/// } +/// +/// assert_eq!(esc("123;"), Ok((";", "123"))); +/// assert_eq!(esc(r#"12\"34;"#), Ok((";", r#"12\"34"#))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed, IResult}; +/// # use winnow::ascii::digit1; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::ascii::escaped; +/// use winnow::token::one_of; +/// +/// fn esc(s: Partial<&str>) -> IResult, &str> { +/// escaped(digit1, '\\', one_of("\"n\\")).parse_next(s) +/// } +/// +/// assert_eq!(esc(Partial::new("123;")), Ok((Partial::new(";"), "123"))); +/// assert_eq!(esc(Partial::new("12\\\"34;")), Ok((Partial::new(";"), "12\\\"34"))); +/// ``` +#[inline(always)] +pub fn escaped<'a, I: 'a, Error, F, G, O1, O2>( + mut normal: F, + control_char: char, + mut escapable: G, +) -> impl Parser::Slice, Error> +where + I: StreamIsPartial, + I: Stream + Offset, + ::Token: crate::stream::AsChar, + F: Parser, + G: Parser, + Error: ParseError, +{ + trace("escaped", move |input: I| { + if ::is_partial_supported() && input.is_partial() { + streaming_escaped_internal(input, &mut normal, control_char, &mut escapable) + } else { + complete_escaped_internal(input, &mut normal, control_char, &mut escapable) + } + }) +} + +fn streaming_escaped_internal( + input: I, + normal: &mut F, + control_char: char, + escapable: &mut G, +) -> IResult::Slice, Error> +where + I: StreamIsPartial, + I: Stream + Offset, + ::Token: crate::stream::AsChar, + F: Parser, + G: Parser, + Error: ParseError, +{ + let mut i = input.clone(); + + while i.eof_offset() > 0 { + let current_len = i.eof_offset(); + + match normal.parse_next(i.clone()) { + Ok((i2, _)) => { + if i2.eof_offset() == 0 { + return Err(ErrMode::Incomplete(Needed::Unknown)); + } else if i2.eof_offset() == current_len { + let offset = input.offset_to(&i2); + return Ok(input.next_slice(offset)); + } else { + i = i2; + } + } + Err(ErrMode::Backtrack(_)) => { + if i.next_token().expect("eof_offset > 0").1.as_char() == control_char { + let next = control_char.len_utf8(); + match escapable.parse_next(i.next_slice(next).0) { + Ok((i2, _)) => { + if i2.eof_offset() == 0 { + return Err(ErrMode::Incomplete(Needed::Unknown)); + } else { + i = i2; + } + } + Err(e) => return Err(e), + } + } else { + let offset = input.offset_to(&i); + return Ok(input.next_slice(offset)); + } + } + Err(e) => { + return Err(e); + } + } + } + + Err(ErrMode::Incomplete(Needed::Unknown)) +} + +fn complete_escaped_internal<'a, I: 'a, Error, F, G, O1, O2>( + input: I, + normal: &mut F, + control_char: char, + escapable: &mut G, +) -> IResult::Slice, Error> +where + I: StreamIsPartial, + I: Stream + Offset, + ::Token: crate::stream::AsChar, + F: Parser, + G: Parser, + Error: ParseError, +{ + let mut i = input.clone(); + + while i.eof_offset() > 0 { + let current_len = i.eof_offset(); + + match normal.parse_next(i.clone()) { + Ok((i2, _)) => { + // return if we consumed everything or if the normal parser + // does not consume anything + if i2.eof_offset() == 0 { + return Ok(input.next_slice(input.eof_offset())); + } else if i2.eof_offset() == current_len { + let offset = input.offset_to(&i2); + return Ok(input.next_slice(offset)); + } else { + i = i2; + } + } + Err(ErrMode::Backtrack(_)) => { + if i.next_token().expect("eof_offset > 0").1.as_char() == control_char { + let next = control_char.len_utf8(); + match escapable.parse_next(i.next_slice(next).0) { + Ok((i2, _)) => { + if i2.eof_offset() == 0 { + return Ok(input.next_slice(input.eof_offset())); + } else { + i = i2; + } + } + Err(e) => return Err(e), + } + } else { + let offset = input.offset_to(&i); + return Ok(input.next_slice(offset)); + } + } + Err(e) => { + return Err(e); + } + } + } + + Ok(input.next_slice(input.eof_offset())) +} + +/// Matches a byte string with escaped characters. +/// +/// * The first argument matches the normal characters (it must not match the control character) +/// * The second argument is the control character (like `\` in most languages) +/// * The third argument matches the escaped characters and transforms them +/// +/// As an example, the chain `abc\tdef` could be `abc def` (it also consumes the control character) +/// +/// # Example +/// +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use std::str::from_utf8; +/// use winnow::token::tag; +/// use winnow::ascii::escaped_transform; +/// use winnow::ascii::alpha1; +/// use winnow::combinator::alt; +/// +/// fn parser(input: &str) -> IResult<&str, String> { +/// escaped_transform( +/// alpha1, +/// '\\', +/// alt(( +/// "\\".value("\\"), +/// "\"".value("\""), +/// "n".value("\n"), +/// )) +/// ).parse_next(input) +/// } +/// +/// assert_eq!(parser("ab\\\"cd"), Ok(("", String::from("ab\"cd")))); +/// assert_eq!(parser("ab\\ncd"), Ok(("", String::from("ab\ncd")))); +/// ``` +/// +/// ``` +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use std::str::from_utf8; +/// # use winnow::Partial; +/// use winnow::token::tag; +/// use winnow::ascii::escaped_transform; +/// use winnow::ascii::alpha1; +/// use winnow::combinator::alt; +/// +/// fn parser(input: Partial<&str>) -> IResult, String> { +/// escaped_transform( +/// alpha1, +/// '\\', +/// alt(( +/// "\\".value("\\"), +/// "\"".value("\""), +/// "n".value("\n"), +/// )) +/// ).parse_next(input) +/// } +/// +/// assert_eq!(parser(Partial::new("ab\\\"cd\"")), Ok((Partial::new("\""), String::from("ab\"cd")))); +/// ``` +#[cfg(feature = "alloc")] +#[inline(always)] +pub fn escaped_transform( + mut normal: F, + control_char: char, + mut transform: G, +) -> impl Parser +where + I: StreamIsPartial, + I: Stream + Offset, + ::Token: crate::stream::AsChar, + Output: crate::stream::Accumulate<::Slice>, + F: Parser::Slice, Error>, + G: Parser::Slice, Error>, + Error: ParseError, +{ + trace("escaped_transform", move |input: I| { + if ::is_partial_supported() && input.is_partial() { + streaming_escaped_transform_internal(input, &mut normal, control_char, &mut transform) + } else { + complete_escaped_transform_internal(input, &mut normal, control_char, &mut transform) + } + }) +} + +#[cfg(feature = "alloc")] +fn streaming_escaped_transform_internal( + input: I, + normal: &mut F, + control_char: char, + transform: &mut G, +) -> IResult +where + I: StreamIsPartial, + I: Stream + Offset, + ::Token: crate::stream::AsChar, + Output: crate::stream::Accumulate<::Slice>, + F: Parser::Slice, Error>, + G: Parser::Slice, Error>, + Error: ParseError, +{ + let mut offset = 0; + let mut res = Output::initial(Some(input.eof_offset())); + + let i = input.clone(); + + while offset < i.eof_offset() { + let current_len = i.eof_offset(); + let remainder = i.next_slice(offset).0; + match normal.parse_next(remainder.clone()) { + Ok((i2, o)) => { + res.accumulate(o); + if i2.eof_offset() == 0 { + return Err(ErrMode::Incomplete(Needed::Unknown)); + } else if i2.eof_offset() == current_len { + return Ok((remainder, res)); + } else { + offset = input.offset_to(&i2); + } + } + Err(ErrMode::Backtrack(_)) => { + if remainder.next_token().expect("eof_offset > 0").1.as_char() == control_char { + let next = offset + control_char.len_utf8(); + match transform.parse_next(i.next_slice(next).0) { + Ok((i2, o)) => { + res.accumulate(o); + if i2.eof_offset() == 0 { + return Err(ErrMode::Incomplete(Needed::Unknown)); + } else { + offset = input.offset_to(&i2); + } + } + Err(e) => return Err(e), + } + } else { + return Ok((remainder, res)); + } + } + Err(e) => return Err(e), + } + } + Err(ErrMode::Incomplete(Needed::Unknown)) +} + +#[cfg(feature = "alloc")] +fn complete_escaped_transform_internal( + input: I, + normal: &mut F, + control_char: char, + transform: &mut G, +) -> IResult +where + I: StreamIsPartial, + I: Stream + Offset, + ::Token: crate::stream::AsChar, + Output: crate::stream::Accumulate<::Slice>, + F: Parser::Slice, Error>, + G: Parser::Slice, Error>, + Error: ParseError, +{ + let mut offset = 0; + let mut res = Output::initial(Some(input.eof_offset())); + + let i = input.clone(); + + while offset < i.eof_offset() { + let current_len = i.eof_offset(); + let (remainder, _) = i.next_slice(offset); + match normal.parse_next(remainder.clone()) { + Ok((i2, o)) => { + res.accumulate(o); + if i2.eof_offset() == 0 { + return Ok((i.next_slice(i.eof_offset()).0, res)); + } else if i2.eof_offset() == current_len { + return Ok((remainder, res)); + } else { + offset = input.offset_to(&i2); + } + } + Err(ErrMode::Backtrack(_)) => { + if remainder.next_token().expect("eof_offset > 0").1.as_char() == control_char { + let next = offset + control_char.len_utf8(); + match transform.parse_next(i.next_slice(next).0) { + Ok((i2, o)) => { + res.accumulate(o); + if i2.eof_offset() == 0 { + return Ok((i.next_slice(i.eof_offset()).0, res)); + } else { + offset = input.offset_to(&i2); + } + } + Err(e) => return Err(e), + } + } else { + return Ok((remainder, res)); + } + } + Err(e) => return Err(e), + } + } + Ok((input.next_slice(offset).0, res)) +} + +mod sealed { + pub struct SealedMarker; +} diff --git a/vendor/winnow/src/ascii/tests.rs b/vendor/winnow/src/ascii/tests.rs new file mode 100644 index 000000000..b715d0920 --- /dev/null +++ b/vendor/winnow/src/ascii/tests.rs @@ -0,0 +1,1496 @@ +use super::*; + +mod complete { + use super::*; + use crate::combinator::alt; + use crate::combinator::opt; + use crate::error::ErrMode; + use crate::error::Error; + use crate::error::ErrorKind; + use crate::stream::ParseSlice; + use crate::token::none_of; + use crate::token::one_of; + #[cfg(feature = "alloc")] + use crate::{lib::std::string::String, lib::std::vec::Vec}; + use proptest::prelude::*; + + macro_rules! assert_parse( + ($left: expr, $right: expr) => { + let res: $crate::IResult<_, _, Error<_>> = $left; + assert_eq!(res, $right); + }; + ); + + #[test] + fn character() { + let empty: &[u8] = b""; + let a: &[u8] = b"abcd"; + let b: &[u8] = b"1234"; + let c: &[u8] = b"a123"; + let d: &[u8] = "azé12".as_bytes(); + let e: &[u8] = b" "; + let f: &[u8] = b" ;"; + //assert_eq!(alpha1::<_, Error>(a), Err(ErrMode::Incomplete(Needed::Size(1)))); + assert_parse!(alpha1(a), Ok((empty, a))); + assert_eq!( + alpha1(b), + Err(ErrMode::Backtrack(Error::new(b, ErrorKind::Slice))) + ); + assert_eq!(alpha1::<_, Error<_>>(c), Ok((&c[1..], &b"a"[..]))); + assert_eq!(alpha1::<_, Error<_>>(d), Ok(("é12".as_bytes(), &b"az"[..]))); + assert_eq!( + digit1(a), + Err(ErrMode::Backtrack(Error::new(a, ErrorKind::Slice))) + ); + assert_eq!(digit1::<_, Error<_>>(b), Ok((empty, b))); + assert_eq!( + digit1(c), + Err(ErrMode::Backtrack(Error::new(c, ErrorKind::Slice))) + ); + assert_eq!( + digit1(d), + Err(ErrMode::Backtrack(Error::new(d, ErrorKind::Slice))) + ); + assert_eq!(hex_digit1::<_, Error<_>>(a), Ok((empty, a))); + assert_eq!(hex_digit1::<_, Error<_>>(b), Ok((empty, b))); + assert_eq!(hex_digit1::<_, Error<_>>(c), Ok((empty, c))); + assert_eq!( + hex_digit1::<_, Error<_>>(d), + Ok(("zé12".as_bytes(), &b"a"[..])) + ); + assert_eq!( + hex_digit1(e), + Err(ErrMode::Backtrack(Error::new(e, ErrorKind::Slice))) + ); + assert_eq!( + oct_digit1(a), + Err(ErrMode::Backtrack(Error::new(a, ErrorKind::Slice))) + ); + assert_eq!(oct_digit1::<_, Error<_>>(b), Ok((empty, b))); + assert_eq!( + oct_digit1(c), + Err(ErrMode::Backtrack(Error::new(c, ErrorKind::Slice))) + ); + assert_eq!( + oct_digit1(d), + Err(ErrMode::Backtrack(Error::new(d, ErrorKind::Slice))) + ); + assert_eq!(alphanumeric1::<_, Error<_>>(a), Ok((empty, a))); + //assert_eq!(fix_error!(b,(), alphanumeric), Ok((empty, b))); + assert_eq!(alphanumeric1::<_, Error<_>>(c), Ok((empty, c))); + assert_eq!( + alphanumeric1::<_, Error<_>>(d), + Ok(("é12".as_bytes(), &b"az"[..])) + ); + assert_eq!(space1::<_, Error<_>>(e), Ok((empty, e))); + assert_eq!(space1::<_, Error<_>>(f), Ok((&b";"[..], &b" "[..]))); + } + + #[cfg(feature = "alloc")] + #[test] + fn character_s() { + let empty = ""; + let a = "abcd"; + let b = "1234"; + let c = "a123"; + let d = "azé12"; + let e = " "; + assert_eq!(alpha1::<_, Error<_>>(a), Ok((empty, a))); + assert_eq!( + alpha1(b), + Err(ErrMode::Backtrack(Error::new(b, ErrorKind::Slice))) + ); + assert_eq!(alpha1::<_, Error<_>>(c), Ok((&c[1..], "a"))); + assert_eq!(alpha1::<_, Error<_>>(d), Ok(("é12", "az"))); + assert_eq!( + digit1(a), + Err(ErrMode::Backtrack(Error::new(a, ErrorKind::Slice))) + ); + assert_eq!(digit1::<_, Error<_>>(b), Ok((empty, b))); + assert_eq!( + digit1(c), + Err(ErrMode::Backtrack(Error::new(c, ErrorKind::Slice))) + ); + assert_eq!( + digit1(d), + Err(ErrMode::Backtrack(Error::new(d, ErrorKind::Slice))) + ); + assert_eq!(hex_digit1::<_, Error<_>>(a), Ok((empty, a))); + assert_eq!(hex_digit1::<_, Error<_>>(b), Ok((empty, b))); + assert_eq!(hex_digit1::<_, Error<_>>(c), Ok((empty, c))); + assert_eq!(hex_digit1::<_, Error<_>>(d), Ok(("zé12", "a"))); + assert_eq!( + hex_digit1(e), + Err(ErrMode::Backtrack(Error::new(e, ErrorKind::Slice))) + ); + assert_eq!( + oct_digit1(a), + Err(ErrMode::Backtrack(Error::new(a, ErrorKind::Slice))) + ); + assert_eq!(oct_digit1::<_, Error<_>>(b), Ok((empty, b))); + assert_eq!( + oct_digit1(c), + Err(ErrMode::Backtrack(Error::new(c, ErrorKind::Slice))) + ); + assert_eq!( + oct_digit1(d), + Err(ErrMode::Backtrack(Error::new(d, ErrorKind::Slice))) + ); + assert_eq!(alphanumeric1::<_, Error<_>>(a), Ok((empty, a))); + //assert_eq!(fix_error!(b,(), alphanumeric), Ok((empty, b))); + assert_eq!(alphanumeric1::<_, Error<_>>(c), Ok((empty, c))); + assert_eq!(alphanumeric1::<_, Error<_>>(d), Ok(("é12", "az"))); + assert_eq!(space1::<_, Error<_>>(e), Ok((empty, e))); + } + + use crate::stream::Offset; + #[test] + fn offset() { + let a = &b"abcd;"[..]; + let b = &b"1234;"[..]; + let c = &b"a123;"[..]; + let d = &b" \t;"[..]; + let e = &b" \t\r\n;"[..]; + let f = &b"123abcDEF;"[..]; + + match alpha1::<_, Error<_>>(a) { + Ok((i, _)) => { + assert_eq!(a.offset_to(i) + i.len(), a.len()); + } + _ => panic!("wrong return type in offset test for alpha"), + } + match digit1::<_, Error<_>>(b) { + Ok((i, _)) => { + assert_eq!(b.offset_to(i) + i.len(), b.len()); + } + _ => panic!("wrong return type in offset test for digit"), + } + match alphanumeric1::<_, Error<_>>(c) { + Ok((i, _)) => { + assert_eq!(c.offset_to(i) + i.len(), c.len()); + } + _ => panic!("wrong return type in offset test for alphanumeric"), + } + match space1::<_, Error<_>>(d) { + Ok((i, _)) => { + assert_eq!(d.offset_to(i) + i.len(), d.len()); + } + _ => panic!("wrong return type in offset test for space"), + } + match multispace1::<_, Error<_>>(e) { + Ok((i, _)) => { + assert_eq!(e.offset_to(i) + i.len(), e.len()); + } + _ => panic!("wrong return type in offset test for multispace"), + } + match hex_digit1::<_, Error<_>>(f) { + Ok((i, _)) => { + assert_eq!(f.offset_to(i) + i.len(), f.len()); + } + _ => panic!("wrong return type in offset test for hex_digit"), + } + match oct_digit1::<_, Error<_>>(f) { + Ok((i, _)) => { + assert_eq!(f.offset_to(i) + i.len(), f.len()); + } + _ => panic!("wrong return type in offset test for oct_digit"), + } + } + + #[test] + fn is_not_line_ending_bytes() { + let a: &[u8] = b"ab12cd\nefgh"; + assert_eq!( + not_line_ending::<_, Error<_>>(a), + Ok((&b"\nefgh"[..], &b"ab12cd"[..])) + ); + + let b: &[u8] = b"ab12cd\nefgh\nijkl"; + assert_eq!( + not_line_ending::<_, Error<_>>(b), + Ok((&b"\nefgh\nijkl"[..], &b"ab12cd"[..])) + ); + + let c: &[u8] = b"ab12cd\r\nefgh\nijkl"; + assert_eq!( + not_line_ending::<_, Error<_>>(c), + Ok((&b"\r\nefgh\nijkl"[..], &b"ab12cd"[..])) + ); + + let d: &[u8] = b"ab12cd"; + assert_eq!(not_line_ending::<_, Error<_>>(d), Ok((&[][..], d))); + } + + #[test] + fn is_not_line_ending_str() { + let f = "βèƒôřè\rÂßÇáƒƭèř"; + assert_eq!( + not_line_ending(f), + Err(ErrMode::Backtrack(Error::new(f, ErrorKind::Tag))) + ); + + let g2: &str = "ab12cd"; + assert_eq!(not_line_ending::<_, Error<_>>(g2), Ok(("", g2))); + } + + #[test] + fn hex_digit_test() { + let i = &b"0123456789abcdefABCDEF;"[..]; + assert_parse!(hex_digit1(i), Ok((&b";"[..], &i[..i.len() - 1]))); + + let i = &b"g"[..]; + assert_parse!( + hex_digit1(i), + Err(ErrMode::Backtrack(error_position!(i, ErrorKind::Slice))) + ); + + let i = &b"G"[..]; + assert_parse!( + hex_digit1(i), + Err(ErrMode::Backtrack(error_position!(i, ErrorKind::Slice))) + ); + + assert!(AsChar::is_hex_digit(b'0')); + assert!(AsChar::is_hex_digit(b'9')); + assert!(AsChar::is_hex_digit(b'a')); + assert!(AsChar::is_hex_digit(b'f')); + assert!(AsChar::is_hex_digit(b'A')); + assert!(AsChar::is_hex_digit(b'F')); + assert!(!AsChar::is_hex_digit(b'g')); + assert!(!AsChar::is_hex_digit(b'G')); + assert!(!AsChar::is_hex_digit(b'/')); + assert!(!AsChar::is_hex_digit(b':')); + assert!(!AsChar::is_hex_digit(b'@')); + assert!(!AsChar::is_hex_digit(b'\x60')); + } + + #[test] + fn oct_digit_test() { + let i = &b"01234567;"[..]; + assert_parse!(oct_digit1(i), Ok((&b";"[..], &i[..i.len() - 1]))); + + let i = &b"8"[..]; + assert_parse!( + oct_digit1(i), + Err(ErrMode::Backtrack(error_position!(i, ErrorKind::Slice))) + ); + + assert!(AsChar::is_oct_digit(b'0')); + assert!(AsChar::is_oct_digit(b'7')); + assert!(!AsChar::is_oct_digit(b'8')); + assert!(!AsChar::is_oct_digit(b'9')); + assert!(!AsChar::is_oct_digit(b'a')); + assert!(!AsChar::is_oct_digit(b'A')); + assert!(!AsChar::is_oct_digit(b'/')); + assert!(!AsChar::is_oct_digit(b':')); + assert!(!AsChar::is_oct_digit(b'@')); + assert!(!AsChar::is_oct_digit(b'\x60')); + } + + #[test] + fn full_line_windows() { + fn take_full_line(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> { + (not_line_ending, line_ending).parse_next(i) + } + let input = b"abc\r\n"; + let output = take_full_line(input); + assert_eq!(output, Ok((&b""[..], (&b"abc"[..], &b"\r\n"[..])))); + } + + #[test] + fn full_line_unix() { + fn take_full_line(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> { + (not_line_ending, line_ending).parse_next(i) + } + let input = b"abc\n"; + let output = take_full_line(input); + assert_eq!(output, Ok((&b""[..], (&b"abc"[..], &b"\n"[..])))); + } + + #[test] + fn check_windows_lineending() { + let input = b"\r\n"; + let output = line_ending(&input[..]); + assert_parse!(output, Ok((&b""[..], &b"\r\n"[..]))); + } + + #[test] + fn check_unix_lineending() { + let input = b"\n"; + let output = line_ending(&input[..]); + assert_parse!(output, Ok((&b""[..], &b"\n"[..]))); + } + + #[test] + fn cr_lf() { + assert_parse!(crlf(&b"\r\na"[..]), Ok((&b"a"[..], &b"\r\n"[..]))); + assert_parse!( + crlf(&b"\r"[..]), + Err(ErrMode::Backtrack(error_position!( + &b"\r"[..], + ErrorKind::Tag + ))) + ); + assert_parse!( + crlf(&b"\ra"[..]), + Err(ErrMode::Backtrack(error_position!( + &b"\ra"[..], + ErrorKind::Tag + ))) + ); + + assert_parse!(crlf("\r\na"), Ok(("a", "\r\n"))); + assert_parse!( + crlf("\r"), + Err(ErrMode::Backtrack(error_position!("\r", ErrorKind::Tag))) + ); + assert_parse!( + crlf("\ra"), + Err(ErrMode::Backtrack(error_position!("\ra", ErrorKind::Tag))) + ); + } + + #[test] + fn end_of_line() { + assert_parse!(line_ending(&b"\na"[..]), Ok((&b"a"[..], &b"\n"[..]))); + assert_parse!(line_ending(&b"\r\na"[..]), Ok((&b"a"[..], &b"\r\n"[..]))); + assert_parse!( + line_ending(&b"\r"[..]), + Err(ErrMode::Backtrack(error_position!( + &b"\r"[..], + ErrorKind::Tag + ))) + ); + assert_parse!( + line_ending(&b"\ra"[..]), + Err(ErrMode::Backtrack(error_position!( + &b"\ra"[..], + ErrorKind::Tag + ))) + ); + + assert_parse!(line_ending("\na"), Ok(("a", "\n"))); + assert_parse!(line_ending("\r\na"), Ok(("a", "\r\n"))); + assert_parse!( + line_ending("\r"), + Err(ErrMode::Backtrack(error_position!("\r", ErrorKind::Tag))) + ); + assert_parse!( + line_ending("\ra"), + Err(ErrMode::Backtrack(error_position!("\ra", ErrorKind::Tag))) + ); + } + + fn digit_to_i16(input: &str) -> IResult<&str, i16> { + let i = input; + let (i, opt_sign) = opt(alt(('+', '-'))).parse_next(i)?; + let sign = match opt_sign { + Some('+') | None => true, + Some('-') => false, + _ => unreachable!(), + }; + + let (i, s) = digit1::<_, crate::error::Error<_>>(i)?; + match s.parse_slice() { + Some(n) => { + if sign { + Ok((i, n)) + } else { + Ok((i, -n)) + } + } + None => Err(ErrMode::from_error_kind(i, ErrorKind::Verify)), + } + } + + fn digit_to_u32(i: &str) -> IResult<&str, u32> { + let (i, s) = digit1(i)?; + match s.parse_slice() { + Some(n) => Ok((i, n)), + None => Err(ErrMode::from_error_kind(i, ErrorKind::Verify)), + } + } + + proptest! { + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn ints(s in "\\PC*") { + let res1 = digit_to_i16(&s); + let res2 = dec_int(s.as_str()); + assert_eq!(res1, res2); + } + + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn uints(s in "\\PC*") { + let res1 = digit_to_u32(&s); + let res2 = dec_uint(s.as_str()); + assert_eq!(res1, res2); + } + } + + #[test] + fn hex_uint_tests() { + fn hex_u32(input: &[u8]) -> IResult<&[u8], u32> { + hex_uint(input) + } + + assert_parse!( + hex_u32(&b";"[..]), + Err(ErrMode::Backtrack(error_position!( + &b";"[..], + ErrorKind::Slice + ))) + ); + assert_parse!(hex_u32(&b"ff;"[..]), Ok((&b";"[..], 255))); + assert_parse!(hex_u32(&b"1be2;"[..]), Ok((&b";"[..], 7138))); + assert_parse!(hex_u32(&b"c5a31be2;"[..]), Ok((&b";"[..], 3_315_801_058))); + assert_parse!(hex_u32(&b"C5A31be2;"[..]), Ok((&b";"[..], 3_315_801_058))); + assert_parse!( + hex_u32(&b"00c5a31be2;"[..]), // overflow + Err(ErrMode::Backtrack(error_position!( + &b"00c5a31be2;"[..], + ErrorKind::Verify + ))) + ); + assert_parse!( + hex_u32(&b"c5a31be201;"[..]), // overflow + Err(ErrMode::Backtrack(error_position!( + &b"c5a31be201;"[..], + ErrorKind::Verify + ))) + ); + assert_parse!(hex_u32(&b"ffffffff;"[..]), Ok((&b";"[..], 4_294_967_295))); + assert_parse!( + hex_u32(&b"ffffffffffffffff;"[..]), // overflow + Err(ErrMode::Backtrack(error_position!( + &b"ffffffffffffffff;"[..], + ErrorKind::Verify + ))) + ); + assert_parse!( + hex_u32(&b"ffffffffffffffff"[..]), // overflow + Err(ErrMode::Backtrack(error_position!( + &b"ffffffffffffffff"[..], + ErrorKind::Verify + ))) + ); + assert_parse!(hex_u32(&b"0x1be2;"[..]), Ok((&b"x1be2;"[..], 0))); + assert_parse!(hex_u32(&b"12af"[..]), Ok((&b""[..], 0x12af))); + } + + #[test] + #[cfg(feature = "std")] + fn float_test() { + let mut test_cases = vec![ + "+3.14", + "3.14", + "-3.14", + "0", + "0.0", + "1.", + ".789", + "-.5", + "1e7", + "-1E-7", + ".3e-2", + "1.e4", + "1.2e4", + "12.34", + "-1.234E-12", + "-1.234e-12", + "0.00000000000000000087", + ]; + + for test in test_cases.drain(..) { + let expected32 = str::parse::(test).unwrap(); + let expected64 = str::parse::(test).unwrap(); + + println!("now parsing: {} -> {}", test, expected32); + + let larger = test.to_string(); + + assert_parse!(float(larger.as_bytes()), Ok((&b""[..], expected32))); + assert_parse!(float(&larger[..]), Ok(("", expected32))); + + assert_parse!(float(larger.as_bytes()), Ok((&b""[..], expected64))); + assert_parse!(float(&larger[..]), Ok(("", expected64))); + } + + let remaining_exponent = "-1.234E-"; + assert_parse!( + float::<_, f64, _>(remaining_exponent), + Err(ErrMode::Cut(Error { + input: "", + kind: ErrorKind::Slice + })) + ); + + let (_i, nan) = float::<_, f32, ()>("NaN").unwrap(); + assert!(nan.is_nan()); + + let (_i, inf) = float::<_, f32, ()>("inf").unwrap(); + assert!(inf.is_infinite()); + let (_i, inf) = float::<_, f32, ()>("infinite").unwrap(); + assert!(inf.is_infinite()); + } + + #[cfg(feature = "std")] + fn parse_f64(i: &str) -> IResult<&str, f64, ()> { + #[allow(deprecated)] // will just become `pub(crate)` later + match super::recognize_float_or_exceptions(i) { + Err(e) => Err(e), + Ok((i, s)) => { + if s.is_empty() { + return Err(ErrMode::Backtrack(())); + } + match s.parse_slice() { + Some(n) => Ok((i, n)), + None => Err(ErrMode::Backtrack(())), + } + } + } + } + + proptest! { + #[test] + #[cfg(feature = "std")] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn floats(s in "\\PC*") { + println!("testing {}", s); + let res1 = parse_f64(&s); + let res2 = float::<_, f64, ()>(s.as_str()); + assert_eq!(res1, res2); + } + } + + // issue #1336 "escaped hangs if normal parser accepts empty" + #[test] + fn complete_escaped_hang() { + // issue #1336 "escaped hangs if normal parser accepts empty" + fn escaped_string(input: &str) -> IResult<&str, &str> { + use crate::ascii::alpha0; + use crate::token::one_of; + escaped(alpha0, '\\', one_of("n")).parse_next(input) + } + + escaped_string("7").unwrap(); + escaped_string("a7").unwrap(); + } + + #[test] + fn complete_escaped_hang_1118() { + // issue ##1118 escaped does not work with empty string + fn unquote(input: &str) -> IResult<&str, &str> { + use crate::combinator::delimited; + use crate::combinator::opt; + use crate::token::one_of; + + delimited( + '"', + escaped(opt(none_of(r#"\""#)), '\\', one_of(r#"\"rnt"#)), + '"', + ) + .parse_next(input) + } + + assert_eq!(unquote(r#""""#), Ok(("", ""))); + } + + #[cfg(feature = "alloc")] + #[allow(unused_variables)] + #[test] + fn complete_escaping() { + use crate::ascii::{alpha1 as alpha, digit1 as digit}; + use crate::token::one_of; + + fn esc(i: &[u8]) -> IResult<&[u8], &[u8]> { + escaped(alpha, '\\', one_of("\"n\\")).parse_next(i) + } + assert_eq!(esc(&b"abcd;"[..]), Ok((&b";"[..], &b"abcd"[..]))); + assert_eq!(esc(&b"ab\\\"cd;"[..]), Ok((&b";"[..], &b"ab\\\"cd"[..]))); + assert_eq!(esc(&b"\\\"abcd;"[..]), Ok((&b";"[..], &b"\\\"abcd"[..]))); + assert_eq!(esc(&b"\\n;"[..]), Ok((&b";"[..], &b"\\n"[..]))); + assert_eq!(esc(&b"ab\\\"12"[..]), Ok((&b"12"[..], &b"ab\\\""[..]))); + assert_eq!( + esc(&b"AB\\"[..]), + Err(ErrMode::Backtrack(error_position!( + &b""[..], + ErrorKind::Token + ))) + ); + assert_eq!( + esc(&b"AB\\A"[..]), + Err(ErrMode::Backtrack(error_node_position!( + &b"AB\\A"[..], + ErrorKind::Token, + error_position!(&b"A"[..], ErrorKind::Verify) + ))) + ); + + fn esc2(i: &[u8]) -> IResult<&[u8], &[u8]> { + escaped(digit, '\\', one_of("\"n\\")).parse_next(i) + } + assert_eq!(esc2(&b"12\\nnn34"[..]), Ok((&b"nn34"[..], &b"12\\n"[..]))); + } + + #[cfg(feature = "alloc")] + #[test] + fn complete_escaping_str() { + use crate::ascii::{alpha1 as alpha, digit1 as digit}; + use crate::token::one_of; + + fn esc(i: &str) -> IResult<&str, &str> { + escaped(alpha, '\\', one_of("\"n\\")).parse_next(i) + } + assert_eq!(esc("abcd;"), Ok((";", "abcd"))); + assert_eq!(esc("ab\\\"cd;"), Ok((";", "ab\\\"cd"))); + assert_eq!(esc("\\\"abcd;"), Ok((";", "\\\"abcd"))); + assert_eq!(esc("\\n;"), Ok((";", "\\n"))); + assert_eq!(esc("ab\\\"12"), Ok(("12", "ab\\\""))); + assert_eq!( + esc("AB\\"), + Err(ErrMode::Backtrack(error_position!("", ErrorKind::Token))) + ); + assert_eq!( + esc("AB\\A"), + Err(ErrMode::Backtrack(error_node_position!( + "AB\\A", + ErrorKind::Token, + error_position!("A", ErrorKind::Verify) + ))) + ); + + fn esc2(i: &str) -> IResult<&str, &str> { + escaped(digit, '\\', one_of("\"n\\")).parse_next(i) + } + assert_eq!(esc2("12\\nnn34"), Ok(("nn34", "12\\n"))); + + fn esc3(i: &str) -> IResult<&str, &str> { + escaped(alpha, '\u{241b}', one_of("\"n")).parse_next(i) + } + assert_eq!(esc3("ab␛ncd;"), Ok((";", "ab␛ncd"))); + } + + #[test] + fn test_escaped_error() { + fn esc(s: &str) -> IResult<&str, &str> { + use crate::ascii::digit1; + escaped(digit1, '\\', one_of("\"n\\")).parse_next(s) + } + + assert_eq!(esc("abcd"), Ok(("abcd", ""))); + } + + #[cfg(feature = "alloc")] + #[test] + fn complete_escape_transform() { + use crate::ascii::alpha1 as alpha; + + #[cfg(feature = "alloc")] + fn to_s(i: Vec) -> String { + String::from_utf8_lossy(&i).into_owned() + } + + fn esc(i: &[u8]) -> IResult<&[u8], String> { + escaped_transform( + alpha, + '\\', + alt(( + "\\".value(&b"\\"[..]), + "\"".value(&b"\""[..]), + "n".value(&b"\n"[..]), + )), + ) + .map(to_s) + .parse_next(i) + } + + assert_eq!(esc(&b"abcd;"[..]), Ok((&b";"[..], String::from("abcd")))); + assert_eq!( + esc(&b"ab\\\"cd;"[..]), + Ok((&b";"[..], String::from("ab\"cd"))) + ); + assert_eq!( + esc(&b"\\\"abcd;"[..]), + Ok((&b";"[..], String::from("\"abcd"))) + ); + assert_eq!(esc(&b"\\n;"[..]), Ok((&b";"[..], String::from("\n")))); + assert_eq!( + esc(&b"ab\\\"12"[..]), + Ok((&b"12"[..], String::from("ab\""))) + ); + assert_eq!( + esc(&b"AB\\"[..]), + Err(ErrMode::Backtrack(error_position!( + &b""[..], + ErrorKind::Tag + ))) + ); + assert_eq!( + esc(&b"AB\\A"[..]), + Err(ErrMode::Backtrack(error_node_position!( + &b"AB\\A"[..], + ErrorKind::Eof, + error_position!(&b"A"[..], ErrorKind::Tag) + ))) + ); + + fn esc2(i: &[u8]) -> IResult<&[u8], String> { + escaped_transform( + alpha, + '&', + alt(( + "egrave;".value("è".as_bytes()), + "agrave;".value("à".as_bytes()), + )), + ) + .map(to_s) + .parse_next(i) + } + assert_eq!( + esc2(&b"abèDEF;"[..]), + Ok((&b";"[..], String::from("abèDEF"))) + ); + assert_eq!( + esc2(&b"abèDàEF;"[..]), + Ok((&b";"[..], String::from("abèDàEF"))) + ); + } + + #[cfg(feature = "std")] + #[test] + fn complete_escape_transform_str() { + use crate::ascii::alpha1 as alpha; + + fn esc(i: &str) -> IResult<&str, String> { + escaped_transform( + alpha, + '\\', + alt(("\\".value("\\"), "\"".value("\""), "n".value("\n"))), + ) + .parse_next(i) + } + + assert_eq!(esc("abcd;"), Ok((";", String::from("abcd")))); + assert_eq!(esc("ab\\\"cd;"), Ok((";", String::from("ab\"cd")))); + assert_eq!(esc("\\\"abcd;"), Ok((";", String::from("\"abcd")))); + assert_eq!(esc("\\n;"), Ok((";", String::from("\n")))); + assert_eq!(esc("ab\\\"12"), Ok(("12", String::from("ab\"")))); + assert_eq!( + esc("AB\\"), + Err(ErrMode::Backtrack(error_position!("", ErrorKind::Tag))) + ); + assert_eq!( + esc("AB\\A"), + Err(ErrMode::Backtrack(error_node_position!( + "AB\\A", + ErrorKind::Eof, + error_position!("A", ErrorKind::Tag) + ))) + ); + + fn esc2(i: &str) -> IResult<&str, String> { + escaped_transform( + alpha, + '&', + alt(("egrave;".value("è"), "agrave;".value("à"))), + ) + .parse_next(i) + } + assert_eq!(esc2("abèDEF;"), Ok((";", String::from("abèDEF")))); + assert_eq!( + esc2("abèDàEF;"), + Ok((";", String::from("abèDàEF"))) + ); + + fn esc3(i: &str) -> IResult<&str, String> { + escaped_transform(alpha, '␛', alt(("0".value("\0"), "n".value("\n")))).parse_next(i) + } + assert_eq!(esc3("a␛0bc␛n"), Ok(("", String::from("a\0bc\n")))); + } + + #[test] + #[cfg(feature = "alloc")] + fn test_escaped_transform_error() { + fn esc_trans(s: &str) -> IResult<&str, String> { + use crate::ascii::digit1; + escaped_transform(digit1, '\\', "n").parse_next(s) + } + + assert_eq!(esc_trans("abcd"), Ok(("abcd", String::new()))); + } +} + +mod partial { + use super::*; + use crate::combinator::opt; + use crate::error::Error; + use crate::error::ErrorKind; + use crate::error::{ErrMode, Needed}; + use crate::stream::ParseSlice; + use crate::IResult; + use crate::Partial; + use proptest::prelude::*; + + macro_rules! assert_parse( + ($left: expr, $right: expr) => { + let res: $crate::IResult<_, _, Error<_>> = $left; + assert_eq!(res, $right); + }; + ); + + #[test] + fn character() { + let a: &[u8] = b"abcd"; + let b: &[u8] = b"1234"; + let c: &[u8] = b"a123"; + let d: &[u8] = "azé12".as_bytes(); + let e: &[u8] = b" "; + let f: &[u8] = b" ;"; + //assert_eq!(alpha1::<_, Error<_>>(a), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_parse!( + alpha1(Partial::new(a)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + alpha1(Partial::new(b)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(b), + ErrorKind::Slice + ))) + ); + assert_eq!( + alpha1::<_, Error<_>>(Partial::new(c)), + Ok((Partial::new(&c[1..]), &b"a"[..])) + ); + assert_eq!( + alpha1::<_, Error<_>>(Partial::new(d)), + Ok((Partial::new("é12".as_bytes()), &b"az"[..])) + ); + assert_eq!( + digit1(Partial::new(a)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(a), + ErrorKind::Slice + ))) + ); + assert_eq!( + digit1::<_, Error<_>>(Partial::new(b)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + digit1(Partial::new(c)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(c), + ErrorKind::Slice + ))) + ); + assert_eq!( + digit1(Partial::new(d)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(d), + ErrorKind::Slice + ))) + ); + assert_eq!( + hex_digit1::<_, Error<_>>(Partial::new(a)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + hex_digit1::<_, Error<_>>(Partial::new(b)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + hex_digit1::<_, Error<_>>(Partial::new(c)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + hex_digit1::<_, Error<_>>(Partial::new(d)), + Ok((Partial::new("zé12".as_bytes()), &b"a"[..])) + ); + assert_eq!( + hex_digit1(Partial::new(e)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(e), + ErrorKind::Slice + ))) + ); + assert_eq!( + oct_digit1(Partial::new(a)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(a), + ErrorKind::Slice + ))) + ); + assert_eq!( + oct_digit1::<_, Error<_>>(Partial::new(b)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + oct_digit1(Partial::new(c)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(c), + ErrorKind::Slice + ))) + ); + assert_eq!( + oct_digit1(Partial::new(d)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(d), + ErrorKind::Slice + ))) + ); + assert_eq!( + alphanumeric1::<_, Error<_>>(Partial::new(a)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + //assert_eq!(fix_error!(b,(), alphanumeric1), Ok((empty, b))); + assert_eq!( + alphanumeric1::<_, Error<_>>(Partial::new(c)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + alphanumeric1::<_, Error<_>>(Partial::new(d)), + Ok((Partial::new("é12".as_bytes()), &b"az"[..])) + ); + assert_eq!( + space1::<_, Error<_>>(Partial::new(e)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + space1::<_, Error<_>>(Partial::new(f)), + Ok((Partial::new(&b";"[..]), &b" "[..])) + ); + } + + #[cfg(feature = "alloc")] + #[test] + fn character_s() { + let a = "abcd"; + let b = "1234"; + let c = "a123"; + let d = "azé12"; + let e = " "; + assert_eq!( + alpha1::<_, Error<_>>(Partial::new(a)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + alpha1(Partial::new(b)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(b), + ErrorKind::Slice + ))) + ); + assert_eq!( + alpha1::<_, Error<_>>(Partial::new(c)), + Ok((Partial::new(&c[1..]), "a")) + ); + assert_eq!( + alpha1::<_, Error<_>>(Partial::new(d)), + Ok((Partial::new("é12"), "az")) + ); + assert_eq!( + digit1(Partial::new(a)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(a), + ErrorKind::Slice + ))) + ); + assert_eq!( + digit1::<_, Error<_>>(Partial::new(b)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + digit1(Partial::new(c)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(c), + ErrorKind::Slice + ))) + ); + assert_eq!( + digit1(Partial::new(d)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(d), + ErrorKind::Slice + ))) + ); + assert_eq!( + hex_digit1::<_, Error<_>>(Partial::new(a)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + hex_digit1::<_, Error<_>>(Partial::new(b)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + hex_digit1::<_, Error<_>>(Partial::new(c)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + hex_digit1::<_, Error<_>>(Partial::new(d)), + Ok((Partial::new("zé12"), "a")) + ); + assert_eq!( + hex_digit1(Partial::new(e)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(e), + ErrorKind::Slice + ))) + ); + assert_eq!( + oct_digit1(Partial::new(a)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(a), + ErrorKind::Slice + ))) + ); + assert_eq!( + oct_digit1::<_, Error<_>>(Partial::new(b)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + oct_digit1(Partial::new(c)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(c), + ErrorKind::Slice + ))) + ); + assert_eq!( + oct_digit1(Partial::new(d)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(d), + ErrorKind::Slice + ))) + ); + assert_eq!( + alphanumeric1::<_, Error<_>>(Partial::new(a)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + //assert_eq!(fix_error!(b,(), alphanumeric1), Ok((empty, b))); + assert_eq!( + alphanumeric1::<_, Error<_>>(Partial::new(c)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + alphanumeric1::<_, Error<_>>(Partial::new(d)), + Ok((Partial::new("é12"), "az")) + ); + assert_eq!( + space1::<_, Error<_>>(Partial::new(e)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + } + + use crate::stream::Offset; + #[test] + fn offset() { + let a = &b"abcd;"[..]; + let b = &b"1234;"[..]; + let c = &b"a123;"[..]; + let d = &b" \t;"[..]; + let e = &b" \t\r\n;"[..]; + let f = &b"123abcDEF;"[..]; + + match alpha1::<_, Error<_>>(Partial::new(a)) { + Ok((i, _)) => { + let i = i.into_inner(); + assert_eq!(a.offset_to(i) + i.len(), a.len()); + } + _ => panic!("wrong return type in offset test for alpha"), + } + match digit1::<_, Error<_>>(Partial::new(b)) { + Ok((i, _)) => { + let i = i.into_inner(); + assert_eq!(b.offset_to(i) + i.len(), b.len()); + } + _ => panic!("wrong return type in offset test for digit"), + } + match alphanumeric1::<_, Error<_>>(Partial::new(c)) { + Ok((i, _)) => { + let i = i.into_inner(); + assert_eq!(c.offset_to(i) + i.len(), c.len()); + } + _ => panic!("wrong return type in offset test for alphanumeric"), + } + match space1::<_, Error<_>>(Partial::new(d)) { + Ok((i, _)) => { + let i = i.into_inner(); + assert_eq!(d.offset_to(i) + i.len(), d.len()); + } + _ => panic!("wrong return type in offset test for space"), + } + match multispace1::<_, Error<_>>(Partial::new(e)) { + Ok((i, _)) => { + let i = i.into_inner(); + assert_eq!(e.offset_to(i) + i.len(), e.len()); + } + _ => panic!("wrong return type in offset test for multispace"), + } + match hex_digit1::<_, Error<_>>(Partial::new(f)) { + Ok((i, _)) => { + let i = i.into_inner(); + assert_eq!(f.offset_to(i) + i.len(), f.len()); + } + _ => panic!("wrong return type in offset test for hex_digit"), + } + match oct_digit1::<_, Error<_>>(Partial::new(f)) { + Ok((i, _)) => { + let i = i.into_inner(); + assert_eq!(f.offset_to(i) + i.len(), f.len()); + } + _ => panic!("wrong return type in offset test for oct_digit"), + } + } + + #[test] + fn is_not_line_ending_bytes() { + let a: &[u8] = b"ab12cd\nefgh"; + assert_eq!( + not_line_ending::<_, Error<_>>(Partial::new(a)), + Ok((Partial::new(&b"\nefgh"[..]), &b"ab12cd"[..])) + ); + + let b: &[u8] = b"ab12cd\nefgh\nijkl"; + assert_eq!( + not_line_ending::<_, Error<_>>(Partial::new(b)), + Ok((Partial::new(&b"\nefgh\nijkl"[..]), &b"ab12cd"[..])) + ); + + let c: &[u8] = b"ab12cd\r\nefgh\nijkl"; + assert_eq!( + not_line_ending::<_, Error<_>>(Partial::new(c)), + Ok((Partial::new(&b"\r\nefgh\nijkl"[..]), &b"ab12cd"[..])) + ); + + let d: &[u8] = b"ab12cd"; + assert_eq!( + not_line_ending::<_, Error<_>>(Partial::new(d)), + Err(ErrMode::Incomplete(Needed::Unknown)) + ); + } + + #[test] + fn is_not_line_ending_str() { + let f = "βèƒôřè\rÂßÇáƒƭèř"; + assert_eq!( + not_line_ending(Partial::new(f)), + Err(ErrMode::Backtrack(Error::new( + Partial::new(f), + ErrorKind::Tag + ))) + ); + + let g2: &str = "ab12cd"; + assert_eq!( + not_line_ending::<_, Error<_>>(Partial::new(g2)), + Err(ErrMode::Incomplete(Needed::Unknown)) + ); + } + + #[test] + fn hex_digit_test() { + let i = &b"0123456789abcdefABCDEF;"[..]; + assert_parse!( + hex_digit1(Partial::new(i)), + Ok((Partial::new(&b";"[..]), &i[..i.len() - 1])) + ); + + let i = &b"g"[..]; + assert_parse!( + hex_digit1(Partial::new(i)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(i), + ErrorKind::Slice + ))) + ); + + let i = &b"G"[..]; + assert_parse!( + hex_digit1(Partial::new(i)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(i), + ErrorKind::Slice + ))) + ); + + assert!(AsChar::is_hex_digit(b'0')); + assert!(AsChar::is_hex_digit(b'9')); + assert!(AsChar::is_hex_digit(b'a')); + assert!(AsChar::is_hex_digit(b'f')); + assert!(AsChar::is_hex_digit(b'A')); + assert!(AsChar::is_hex_digit(b'F')); + assert!(!AsChar::is_hex_digit(b'g')); + assert!(!AsChar::is_hex_digit(b'G')); + assert!(!AsChar::is_hex_digit(b'/')); + assert!(!AsChar::is_hex_digit(b':')); + assert!(!AsChar::is_hex_digit(b'@')); + assert!(!AsChar::is_hex_digit(b'\x60')); + } + + #[test] + fn oct_digit_test() { + let i = &b"01234567;"[..]; + assert_parse!( + oct_digit1(Partial::new(i)), + Ok((Partial::new(&b";"[..]), &i[..i.len() - 1])) + ); + + let i = &b"8"[..]; + assert_parse!( + oct_digit1(Partial::new(i)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(i), + ErrorKind::Slice + ))) + ); + + assert!(AsChar::is_oct_digit(b'0')); + assert!(AsChar::is_oct_digit(b'7')); + assert!(!AsChar::is_oct_digit(b'8')); + assert!(!AsChar::is_oct_digit(b'9')); + assert!(!AsChar::is_oct_digit(b'a')); + assert!(!AsChar::is_oct_digit(b'A')); + assert!(!AsChar::is_oct_digit(b'/')); + assert!(!AsChar::is_oct_digit(b':')); + assert!(!AsChar::is_oct_digit(b'@')); + assert!(!AsChar::is_oct_digit(b'\x60')); + } + + #[test] + fn full_line_windows() { + #[allow(clippy::type_complexity)] + fn take_full_line(i: Partial<&[u8]>) -> IResult, (&[u8], &[u8])> { + (not_line_ending, line_ending).parse_next(i) + } + let input = b"abc\r\n"; + let output = take_full_line(Partial::new(input)); + assert_eq!( + output, + Ok((Partial::new(&b""[..]), (&b"abc"[..], &b"\r\n"[..]))) + ); + } + + #[test] + fn full_line_unix() { + #[allow(clippy::type_complexity)] + fn take_full_line(i: Partial<&[u8]>) -> IResult, (&[u8], &[u8])> { + (not_line_ending, line_ending).parse_next(i) + } + let input = b"abc\n"; + let output = take_full_line(Partial::new(input)); + assert_eq!( + output, + Ok((Partial::new(&b""[..]), (&b"abc"[..], &b"\n"[..]))) + ); + } + + #[test] + fn check_windows_lineending() { + let input = b"\r\n"; + let output = line_ending(Partial::new(&input[..])); + assert_parse!(output, Ok((Partial::new(&b""[..]), &b"\r\n"[..]))); + } + + #[test] + fn check_unix_lineending() { + let input = b"\n"; + let output = line_ending(Partial::new(&input[..])); + assert_parse!(output, Ok((Partial::new(&b""[..]), &b"\n"[..]))); + } + + #[test] + fn cr_lf() { + assert_parse!( + crlf(Partial::new(&b"\r\na"[..])), + Ok((Partial::new(&b"a"[..]), &b"\r\n"[..])) + ); + assert_parse!( + crlf(Partial::new(&b"\r"[..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_parse!( + crlf(Partial::new(&b"\ra"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"\ra"[..]), + ErrorKind::Tag + ))) + ); + + assert_parse!(crlf(Partial::new("\r\na")), Ok((Partial::new("a"), "\r\n"))); + assert_parse!( + crlf(Partial::new("\r")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_parse!( + crlf(Partial::new("\ra")), + Err(ErrMode::Backtrack(error_position!( + Partial::new("\ra"), + ErrorKind::Tag + ))) + ); + } + + #[test] + fn end_of_line() { + assert_parse!( + line_ending(Partial::new(&b"\na"[..])), + Ok((Partial::new(&b"a"[..]), &b"\n"[..])) + ); + assert_parse!( + line_ending(Partial::new(&b"\r\na"[..])), + Ok((Partial::new(&b"a"[..]), &b"\r\n"[..])) + ); + assert_parse!( + line_ending(Partial::new(&b"\r"[..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_parse!( + line_ending(Partial::new(&b"\ra"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"\ra"[..]), + ErrorKind::Tag + ))) + ); + + assert_parse!( + line_ending(Partial::new("\na")), + Ok((Partial::new("a"), "\n")) + ); + assert_parse!( + line_ending(Partial::new("\r\na")), + Ok((Partial::new("a"), "\r\n")) + ); + assert_parse!( + line_ending(Partial::new("\r")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_parse!( + line_ending(Partial::new("\ra")), + Err(ErrMode::Backtrack(error_position!( + Partial::new("\ra"), + ErrorKind::Tag + ))) + ); + } + + fn digit_to_i16(input: Partial<&str>) -> IResult, i16> { + let i = input; + let (i, opt_sign) = opt(one_of("+-")).parse_next(i)?; + let sign = match opt_sign { + Some('+') | None => true, + Some('-') => false, + _ => unreachable!(), + }; + + let (i, s) = digit1::<_, crate::error::Error<_>>(i)?; + match s.parse_slice() { + Some(n) => { + if sign { + Ok((i, n)) + } else { + Ok((i, -n)) + } + } + None => Err(ErrMode::from_error_kind(i, ErrorKind::Verify)), + } + } + + fn digit_to_u32(i: Partial<&str>) -> IResult, u32> { + let (i, s) = digit1(i)?; + match s.parse_slice() { + Some(n) => Ok((i, n)), + None => Err(ErrMode::from_error_kind(i, ErrorKind::Verify)), + } + } + + proptest! { + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn ints(s in "\\PC*") { + let res1 = digit_to_i16(Partial::new(&s)); + let res2 = dec_int(Partial::new(s.as_str())); + assert_eq!(res1, res2); + } + + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn uints(s in "\\PC*") { + let res1 = digit_to_u32(Partial::new(&s)); + let res2 = dec_uint(Partial::new(s.as_str())); + assert_eq!(res1, res2); + } + } + + #[test] + fn hex_uint_tests() { + fn hex_u32(input: Partial<&[u8]>) -> IResult, u32> { + hex_uint(input) + } + + assert_parse!( + hex_u32(Partial::new(&b";"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b";"[..]), + ErrorKind::Slice + ))) + ); + assert_parse!( + hex_u32(Partial::new(&b"ff;"[..])), + Ok((Partial::new(&b";"[..]), 255)) + ); + assert_parse!( + hex_u32(Partial::new(&b"1be2;"[..])), + Ok((Partial::new(&b";"[..]), 7138)) + ); + assert_parse!( + hex_u32(Partial::new(&b"c5a31be2;"[..])), + Ok((Partial::new(&b";"[..]), 3_315_801_058)) + ); + assert_parse!( + hex_u32(Partial::new(&b"C5A31be2;"[..])), + Ok((Partial::new(&b";"[..]), 3_315_801_058)) + ); + assert_parse!( + hex_u32(Partial::new(&b"00c5a31be2;"[..])), // overflow + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"00c5a31be2;"[..]), + ErrorKind::Verify + ))) + ); + assert_parse!( + hex_u32(Partial::new(&b"c5a31be201;"[..])), // overflow + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"c5a31be201;"[..]), + ErrorKind::Verify + ))) + ); + assert_parse!( + hex_u32(Partial::new(&b"ffffffff;"[..])), + Ok((Partial::new(&b";"[..]), 4_294_967_295)) + ); + assert_parse!( + hex_u32(Partial::new(&b"ffffffffffffffff;"[..])), // overflow + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"ffffffffffffffff;"[..]), + ErrorKind::Verify + ))) + ); + assert_parse!( + hex_u32(Partial::new(&b"ffffffffffffffff"[..])), // overflow + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"ffffffffffffffff"[..]), + ErrorKind::Verify + ))) + ); + assert_parse!( + hex_u32(Partial::new(&b"0x1be2;"[..])), + Ok((Partial::new(&b"x1be2;"[..]), 0)) + ); + assert_parse!( + hex_u32(Partial::new(&b"12af"[..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + } +} diff --git a/vendor/winnow/src/binary/bits/mod.rs b/vendor/winnow/src/binary/bits/mod.rs new file mode 100644 index 000000000..5400e3308 --- /dev/null +++ b/vendor/winnow/src/binary/bits/mod.rs @@ -0,0 +1,342 @@ +//! Bit level parsers +//! + +#[cfg(test)] +mod tests; + +use crate::error::{ErrMode, ErrorConvert, ErrorKind, Needed, ParseError}; +use crate::lib::std::ops::{AddAssign, Div, Shl, Shr}; +use crate::stream::{AsBytes, Stream, StreamIsPartial, ToUsize}; +use crate::trace::trace; +use crate::{IResult, Parser}; + +/// Converts a byte-level input to a bit-level input +/// +/// See [`bytes`] to convert it back. +/// +/// # Example +/// ``` +/// use winnow::prelude::*; +/// use winnow::Bytes; +/// use winnow::binary::bits::{bits, take}; +/// use winnow::error::Error; +/// +/// type Stream<'i> = &'i Bytes; +/// +/// fn stream(b: &[u8]) -> Stream<'_> { +/// Bytes::new(b) +/// } +/// +/// fn parse(input: Stream<'_>) -> IResult, (u8, u8)> { +/// bits::<_, _, Error<(_, usize)>, _, _>((take(4usize), take(8usize))).parse_next(input) +/// } +/// +/// let input = stream(&[0x12, 0x34, 0xff, 0xff]); +/// +/// let output = parse(input).expect("We take 1.5 bytes and the input is longer than 2 bytes"); +/// +/// // The first byte is consumed, the second byte is partially consumed and dropped. +/// let remaining = output.0; +/// assert_eq!(remaining, stream(&[0xff, 0xff])); +/// +/// let parsed = output.1; +/// assert_eq!(parsed.0, 0x01); +/// assert_eq!(parsed.1, 0x23); +/// ``` +pub fn bits(mut parser: P) -> impl Parser +where + E1: ParseError<(I, usize)> + ErrorConvert, + E2: ParseError, + I: Stream, + P: Parser<(I, usize), O, E1>, +{ + trace("bits", move |input: I| { + match parser.parse_next((input, 0)) { + Ok(((rest, offset), result)) => { + // If the next byte has been partially read, it will be sliced away as well. + // The parser functions might already slice away all fully read bytes. + // That's why `offset / 8` isn't necessarily needed at all times. + let remaining_bytes_index = offset / 8 + if offset % 8 == 0 { 0 } else { 1 }; + let (input, _) = rest.next_slice(remaining_bytes_index); + Ok((input, result)) + } + Err(ErrMode::Incomplete(n)) => Err(ErrMode::Incomplete(n.map(|u| u.get() / 8 + 1))), + Err(e) => Err(e.convert()), + } + }) +} + +/// Convert a [`bits`] stream back into a byte stream +/// +/// **Warning:** A partial byte remaining in the input will be ignored and the given parser will +/// start parsing at the next full byte. +/// +/// ``` +/// use winnow::prelude::*; +/// use winnow::Bytes; +/// use winnow::binary::bits::{bits, bytes, take}; +/// use winnow::combinator::rest; +/// use winnow::error::Error; +/// +/// type Stream<'i> = &'i Bytes; +/// +/// fn stream(b: &[u8]) -> Stream<'_> { +/// Bytes::new(b) +/// } +/// +/// fn parse(input: Stream<'_>) -> IResult, (u8, u8, &[u8])> { +/// bits::<_, _, Error<(_, usize)>, _, _>(( +/// take(4usize), +/// take(8usize), +/// bytes::<_, _, Error<_>, _, _>(rest) +/// )).parse_next(input) +/// } +/// +/// let input = stream(&[0x12, 0x34, 0xff, 0xff]); +/// +/// assert_eq!(parse(input), Ok(( stream(&[]), (0x01, 0x23, &[0xff, 0xff][..]) ))); +/// ``` +pub fn bytes(mut parser: P) -> impl Parser<(I, usize), O, E2> +where + E1: ParseError + ErrorConvert, + E2: ParseError<(I, usize)>, + I: Stream, + P: Parser, +{ + trace("bytes", move |(input, offset): (I, usize)| { + let (inner, _) = if offset % 8 != 0 { + input.next_slice(1 + offset / 8) + } else { + input.next_slice(offset / 8) + }; + let i = (input, offset); + match parser.parse_next(inner) { + Ok((rest, res)) => Ok(((rest, 0), res)), + Err(ErrMode::Incomplete(Needed::Unknown)) => Err(ErrMode::Incomplete(Needed::Unknown)), + Err(ErrMode::Incomplete(Needed::Size(sz))) => Err(match sz.get().checked_mul(8) { + Some(v) => ErrMode::Incomplete(Needed::new(v)), + None => ErrMode::Cut(E2::assert( + i, + "overflow in turning needed bytes into needed bits", + )), + }), + Err(e) => Err(e.convert()), + } + }) +} + +/// Parse taking `count` bits +/// +/// # Example +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::Bytes; +/// # use winnow::error::{Error, ErrorKind}; +/// use winnow::binary::bits::take; +/// +/// type Stream<'i> = &'i Bytes; +/// +/// fn stream(b: &[u8]) -> Stream<'_> { +/// Bytes::new(b) +/// } +/// +/// fn parser(input: (Stream<'_>, usize), count: usize)-> IResult<(Stream<'_>, usize), u8> { +/// take(count).parse_next(input) +/// } +/// +/// // Consumes 0 bits, returns 0 +/// assert_eq!(parser((stream(&[0b00010010]), 0), 0), Ok(((stream(&[0b00010010]), 0), 0))); +/// +/// // Consumes 4 bits, returns their values and increase offset to 4 +/// assert_eq!(parser((stream(&[0b00010010]), 0), 4), Ok(((stream(&[0b00010010]), 4), 0b00000001))); +/// +/// // Consumes 4 bits, offset is 4, returns their values and increase offset to 0 of next byte +/// assert_eq!(parser((stream(&[0b00010010]), 4), 4), Ok(((stream(&[]), 0), 0b00000010))); +/// +/// // Tries to consume 12 bits but only 8 are available +/// assert_eq!(parser((stream(&[0b00010010]), 0), 12), Err(winnow::error::ErrMode::Backtrack(Error{input: (stream(&[0b00010010]), 0), kind: ErrorKind::Eof }))); +/// ``` +#[inline(always)] +pub fn take>(count: C) -> impl Parser<(I, usize), O, E> +where + I: Stream + AsBytes + StreamIsPartial, + C: ToUsize, + O: From + AddAssign + Shl + Shr, +{ + let count = count.to_usize(); + trace("take", move |input: (I, usize)| { + if ::is_partial_supported() { + take_::<_, _, _, true>(input, count) + } else { + take_::<_, _, _, false>(input, count) + } + }) +} + +fn take_, const PARTIAL: bool>( + (input, bit_offset): (I, usize), + count: usize, +) -> IResult<(I, usize), O, E> +where + I: StreamIsPartial, + I: Stream + AsBytes, + O: From + AddAssign + Shl + Shr, +{ + if count == 0 { + Ok(((input, bit_offset), 0u8.into())) + } else { + let cnt = (count + bit_offset).div(8); + if input.eof_offset() * 8 < count + bit_offset { + if PARTIAL && input.is_partial() { + Err(ErrMode::Incomplete(Needed::new(count))) + } else { + Err(ErrMode::from_error_kind( + (input, bit_offset), + ErrorKind::Eof, + )) + } + } else { + let mut acc: O = 0_u8.into(); + let mut offset: usize = bit_offset; + let mut remaining: usize = count; + let mut end_offset: usize = 0; + + for byte in input.as_bytes().iter().copied().take(cnt + 1) { + if remaining == 0 { + break; + } + let val: O = if offset == 0 { + byte.into() + } else { + (byte << offset >> offset).into() + }; + + if remaining < 8 - offset { + acc += val >> (8 - offset - remaining); + end_offset = remaining + offset; + break; + } else { + acc += val << (remaining - (8 - offset)); + remaining -= 8 - offset; + offset = 0; + } + } + let (input, _) = input.next_slice(cnt); + Ok(((input, end_offset), acc)) + } + } +} + +/// Parse taking `count` bits and comparing them to `pattern` +/// +/// # Example +/// +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::Bytes; +/// # use winnow::error::{Error, ErrorKind}; +/// use winnow::binary::bits::tag; +/// +/// type Stream<'i> = &'i Bytes; +/// +/// fn stream(b: &[u8]) -> Stream<'_> { +/// Bytes::new(b) +/// } +/// +/// /// Compare the lowest `count` bits of `input` against the lowest `count` bits of `pattern`. +/// /// Return Ok and the matching section of `input` if there's a match. +/// /// Return Err if there's no match. +/// fn parser(pattern: u8, count: u8, input: (Stream<'_>, usize)) -> IResult<(Stream<'_>, usize), u8> { +/// tag(pattern, count).parse_next(input) +/// } +/// +/// // The lowest 4 bits of 0b00001111 match the lowest 4 bits of 0b11111111. +/// assert_eq!( +/// parser(0b0000_1111, 4, (stream(&[0b1111_1111]), 0)), +/// Ok(((stream(&[0b1111_1111]), 4), 0b0000_1111)) +/// ); +/// +/// // The lowest bit of 0b00001111 matches the lowest bit of 0b11111111 (both are 1). +/// assert_eq!( +/// parser(0b00000001, 1, (stream(&[0b11111111]), 0)), +/// Ok(((stream(&[0b11111111]), 1), 0b00000001)) +/// ); +/// +/// // The lowest 2 bits of 0b11111111 and 0b00000001 are different. +/// assert_eq!( +/// parser(0b000000_01, 2, (stream(&[0b111111_11]), 0)), +/// Err(winnow::error::ErrMode::Backtrack(Error { +/// input: (stream(&[0b11111111]), 0), +/// kind: ErrorKind::Tag +/// })) +/// ); +/// +/// // The lowest 8 bits of 0b11111111 and 0b11111110 are different. +/// assert_eq!( +/// parser(0b11111110, 8, (stream(&[0b11111111]), 0)), +/// Err(winnow::error::ErrMode::Backtrack(Error { +/// input: (stream(&[0b11111111]), 0), +/// kind: ErrorKind::Tag +/// })) +/// ); +/// ``` +#[inline(always)] +#[doc(alias = "literal")] +#[doc(alias = "just")] +pub fn tag>( + pattern: O, + count: C, +) -> impl Parser<(I, usize), O, E> +where + I: Stream + AsBytes + StreamIsPartial, + C: ToUsize, + O: From + AddAssign + Shl + Shr + PartialEq, +{ + let count = count.to_usize(); + trace("tag", move |input: (I, usize)| { + let inp = input.clone(); + + take(count).parse_next(input).and_then(|(i, o)| { + if pattern == o { + Ok((i, o)) + } else { + Err(ErrMode::Backtrack(E::from_error_kind(inp, ErrorKind::Tag))) + } + }) + }) +} + +/// Parses one specific bit as a bool. +/// +/// # Example +/// +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::Bytes; +/// # use winnow::error::{Error, ErrorKind}; +/// use winnow::binary::bits::bool; +/// +/// type Stream<'i> = &'i Bytes; +/// +/// fn stream(b: &[u8]) -> Stream<'_> { +/// Bytes::new(b) +/// } +/// +/// fn parse(input: (Stream<'_>, usize)) -> IResult<(Stream<'_>, usize), bool> { +/// bool.parse_next(input) +/// } +/// +/// assert_eq!(parse((stream(&[0b10000000]), 0)), Ok(((stream(&[0b10000000]), 1), true))); +/// assert_eq!(parse((stream(&[0b10000000]), 1)), Ok(((stream(&[0b10000000]), 2), false))); +/// ``` +#[doc(alias = "any")] +pub fn bool>(input: (I, usize)) -> IResult<(I, usize), bool, E> +where + I: Stream + AsBytes + StreamIsPartial, +{ + trace("bool", |input: (I, usize)| { + let (res, bit): (_, u32) = take(1usize).parse_next(input)?; + Ok((res, bit != 0)) + }) + .parse_next(input) +} diff --git a/vendor/winnow/src/binary/bits/tests.rs b/vendor/winnow/src/binary/bits/tests.rs new file mode 100644 index 000000000..61dba2c31 --- /dev/null +++ b/vendor/winnow/src/binary/bits/tests.rs @@ -0,0 +1,190 @@ +use super::*; +use crate::error::Error; +use crate::Partial; + +#[test] +/// Take the `bits` function and assert that remaining bytes are correctly returned, if the +/// previous bytes are fully consumed +fn test_complete_byte_consumption_bits() { + let input = &[0x12, 0x34, 0x56, 0x78][..]; + + // Take 3 bit slices with sizes [4, 8, 4]. + let result: IResult<&[u8], (u8, u8, u8)> = + bits::<_, _, Error<(&[u8], usize)>, _, _>((take(4usize), take(8usize), take(4usize))) + .parse_next(input); + + let output = result.expect("We take 2 bytes and the input is longer than 2 bytes"); + + let remaining = output.0; + assert_eq!(remaining, [0x56, 0x78]); + + let parsed = output.1; + assert_eq!(parsed.0, 0x01); + assert_eq!(parsed.1, 0x23); + assert_eq!(parsed.2, 0x04); +} + +#[test] +/// Take the `bits` function and assert that remaining bytes are correctly returned, if the +/// previous bytes are NOT fully consumed. Partially consumed bytes are supposed to be dropped. +/// I.e. if we consume 1.5 bytes of 4 bytes, 2 bytes will be returned, bits 13-16 will be +/// dropped. +fn test_partial_byte_consumption_bits() { + let input = &[0x12, 0x34, 0x56, 0x78][..]; + + // Take bit slices with sizes [4, 8]. + let result: IResult<&[u8], (u8, u8)> = + bits::<_, _, Error<(&[u8], usize)>, _, _>((take(4usize), take(8usize))).parse_next(input); + + let output = result.expect("We take 1.5 bytes and the input is longer than 2 bytes"); + + let remaining = output.0; + assert_eq!(remaining, [0x56, 0x78]); + + let parsed = output.1; + assert_eq!(parsed.0, 0x01); + assert_eq!(parsed.1, 0x23); +} + +#[test] +#[cfg(feature = "std")] +/// Ensure that in Incomplete error is thrown, if too few bytes are passed for a given parser. +fn test_incomplete_bits() { + let input = Partial::new(&[0x12][..]); + + // Take bit slices with sizes [4, 8]. + let result: IResult<_, (u8, u8)> = + bits::<_, _, Error<(_, usize)>, _, _>((take(4usize), take(8usize))).parse_next(input); + + assert!(result.is_err()); + let error = result.err().unwrap(); + assert_eq!("Parsing requires 2 bytes/chars", error.to_string()); +} + +#[test] +fn test_take_complete_0() { + let input = &[0b00010010][..]; + let count = 0usize; + assert_eq!(count, 0usize); + let offset = 0usize; + + let result: crate::IResult<(&[u8], usize), usize> = take(count).parse_next((input, offset)); + + assert_eq!(result, Ok(((input, offset), 0))); +} + +#[test] +fn test_take_complete_eof() { + let input = &[0b00010010][..]; + + let result: crate::IResult<(&[u8], usize), usize> = take(1usize).parse_next((input, 8)); + + assert_eq!( + result, + Err(crate::error::ErrMode::Backtrack(crate::error::Error { + input: (input, 8), + kind: ErrorKind::Eof + })) + ); +} + +#[test] +fn test_take_complete_span_over_multiple_bytes() { + let input = &[0b00010010, 0b00110100, 0b11111111, 0b11111111][..]; + + let result: crate::IResult<(&[u8], usize), usize> = take(24usize).parse_next((input, 4)); + + assert_eq!( + result, + Ok((([0b11111111].as_ref(), 4), 0b1000110100111111111111)) + ); +} + +#[test] +fn test_take_partial_0() { + let input = Partial::new(&[][..]); + let count = 0usize; + assert_eq!(count, 0usize); + let offset = 0usize; + + let result: crate::IResult<(_, usize), usize> = take(count).parse_next((input, offset)); + + assert_eq!(result, Ok(((input, offset), 0))); +} + +#[test] +fn test_tag_partial_ok() { + let input = Partial::new(&[0b00011111][..]); + let offset = 0usize; + let bits_to_take = 4usize; + let value_to_tag = 0b0001; + + let result: crate::IResult<(_, usize), usize> = + tag(value_to_tag, bits_to_take).parse_next((input, offset)); + + assert_eq!(result, Ok(((input, bits_to_take), value_to_tag))); +} + +#[test] +fn test_tag_partial_err() { + let input = Partial::new(&[0b00011111][..]); + let offset = 0usize; + let bits_to_take = 4usize; + let value_to_tag = 0b1111; + + let result: crate::IResult<(_, usize), usize> = + tag(value_to_tag, bits_to_take).parse_next((input, offset)); + + assert_eq!( + result, + Err(crate::error::ErrMode::Backtrack(crate::error::Error { + input: (input, offset), + kind: ErrorKind::Tag + })) + ); +} + +#[test] +fn test_bool_0_complete() { + let input = [0b10000000].as_ref(); + + let result: crate::IResult<(&[u8], usize), bool> = bool((input, 0)); + + assert_eq!(result, Ok(((input, 1), true))); +} + +#[test] +fn test_bool_eof_complete() { + let input = [0b10000000].as_ref(); + + let result: crate::IResult<(&[u8], usize), bool> = bool((input, 8)); + + assert_eq!( + result, + Err(crate::error::ErrMode::Backtrack(crate::error::Error { + input: (input, 8), + kind: ErrorKind::Eof + })) + ); +} + +#[test] +fn test_bool_0_partial() { + let input = Partial::new([0b10000000].as_ref()); + + let result: crate::IResult<(Partial<&[u8]>, usize), bool> = bool((input, 0)); + + assert_eq!(result, Ok(((input, 1), true))); +} + +#[test] +fn test_bool_eof_partial() { + let input = Partial::new([0b10000000].as_ref()); + + let result: crate::IResult<(Partial<&[u8]>, usize), bool> = bool.parse_next((input, 8)); + + assert_eq!( + result, + Err(crate::error::ErrMode::Incomplete(Needed::new(1))) + ); +} diff --git a/vendor/winnow/src/binary/mod.rs b/vendor/winnow/src/binary/mod.rs new file mode 100644 index 000000000..80435e359 --- /dev/null +++ b/vendor/winnow/src/binary/mod.rs @@ -0,0 +1,2550 @@ +//! Parsers recognizing numbers + +#![allow(clippy::match_same_arms)] + +pub mod bits; + +#[cfg(test)] +mod tests; + +use crate::combinator::repeat; +use crate::error::ErrMode; +use crate::error::ErrorKind; +use crate::error::Needed; +use crate::error::ParseError; +use crate::lib::std::ops::{Add, Shl}; +use crate::stream::Accumulate; +use crate::stream::{AsBytes, Stream, StreamIsPartial}; +use crate::stream::{ToUsize, UpdateSlice}; +use crate::token::take; +use crate::trace::trace; +use crate::IResult; +use crate::Parser; + +/// Configurable endianness +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum Endianness { + /// Big endian + Big, + /// Little endian + Little, + /// Will match the host's endianness + Native, +} + +/// Recognizes an unsigned 1 byte integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::be_u8; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], u8> { +/// be_u8.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"\x03abcefg"[..], 0x00))); +/// assert_eq!(parser(&b""[..]), Err(ErrMode::Backtrack(Error::new(&[][..], ErrorKind::Token)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::be_u8; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, u8> { +/// be_u8.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01abcd"[..])), Ok((Partial::new(&b"\x01abcd"[..]), 0x00))); +/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn be_u8>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, +{ + u8(input) +} + +/// Recognizes a big endian unsigned 2 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::be_u16; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], u16> { +/// be_u16.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"abcefg"[..], 0x0003))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::be_u16; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, u16> { +/// be_u16.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x0001))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn be_u16>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("be_u16", move |input: I| be_uint(input, 2)).parse_next(input) +} + +/// Recognizes a big endian unsigned 3 byte integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::be_u24; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], u32> { +/// be_u24.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03\x05abcefg"[..]), Ok((&b"abcefg"[..], 0x000305))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::be_u24; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, u32> { +/// be_u24.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x000102))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(2)))); +/// ``` +#[inline(always)] +pub fn be_u24>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("be_u23", move |input: I| be_uint(input, 3)).parse_next(input) +} + +/// Recognizes a big endian unsigned 4 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::be_u32; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], u32> { +/// be_u32.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03\x05\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x00030507))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::be_u32; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, u32> { +/// be_u32.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x00010203))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(3)))); +/// ``` +#[inline(always)] +pub fn be_u32>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("be_u32", move |input: I| be_uint(input, 4)).parse_next(input) +} + +/// Recognizes a big endian unsigned 8 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::be_u64; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], u64> { +/// be_u64.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x0001020304050607))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::be_u64; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, u64> { +/// be_u64.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x0001020304050607))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(7)))); +/// ``` +#[inline(always)] +pub fn be_u64>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("be_u64", move |input: I| be_uint(input, 8)).parse_next(input) +} + +/// Recognizes a big endian unsigned 16 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::be_u128; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], u128> { +/// be_u128.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x00010203040506070001020304050607))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::be_u128; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, u128> { +/// be_u128.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x00010203040506070809101112131415))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(15)))); +/// ``` +#[inline(always)] +pub fn be_u128>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("be_u128", move |input: I| be_uint(input, 16)).parse_next(input) +} + +#[inline] +fn be_uint>(input: I, bound: usize) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, + Uint: Default + Shl + Add + From, +{ + debug_assert_ne!(bound, 1, "to_be_uint needs extra work to avoid overflow"); + take(bound) + .map(|n: ::Slice| to_be_uint(n.as_bytes())) + .parse_next(input) +} + +#[inline] +fn to_be_uint(number: &[u8]) -> Uint +where + Uint: Default + Shl + Add + From, +{ + let mut res = Uint::default(); + for byte in number.iter().copied() { + res = (res << 8) + byte.into(); + } + + res +} + +/// Recognizes a signed 1 byte integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::be_i8; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], i8> { +/// be_i8.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"\x03abcefg"[..], 0x00))); +/// assert_eq!(parser(&b""[..]), Err(ErrMode::Backtrack(Error::new(&[][..], ErrorKind::Token)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::be_i8; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, i8> { +/// be_i8.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01abcd"[..])), Ok((Partial::new(&b"\x01abcd"[..]), 0x00))); +/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn be_i8>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, +{ + i8(input) +} + +/// Recognizes a big endian signed 2 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::be_i16; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], i16> { +/// be_i16.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"abcefg"[..], 0x0003))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::be_i16; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, i16> { +/// be_i16.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x0001))); +/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(2)))); +/// ``` +#[inline(always)] +pub fn be_i16>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("be_i16", move |input: I| { + be_uint::<_, u16, _>(input, 2).map(|(i, n)| (i, n as i16)) + }) + .parse_next(input) +} + +/// Recognizes a big endian signed 3 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::be_i24; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], i32> { +/// be_i24.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03\x05abcefg"[..]), Ok((&b"abcefg"[..], 0x000305))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::be_i24; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, i32> { +/// be_i24.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x000102))); +/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(3)))); +/// ``` +#[inline(always)] +pub fn be_i24>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("be_i24", move |input: I| { + be_uint::<_, u32, _>(input, 3).map(|(i, n)| { + // Same as the unsigned version but we need to sign-extend manually here + let n = if n & 0x80_00_00 != 0 { + (n | 0xff_00_00_00) as i32 + } else { + n as i32 + }; + (i, n) + }) + }) + .parse_next(input) +} + +/// Recognizes a big endian signed 4 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::be_i32; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], i32> { +/// be_i32.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03\x05\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x00030507))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::be_i32; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, i32> { +/// be_i32.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x00010203))); +/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(4)))); +/// ``` +#[inline(always)] +pub fn be_i32>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("be_i32", move |input: I| { + be_uint::<_, u32, _>(input, 4).map(|(i, n)| (i, n as i32)) + }) + .parse_next(input) +} + +/// Recognizes a big endian signed 8 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::be_i64; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], i64> { +/// be_i64.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x0001020304050607))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::be_i64; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, i64> { +/// be_i64.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x0001020304050607))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(7)))); +/// ``` +#[inline(always)] +pub fn be_i64>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("be_i64", move |input: I| { + be_uint::<_, u64, _>(input, 8).map(|(i, n)| (i, n as i64)) + }) + .parse_next(input) +} + +/// Recognizes a big endian signed 16 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::be_i128; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], i128> { +/// be_i128.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x00010203040506070001020304050607))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::be_i128; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, i128> { +/// be_i128.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x00010203040506070809101112131415))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(15)))); +/// ``` +#[inline(always)] +pub fn be_i128>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("be_i128", move |input: I| { + be_uint::<_, u128, _>(input, 16).map(|(i, n)| (i, n as i128)) + }) + .parse_next(input) +} + +/// Recognizes an unsigned 1 byte integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::le_u8; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], u8> { +/// le_u8.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"\x03abcefg"[..], 0x00))); +/// assert_eq!(parser(&b""[..]), Err(ErrMode::Backtrack(Error::new(&[][..], ErrorKind::Token)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::le_u8; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, u8> { +/// le_u8.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01abcd"[..])), Ok((Partial::new(&b"\x01abcd"[..]), 0x00))); +/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn le_u8>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, +{ + u8(input) +} + +/// Recognizes a little endian unsigned 2 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::le_u16; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], u16> { +/// le_u16.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"abcefg"[..], 0x0300))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::le_u16; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, u16> { +/// le_u16::<_, Error<_>>.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x0100))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn le_u16>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("le_u16", move |input: I| le_uint(input, 2)).parse_next(input) +} + +/// Recognizes a little endian unsigned 3 byte integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::le_u24; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], u32> { +/// le_u24.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03\x05abcefg"[..]), Ok((&b"abcefg"[..], 0x050300))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::le_u24; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, u32> { +/// le_u24::<_, Error<_>>.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x020100))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(2)))); +/// ``` +#[inline(always)] +pub fn le_u24>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("le_u24", move |input: I| le_uint(input, 3)).parse_next(input) +} + +/// Recognizes a little endian unsigned 4 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::le_u32; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], u32> { +/// le_u32.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03\x05\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x07050300))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::le_u32; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, u32> { +/// le_u32::<_, Error<_>>.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x03020100))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(3)))); +/// ``` +#[inline(always)] +pub fn le_u32>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("le_u32", move |input: I| le_uint(input, 4)).parse_next(input) +} + +/// Recognizes a little endian unsigned 8 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::le_u64; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], u64> { +/// le_u64.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x0706050403020100))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::le_u64; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, u64> { +/// le_u64::<_, Error<_>>.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x0706050403020100))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(7)))); +/// ``` +#[inline(always)] +pub fn le_u64>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("le_u64", move |input: I| le_uint(input, 8)).parse_next(input) +} + +/// Recognizes a little endian unsigned 16 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::le_u128; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], u128> { +/// le_u128.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x07060504030201000706050403020100))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::le_u128; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, u128> { +/// le_u128::<_, Error<_>>.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x15141312111009080706050403020100))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(15)))); +/// ``` +#[inline(always)] +pub fn le_u128>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("le_u128", move |input: I| le_uint(input, 16)).parse_next(input) +} + +#[inline] +fn le_uint>(input: I, bound: usize) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, + Uint: Default + Shl + Add + From, +{ + take(bound) + .map(|n: ::Slice| to_le_uint(n.as_bytes())) + .parse_next(input) +} + +#[inline] +fn to_le_uint(number: &[u8]) -> Uint +where + Uint: Default + Shl + Add + From, +{ + let mut res = Uint::default(); + for (index, byte) in number.iter_offsets() { + res = res + (Uint::from(byte) << (8 * index as u8)); + } + + res +} + +/// Recognizes a signed 1 byte integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::le_i8; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], i8> { +/// le_i8.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"\x03abcefg"[..], 0x00))); +/// assert_eq!(parser(&b""[..]), Err(ErrMode::Backtrack(Error::new(&[][..], ErrorKind::Token)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::le_i8; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, i8> { +/// le_i8.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01abcd"[..])), Ok((Partial::new(&b"\x01abcd"[..]), 0x00))); +/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn le_i8>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, +{ + i8(input) +} + +/// Recognizes a little endian signed 2 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::le_i16; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], i16> { +/// le_i16.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"abcefg"[..], 0x0300))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::le_i16; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, i16> { +/// le_i16::<_, Error<_>>.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x0100))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn le_i16>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("le_i16", move |input: I| { + le_uint::<_, u16, _>(input, 2).map(|(i, n)| (i, n as i16)) + }) + .parse_next(input) +} + +/// Recognizes a little endian signed 3 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::le_i24; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], i32> { +/// le_i24.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03\x05abcefg"[..]), Ok((&b"abcefg"[..], 0x050300))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::le_i24; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, i32> { +/// le_i24::<_, Error<_>>.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x020100))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(2)))); +/// ``` +#[inline(always)] +pub fn le_i24>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("le_i24", move |input: I| { + le_uint::<_, u32, _>(input, 3).map(|(i, n)| { + // Same as the unsigned version but we need to sign-extend manually here + let n = if n & 0x80_00_00 != 0 { + (n | 0xff_00_00_00) as i32 + } else { + n as i32 + }; + (i, n) + }) + }) + .parse_next(input) +} + +/// Recognizes a little endian signed 4 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::le_i32; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], i32> { +/// le_i32.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03\x05\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x07050300))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::le_i32; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, i32> { +/// le_i32::<_, Error<_>>.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x03020100))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(3)))); +/// ``` +#[inline(always)] +pub fn le_i32>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("le_i32", move |input: I| { + le_uint::<_, u32, _>(input, 4).map(|(i, n)| (i, n as i32)) + }) + .parse_next(input) +} + +/// Recognizes a little endian signed 8 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::le_i64; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], i64> { +/// le_i64.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x0706050403020100))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::le_i64; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, i64> { +/// le_i64::<_, Error<_>>.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x0706050403020100))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(7)))); +/// ``` +#[inline(always)] +pub fn le_i64>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("le_i64", move |input: I| { + le_uint::<_, u64, _>(input, 8).map(|(i, n)| (i, n as i64)) + }) + .parse_next(input) +} + +/// Recognizes a little endian signed 16 bytes integer. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::le_i128; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], i128> { +/// le_i128.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x07060504030201000706050403020100))); +/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::le_i128; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, i128> { +/// le_i128::<_, Error<_>>.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x15141312111009080706050403020100))); +/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(15)))); +/// ``` +#[inline(always)] +pub fn le_i128>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("le_i128", move |input: I| { + le_uint::<_, u128, _>(input, 16).map(|(i, n)| (i, n as i128)) + }) + .parse_next(input) +} + +/// Recognizes an unsigned 1 byte integer +/// +/// **Note:** that endianness does not apply to 1 byte numbers. +/// +/// *Complete version*: returns an error if there is not enough input data +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::u8; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], u8> { +/// u8.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"\x03abcefg"[..], 0x00))); +/// assert_eq!(parser(&b""[..]), Err(ErrMode::Backtrack(Error::new(&[][..], ErrorKind::Token)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// # use winnow::Partial; +/// use winnow::binary::u8; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, u8> { +/// u8::<_, Error<_>>.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x03abcefg"[..])), Ok((Partial::new(&b"\x03abcefg"[..]), 0x00))); +/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn u8>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, +{ + trace("u8", move |input: I| { + if ::is_partial_supported() { + u8_::<_, _, true>(input) + } else { + u8_::<_, _, false>(input) + } + }) + .parse_next(input) +} + +fn u8_, const PARTIAL: bool>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, +{ + input.next_token().ok_or_else(|| { + if PARTIAL && input.is_partial() { + ErrMode::Incomplete(Needed::new(1)) + } else { + ErrMode::Backtrack(E::from_error_kind(input, ErrorKind::Token)) + } + }) +} + +/// Recognizes an unsigned 2 bytes integer +/// +/// If the parameter is `winnow::binary::Endianness::Big`, parse a big endian u16 integer, +/// otherwise if `winnow::binary::Endianness::Little` parse a little endian u16 integer. +/// +/// *Complete version*: returns an error if there is not enough input data +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::u16; +/// +/// let be_u16 = |s| { +/// u16(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_u16(&b"\x00\x03abcefg"[..]), Ok((&b"abcefg"[..], 0x0003))); +/// assert_eq!(be_u16(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// +/// let le_u16 = |s| { +/// u16(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_u16(&b"\x00\x03abcefg"[..]), Ok((&b"abcefg"[..], 0x0300))); +/// assert_eq!(le_u16(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// # use winnow::Partial; +/// use winnow::binary::u16; +/// +/// let be_u16 = |s| { +/// u16::<_, Error<_>>(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_u16(Partial::new(&b"\x00\x03abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x0003))); +/// assert_eq!(be_u16(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); +/// +/// let le_u16 = |s| { +/// u16::<_, Error<_>>(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_u16(Partial::new(&b"\x00\x03abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x0300))); +/// assert_eq!(le_u16(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn u16>(endian: Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + move |input: I| { + match endian { + Endianness::Big => be_u16, + Endianness::Little => le_u16, + #[cfg(target_endian = "big")] + Endianness::Native => be_u16, + #[cfg(target_endian = "little")] + Endianness::Native => le_u16, + } + }(input) +} + +/// Recognizes an unsigned 3 byte integer +/// +/// If the parameter is `winnow::binary::Endianness::Big`, parse a big endian u24 integer, +/// otherwise if `winnow::binary::Endianness::Little` parse a little endian u24 integer. +/// +/// *Complete version*: returns an error if there is not enough input data +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::u24; +/// +/// let be_u24 = |s| { +/// u24(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_u24(&b"\x00\x03\x05abcefg"[..]), Ok((&b"abcefg"[..], 0x000305))); +/// assert_eq!(be_u24(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// +/// let le_u24 = |s| { +/// u24(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_u24(&b"\x00\x03\x05abcefg"[..]), Ok((&b"abcefg"[..], 0x050300))); +/// assert_eq!(le_u24(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// # use winnow::Partial; +/// use winnow::binary::u24; +/// +/// let be_u24 = |s| { +/// u24::<_,Error<_>>(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_u24(Partial::new(&b"\x00\x03\x05abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x000305))); +/// assert_eq!(be_u24(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(2)))); +/// +/// let le_u24 = |s| { +/// u24::<_, Error<_>>(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_u24(Partial::new(&b"\x00\x03\x05abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x050300))); +/// assert_eq!(le_u24(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(2)))); +/// ``` +#[inline(always)] +pub fn u24>(endian: Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + move |input: I| { + match endian { + Endianness::Big => be_u24, + Endianness::Little => le_u24, + #[cfg(target_endian = "big")] + Endianness::Native => be_u24, + #[cfg(target_endian = "little")] + Endianness::Native => le_u24, + } + }(input) +} + +/// Recognizes an unsigned 4 byte integer +/// +/// If the parameter is `winnow::binary::Endianness::Big`, parse a big endian u32 integer, +/// otherwise if `winnow::binary::Endianness::Little` parse a little endian u32 integer. +/// +/// *Complete version*: returns an error if there is not enough input data +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::u32; +/// +/// let be_u32 = |s| { +/// u32(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_u32(&b"\x00\x03\x05\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x00030507))); +/// assert_eq!(be_u32(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// +/// let le_u32 = |s| { +/// u32(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_u32(&b"\x00\x03\x05\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x07050300))); +/// assert_eq!(le_u32(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// # use winnow::Partial; +/// use winnow::binary::u32; +/// +/// let be_u32 = |s| { +/// u32::<_, Error<_>>(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_u32(Partial::new(&b"\x00\x03\x05\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x00030507))); +/// assert_eq!(be_u32(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(3)))); +/// +/// let le_u32 = |s| { +/// u32::<_, Error<_>>(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_u32(Partial::new(&b"\x00\x03\x05\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x07050300))); +/// assert_eq!(le_u32(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(3)))); +/// ``` +#[inline(always)] +pub fn u32>(endian: Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + move |input: I| { + match endian { + Endianness::Big => be_u32, + Endianness::Little => le_u32, + #[cfg(target_endian = "big")] + Endianness::Native => be_u32, + #[cfg(target_endian = "little")] + Endianness::Native => le_u32, + } + }(input) +} + +/// Recognizes an unsigned 8 byte integer +/// +/// If the parameter is `winnow::binary::Endianness::Big`, parse a big endian u64 integer, +/// otherwise if `winnow::binary::Endianness::Little` parse a little endian u64 integer. +/// +/// *Complete version*: returns an error if there is not enough input data +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::u64; +/// +/// let be_u64 = |s| { +/// u64(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_u64(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x0001020304050607))); +/// assert_eq!(be_u64(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// +/// let le_u64 = |s| { +/// u64(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_u64(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x0706050403020100))); +/// assert_eq!(le_u64(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// # use winnow::Partial; +/// use winnow::binary::u64; +/// +/// let be_u64 = |s| { +/// u64::<_, Error<_>>(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_u64(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x0001020304050607))); +/// assert_eq!(be_u64(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(7)))); +/// +/// let le_u64 = |s| { +/// u64::<_, Error<_>>(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_u64(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x0706050403020100))); +/// assert_eq!(le_u64(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(7)))); +/// ``` +#[inline(always)] +pub fn u64>(endian: Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + move |input: I| { + match endian { + Endianness::Big => be_u64, + Endianness::Little => le_u64, + #[cfg(target_endian = "big")] + Endianness::Native => be_u64, + #[cfg(target_endian = "little")] + Endianness::Native => le_u64, + } + }(input) +} + +/// Recognizes an unsigned 16 byte integer +/// +/// If the parameter is `winnow::binary::Endianness::Big`, parse a big endian u128 integer, +/// otherwise if `winnow::binary::Endianness::Little` parse a little endian u128 integer. +/// +/// *Complete version*: returns an error if there is not enough input data +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::u128; +/// +/// let be_u128 = |s| { +/// u128(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_u128(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x00010203040506070001020304050607))); +/// assert_eq!(be_u128(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// +/// let le_u128 = |s| { +/// u128(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_u128(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x07060504030201000706050403020100))); +/// assert_eq!(le_u128(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// # use winnow::Partial; +/// use winnow::binary::u128; +/// +/// let be_u128 = |s| { +/// u128::<_, Error<_>>(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_u128(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x00010203040506070001020304050607))); +/// assert_eq!(be_u128(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(15)))); +/// +/// let le_u128 = |s| { +/// u128::<_, Error<_>>(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_u128(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x07060504030201000706050403020100))); +/// assert_eq!(le_u128(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(15)))); +/// ``` +#[inline(always)] +pub fn u128>(endian: Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + move |input: I| { + match endian { + Endianness::Big => be_u128, + Endianness::Little => le_u128, + #[cfg(target_endian = "big")] + Endianness::Native => be_u128, + #[cfg(target_endian = "little")] + Endianness::Native => le_u128, + } + }(input) +} + +/// Recognizes a signed 1 byte integer +/// +/// **Note:** that endianness does not apply to 1 byte numbers. +/// +/// *Complete version*: returns an error if there is not enough input data +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::i8; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], i8> { +/// i8.parse_next(s) +/// } +/// +/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"\x03abcefg"[..], 0x00))); +/// assert_eq!(parser(&b""[..]), Err(ErrMode::Backtrack(Error::new(&[][..], ErrorKind::Token)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// # use winnow::Partial; +/// use winnow::binary::i8; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, i8> { +/// i8.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&b"\x00\x03abcefg"[..])), Ok((Partial::new(&b"\x03abcefg"[..]), 0x00))); +/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn i8>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, +{ + trace("i8", move |input: I| { + if ::is_partial_supported() { + u8_::<_, _, true>(input) + } else { + u8_::<_, _, false>(input) + } + .map(|(i, n)| (i, n as i8)) + }) + .parse_next(input) +} + +/// Recognizes a signed 2 byte integer +/// +/// If the parameter is `winnow::binary::Endianness::Big`, parse a big endian i16 integer, +/// otherwise if `winnow::binary::Endianness::Little` parse a little endian i16 integer. +/// +/// *Complete version*: returns an error if there is not enough input data +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::i16; +/// +/// let be_i16 = |s| { +/// i16(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_i16(&b"\x00\x03abcefg"[..]), Ok((&b"abcefg"[..], 0x0003))); +/// assert_eq!(be_i16(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// +/// let le_i16 = |s| { +/// i16(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_i16(&b"\x00\x03abcefg"[..]), Ok((&b"abcefg"[..], 0x0300))); +/// assert_eq!(le_i16(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// # use winnow::Partial; +/// use winnow::binary::i16; +/// +/// let be_i16 = |s| { +/// i16::<_, Error<_>>(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_i16(Partial::new(&b"\x00\x03abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x0003))); +/// assert_eq!(be_i16(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); +/// +/// let le_i16 = |s| { +/// i16::<_, Error<_>>(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_i16(Partial::new(&b"\x00\x03abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x0300))); +/// assert_eq!(le_i16(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn i16>(endian: Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + move |input: I| { + match endian { + Endianness::Big => be_i16, + Endianness::Little => le_i16, + #[cfg(target_endian = "big")] + Endianness::Native => be_i16, + #[cfg(target_endian = "little")] + Endianness::Native => le_i16, + } + }(input) +} + +/// Recognizes a signed 3 byte integer +/// +/// If the parameter is `winnow::binary::Endianness::Big`, parse a big endian i24 integer, +/// otherwise if `winnow::binary::Endianness::Little` parse a little endian i24 integer. +/// +/// *Complete version*: returns an error if there is not enough input data +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::i24; +/// +/// let be_i24 = |s| { +/// i24(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_i24(&b"\x00\x03\x05abcefg"[..]), Ok((&b"abcefg"[..], 0x000305))); +/// assert_eq!(be_i24(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// +/// let le_i24 = |s| { +/// i24(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_i24(&b"\x00\x03\x05abcefg"[..]), Ok((&b"abcefg"[..], 0x050300))); +/// assert_eq!(le_i24(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// # use winnow::Partial; +/// use winnow::binary::i24; +/// +/// let be_i24 = |s| { +/// i24::<_, Error<_>>(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_i24(Partial::new(&b"\x00\x03\x05abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x000305))); +/// assert_eq!(be_i24(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(2)))); +/// +/// let le_i24 = |s| { +/// i24::<_, Error<_>>(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_i24(Partial::new(&b"\x00\x03\x05abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x050300))); +/// assert_eq!(le_i24(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(2)))); +/// ``` +#[inline(always)] +pub fn i24>(endian: Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + move |input: I| { + match endian { + Endianness::Big => be_i24, + Endianness::Little => le_i24, + #[cfg(target_endian = "big")] + Endianness::Native => be_i24, + #[cfg(target_endian = "little")] + Endianness::Native => le_i24, + } + }(input) +} + +/// Recognizes a signed 4 byte integer +/// +/// If the parameter is `winnow::binary::Endianness::Big`, parse a big endian i32 integer, +/// otherwise if `winnow::binary::Endianness::Little` parse a little endian i32 integer. +/// +/// *Complete version*: returns an error if there is not enough input data +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::i32; +/// +/// let be_i32 = |s| { +/// i32(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_i32(&b"\x00\x03\x05\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x00030507))); +/// assert_eq!(be_i32(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// +/// let le_i32 = |s| { +/// i32(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_i32(&b"\x00\x03\x05\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x07050300))); +/// assert_eq!(le_i32(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// # use winnow::Partial; +/// use winnow::binary::i32; +/// +/// let be_i32 = |s| { +/// i32::<_, Error<_>>(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_i32(Partial::new(&b"\x00\x03\x05\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x00030507))); +/// assert_eq!(be_i32(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(3)))); +/// +/// let le_i32 = |s| { +/// i32::<_, Error<_>>(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_i32(Partial::new(&b"\x00\x03\x05\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x07050300))); +/// assert_eq!(le_i32(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(3)))); +/// ``` +#[inline(always)] +pub fn i32>(endian: Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + move |input: I| { + match endian { + Endianness::Big => be_i32, + Endianness::Little => le_i32, + #[cfg(target_endian = "big")] + Endianness::Native => be_i32, + #[cfg(target_endian = "little")] + Endianness::Native => le_i32, + } + }(input) +} + +/// Recognizes a signed 8 byte integer +/// +/// If the parameter is `winnow::binary::Endianness::Big`, parse a big endian i64 integer, +/// otherwise if `winnow::binary::Endianness::Little` parse a little endian i64 integer. +/// +/// *Complete version*: returns an error if there is not enough input data +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::i64; +/// +/// let be_i64 = |s| { +/// i64(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_i64(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x0001020304050607))); +/// assert_eq!(be_i64(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// +/// let le_i64 = |s| { +/// i64(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_i64(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x0706050403020100))); +/// assert_eq!(le_i64(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// # use winnow::Partial; +/// use winnow::binary::i64; +/// +/// let be_i64 = |s| { +/// i64::<_, Error<_>>(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_i64(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x0001020304050607))); +/// assert_eq!(be_i64(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(7)))); +/// +/// let le_i64 = |s| { +/// i64::<_, Error<_>>(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_i64(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x0706050403020100))); +/// assert_eq!(le_i64(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(7)))); +/// ``` +#[inline(always)] +pub fn i64>(endian: Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + move |input: I| { + match endian { + Endianness::Big => be_i64, + Endianness::Little => le_i64, + #[cfg(target_endian = "big")] + Endianness::Native => be_i64, + #[cfg(target_endian = "little")] + Endianness::Native => le_i64, + } + }(input) +} + +/// Recognizes a signed 16 byte integer +/// +/// If the parameter is `winnow::binary::Endianness::Big`, parse a big endian i128 integer, +/// otherwise if `winnow::binary::Endianness::Little` parse a little endian i128 integer. +/// +/// *Complete version*: returns an error if there is not enough input data +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::i128; +/// +/// let be_i128 = |s| { +/// i128(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_i128(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x00010203040506070001020304050607))); +/// assert_eq!(be_i128(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// +/// let le_i128 = |s| { +/// i128(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_i128(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x07060504030201000706050403020100))); +/// assert_eq!(le_i128(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// # use winnow::Partial; +/// use winnow::binary::i128; +/// +/// let be_i128 = |s| { +/// i128::<_, Error<_>>(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_i128(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x00010203040506070001020304050607))); +/// assert_eq!(be_i128(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(15)))); +/// +/// let le_i128 = |s| { +/// i128::<_, Error<_>>(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_i128(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x07060504030201000706050403020100))); +/// assert_eq!(le_i128(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(15)))); +/// ``` +#[inline(always)] +pub fn i128>(endian: Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + move |input: I| { + match endian { + Endianness::Big => be_i128, + Endianness::Little => le_i128, + #[cfg(target_endian = "big")] + Endianness::Native => be_i128, + #[cfg(target_endian = "little")] + Endianness::Native => le_i128, + } + }(input) +} + +/// Recognizes a big endian 4 bytes floating point number. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::be_f32; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], f32> { +/// be_f32.parse_next(s) +/// } +/// +/// assert_eq!(parser(&[0x41, 0x48, 0x00, 0x00][..]), Ok((&b""[..], 12.5))); +/// assert_eq!(parser(&b"abc"[..]), Err(ErrMode::Backtrack(Error::new(&b"abc"[..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::be_f32; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, f32> { +/// be_f32.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&[0x40, 0x29, 0x00, 0x00][..])), Ok((Partial::new(&b""[..]), 2.640625))); +/// assert_eq!(parser(Partial::new(&[0x01][..])), Err(ErrMode::Incomplete(Needed::new(3)))); +/// ``` +#[inline(always)] +pub fn be_f32>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("be_f32", move |input: I| { + be_uint::<_, u32, _>(input, 4).map(|(i, n)| (i, f32::from_bits(n))) + }) + .parse_next(input) +} + +/// Recognizes a big endian 8 bytes floating point number. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::be_f64; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], f64> { +/// be_f64.parse_next(s) +/// } +/// +/// assert_eq!(parser(&[0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]), Ok((&b""[..], 12.5))); +/// assert_eq!(parser(&b"abc"[..]), Err(ErrMode::Backtrack(Error::new(&b"abc"[..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::be_f64; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, f64> { +/// be_f64::<_, Error<_>>.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&[0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..])), Ok((Partial::new(&b""[..]), 12.5))); +/// assert_eq!(parser(Partial::new(&[0x01][..])), Err(ErrMode::Incomplete(Needed::new(7)))); +/// ``` +#[inline(always)] +pub fn be_f64>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("be_f64", move |input: I| { + be_uint::<_, u64, _>(input, 8).map(|(i, n)| (i, f64::from_bits(n))) + }) + .parse_next(input) +} + +/// Recognizes a little endian 4 bytes floating point number. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::le_f32; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], f32> { +/// le_f32.parse_next(s) +/// } +/// +/// assert_eq!(parser(&[0x00, 0x00, 0x48, 0x41][..]), Ok((&b""[..], 12.5))); +/// assert_eq!(parser(&b"abc"[..]), Err(ErrMode::Backtrack(Error::new(&b"abc"[..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::le_f32; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, f32> { +/// le_f32::<_, Error<_>>.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&[0x00, 0x00, 0x48, 0x41][..])), Ok((Partial::new(&b""[..]), 12.5))); +/// assert_eq!(parser(Partial::new(&[0x01][..])), Err(ErrMode::Incomplete(Needed::new(3)))); +/// ``` +#[inline(always)] +pub fn le_f32>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("le_f32", move |input: I| { + le_uint::<_, u32, _>(input, 4).map(|(i, n)| (i, f32::from_bits(n))) + }) + .parse_next(input) +} + +/// Recognizes a little endian 8 bytes floating point number. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::le_f64; +/// +/// fn parser(s: &[u8]) -> IResult<&[u8], f64> { +/// le_f64.parse_next(s) +/// } +/// +/// assert_eq!(parser(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40][..]), Ok((&b""[..], 12.5))); +/// assert_eq!(parser(&b"abc"[..]), Err(ErrMode::Backtrack(Error::new(&b"abc"[..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::binary::le_f64; +/// +/// fn parser(s: Partial<&[u8]>) -> IResult, f64> { +/// le_f64::<_, Error<_>>.parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x41][..])), Ok((Partial::new(&b""[..]), 3145728.0))); +/// assert_eq!(parser(Partial::new(&[0x01][..])), Err(ErrMode::Incomplete(Needed::new(7)))); +/// ``` +#[inline(always)] +pub fn le_f64>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + trace("be_f64", move |input: I| { + le_uint::<_, u64, _>(input, 8).map(|(i, n)| (i, f64::from_bits(n))) + }) + .parse_next(input) +} + +/// Recognizes a 4 byte floating point number +/// +/// If the parameter is `winnow::binary::Endianness::Big`, parse a big endian f32 float, +/// otherwise if `winnow::binary::Endianness::Little` parse a little endian f32 float. +/// +/// *Complete version*: returns an error if there is not enough input data +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::f32; +/// +/// let be_f32 = |s| { +/// f32(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_f32(&[0x41, 0x48, 0x00, 0x00][..]), Ok((&b""[..], 12.5))); +/// assert_eq!(be_f32(&b"abc"[..]), Err(ErrMode::Backtrack(Error::new(&b"abc"[..], ErrorKind::Slice)))); +/// +/// let le_f32 = |s| { +/// f32(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_f32(&[0x00, 0x00, 0x48, 0x41][..]), Ok((&b""[..], 12.5))); +/// assert_eq!(le_f32(&b"abc"[..]), Err(ErrMode::Backtrack(Error::new(&b"abc"[..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// # use winnow::Partial; +/// use winnow::binary::f32; +/// +/// let be_f32 = |s| { +/// f32::<_, Error<_>>(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_f32(Partial::new(&[0x41, 0x48, 0x00, 0x00][..])), Ok((Partial::new(&b""[..]), 12.5))); +/// assert_eq!(be_f32(Partial::new(&b"abc"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); +/// +/// let le_f32 = |s| { +/// f32::<_, Error<_>>(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_f32(Partial::new(&[0x00, 0x00, 0x48, 0x41][..])), Ok((Partial::new(&b""[..]), 12.5))); +/// assert_eq!(le_f32(Partial::new(&b"abc"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn f32>(endian: Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + move |input: I| { + match endian { + Endianness::Big => be_f32, + Endianness::Little => le_f32, + #[cfg(target_endian = "big")] + Endianness::Native => be_f32, + #[cfg(target_endian = "little")] + Endianness::Native => le_f32, + } + }(input) +} + +/// Recognizes an 8 byte floating point number +/// +/// If the parameter is `winnow::binary::Endianness::Big`, parse a big endian f64 float, +/// otherwise if `winnow::binary::Endianness::Little` parse a little endian f64 float. +/// +/// *Complete version*: returns an error if there is not enough input data +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::binary::f64; +/// +/// let be_f64 = |s| { +/// f64(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_f64(&[0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]), Ok((&b""[..], 12.5))); +/// assert_eq!(be_f64(&b"abc"[..]), Err(ErrMode::Backtrack(Error::new(&b"abc"[..], ErrorKind::Slice)))); +/// +/// let le_f64 = |s| { +/// f64(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_f64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40][..]), Ok((&b""[..], 12.5))); +/// assert_eq!(le_f64(&b"abc"[..]), Err(ErrMode::Backtrack(Error::new(&b"abc"[..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// # use winnow::Partial; +/// use winnow::binary::f64; +/// +/// let be_f64 = |s| { +/// f64::<_, Error<_>>(winnow::binary::Endianness::Big).parse_next(s) +/// }; +/// +/// assert_eq!(be_f64(Partial::new(&[0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..])), Ok((Partial::new(&b""[..]), 12.5))); +/// assert_eq!(be_f64(Partial::new(&b"abc"[..])), Err(ErrMode::Incomplete(Needed::new(5)))); +/// +/// let le_f64 = |s| { +/// f64::<_, Error<_>>(winnow::binary::Endianness::Little).parse_next(s) +/// }; +/// +/// assert_eq!(le_f64(Partial::new(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40][..])), Ok((Partial::new(&b""[..]), 12.5))); +/// assert_eq!(le_f64(Partial::new(&b"abc"[..])), Err(ErrMode::Incomplete(Needed::new(5)))); +/// ``` +#[inline(always)] +pub fn f64>(endian: Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + move |input: I| { + match endian { + Endianness::Big => be_f64, + Endianness::Little => le_f64, + #[cfg(target_endian = "big")] + Endianness::Native => be_f64, + #[cfg(target_endian = "little")] + Endianness::Native => le_f64, + } + }(input) +} + +/// Gets a number from the parser and returns a +/// subslice of the input of that size. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Arguments +/// * `f` The parser to apply. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed, stream::Partial}; +/// # use winnow::prelude::*; +/// use winnow::Bytes; +/// use winnow::binary::be_u16; +/// use winnow::binary::length_data; +/// use winnow::token::tag; +/// +/// type Stream<'i> = Partial<&'i Bytes>; +/// +/// fn stream(b: &[u8]) -> Stream<'_> { +/// Partial::new(Bytes::new(b)) +/// } +/// +/// fn parser(s: Stream<'_>) -> IResult, &[u8]> { +/// length_data(be_u16).parse_next(s) +/// } +/// +/// assert_eq!(parser(stream(b"\x00\x03abcefg")), Ok((stream(&b"efg"[..]), &b"abc"[..]))); +/// assert_eq!(parser(stream(b"\x00\x03a")), Err(ErrMode::Incomplete(Needed::new(2)))); +/// ``` +pub fn length_data(mut f: F) -> impl Parser::Slice, E> +where + I: StreamIsPartial, + I: Stream, + N: ToUsize, + F: Parser, + E: ParseError, +{ + trace("length_data", move |i: I| { + let (i, length) = f.parse_next(i)?; + + crate::token::take(length).parse_next(i) + }) +} + +/// 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. +/// +/// *Complete version*: Returns an error if there is not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. +/// +/// # Arguments +/// * `f` The parser to apply. +/// * `g` The parser to apply on the subslice. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed, stream::{Partial, StreamIsPartial}}; +/// # use winnow::prelude::*; +/// use winnow::Bytes; +/// use winnow::binary::be_u16; +/// use winnow::binary::length_value; +/// use winnow::token::tag; +/// +/// type Stream<'i> = Partial<&'i Bytes>; +/// +/// fn stream(b: &[u8]) -> Stream<'_> { +/// Partial::new(Bytes::new(b)) +/// } +/// +/// fn complete_stream(b: &[u8]) -> Stream<'_> { +/// let mut p = Partial::new(Bytes::new(b)); +/// let _ = p.complete(); +/// p +/// } +/// +/// fn parser(s: Stream<'_>) -> IResult, &[u8]> { +/// length_value(be_u16, "abc").parse_next(s) +/// } +/// +/// assert_eq!(parser(stream(b"\x00\x03abcefg")), Ok((stream(&b"efg"[..]), &b"abc"[..]))); +/// assert_eq!(parser(stream(b"\x00\x03123123")), Err(ErrMode::Backtrack(Error::new(complete_stream(&b"123"[..]), ErrorKind::Tag)))); +/// assert_eq!(parser(stream(b"\x00\x03a")), Err(ErrMode::Incomplete(Needed::new(2)))); +/// ``` +pub fn length_value(mut f: F, mut g: G) -> impl Parser +where + I: StreamIsPartial, + I: Stream + UpdateSlice, + N: ToUsize, + F: Parser, + G: Parser, + E: ParseError, +{ + trace("length_value", move |i: I| { + let (i, data) = length_data(f.by_ref()).parse_next(i)?; + let mut data = I::update_slice(i.clone(), data); + let _ = data.complete(); + let (_, o) = g.by_ref().complete_err().parse_next(data)?; + Ok((i, o)) + }) +} + +/// Gets a number from the first parser, +/// then applies the second parser that many times. +/// +/// # Arguments +/// * `f` The parser to apply to obtain the count. +/// * `g` The parser to apply repeatedly. +/// +/// # Example +/// +/// ```rust +/// # #[cfg(feature = "std")] { +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::Bytes; +/// use winnow::binary::u8; +/// use winnow::binary::length_count; +/// use winnow::token::tag; +/// +/// type Stream<'i> = &'i Bytes; +/// +/// fn stream(b: &[u8]) -> Stream<'_> { +/// Bytes::new(b) +/// } +/// +/// fn parser(s: Stream<'_>) -> IResult, Vec<&[u8]>> { +/// length_count(u8.map(|i| { +/// println!("got number: {}", i); +/// i +/// }), "abc").parse_next(s) +/// } +/// +/// assert_eq!(parser(stream(b"\x02abcabcabc")), Ok((stream(b"abc"), vec![&b"abc"[..], &b"abc"[..]]))); +/// assert_eq!(parser(stream(b"\x03123123123")), Err(ErrMode::Backtrack(Error::new(stream(b"123123123"), ErrorKind::Tag)))); +/// # } +/// ``` +pub fn length_count(mut f: F, mut g: G) -> impl Parser +where + I: Stream, + N: ToUsize, + C: Accumulate, + F: Parser, + G: Parser, + E: ParseError, +{ + trace("length_count", move |i: I| { + let (i, n) = f.parse_next(i)?; + let n = n.to_usize(); + repeat(n, g.by_ref()).parse_next(i) + }) +} diff --git a/vendor/winnow/src/binary/tests.rs b/vendor/winnow/src/binary/tests.rs new file mode 100644 index 000000000..4307d88fe --- /dev/null +++ b/vendor/winnow/src/binary/tests.rs @@ -0,0 +1,1214 @@ +use super::*; + +mod complete { + use super::*; + use crate::error::Error; + + macro_rules! assert_parse( + ($left: expr, $right: expr) => { + let res: $crate::IResult<_, _, Error<_>> = $left; + assert_eq!(res, $right); + }; + ); + + #[test] + fn i8_tests() { + assert_parse!(i8(&[0x00][..]), Ok((&b""[..], 0))); + assert_parse!(i8(&[0x7f][..]), Ok((&b""[..], 127))); + assert_parse!(i8(&[0xff][..]), Ok((&b""[..], -1))); + assert_parse!(i8(&[0x80][..]), Ok((&b""[..], -128))); + } + + #[test] + fn be_i8_tests() { + assert_parse!(be_i8(&[0x00][..]), Ok((&b""[..], 0))); + assert_parse!(be_i8(&[0x7f][..]), Ok((&b""[..], 127))); + assert_parse!(be_i8(&[0xff][..]), Ok((&b""[..], -1))); + assert_parse!(be_i8(&[0x80][..]), Ok((&b""[..], -128))); + } + + #[test] + fn be_i16_tests() { + assert_parse!(be_i16(&[0x00, 0x00][..]), Ok((&b""[..], 0))); + assert_parse!(be_i16(&[0x7f, 0xff][..]), Ok((&b""[..], 32_767_i16))); + assert_parse!(be_i16(&[0xff, 0xff][..]), Ok((&b""[..], -1))); + assert_parse!(be_i16(&[0x80, 0x00][..]), Ok((&b""[..], -32_768_i16))); + } + + #[test] + fn be_u24_tests() { + assert_parse!(be_u24(&[0x00, 0x00, 0x00][..]), Ok((&b""[..], 0))); + assert_parse!(be_u24(&[0x00, 0xFF, 0xFF][..]), Ok((&b""[..], 65_535_u32))); + assert_parse!( + be_u24(&[0x12, 0x34, 0x56][..]), + Ok((&b""[..], 1_193_046_u32)) + ); + } + + #[test] + fn be_i24_tests() { + assert_parse!(be_i24(&[0xFF, 0xFF, 0xFF][..]), Ok((&b""[..], -1_i32))); + assert_parse!(be_i24(&[0xFF, 0x00, 0x00][..]), Ok((&b""[..], -65_536_i32))); + assert_parse!( + be_i24(&[0xED, 0xCB, 0xAA][..]), + Ok((&b""[..], -1_193_046_i32)) + ); + } + + #[test] + fn be_i32_tests() { + assert_parse!(be_i32(&[0x00, 0x00, 0x00, 0x00][..]), Ok((&b""[..], 0))); + assert_parse!( + be_i32(&[0x7f, 0xff, 0xff, 0xff][..]), + Ok((&b""[..], 2_147_483_647_i32)) + ); + assert_parse!(be_i32(&[0xff, 0xff, 0xff, 0xff][..]), Ok((&b""[..], -1))); + assert_parse!( + be_i32(&[0x80, 0x00, 0x00, 0x00][..]), + Ok((&b""[..], -2_147_483_648_i32)) + ); + } + + #[test] + fn be_i64_tests() { + assert_parse!( + be_i64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]), + Ok((&b""[..], 0)) + ); + assert_parse!( + be_i64(&[0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff][..]), + Ok((&b""[..], 9_223_372_036_854_775_807_i64)) + ); + assert_parse!( + be_i64(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff][..]), + Ok((&b""[..], -1)) + ); + assert_parse!( + be_i64(&[0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]), + Ok((&b""[..], -9_223_372_036_854_775_808_i64)) + ); + } + + #[test] + fn be_i128_tests() { + assert_parse!( + be_i128( + &[ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 + ][..] + ), + Ok((&b""[..], 0)) + ); + assert_parse!( + be_i128( + &[ + 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff + ][..] + ), + Ok(( + &b""[..], + 170_141_183_460_469_231_731_687_303_715_884_105_727_i128 + )) + ); + assert_parse!( + be_i128( + &[ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff + ][..] + ), + Ok((&b""[..], -1)) + ); + assert_parse!( + be_i128( + &[ + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 + ][..] + ), + Ok(( + &b""[..], + -170_141_183_460_469_231_731_687_303_715_884_105_728_i128 + )) + ); + } + + #[test] + fn le_i8_tests() { + assert_parse!(le_i8(&[0x00][..]), Ok((&b""[..], 0))); + assert_parse!(le_i8(&[0x7f][..]), Ok((&b""[..], 127))); + assert_parse!(le_i8(&[0xff][..]), Ok((&b""[..], -1))); + assert_parse!(le_i8(&[0x80][..]), Ok((&b""[..], -128))); + } + + #[test] + fn le_i16_tests() { + assert_parse!(le_i16(&[0x00, 0x00][..]), Ok((&b""[..], 0))); + assert_parse!(le_i16(&[0xff, 0x7f][..]), Ok((&b""[..], 32_767_i16))); + assert_parse!(le_i16(&[0xff, 0xff][..]), Ok((&b""[..], -1))); + assert_parse!(le_i16(&[0x00, 0x80][..]), Ok((&b""[..], -32_768_i16))); + } + + #[test] + fn le_u24_tests() { + assert_parse!(le_u24(&[0x00, 0x00, 0x00][..]), Ok((&b""[..], 0))); + assert_parse!(le_u24(&[0xFF, 0xFF, 0x00][..]), Ok((&b""[..], 65_535_u32))); + assert_parse!( + le_u24(&[0x56, 0x34, 0x12][..]), + Ok((&b""[..], 1_193_046_u32)) + ); + } + + #[test] + fn le_i24_tests() { + assert_parse!(le_i24(&[0xFF, 0xFF, 0xFF][..]), Ok((&b""[..], -1_i32))); + assert_parse!(le_i24(&[0x00, 0x00, 0xFF][..]), Ok((&b""[..], -65_536_i32))); + assert_parse!( + le_i24(&[0xAA, 0xCB, 0xED][..]), + Ok((&b""[..], -1_193_046_i32)) + ); + } + + #[test] + fn le_i32_tests() { + assert_parse!(le_i32(&[0x00, 0x00, 0x00, 0x00][..]), Ok((&b""[..], 0))); + assert_parse!( + le_i32(&[0xff, 0xff, 0xff, 0x7f][..]), + Ok((&b""[..], 2_147_483_647_i32)) + ); + assert_parse!(le_i32(&[0xff, 0xff, 0xff, 0xff][..]), Ok((&b""[..], -1))); + assert_parse!( + le_i32(&[0x00, 0x00, 0x00, 0x80][..]), + Ok((&b""[..], -2_147_483_648_i32)) + ); + } + + #[test] + fn le_i64_tests() { + assert_parse!( + le_i64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]), + Ok((&b""[..], 0)) + ); + assert_parse!( + le_i64(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f][..]), + Ok((&b""[..], 9_223_372_036_854_775_807_i64)) + ); + assert_parse!( + le_i64(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff][..]), + Ok((&b""[..], -1)) + ); + assert_parse!( + le_i64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80][..]), + Ok((&b""[..], -9_223_372_036_854_775_808_i64)) + ); + } + + #[test] + fn le_i128_tests() { + assert_parse!( + le_i128( + &[ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 + ][..] + ), + Ok((&b""[..], 0)) + ); + assert_parse!( + le_i128( + &[ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x7f + ][..] + ), + Ok(( + &b""[..], + 170_141_183_460_469_231_731_687_303_715_884_105_727_i128 + )) + ); + assert_parse!( + le_i128( + &[ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff + ][..] + ), + Ok((&b""[..], -1)) + ); + assert_parse!( + le_i128( + &[ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80 + ][..] + ), + Ok(( + &b""[..], + -170_141_183_460_469_231_731_687_303_715_884_105_728_i128 + )) + ); + } + + #[test] + fn be_f32_tests() { + assert_parse!(be_f32(&[0x00, 0x00, 0x00, 0x00][..]), Ok((&b""[..], 0_f32))); + assert_parse!( + be_f32(&[0x4d, 0x31, 0x1f, 0xd8][..]), + Ok((&b""[..], 185_728_380_f32)) + ); + } + + #[test] + fn be_f64_tests() { + assert_parse!( + be_f64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]), + Ok((&b""[..], 0_f64)) + ); + assert_parse!( + be_f64(&[0x41, 0xa6, 0x23, 0xfb, 0x10, 0x00, 0x00, 0x00][..]), + Ok((&b""[..], 185_728_392_f64)) + ); + } + + #[test] + fn le_f32_tests() { + assert_parse!(le_f32(&[0x00, 0x00, 0x00, 0x00][..]), Ok((&b""[..], 0_f32))); + assert_parse!( + le_f32(&[0xd8, 0x1f, 0x31, 0x4d][..]), + Ok((&b""[..], 185_728_380_f32)) + ); + } + + #[test] + fn le_f64_tests() { + assert_parse!( + le_f64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]), + Ok((&b""[..], 0_f64)) + ); + assert_parse!( + le_f64(&[0x00, 0x00, 0x00, 0x10, 0xfb, 0x23, 0xa6, 0x41][..]), + Ok((&b""[..], 185_728_392_f64)) + ); + } + + #[test] + fn configurable_endianness() { + use crate::binary::Endianness; + + fn be_tst16(i: &[u8]) -> IResult<&[u8], u16> { + u16(Endianness::Big).parse_next(i) + } + fn le_tst16(i: &[u8]) -> IResult<&[u8], u16> { + u16(Endianness::Little).parse_next(i) + } + assert_eq!(be_tst16(&[0x80, 0x00]), Ok((&b""[..], 32_768_u16))); + assert_eq!(le_tst16(&[0x80, 0x00]), Ok((&b""[..], 128_u16))); + + fn be_tst32(i: &[u8]) -> IResult<&[u8], u32> { + u32(Endianness::Big).parse_next(i) + } + fn le_tst32(i: &[u8]) -> IResult<&[u8], u32> { + u32(Endianness::Little).parse_next(i) + } + assert_eq!( + be_tst32(&[0x12, 0x00, 0x60, 0x00]), + Ok((&b""[..], 302_014_464_u32)) + ); + assert_eq!( + le_tst32(&[0x12, 0x00, 0x60, 0x00]), + Ok((&b""[..], 6_291_474_u32)) + ); + + fn be_tst64(i: &[u8]) -> IResult<&[u8], u64> { + u64(Endianness::Big).parse_next(i) + } + fn le_tst64(i: &[u8]) -> IResult<&[u8], u64> { + u64(Endianness::Little).parse_next(i) + } + assert_eq!( + be_tst64(&[0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]), + Ok((&b""[..], 1_297_142_246_100_992_000_u64)) + ); + assert_eq!( + le_tst64(&[0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]), + Ok((&b""[..], 36_028_874_334_666_770_u64)) + ); + + fn be_tsti16(i: &[u8]) -> IResult<&[u8], i16> { + i16(Endianness::Big).parse_next(i) + } + fn le_tsti16(i: &[u8]) -> IResult<&[u8], i16> { + i16(Endianness::Little).parse_next(i) + } + assert_eq!(be_tsti16(&[0x00, 0x80]), Ok((&b""[..], 128_i16))); + assert_eq!(le_tsti16(&[0x00, 0x80]), Ok((&b""[..], -32_768_i16))); + + fn be_tsti32(i: &[u8]) -> IResult<&[u8], i32> { + i32(Endianness::Big).parse_next(i) + } + fn le_tsti32(i: &[u8]) -> IResult<&[u8], i32> { + i32(Endianness::Little).parse_next(i) + } + assert_eq!( + be_tsti32(&[0x00, 0x12, 0x60, 0x00]), + Ok((&b""[..], 1_204_224_i32)) + ); + assert_eq!( + le_tsti32(&[0x00, 0x12, 0x60, 0x00]), + Ok((&b""[..], 6_296_064_i32)) + ); + + fn be_tsti64(i: &[u8]) -> IResult<&[u8], i64> { + i64(Endianness::Big).parse_next(i) + } + fn le_tsti64(i: &[u8]) -> IResult<&[u8], i64> { + i64(Endianness::Little).parse_next(i) + } + assert_eq!( + be_tsti64(&[0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]), + Ok((&b""[..], 71_881_672_479_506_432_i64)) + ); + assert_eq!( + le_tsti64(&[0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]), + Ok((&b""[..], 36_028_874_334_732_032_i64)) + ); + } +} + +mod partial { + use super::*; + use crate::error::ErrMode; + use crate::error::Error; + use crate::error::Needed; + #[cfg(feature = "alloc")] + use crate::lib::std::vec::Vec; + use crate::Partial; + use crate::{ + ascii::digit1 as digit, + binary::{be_u16, be_u8}, + error::ErrorKind, + lib::std::str::{self, FromStr}, + IResult, + }; + + macro_rules! assert_parse( + ($left: expr, $right: expr) => { + let res: $crate::IResult<_, _, Error<_>> = $left; + assert_eq!(res, $right); + }; + ); + + #[test] + fn i8_tests() { + assert_parse!( + be_i8(Partial::new(&[0x00][..])), + Ok((Partial::new(&b""[..]), 0)) + ); + assert_parse!( + be_i8(Partial::new(&[0x7f][..])), + Ok((Partial::new(&b""[..]), 127)) + ); + assert_parse!( + be_i8(Partial::new(&[0xff][..])), + Ok((Partial::new(&b""[..]), -1)) + ); + assert_parse!( + be_i8(Partial::new(&[0x80][..])), + Ok((Partial::new(&b""[..]), -128)) + ); + assert_parse!( + be_i8(Partial::new(&[][..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + } + + #[test] + fn i16_tests() { + assert_parse!( + be_i16(Partial::new(&[0x00, 0x00][..])), + Ok((Partial::new(&b""[..]), 0)) + ); + assert_parse!( + be_i16(Partial::new(&[0x7f, 0xff][..])), + Ok((Partial::new(&b""[..]), 32_767_i16)) + ); + assert_parse!( + be_i16(Partial::new(&[0xff, 0xff][..])), + Ok((Partial::new(&b""[..]), -1)) + ); + assert_parse!( + be_i16(Partial::new(&[0x80, 0x00][..])), + Ok((Partial::new(&b""[..]), -32_768_i16)) + ); + assert_parse!( + be_i16(Partial::new(&[][..])), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_parse!( + be_i16(Partial::new(&[0x00][..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + } + + #[test] + fn u24_tests() { + assert_parse!( + be_u24(Partial::new(&[0x00, 0x00, 0x00][..])), + Ok((Partial::new(&b""[..]), 0)) + ); + assert_parse!( + be_u24(Partial::new(&[0x00, 0xFF, 0xFF][..])), + Ok((Partial::new(&b""[..]), 65_535_u32)) + ); + assert_parse!( + be_u24(Partial::new(&[0x12, 0x34, 0x56][..])), + Ok((Partial::new(&b""[..]), 1_193_046_u32)) + ); + assert_parse!( + be_u24(Partial::new(&[][..])), + Err(ErrMode::Incomplete(Needed::new(3))) + ); + assert_parse!( + be_u24(Partial::new(&[0x00][..])), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_parse!( + be_u24(Partial::new(&[0x00, 0x00][..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + } + + #[test] + fn i24_tests() { + assert_parse!( + be_i24(Partial::new(&[0xFF, 0xFF, 0xFF][..])), + Ok((Partial::new(&b""[..]), -1_i32)) + ); + assert_parse!( + be_i24(Partial::new(&[0xFF, 0x00, 0x00][..])), + Ok((Partial::new(&b""[..]), -65_536_i32)) + ); + assert_parse!( + be_i24(Partial::new(&[0xED, 0xCB, 0xAA][..])), + Ok((Partial::new(&b""[..]), -1_193_046_i32)) + ); + assert_parse!( + be_i24(Partial::new(&[][..])), + Err(ErrMode::Incomplete(Needed::new(3))) + ); + assert_parse!( + be_i24(Partial::new(&[0x00][..])), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_parse!( + be_i24(Partial::new(&[0x00, 0x00][..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + } + + #[test] + fn i32_tests() { + assert_parse!( + be_i32(Partial::new(&[0x00, 0x00, 0x00, 0x00][..])), + Ok((Partial::new(&b""[..]), 0)) + ); + assert_parse!( + be_i32(Partial::new(&[0x7f, 0xff, 0xff, 0xff][..])), + Ok((Partial::new(&b""[..]), 2_147_483_647_i32)) + ); + assert_parse!( + be_i32(Partial::new(&[0xff, 0xff, 0xff, 0xff][..])), + Ok((Partial::new(&b""[..]), -1)) + ); + assert_parse!( + be_i32(Partial::new(&[0x80, 0x00, 0x00, 0x00][..])), + Ok((Partial::new(&b""[..]), -2_147_483_648_i32)) + ); + assert_parse!( + be_i32(Partial::new(&[][..])), + Err(ErrMode::Incomplete(Needed::new(4))) + ); + assert_parse!( + be_i32(Partial::new(&[0x00][..])), + Err(ErrMode::Incomplete(Needed::new(3))) + ); + assert_parse!( + be_i32(Partial::new(&[0x00, 0x00][..])), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_parse!( + be_i32(Partial::new(&[0x00, 0x00, 0x00][..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + } + + #[test] + fn i64_tests() { + assert_parse!( + be_i64(Partial::new( + &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] + )), + Ok((Partial::new(&b""[..]), 0)) + ); + assert_parse!( + be_i64(Partial::new( + &[0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff][..] + )), + Ok((Partial::new(&b""[..]), 9_223_372_036_854_775_807_i64)) + ); + assert_parse!( + be_i64(Partial::new( + &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff][..] + )), + Ok((Partial::new(&b""[..]), -1)) + ); + assert_parse!( + be_i64(Partial::new( + &[0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] + )), + Ok((Partial::new(&b""[..]), -9_223_372_036_854_775_808_i64)) + ); + assert_parse!( + be_i64(Partial::new(&[][..])), + Err(ErrMode::Incomplete(Needed::new(8))) + ); + assert_parse!( + be_i64(Partial::new(&[0x00][..])), + Err(ErrMode::Incomplete(Needed::new(7))) + ); + assert_parse!( + be_i64(Partial::new(&[0x00, 0x00][..])), + Err(ErrMode::Incomplete(Needed::new(6))) + ); + assert_parse!( + be_i64(Partial::new(&[0x00, 0x00, 0x00][..])), + Err(ErrMode::Incomplete(Needed::new(5))) + ); + assert_parse!( + be_i64(Partial::new(&[0x00, 0x00, 0x00, 0x00][..])), + Err(ErrMode::Incomplete(Needed::new(4))) + ); + assert_parse!( + be_i64(Partial::new(&[0x00, 0x00, 0x00, 0x00, 0x00][..])), + Err(ErrMode::Incomplete(Needed::new(3))) + ); + assert_parse!( + be_i64(Partial::new(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..])), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_parse!( + be_i64(Partial::new( + &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] + )), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + } + + #[test] + fn i128_tests() { + assert_parse!( + be_i128(Partial::new( + &[ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 + ][..] + )), + Ok((Partial::new(&b""[..]), 0)) + ); + assert_parse!( + be_i128(Partial::new( + &[ + 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff + ][..] + )), + Ok(( + Partial::new(&b""[..]), + 170_141_183_460_469_231_731_687_303_715_884_105_727_i128 + )) + ); + assert_parse!( + be_i128(Partial::new( + &[ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff + ][..] + )), + Ok((Partial::new(&b""[..]), -1)) + ); + assert_parse!( + be_i128(Partial::new( + &[ + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 + ][..] + )), + Ok(( + Partial::new(&b""[..]), + -170_141_183_460_469_231_731_687_303_715_884_105_728_i128 + )) + ); + assert_parse!( + be_i128(Partial::new(&[][..])), + Err(ErrMode::Incomplete(Needed::new(16))) + ); + assert_parse!( + be_i128(Partial::new(&[0x00][..])), + Err(ErrMode::Incomplete(Needed::new(15))) + ); + assert_parse!( + be_i128(Partial::new(&[0x00, 0x00][..])), + Err(ErrMode::Incomplete(Needed::new(14))) + ); + assert_parse!( + be_i128(Partial::new(&[0x00, 0x00, 0x00][..])), + Err(ErrMode::Incomplete(Needed::new(13))) + ); + assert_parse!( + be_i128(Partial::new(&[0x00, 0x00, 0x00, 0x00][..])), + Err(ErrMode::Incomplete(Needed::new(12))) + ); + assert_parse!( + be_i128(Partial::new(&[0x00, 0x00, 0x00, 0x00, 0x00][..])), + Err(ErrMode::Incomplete(Needed::new(11))) + ); + assert_parse!( + be_i128(Partial::new(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..])), + Err(ErrMode::Incomplete(Needed::new(10))) + ); + assert_parse!( + be_i128(Partial::new( + &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] + )), + Err(ErrMode::Incomplete(Needed::new(9))) + ); + assert_parse!( + be_i128(Partial::new( + &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] + )), + Err(ErrMode::Incomplete(Needed::new(8))) + ); + assert_parse!( + be_i128(Partial::new( + &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] + )), + Err(ErrMode::Incomplete(Needed::new(7))) + ); + assert_parse!( + be_i128(Partial::new( + &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] + )), + Err(ErrMode::Incomplete(Needed::new(6))) + ); + assert_parse!( + be_i128(Partial::new( + &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] + )), + Err(ErrMode::Incomplete(Needed::new(5))) + ); + assert_parse!( + be_i128(Partial::new( + &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] + )), + Err(ErrMode::Incomplete(Needed::new(4))) + ); + assert_parse!( + be_i128(Partial::new( + &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] + )), + Err(ErrMode::Incomplete(Needed::new(3))) + ); + assert_parse!( + be_i128(Partial::new( + &[ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 + ][..] + )), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_parse!( + be_i128(Partial::new( + &[ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 + ][..] + )), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + } + + #[test] + fn le_i8_tests() { + assert_parse!( + le_i8(Partial::new(&[0x00][..])), + Ok((Partial::new(&b""[..]), 0)) + ); + assert_parse!( + le_i8(Partial::new(&[0x7f][..])), + Ok((Partial::new(&b""[..]), 127)) + ); + assert_parse!( + le_i8(Partial::new(&[0xff][..])), + Ok((Partial::new(&b""[..]), -1)) + ); + assert_parse!( + le_i8(Partial::new(&[0x80][..])), + Ok((Partial::new(&b""[..]), -128)) + ); + } + + #[test] + fn le_i16_tests() { + assert_parse!( + le_i16(Partial::new(&[0x00, 0x00][..])), + Ok((Partial::new(&b""[..]), 0)) + ); + assert_parse!( + le_i16(Partial::new(&[0xff, 0x7f][..])), + Ok((Partial::new(&b""[..]), 32_767_i16)) + ); + assert_parse!( + le_i16(Partial::new(&[0xff, 0xff][..])), + Ok((Partial::new(&b""[..]), -1)) + ); + assert_parse!( + le_i16(Partial::new(&[0x00, 0x80][..])), + Ok((Partial::new(&b""[..]), -32_768_i16)) + ); + } + + #[test] + fn le_u24_tests() { + assert_parse!( + le_u24(Partial::new(&[0x00, 0x00, 0x00][..])), + Ok((Partial::new(&b""[..]), 0)) + ); + assert_parse!( + le_u24(Partial::new(&[0xFF, 0xFF, 0x00][..])), + Ok((Partial::new(&b""[..]), 65_535_u32)) + ); + assert_parse!( + le_u24(Partial::new(&[0x56, 0x34, 0x12][..])), + Ok((Partial::new(&b""[..]), 1_193_046_u32)) + ); + } + + #[test] + fn le_i24_tests() { + assert_parse!( + le_i24(Partial::new(&[0xFF, 0xFF, 0xFF][..])), + Ok((Partial::new(&b""[..]), -1_i32)) + ); + assert_parse!( + le_i24(Partial::new(&[0x00, 0x00, 0xFF][..])), + Ok((Partial::new(&b""[..]), -65_536_i32)) + ); + assert_parse!( + le_i24(Partial::new(&[0xAA, 0xCB, 0xED][..])), + Ok((Partial::new(&b""[..]), -1_193_046_i32)) + ); + } + + #[test] + fn le_i32_tests() { + assert_parse!( + le_i32(Partial::new(&[0x00, 0x00, 0x00, 0x00][..])), + Ok((Partial::new(&b""[..]), 0)) + ); + assert_parse!( + le_i32(Partial::new(&[0xff, 0xff, 0xff, 0x7f][..])), + Ok((Partial::new(&b""[..]), 2_147_483_647_i32)) + ); + assert_parse!( + le_i32(Partial::new(&[0xff, 0xff, 0xff, 0xff][..])), + Ok((Partial::new(&b""[..]), -1)) + ); + assert_parse!( + le_i32(Partial::new(&[0x00, 0x00, 0x00, 0x80][..])), + Ok((Partial::new(&b""[..]), -2_147_483_648_i32)) + ); + } + + #[test] + fn le_i64_tests() { + assert_parse!( + le_i64(Partial::new( + &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] + )), + Ok((Partial::new(&b""[..]), 0)) + ); + assert_parse!( + le_i64(Partial::new( + &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f][..] + )), + Ok((Partial::new(&b""[..]), 9_223_372_036_854_775_807_i64)) + ); + assert_parse!( + le_i64(Partial::new( + &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff][..] + )), + Ok((Partial::new(&b""[..]), -1)) + ); + assert_parse!( + le_i64(Partial::new( + &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80][..] + )), + Ok((Partial::new(&b""[..]), -9_223_372_036_854_775_808_i64)) + ); + } + + #[test] + fn le_i128_tests() { + assert_parse!( + le_i128(Partial::new( + &[ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 + ][..] + )), + Ok((Partial::new(&b""[..]), 0)) + ); + assert_parse!( + le_i128(Partial::new( + &[ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x7f + ][..] + )), + Ok(( + Partial::new(&b""[..]), + 170_141_183_460_469_231_731_687_303_715_884_105_727_i128 + )) + ); + assert_parse!( + le_i128(Partial::new( + &[ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff + ][..] + )), + Ok((Partial::new(&b""[..]), -1)) + ); + assert_parse!( + le_i128(Partial::new( + &[ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80 + ][..] + )), + Ok(( + Partial::new(&b""[..]), + -170_141_183_460_469_231_731_687_303_715_884_105_728_i128 + )) + ); + } + + #[test] + fn be_f32_tests() { + assert_parse!( + be_f32(Partial::new(&[0x00, 0x00, 0x00, 0x00][..])), + Ok((Partial::new(&b""[..]), 0_f32)) + ); + assert_parse!( + be_f32(Partial::new(&[0x4d, 0x31, 0x1f, 0xd8][..])), + Ok((Partial::new(&b""[..]), 185_728_380_f32)) + ); + } + + #[test] + fn be_f64_tests() { + assert_parse!( + be_f64(Partial::new( + &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] + )), + Ok((Partial::new(&b""[..]), 0_f64)) + ); + assert_parse!( + be_f64(Partial::new( + &[0x41, 0xa6, 0x23, 0xfb, 0x10, 0x00, 0x00, 0x00][..] + )), + Ok((Partial::new(&b""[..]), 185_728_392_f64)) + ); + } + + #[test] + fn le_f32_tests() { + assert_parse!( + le_f32(Partial::new(&[0x00, 0x00, 0x00, 0x00][..])), + Ok((Partial::new(&b""[..]), 0_f32)) + ); + assert_parse!( + le_f32(Partial::new(&[0xd8, 0x1f, 0x31, 0x4d][..])), + Ok((Partial::new(&b""[..]), 185_728_380_f32)) + ); + } + + #[test] + fn le_f64_tests() { + assert_parse!( + le_f64(Partial::new( + &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] + )), + Ok((Partial::new(&b""[..]), 0_f64)) + ); + assert_parse!( + le_f64(Partial::new( + &[0x00, 0x00, 0x00, 0x10, 0xfb, 0x23, 0xa6, 0x41][..] + )), + Ok((Partial::new(&b""[..]), 185_728_392_f64)) + ); + } + + #[test] + fn configurable_endianness() { + use crate::binary::Endianness; + + fn be_tst16(i: Partial<&[u8]>) -> IResult, u16> { + u16(Endianness::Big).parse_next(i) + } + fn le_tst16(i: Partial<&[u8]>) -> IResult, u16> { + u16(Endianness::Little).parse_next(i) + } + assert_eq!( + be_tst16(Partial::new(&[0x80, 0x00])), + Ok((Partial::new(&b""[..]), 32_768_u16)) + ); + assert_eq!( + le_tst16(Partial::new(&[0x80, 0x00])), + Ok((Partial::new(&b""[..]), 128_u16)) + ); + + fn be_tst32(i: Partial<&[u8]>) -> IResult, u32> { + u32(Endianness::Big).parse_next(i) + } + fn le_tst32(i: Partial<&[u8]>) -> IResult, u32> { + u32(Endianness::Little).parse_next(i) + } + assert_eq!( + be_tst32(Partial::new(&[0x12, 0x00, 0x60, 0x00])), + Ok((Partial::new(&b""[..]), 302_014_464_u32)) + ); + assert_eq!( + le_tst32(Partial::new(&[0x12, 0x00, 0x60, 0x00])), + Ok((Partial::new(&b""[..]), 6_291_474_u32)) + ); + + fn be_tst64(i: Partial<&[u8]>) -> IResult, u64> { + u64(Endianness::Big).parse_next(i) + } + fn le_tst64(i: Partial<&[u8]>) -> IResult, u64> { + u64(Endianness::Little).parse_next(i) + } + assert_eq!( + be_tst64(Partial::new(&[ + 0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00 + ])), + Ok((Partial::new(&b""[..]), 1_297_142_246_100_992_000_u64)) + ); + assert_eq!( + le_tst64(Partial::new(&[ + 0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00 + ])), + Ok((Partial::new(&b""[..]), 36_028_874_334_666_770_u64)) + ); + + fn be_tsti16(i: Partial<&[u8]>) -> IResult, i16> { + i16(Endianness::Big).parse_next(i) + } + fn le_tsti16(i: Partial<&[u8]>) -> IResult, i16> { + i16(Endianness::Little).parse_next(i) + } + assert_eq!( + be_tsti16(Partial::new(&[0x00, 0x80])), + Ok((Partial::new(&b""[..]), 128_i16)) + ); + assert_eq!( + le_tsti16(Partial::new(&[0x00, 0x80])), + Ok((Partial::new(&b""[..]), -32_768_i16)) + ); + + fn be_tsti32(i: Partial<&[u8]>) -> IResult, i32> { + i32(Endianness::Big).parse_next(i) + } + fn le_tsti32(i: Partial<&[u8]>) -> IResult, i32> { + i32(Endianness::Little).parse_next(i) + } + assert_eq!( + be_tsti32(Partial::new(&[0x00, 0x12, 0x60, 0x00])), + Ok((Partial::new(&b""[..]), 1_204_224_i32)) + ); + assert_eq!( + le_tsti32(Partial::new(&[0x00, 0x12, 0x60, 0x00])), + Ok((Partial::new(&b""[..]), 6_296_064_i32)) + ); + + fn be_tsti64(i: Partial<&[u8]>) -> IResult, i64> { + i64(Endianness::Big).parse_next(i) + } + fn le_tsti64(i: Partial<&[u8]>) -> IResult, i64> { + i64(Endianness::Little).parse_next(i) + } + assert_eq!( + be_tsti64(Partial::new(&[ + 0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00 + ])), + Ok((Partial::new(&b""[..]), 71_881_672_479_506_432_i64)) + ); + assert_eq!( + le_tsti64(Partial::new(&[ + 0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00 + ])), + Ok((Partial::new(&b""[..]), 36_028_874_334_732_032_i64)) + ); + } + + #[test] + #[cfg(feature = "alloc")] + fn length_count_test() { + fn number(i: Partial<&[u8]>) -> IResult, u32> { + digit + .try_map(str::from_utf8) + .try_map(FromStr::from_str) + .parse_next(i) + } + + fn cnt(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { + length_count(number, "abc").parse_next(i) + } + + assert_eq!( + cnt(Partial::new(&b"2abcabcabcdef"[..])), + Ok((Partial::new(&b"abcdef"[..]), vec![&b"abc"[..], &b"abc"[..]])) + ); + assert_eq!( + cnt(Partial::new(&b"2ab"[..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + cnt(Partial::new(&b"3abcab"[..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + cnt(Partial::new(&b"xxx"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxx"[..]), + ErrorKind::Slice + ))) + ); + assert_eq!( + cnt(Partial::new(&b"2abcxxx"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxx"[..]), + ErrorKind::Tag + ))) + ); + } + + #[test] + fn length_data_test() { + fn number(i: Partial<&[u8]>) -> IResult, u32> { + digit + .try_map(str::from_utf8) + .try_map(FromStr::from_str) + .parse_next(i) + } + + fn take(i: Partial<&[u8]>) -> IResult, &[u8]> { + length_data(number).parse_next(i) + } + + assert_eq!( + take(Partial::new(&b"6abcabcabcdef"[..])), + Ok((Partial::new(&b"abcdef"[..]), &b"abcabc"[..])) + ); + assert_eq!( + take(Partial::new(&b"3ab"[..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + take(Partial::new(&b"xxx"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxx"[..]), + ErrorKind::Slice + ))) + ); + assert_eq!( + take(Partial::new(&b"2abcxxx"[..])), + Ok((Partial::new(&b"cxxx"[..]), &b"ab"[..])) + ); + } + + #[test] + fn length_value_test() { + use crate::stream::StreamIsPartial; + + fn length_value_1(i: Partial<&[u8]>) -> IResult, u16> { + length_value(be_u8, be_u16).parse_next(i) + } + fn length_value_2(i: Partial<&[u8]>) -> IResult, (u8, u8)> { + length_value(be_u8, (be_u8, be_u8)).parse_next(i) + } + + let mut empty_complete = Partial::new(&b""[..]); + let _ = empty_complete.complete(); + + let i1 = [0, 5, 6]; + assert_eq!( + length_value_1(Partial::new(&i1)), + Err(ErrMode::Backtrack(error_position!( + empty_complete, + ErrorKind::Slice + ))) + ); + assert_eq!( + length_value_2(Partial::new(&i1)), + Err(ErrMode::Backtrack(error_position!( + empty_complete, + ErrorKind::Token + ))) + ); + + let i2 = [1, 5, 6, 3]; + { + let mut middle_complete = Partial::new(&i2[1..2]); + let _ = middle_complete.complete(); + assert_eq!( + length_value_1(Partial::new(&i2)), + Err(ErrMode::Backtrack(error_position!( + middle_complete, + ErrorKind::Slice + ))) + ); + assert_eq!( + length_value_2(Partial::new(&i2)), + Err(ErrMode::Backtrack(error_position!( + empty_complete, + ErrorKind::Token + ))) + ); + } + + let i3 = [2, 5, 6, 3, 4, 5, 7]; + assert_eq!( + length_value_1(Partial::new(&i3)), + Ok((Partial::new(&i3[3..]), 1286)) + ); + assert_eq!( + length_value_2(Partial::new(&i3)), + Ok((Partial::new(&i3[3..]), (5, 6))) + ); + + let i4 = [3, 5, 6, 3, 4, 5]; + assert_eq!( + length_value_1(Partial::new(&i4)), + Ok((Partial::new(&i4[4..]), 1286)) + ); + assert_eq!( + length_value_2(Partial::new(&i4)), + Ok((Partial::new(&i4[4..]), (5, 6))) + ); + } +} diff --git a/vendor/winnow/src/bits.rs b/vendor/winnow/src/bits.rs new file mode 100644 index 000000000..6b4981f30 --- /dev/null +++ b/vendor/winnow/src/bits.rs @@ -0,0 +1,71 @@ +//! Deprecated, see [`binary::bits`] +#![deprecated(since = "0.4.2", note = "Replaced with `binary::bits`")] + +use crate::binary; +use crate::error::{ErrorConvert, ParseError}; +use crate::lib::std::ops::{AddAssign, Shl, Shr}; +use crate::stream::{AsBytes, Stream, StreamIsPartial, ToUsize}; +use crate::{IResult, Parser}; + +/// Deprecated, replaced with [`binary::bits::bits`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::bits::bits`")] +#[inline(always)] +pub fn bits(parser: P) -> impl Parser +where + E1: ParseError<(I, usize)> + ErrorConvert, + E2: ParseError, + I: Stream, + P: Parser<(I, usize), O, E1>, +{ + binary::bits::bits(parser) +} + +/// Deprecated, replaced with [`binary::bits::bytes`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::bits::bytes`")] +#[inline(always)] +pub fn bytes(parser: P) -> impl Parser<(I, usize), O, E2> +where + E1: ParseError + ErrorConvert, + E2: ParseError<(I, usize)>, + I: Stream, + P: Parser, +{ + binary::bits::bytes(parser) +} + +/// Deprecated, replaced with [`binary::bits::take`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::bits::take`")] +#[inline(always)] +pub fn take>(count: C) -> impl Parser<(I, usize), O, E> +where + I: Stream + AsBytes + StreamIsPartial, + C: ToUsize, + O: From + AddAssign + Shl + Shr, +{ + binary::bits::take(count) +} + +/// Deprecated, replaced with [`binary::bits::tag`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::bits::tag`")] +#[inline(always)] +pub fn tag>( + pattern: O, + count: C, +) -> impl Parser<(I, usize), O, E> +where + I: Stream + AsBytes + StreamIsPartial, + C: ToUsize, + O: From + AddAssign + Shl + Shr + PartialEq, +{ + binary::bits::tag(pattern, count) +} + +/// Deprecated, replaced with [`binary::bits::bool`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::bits::bool`")] +#[inline(always)] +pub fn bool>(input: (I, usize)) -> IResult<(I, usize), bool, E> +where + I: Stream + AsBytes + StreamIsPartial, +{ + binary::bits::bool(input) +} diff --git a/vendor/winnow/src/bits/mod.rs b/vendor/winnow/src/bits/mod.rs deleted file mode 100644 index 18cce6f67..000000000 --- a/vendor/winnow/src/bits/mod.rs +++ /dev/null @@ -1,383 +0,0 @@ -//! Bit level parsers -//! - -#[cfg(test)] -mod tests; - -use crate::error::{ErrMode, ErrorConvert, ErrorKind, Needed, ParseError}; -use crate::lib::std::ops::{AddAssign, Div, Shl, Shr}; -use crate::stream::{AsBytes, Stream, StreamIsPartial, ToUsize}; -use crate::trace::trace; -use crate::{IResult, Parser}; - -/// Converts a byte-level input to a bit-level input -/// -/// See [`bytes`] to convert it back. -/// -/// # Example -/// ``` -/// use winnow::prelude::*; -/// use winnow::Bytes; -/// use winnow::bits::{bits, take}; -/// use winnow::error::Error; -/// -/// type Stream<'i> = &'i Bytes; -/// -/// fn stream(b: &[u8]) -> Stream<'_> { -/// Bytes::new(b) -/// } -/// -/// fn parse(input: Stream<'_>) -> IResult, (u8, u8)> { -/// bits::<_, _, Error<(_, usize)>, _, _>((take(4usize), take(8usize))).parse_next(input) -/// } -/// -/// let input = stream(&[0x12, 0x34, 0xff, 0xff]); -/// -/// let output = parse(input).expect("We take 1.5 bytes and the input is longer than 2 bytes"); -/// -/// // The first byte is consumed, the second byte is partially consumed and dropped. -/// let remaining = output.0; -/// assert_eq!(remaining, stream(&[0xff, 0xff])); -/// -/// let parsed = output.1; -/// assert_eq!(parsed.0, 0x01); -/// assert_eq!(parsed.1, 0x23); -/// ``` -pub fn bits(mut parser: P) -> impl Parser -where - E1: ParseError<(I, usize)> + ErrorConvert, - E2: ParseError, - I: Stream, - P: Parser<(I, usize), O, E1>, -{ - trace("bits", move |input: I| { - match parser.parse_next((input, 0)) { - Ok(((rest, offset), result)) => { - // If the next byte has been partially read, it will be sliced away as well. - // The parser functions might already slice away all fully read bytes. - // That's why `offset / 8` isn't necessarily needed at all times. - let remaining_bytes_index = offset / 8 + if offset % 8 == 0 { 0 } else { 1 }; - let (input, _) = rest.next_slice(remaining_bytes_index); - Ok((input, result)) - } - Err(ErrMode::Incomplete(n)) => Err(ErrMode::Incomplete(n.map(|u| u.get() / 8 + 1))), - Err(e) => Err(e.convert()), - } - }) -} - -/// Convert a [`bits`] stream back into a byte stream -/// -/// **Warning:** A partial byte remaining in the input will be ignored and the given parser will -/// start parsing at the next full byte. -/// -/// ``` -/// use winnow::prelude::*; -/// use winnow::Bytes; -/// use winnow::bits::{bits, bytes, take}; -/// use winnow::combinator::rest; -/// use winnow::error::Error; -/// -/// type Stream<'i> = &'i Bytes; -/// -/// fn stream(b: &[u8]) -> Stream<'_> { -/// Bytes::new(b) -/// } -/// -/// fn parse(input: Stream<'_>) -> IResult, (u8, u8, &[u8])> { -/// bits::<_, _, Error<(_, usize)>, _, _>(( -/// take(4usize), -/// take(8usize), -/// bytes::<_, _, Error<_>, _, _>(rest) -/// )).parse_next(input) -/// } -/// -/// let input = stream(&[0x12, 0x34, 0xff, 0xff]); -/// -/// assert_eq!(parse(input), Ok(( stream(&[]), (0x01, 0x23, &[0xff, 0xff][..]) ))); -/// ``` -pub fn bytes(mut parser: P) -> impl Parser<(I, usize), O, E2> -where - E1: ParseError + ErrorConvert, - E2: ParseError<(I, usize)>, - I: Stream, - P: Parser, -{ - trace("bytes", move |(input, offset): (I, usize)| { - let (inner, _) = if offset % 8 != 0 { - input.next_slice(1 + offset / 8) - } else { - input.next_slice(offset / 8) - }; - let i = (input, offset); - match parser.parse_next(inner) { - Ok((rest, res)) => Ok(((rest, 0), res)), - Err(ErrMode::Incomplete(Needed::Unknown)) => Err(ErrMode::Incomplete(Needed::Unknown)), - Err(ErrMode::Incomplete(Needed::Size(sz))) => Err(match sz.get().checked_mul(8) { - Some(v) => ErrMode::Incomplete(Needed::new(v)), - None => ErrMode::Cut(E2::assert( - i, - "overflow in turning needed bytes into needed bits", - )), - }), - Err(e) => Err(e.convert()), - } - }) -} - -/// Parse taking `count` bits -/// -/// # Example -/// ```rust -/// # use winnow::prelude::*; -/// # use winnow::Bytes; -/// # use winnow::error::{Error, ErrorKind}; -/// use winnow::bits::take; -/// -/// type Stream<'i> = &'i Bytes; -/// -/// fn stream(b: &[u8]) -> Stream<'_> { -/// Bytes::new(b) -/// } -/// -/// fn parser(input: (Stream<'_>, usize), count: usize)-> IResult<(Stream<'_>, usize), u8> { -/// take(count).parse_next(input) -/// } -/// -/// // Consumes 0 bits, returns 0 -/// assert_eq!(parser((stream(&[0b00010010]), 0), 0), Ok(((stream(&[0b00010010]), 0), 0))); -/// -/// // Consumes 4 bits, returns their values and increase offset to 4 -/// assert_eq!(parser((stream(&[0b00010010]), 0), 4), Ok(((stream(&[0b00010010]), 4), 0b00000001))); -/// -/// // Consumes 4 bits, offset is 4, returns their values and increase offset to 0 of next byte -/// assert_eq!(parser((stream(&[0b00010010]), 4), 4), Ok(((stream(&[]), 0), 0b00000010))); -/// -/// // Tries to consume 12 bits but only 8 are available -/// assert_eq!(parser((stream(&[0b00010010]), 0), 12), Err(winnow::error::ErrMode::Backtrack(Error{input: (stream(&[0b00010010]), 0), kind: ErrorKind::Eof }))); -/// ``` -#[inline(always)] -pub fn take>(count: C) -> impl Parser<(I, usize), O, E> -where - I: Stream + AsBytes + StreamIsPartial, - C: ToUsize, - O: From + AddAssign + Shl + Shr, -{ - let count = count.to_usize(); - trace("take", move |input: (I, usize)| { - if input.is_partial() { - streaming_take_internal(input, count) - } else { - complete_take_internal(input, count) - } - }) -} - -pub(crate) fn streaming_take_internal>( - (input, bit_offset): (I, usize), - count: usize, -) -> IResult<(I, usize), O, E> -where - I: Stream + AsBytes, - O: From + AddAssign + Shl + Shr, -{ - if count == 0 { - Ok(((input, bit_offset), 0u8.into())) - } else { - let cnt = (count + bit_offset).div(8); - if input.eof_offset() * 8 < count + bit_offset { - Err(ErrMode::Incomplete(Needed::new(count))) - } else { - let mut acc: O = 0_u8.into(); - let mut offset: usize = bit_offset; - let mut remaining: usize = count; - let mut end_offset: usize = 0; - - for byte in input.as_bytes().iter().copied().take(cnt + 1) { - if remaining == 0 { - break; - } - let val: O = if offset == 0 { - byte.into() - } else { - (byte << offset >> offset).into() - }; - - if remaining < 8 - offset { - acc += val >> (8 - offset - remaining); - end_offset = remaining + offset; - break; - } else { - acc += val << (remaining - (8 - offset)); - remaining -= 8 - offset; - offset = 0; - } - } - let (input, _) = input.next_slice(cnt); - Ok(((input, end_offset), acc)) - } - } -} - -pub(crate) fn complete_take_internal>( - (input, bit_offset): (I, usize), - count: usize, -) -> IResult<(I, usize), O, E> -where - I: Stream + AsBytes, - O: From + AddAssign + Shl + Shr, -{ - if count == 0 { - Ok(((input, bit_offset), 0u8.into())) - } else { - let cnt = (count + bit_offset).div(8); - if input.eof_offset() * 8 < count + bit_offset { - Err(ErrMode::from_error_kind( - (input, bit_offset), - ErrorKind::Eof, - )) - } else { - let mut acc: O = 0_u8.into(); - let mut offset: usize = bit_offset; - let mut remaining: usize = count; - let mut end_offset: usize = 0; - - for byte in input.as_bytes().iter().copied().take(cnt + 1) { - if remaining == 0 { - break; - } - let val: O = if offset == 0 { - byte.into() - } else { - (byte << offset >> offset).into() - }; - - if remaining < 8 - offset { - acc += val >> (8 - offset - remaining); - end_offset = remaining + offset; - break; - } else { - acc += val << (remaining - (8 - offset)); - remaining -= 8 - offset; - offset = 0; - } - } - let (input, _) = input.next_slice(cnt); - Ok(((input, end_offset), acc)) - } - } -} - -/// Parse taking `count` bits and comparing them to `pattern` -/// -/// # Example -/// -/// ```rust -/// # use winnow::prelude::*; -/// # use winnow::Bytes; -/// # use winnow::error::{Error, ErrorKind}; -/// use winnow::bits::tag; -/// -/// type Stream<'i> = &'i Bytes; -/// -/// fn stream(b: &[u8]) -> Stream<'_> { -/// Bytes::new(b) -/// } -/// -/// /// Compare the lowest `count` bits of `input` against the lowest `count` bits of `pattern`. -/// /// Return Ok and the matching section of `input` if there's a match. -/// /// Return Err if there's no match. -/// fn parser(pattern: u8, count: u8, input: (Stream<'_>, usize)) -> IResult<(Stream<'_>, usize), u8> { -/// tag(pattern, count).parse_next(input) -/// } -/// -/// // The lowest 4 bits of 0b00001111 match the lowest 4 bits of 0b11111111. -/// assert_eq!( -/// parser(0b0000_1111, 4, (stream(&[0b1111_1111]), 0)), -/// Ok(((stream(&[0b1111_1111]), 4), 0b0000_1111)) -/// ); -/// -/// // The lowest bit of 0b00001111 matches the lowest bit of 0b11111111 (both are 1). -/// assert_eq!( -/// parser(0b00000001, 1, (stream(&[0b11111111]), 0)), -/// Ok(((stream(&[0b11111111]), 1), 0b00000001)) -/// ); -/// -/// // The lowest 2 bits of 0b11111111 and 0b00000001 are different. -/// assert_eq!( -/// parser(0b000000_01, 2, (stream(&[0b111111_11]), 0)), -/// Err(winnow::error::ErrMode::Backtrack(Error { -/// input: (stream(&[0b11111111]), 0), -/// kind: ErrorKind::Tag -/// })) -/// ); -/// -/// // The lowest 8 bits of 0b11111111 and 0b11111110 are different. -/// assert_eq!( -/// parser(0b11111110, 8, (stream(&[0b11111111]), 0)), -/// Err(winnow::error::ErrMode::Backtrack(Error { -/// input: (stream(&[0b11111111]), 0), -/// kind: ErrorKind::Tag -/// })) -/// ); -/// ``` -#[inline(always)] -#[doc(alias = "literal")] -#[doc(alias = "just")] -pub fn tag>( - pattern: O, - count: C, -) -> impl Parser<(I, usize), O, E> -where - I: Stream + AsBytes + StreamIsPartial, - C: ToUsize, - O: From + AddAssign + Shl + Shr + PartialEq, -{ - let count = count.to_usize(); - trace("tag", move |input: (I, usize)| { - let inp = input.clone(); - - take(count).parse_next(input).and_then(|(i, o)| { - if pattern == o { - Ok((i, o)) - } else { - Err(ErrMode::Backtrack(E::from_error_kind(inp, ErrorKind::Tag))) - } - }) - }) -} - -/// Parses one specific bit as a bool. -/// -/// # Example -/// -/// ```rust -/// # use winnow::prelude::*; -/// # use winnow::Bytes; -/// # use winnow::error::{Error, ErrorKind}; -/// use winnow::bits::bool; -/// -/// type Stream<'i> = &'i Bytes; -/// -/// fn stream(b: &[u8]) -> Stream<'_> { -/// Bytes::new(b) -/// } -/// -/// fn parse(input: (Stream<'_>, usize)) -> IResult<(Stream<'_>, usize), bool> { -/// bool.parse_next(input) -/// } -/// -/// assert_eq!(parse((stream(&[0b10000000]), 0)), Ok(((stream(&[0b10000000]), 1), true))); -/// assert_eq!(parse((stream(&[0b10000000]), 1)), Ok(((stream(&[0b10000000]), 2), false))); -/// ``` -#[doc(alias = "any")] -pub fn bool>(input: (I, usize)) -> IResult<(I, usize), bool, E> -where - I: Stream + AsBytes + StreamIsPartial, -{ - trace("bool", |input: (I, usize)| { - let (res, bit): (_, u32) = take(1usize).parse_next(input)?; - Ok((res, bit != 0)) - }) - .parse_next(input) -} diff --git a/vendor/winnow/src/bits/tests.rs b/vendor/winnow/src/bits/tests.rs deleted file mode 100644 index 61dba2c31..000000000 --- a/vendor/winnow/src/bits/tests.rs +++ /dev/null @@ -1,190 +0,0 @@ -use super::*; -use crate::error::Error; -use crate::Partial; - -#[test] -/// Take the `bits` function and assert that remaining bytes are correctly returned, if the -/// previous bytes are fully consumed -fn test_complete_byte_consumption_bits() { - let input = &[0x12, 0x34, 0x56, 0x78][..]; - - // Take 3 bit slices with sizes [4, 8, 4]. - let result: IResult<&[u8], (u8, u8, u8)> = - bits::<_, _, Error<(&[u8], usize)>, _, _>((take(4usize), take(8usize), take(4usize))) - .parse_next(input); - - let output = result.expect("We take 2 bytes and the input is longer than 2 bytes"); - - let remaining = output.0; - assert_eq!(remaining, [0x56, 0x78]); - - let parsed = output.1; - assert_eq!(parsed.0, 0x01); - assert_eq!(parsed.1, 0x23); - assert_eq!(parsed.2, 0x04); -} - -#[test] -/// Take the `bits` function and assert that remaining bytes are correctly returned, if the -/// previous bytes are NOT fully consumed. Partially consumed bytes are supposed to be dropped. -/// I.e. if we consume 1.5 bytes of 4 bytes, 2 bytes will be returned, bits 13-16 will be -/// dropped. -fn test_partial_byte_consumption_bits() { - let input = &[0x12, 0x34, 0x56, 0x78][..]; - - // Take bit slices with sizes [4, 8]. - let result: IResult<&[u8], (u8, u8)> = - bits::<_, _, Error<(&[u8], usize)>, _, _>((take(4usize), take(8usize))).parse_next(input); - - let output = result.expect("We take 1.5 bytes and the input is longer than 2 bytes"); - - let remaining = output.0; - assert_eq!(remaining, [0x56, 0x78]); - - let parsed = output.1; - assert_eq!(parsed.0, 0x01); - assert_eq!(parsed.1, 0x23); -} - -#[test] -#[cfg(feature = "std")] -/// Ensure that in Incomplete error is thrown, if too few bytes are passed for a given parser. -fn test_incomplete_bits() { - let input = Partial::new(&[0x12][..]); - - // Take bit slices with sizes [4, 8]. - let result: IResult<_, (u8, u8)> = - bits::<_, _, Error<(_, usize)>, _, _>((take(4usize), take(8usize))).parse_next(input); - - assert!(result.is_err()); - let error = result.err().unwrap(); - assert_eq!("Parsing requires 2 bytes/chars", error.to_string()); -} - -#[test] -fn test_take_complete_0() { - let input = &[0b00010010][..]; - let count = 0usize; - assert_eq!(count, 0usize); - let offset = 0usize; - - let result: crate::IResult<(&[u8], usize), usize> = take(count).parse_next((input, offset)); - - assert_eq!(result, Ok(((input, offset), 0))); -} - -#[test] -fn test_take_complete_eof() { - let input = &[0b00010010][..]; - - let result: crate::IResult<(&[u8], usize), usize> = take(1usize).parse_next((input, 8)); - - assert_eq!( - result, - Err(crate::error::ErrMode::Backtrack(crate::error::Error { - input: (input, 8), - kind: ErrorKind::Eof - })) - ); -} - -#[test] -fn test_take_complete_span_over_multiple_bytes() { - let input = &[0b00010010, 0b00110100, 0b11111111, 0b11111111][..]; - - let result: crate::IResult<(&[u8], usize), usize> = take(24usize).parse_next((input, 4)); - - assert_eq!( - result, - Ok((([0b11111111].as_ref(), 4), 0b1000110100111111111111)) - ); -} - -#[test] -fn test_take_partial_0() { - let input = Partial::new(&[][..]); - let count = 0usize; - assert_eq!(count, 0usize); - let offset = 0usize; - - let result: crate::IResult<(_, usize), usize> = take(count).parse_next((input, offset)); - - assert_eq!(result, Ok(((input, offset), 0))); -} - -#[test] -fn test_tag_partial_ok() { - let input = Partial::new(&[0b00011111][..]); - let offset = 0usize; - let bits_to_take = 4usize; - let value_to_tag = 0b0001; - - let result: crate::IResult<(_, usize), usize> = - tag(value_to_tag, bits_to_take).parse_next((input, offset)); - - assert_eq!(result, Ok(((input, bits_to_take), value_to_tag))); -} - -#[test] -fn test_tag_partial_err() { - let input = Partial::new(&[0b00011111][..]); - let offset = 0usize; - let bits_to_take = 4usize; - let value_to_tag = 0b1111; - - let result: crate::IResult<(_, usize), usize> = - tag(value_to_tag, bits_to_take).parse_next((input, offset)); - - assert_eq!( - result, - Err(crate::error::ErrMode::Backtrack(crate::error::Error { - input: (input, offset), - kind: ErrorKind::Tag - })) - ); -} - -#[test] -fn test_bool_0_complete() { - let input = [0b10000000].as_ref(); - - let result: crate::IResult<(&[u8], usize), bool> = bool((input, 0)); - - assert_eq!(result, Ok(((input, 1), true))); -} - -#[test] -fn test_bool_eof_complete() { - let input = [0b10000000].as_ref(); - - let result: crate::IResult<(&[u8], usize), bool> = bool((input, 8)); - - assert_eq!( - result, - Err(crate::error::ErrMode::Backtrack(crate::error::Error { - input: (input, 8), - kind: ErrorKind::Eof - })) - ); -} - -#[test] -fn test_bool_0_partial() { - let input = Partial::new([0b10000000].as_ref()); - - let result: crate::IResult<(Partial<&[u8]>, usize), bool> = bool((input, 0)); - - assert_eq!(result, Ok(((input, 1), true))); -} - -#[test] -fn test_bool_eof_partial() { - let input = Partial::new([0b10000000].as_ref()); - - let result: crate::IResult<(Partial<&[u8]>, usize), bool> = bool.parse_next((input, 8)); - - assert_eq!( - result, - Err(crate::error::ErrMode::Incomplete(Needed::new(1))) - ); -} diff --git a/vendor/winnow/src/branch.rs b/vendor/winnow/src/branch.rs new file mode 100644 index 000000000..0783262b4 --- /dev/null +++ b/vendor/winnow/src/branch.rs @@ -0,0 +1,10 @@ +//! Deprecated, see [`combinator`] +#![deprecated(since = "0.4.2", note = "Replaced with `combinator`")] + +use crate::combinator; + +pub use combinator::alt; +pub use combinator::dispatch; +pub use combinator::permutation; +pub use combinator::Alt; +pub use combinator::Permutation; diff --git a/vendor/winnow/src/branch/mod.rs b/vendor/winnow/src/branch/mod.rs deleted file mode 100644 index 6a2c9bc3a..000000000 --- a/vendor/winnow/src/branch/mod.rs +++ /dev/null @@ -1,275 +0,0 @@ -//! Choice combinators - -#[cfg(test)] -mod tests; - -use crate::error::ErrMode; -use crate::error::ErrorKind; -use crate::error::ParseError; -use crate::stream::Stream; -use crate::trace::trace; -use crate::{IResult, Parser}; - -#[doc(inline)] -pub use crate::dispatch; - -/// Helper trait for the [alt()] combinator. -/// -/// This trait is implemented for tuples of up to 21 elements -pub trait Alt { - /// Tests each parser in the tuple and returns the result of the first one that succeeds - fn choice(&mut self, input: I) -> IResult; -} - -/// Pick the first successful parser -/// -/// For tight control over the error, add a final case using [`fail`][crate::combinator::fail]. -/// Alternatively, with a [custom error type][crate::_topic::error], it is possible to track all -/// errors or return the error of the parser that went the farthest in the input data. -/// -/// When the alternative cases have unique prefixes, [`dispatch`] can offer better performance. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::Error,error::ErrorKind, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::character::{alpha1, digit1}; -/// use winnow::branch::alt; -/// # fn main() { -/// fn parser(input: &str) -> IResult<&str, &str> { -/// alt((alpha1, digit1)).parse_next(input) -/// }; -/// -/// // the first parser, alpha1, recognizes the input -/// assert_eq!(parser("abc"), Ok(("", "abc"))); -/// -/// // the first parser returns an error, so alt tries the second one -/// assert_eq!(parser("123456"), Ok(("", "123456"))); -/// -/// // both parsers failed, and with the default error type, alt will return the last error -/// assert_eq!(parser(" "), Err(ErrMode::Backtrack(Error::new(" ", ErrorKind::Slice)))); -/// # } -/// ``` -#[doc(alias = "choice")] -pub fn alt, List: Alt>( - mut l: List, -) -> impl Parser { - trace("alt", move |i: I| l.choice(i)) -} - -/// Helper trait for the [permutation()] combinator. -/// -/// This trait is implemented for tuples of up to 21 elements -pub trait Permutation { - /// Tries to apply all parsers in the tuple in various orders until all of them succeed - fn permutation(&mut self, input: I) -> IResult; -} - -/// Applies a list of parsers in any order. -/// -/// Permutation will succeed if all of the child parsers succeeded. -/// It takes as argument a tuple of parsers, and returns a -/// tuple of the parser results. -/// -/// ```rust -/// # use winnow::{error::ErrMode,error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::character::{alpha1, digit1}; -/// use winnow::branch::permutation; -/// # fn main() { -/// fn parser(input: &str) -> IResult<&str, (&str, &str)> { -/// permutation((alpha1, digit1)).parse_next(input) -/// } -/// -/// // permutation recognizes alphabetic characters then digit -/// assert_eq!(parser("abc123"), Ok(("", ("abc", "123")))); -/// -/// // but also in inverse order -/// assert_eq!(parser("123abc"), Ok(("", ("abc", "123")))); -/// -/// // it will fail if one of the parsers failed -/// assert_eq!(parser("abc;"), Err(ErrMode::Backtrack(Error::new(";", ErrorKind::Slice)))); -/// # } -/// ``` -/// -/// The parsers are applied greedily: if there are multiple unapplied parsers -/// that could parse the next slice of input, the first one is used. -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}}; -/// # use winnow::prelude::*; -/// use winnow::branch::permutation; -/// use winnow::bytes::any; -/// -/// fn parser(input: &str) -> IResult<&str, (char, char)> { -/// permutation((any, 'a')).parse_next(input) -/// } -/// -/// // any parses 'b', then char('a') parses 'a' -/// assert_eq!(parser("ba"), Ok(("", ('b', 'a')))); -/// -/// // any parses 'a', then char('a') fails on 'b', -/// // even though char('a') followed by any would succeed -/// assert_eq!(parser("ab"), Err(ErrMode::Backtrack(Error::new("b", ErrorKind::Verify)))); -/// ``` -/// -pub fn permutation, List: Permutation>( - mut l: List, -) -> impl Parser { - trace("permutation", move |i: I| l.permutation(i)) -} - -macro_rules! alt_trait( - ($first:ident $second:ident $($id: ident)+) => ( - alt_trait!(__impl $first $second; $($id)+); - ); - (__impl $($current:ident)*; $head:ident $($id: ident)+) => ( - alt_trait_impl!($($current)*); - - alt_trait!(__impl $($current)* $head; $($id)+); - ); - (__impl $($current:ident)*; $head:ident) => ( - alt_trait_impl!($($current)*); - alt_trait_impl!($($current)* $head); - ); -); - -macro_rules! alt_trait_impl( - ($($id:ident)+) => ( - impl< - I: Clone, Output, Error: ParseError, - $($id: Parser),+ - > Alt for ( $($id),+ ) { - - fn choice(&mut self, input: I) -> IResult { - match self.0.parse_next(input.clone()) { - Err(ErrMode::Backtrack(e)) => alt_trait_inner!(1, self, input, e, $($id)+), - res => res, - } - } - } - ); -); - -macro_rules! alt_trait_inner( - ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident $($id:ident)+) => ( - match $self.$it.parse_next($input.clone()) { - Err(ErrMode::Backtrack(e)) => { - let err = $err.or(e); - succ!($it, alt_trait_inner!($self, $input, err, $($id)+)) - } - res => res, - } - ); - ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident) => ( - Err(ErrMode::Backtrack($err.append($input, ErrorKind::Alt))) - ); -); - -alt_trait!(Alt2 Alt3 Alt4 Alt5 Alt6 Alt7 Alt8 Alt9 Alt10 Alt11 Alt12 Alt13 Alt14 Alt15 Alt16 Alt17 Alt18 Alt19 Alt20 Alt21 Alt22); - -// Manually implement Alt for (A,), the 1-tuple type -impl, A: Parser> Alt for (A,) { - fn choice(&mut self, input: I) -> IResult { - self.0.parse_next(input) - } -} - -macro_rules! permutation_trait( - ( - $name1:ident $ty1:ident $item1:ident - $name2:ident $ty2:ident $item2:ident - $($name3:ident $ty3:ident $item3:ident)* - ) => ( - permutation_trait!(__impl $name1 $ty1 $item1, $name2 $ty2 $item2; $($name3 $ty3 $item3)*); - ); - ( - __impl $($name:ident $ty:ident $item:ident),+; - $name1:ident $ty1:ident $item1:ident $($name2:ident $ty2:ident $item2:ident)* - ) => ( - permutation_trait_impl!($($name $ty $item),+); - permutation_trait!(__impl $($name $ty $item),+ , $name1 $ty1 $item1; $($name2 $ty2 $item2)*); - ); - (__impl $($name:ident $ty:ident $item:ident),+;) => ( - permutation_trait_impl!($($name $ty $item),+); - ); -); - -macro_rules! permutation_trait_impl( - ($($name:ident $ty:ident $item:ident),+) => ( - impl< - I: Clone, $($ty),+ , Error: ParseError, - $($name: Parser),+ - > Permutation for ( $($name),+ ) { - - fn permutation(&mut self, mut input: I) -> IResult { - let mut res = ($(Option::<$ty>::None),+); - - loop { - let mut err: Option = None; - permutation_trait_inner!(0, self, input, res, err, $($name)+); - - // If we reach here, every iterator has either been applied before, - // or errored on the remaining input - if let Some(err) = err { - // There are remaining parsers, and all errored on the remaining input - return Err(ErrMode::Backtrack(err.append(input, ErrorKind::Alt))); - } - - // All parsers were applied - match res { - ($(Some($item)),+) => return Ok((input, ($($item),+))), - _ => unreachable!(), - } - } - } - } - ); -); - -macro_rules! permutation_trait_inner( - ($it:tt, $self:expr, $input:ident, $res:expr, $err:expr, $head:ident $($id:ident)*) => ( - if $res.$it.is_none() { - match $self.$it.parse_next($input.clone()) { - Ok((i, o)) => { - $input = i; - $res.$it = Some(o); - continue; - } - Err(ErrMode::Backtrack(e)) => { - $err = Some(match $err { - Some(err) => err.or(e), - None => e, - }); - } - Err(e) => return Err(e), - }; - } - succ!($it, permutation_trait_inner!($self, $input, $res, $err, $($id)*)); - ); - ($it:tt, $self:expr, $input:ident, $res:expr, $err:expr,) => (); -); - -permutation_trait!( - P1 O1 o1 - P2 O2 o2 - P3 O3 o3 - P4 O4 o4 - P5 O5 o5 - P6 O6 o6 - P7 O7 o7 - P8 O8 o8 - P9 O9 o9 - P10 O10 o10 - P11 O11 o11 - P12 O12 o12 - P13 O13 o13 - P14 O14 o14 - P15 O15 o15 - P16 O16 o16 - P17 O17 o17 - P18 O18 o18 - P19 O19 o19 - P20 O20 o20 - P21 O21 o21 -); diff --git a/vendor/winnow/src/branch/tests.rs b/vendor/winnow/src/branch/tests.rs deleted file mode 100644 index 80bc163ce..000000000 --- a/vendor/winnow/src/branch/tests.rs +++ /dev/null @@ -1,180 +0,0 @@ -use crate::branch::{alt, permutation}; - -use crate::error::ErrMode; -use crate::error::ErrorKind; -use crate::error::Needed; -use crate::IResult; -use crate::Parser; -use crate::Partial; -#[cfg(feature = "alloc")] -use crate::{ - error::ParseError, - lib::std::{ - fmt::Debug, - string::{String, ToString}, - }, -}; - -#[cfg(feature = "alloc")] -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct ErrorStr(String); - -#[cfg(feature = "alloc")] -impl From for ErrorStr { - fn from(i: u32) -> Self { - ErrorStr(format!("custom error code: {}", i)) - } -} - -#[cfg(feature = "alloc")] -impl<'a> From<&'a str> for ErrorStr { - fn from(i: &'a str) -> Self { - ErrorStr(format!("custom error message: {}", i)) - } -} - -#[cfg(feature = "alloc")] -impl ParseError for ErrorStr { - fn from_error_kind(input: I, kind: ErrorKind) -> Self { - ErrorStr(format!("custom error message: ({:?}, {:?})", input, kind)) - } - - fn append(self, input: I, kind: ErrorKind) -> Self { - ErrorStr(format!( - "custom error message: ({:?}, {:?}) - {:?}", - input, kind, self - )) - } -} - -#[cfg(feature = "alloc")] -#[test] -fn alt_test() { - fn work(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { - Ok((&b""[..], input)) - } - - #[allow(unused_variables)] - fn dont_work(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { - Err(ErrMode::Backtrack(ErrorStr("abcd".to_string()))) - } - - fn work2(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { - Ok((input, &b""[..])) - } - - fn alt1(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { - alt((dont_work, dont_work)).parse_next(i) - } - fn alt2(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { - alt((dont_work, work)).parse_next(i) - } - fn alt3(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { - alt((dont_work, dont_work, work2, dont_work)).parse_next(i) - } - //named!(alt1, alt!(dont_work | dont_work)); - //named!(alt2, alt!(dont_work | work)); - //named!(alt3, alt!(dont_work | dont_work | work2 | dont_work)); - - let a = &b"abcd"[..]; - assert_eq!( - alt1(a), - Err(ErrMode::Backtrack(error_node_position!( - a, - ErrorKind::Alt, - ErrorStr("abcd".to_string()) - ))) - ); - assert_eq!(alt2(a), Ok((&b""[..], a))); - assert_eq!(alt3(a), Ok((a, &b""[..]))); - - fn alt4(i: &[u8]) -> IResult<&[u8], &[u8]> { - alt(("abcd", "efgh")).parse_next(i) - } - let b = &b"efgh"[..]; - assert_eq!(alt4(a), Ok((&b""[..], a))); - assert_eq!(alt4(b), Ok((&b""[..], b))); -} - -#[test] -fn alt_incomplete() { - fn alt1(i: Partial<&[u8]>) -> IResult, &[u8]> { - alt(("a", "bc", "def")).parse_next(i) - } - - let a = &b""[..]; - assert_eq!( - alt1(Partial::new(a)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - let a = &b"b"[..]; - assert_eq!( - alt1(Partial::new(a)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - let a = &b"bcd"[..]; - assert_eq!( - alt1(Partial::new(a)), - Ok((Partial::new(&b"d"[..]), &b"bc"[..])) - ); - let a = &b"cde"[..]; - assert_eq!( - alt1(Partial::new(a)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(a), - ErrorKind::Tag - ))) - ); - let a = &b"de"[..]; - assert_eq!( - alt1(Partial::new(a)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - let a = &b"defg"[..]; - assert_eq!( - alt1(Partial::new(a)), - Ok((Partial::new(&b"g"[..]), &b"def"[..])) - ); -} - -#[test] -fn permutation_test() { - #[allow(clippy::type_complexity)] - fn perm(i: Partial<&[u8]>) -> IResult, (&[u8], &[u8], &[u8])> { - permutation(("abcd", "efg", "hi")).parse_next(i) - } - - let expected = (&b"abcd"[..], &b"efg"[..], &b"hi"[..]); - - let a = &b"abcdefghijk"[..]; - assert_eq!( - perm(Partial::new(a)), - Ok((Partial::new(&b"jk"[..]), expected)) - ); - let b = &b"efgabcdhijk"[..]; - assert_eq!( - perm(Partial::new(b)), - Ok((Partial::new(&b"jk"[..]), expected)) - ); - let c = &b"hiefgabcdjk"[..]; - assert_eq!( - perm(Partial::new(c)), - Ok((Partial::new(&b"jk"[..]), expected)) - ); - - let d = &b"efgxyzabcdefghi"[..]; - assert_eq!( - perm(Partial::new(d)), - Err(ErrMode::Backtrack(error_node_position!( - Partial::new(&b"efgxyzabcdefghi"[..]), - ErrorKind::Alt, - error_position!(Partial::new(&b"xyzabcdefghi"[..]), ErrorKind::Tag) - ))) - ); - - let e = &b"efgabc"[..]; - assert_eq!( - perm(Partial::new(e)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); -} diff --git a/vendor/winnow/src/bytes.rs b/vendor/winnow/src/bytes.rs new file mode 100644 index 000000000..9f57a56d2 --- /dev/null +++ b/vendor/winnow/src/bytes.rs @@ -0,0 +1,26 @@ +//! Deprecated, see [`token`] +#![deprecated(since = "0.4.2", note = "Replaced with `token`")] + +use crate::error::ParseError; +use crate::stream::StreamIsPartial; +use crate::stream::{ContainsToken, Stream}; +use crate::token; +use crate::Parser; + +pub use crate::token::*; + +/// Deprecated, see [`token::take_while`] +#[deprecated(since = "0.4.2", note = "Replaced with `token::take_while`")] +#[inline(always)] +pub fn take_while_m_n>( + m: usize, + n: usize, + list: T, +) -> impl Parser::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<::Token>, +{ + token::take_while(m..=n, list) +} diff --git a/vendor/winnow/src/bytes/mod.rs b/vendor/winnow/src/bytes/mod.rs deleted file mode 100644 index 0bf8681b7..000000000 --- a/vendor/winnow/src/bytes/mod.rs +++ /dev/null @@ -1,1167 +0,0 @@ -//! Parsers recognizing bytes streams - -#[cfg(test)] -mod tests; - -use crate::error::ErrMode; -use crate::error::ErrorKind; -use crate::error::Needed; -use crate::error::ParseError; -use crate::lib::std::result::Result::Ok; -use crate::stream::{ - split_at_offset1_complete, split_at_offset1_partial, split_at_offset_complete, - split_at_offset_partial, Compare, CompareResult, ContainsToken, FindSlice, SliceLen, Stream, -}; -use crate::stream::{StreamIsPartial, ToUsize}; -use crate::trace::trace; -use crate::IResult; -use crate::Parser; - -/// Matches one token -/// -/// *Complete version*: Will return an error if there's not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{bytes::any, error::ErrMode, error::{Error, ErrorKind}}; -/// # use winnow::prelude::*; -/// fn parser(input: &str) -> IResult<&str, char> { -/// any.parse_next(input) -/// } -/// -/// assert_eq!(parser("abc"), Ok(("bc",'a'))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Token)))); -/// ``` -/// -/// ```rust -/// # use winnow::{bytes::any, error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// assert_eq!(any::<_, Error<_>>.parse_next(Partial::new("abc")), Ok((Partial::new("bc"),'a'))); -/// assert_eq!(any::<_, Error<_>>.parse_next(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -#[doc(alias = "token")] -pub fn any>(input: I) -> IResult::Token, E> -where - I: StreamIsPartial, - I: Stream, -{ - trace("any", move |input: I| { - if input.is_partial() { - streaming_any(input) - } else { - complete_any(input) - } - }) - .parse_next(input) -} - -pub(crate) fn streaming_any>(input: I) -> IResult::Token, E> -where - I: Stream, -{ - input - .next_token() - .ok_or_else(|| ErrMode::Incomplete(Needed::new(1))) -} - -pub(crate) fn complete_any>(input: I) -> IResult::Token, E> -where - I: Stream, -{ - input - .next_token() - .ok_or_else(|| ErrMode::from_error_kind(input, ErrorKind::Token)) -} - -/// Recognizes a literal -/// -/// The input data will be compared to the tag combinator's argument and will return the part of -/// the input that matches the argument -/// -/// It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Tag)))` if the input doesn't match the pattern -/// -/// **Note:** [`Parser`][crate::Parser] is implemented for strings and byte strings as a convenience (complete -/// only) -/// -/// # Example -/// ```rust -/// # use winnow::prelude::*; -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// use winnow::bytes::tag; -/// -/// fn parser(s: &str) -> IResult<&str, &str> { -/// "Hello".parse_next(s) -/// } -/// -/// assert_eq!(parser("Hello, World!"), Ok((", World!", "Hello"))); -/// assert_eq!(parser("Something"), Err(ErrMode::Backtrack(Error::new("Something", ErrorKind::Tag)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); -/// ``` -/// -/// ```rust -/// # use winnow::prelude::*; -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::Partial; -/// use winnow::bytes::tag; -/// -/// fn parser(s: Partial<&str>) -> IResult, &str> { -/// "Hello".parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new("Hello, World!")), Ok((Partial::new(", World!"), "Hello"))); -/// assert_eq!(parser(Partial::new("Something")), Err(ErrMode::Backtrack(Error::new(Partial::new("Something"), ErrorKind::Tag)))); -/// assert_eq!(parser(Partial::new("S")), Err(ErrMode::Backtrack(Error::new(Partial::new("S"), ErrorKind::Tag)))); -/// assert_eq!(parser(Partial::new("H")), Err(ErrMode::Incomplete(Needed::new(4)))); -/// ``` -#[inline(always)] -#[doc(alias = "literal")] -#[doc(alias = "bytes")] -#[doc(alias = "just")] -pub fn tag>(tag: T) -> impl Parser::Slice, Error> -where - I: StreamIsPartial, - I: Stream + Compare, - T: SliceLen + Clone, -{ - trace("tag", move |i: I| { - let t = tag.clone(); - if i.is_partial() { - streaming_tag_internal(i, t) - } else { - complete_tag_internal(i, t) - } - }) -} - -pub(crate) fn streaming_tag_internal>( - i: I, - t: T, -) -> IResult::Slice, Error> -where - I: Stream + Compare, - T: SliceLen, -{ - let tag_len = t.slice_len(); - match i.compare(t) { - CompareResult::Ok => Ok(i.next_slice(tag_len)), - CompareResult::Incomplete => { - Err(ErrMode::Incomplete(Needed::new(tag_len - i.eof_offset()))) - } - CompareResult::Error => { - let e: ErrorKind = ErrorKind::Tag; - Err(ErrMode::from_error_kind(i, e)) - } - } -} - -pub(crate) fn complete_tag_internal>( - i: I, - t: T, -) -> IResult::Slice, Error> -where - I: Stream + Compare, - T: SliceLen, -{ - let tag_len = t.slice_len(); - match i.compare(t) { - CompareResult::Ok => Ok(i.next_slice(tag_len)), - CompareResult::Incomplete | CompareResult::Error => { - let e: ErrorKind = ErrorKind::Tag; - Err(ErrMode::from_error_kind(i, e)) - } - } -} - -/// Recognizes a case insensitive literal. -/// -/// The input data will be compared to the tag combinator's argument and will return the part of -/// the input that matches the argument with no regard to case. -/// -/// It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Tag)))` if the input doesn't match the pattern. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::bytes::tag_no_case; -/// -/// fn parser(s: &str) -> IResult<&str, &str> { -/// tag_no_case("hello").parse_next(s) -/// } -/// -/// assert_eq!(parser("Hello, World!"), Ok((", World!", "Hello"))); -/// assert_eq!(parser("hello, World!"), Ok((", World!", "hello"))); -/// assert_eq!(parser("HeLlO, World!"), Ok((", World!", "HeLlO"))); -/// assert_eq!(parser("Something"), Err(ErrMode::Backtrack(Error::new("Something", ErrorKind::Tag)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::bytes::tag_no_case; -/// -/// fn parser(s: Partial<&str>) -> IResult, &str> { -/// tag_no_case("hello").parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new("Hello, World!")), Ok((Partial::new(", World!"), "Hello"))); -/// assert_eq!(parser(Partial::new("hello, World!")), Ok((Partial::new(", World!"), "hello"))); -/// assert_eq!(parser(Partial::new("HeLlO, World!")), Ok((Partial::new(", World!"), "HeLlO"))); -/// assert_eq!(parser(Partial::new("Something")), Err(ErrMode::Backtrack(Error::new(Partial::new("Something"), ErrorKind::Tag)))); -/// assert_eq!(parser(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(5)))); -/// ``` -#[inline(always)] -#[doc(alias = "literal")] -#[doc(alias = "bytes")] -#[doc(alias = "just")] -pub fn tag_no_case>( - tag: T, -) -> impl Parser::Slice, Error> -where - I: StreamIsPartial, - I: Stream + Compare, - T: SliceLen + Clone, -{ - trace("tag_no_case", move |i: I| { - let t = tag.clone(); - if i.is_partial() { - streaming_tag_no_case_internal(i, t) - } else { - complete_tag_no_case_internal(i, t) - } - }) -} - -pub(crate) fn streaming_tag_no_case_internal>( - i: I, - t: T, -) -> IResult::Slice, Error> -where - I: Stream + Compare, - T: SliceLen, -{ - let tag_len = t.slice_len(); - - match (i).compare_no_case(t) { - CompareResult::Ok => Ok(i.next_slice(tag_len)), - CompareResult::Incomplete => { - Err(ErrMode::Incomplete(Needed::new(tag_len - i.eof_offset()))) - } - CompareResult::Error => { - let e: ErrorKind = ErrorKind::Tag; - Err(ErrMode::from_error_kind(i, e)) - } - } -} - -pub(crate) fn complete_tag_no_case_internal>( - i: I, - t: T, -) -> IResult::Slice, Error> -where - I: Stream + Compare, - T: SliceLen, -{ - let tag_len = t.slice_len(); - - match (i).compare_no_case(t) { - CompareResult::Ok => Ok(i.next_slice(tag_len)), - CompareResult::Incomplete | CompareResult::Error => { - let e: ErrorKind = ErrorKind::Tag; - Err(ErrMode::from_error_kind(i, e)) - } - } -} - -/// Recognize a token that matches the [pattern][ContainsToken] -/// -/// **Note:** [`Parser`][crate::Parser] is implemented as a convenience (complete -/// only) for -/// - `u8` -/// - `char` -/// -/// *Complete version*: Will return an error if there's not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::prelude::*; -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error}; -/// # use winnow::bytes::one_of; -/// assert_eq!(one_of::<_, _, Error<_>>("abc").parse_next("b"), Ok(("", 'b'))); -/// assert_eq!(one_of::<_, _, Error<_>>("a").parse_next("bc"), Err(ErrMode::Backtrack(Error::new("bc", ErrorKind::Verify)))); -/// assert_eq!(one_of::<_, _, Error<_>>("a").parse_next(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Token)))); -/// -/// fn parser_fn(i: &str) -> IResult<&str, char> { -/// one_of(|c| c == 'a' || c == 'b').parse_next(i) -/// } -/// assert_eq!(parser_fn("abc"), Ok(("bc", 'a'))); -/// assert_eq!(parser_fn("cd"), Err(ErrMode::Backtrack(Error::new("cd", ErrorKind::Verify)))); -/// assert_eq!(parser_fn(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Token)))); -/// ``` -/// -/// ``` -/// # use winnow::prelude::*; -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::bytes::one_of; -/// assert_eq!(one_of::<_, _, Error<_>>("abc").parse_next(Partial::new("b")), Ok((Partial::new(""), 'b'))); -/// assert_eq!(one_of::<_, _, Error<_>>("a").parse_next(Partial::new("bc")), Err(ErrMode::Backtrack(Error::new(Partial::new("bc"), ErrorKind::Verify)))); -/// assert_eq!(one_of::<_, _, Error<_>>("a").parse_next(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// -/// fn parser_fn(i: Partial<&str>) -> IResult, char> { -/// one_of(|c| c == 'a' || c == 'b').parse_next(i) -/// } -/// assert_eq!(parser_fn(Partial::new("abc")), Ok((Partial::new("bc"), 'a'))); -/// assert_eq!(parser_fn(Partial::new("cd")), Err(ErrMode::Backtrack(Error::new(Partial::new("cd"), ErrorKind::Verify)))); -/// assert_eq!(parser_fn(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -#[doc(alias = "char")] -#[doc(alias = "token")] -#[doc(alias = "satisfy")] -pub fn one_of>(list: T) -> impl Parser::Token, Error> -where - I: StreamIsPartial, - I: Stream, - ::Token: Copy, - T: ContainsToken<::Token>, -{ - trace( - "one_of", - any.verify(move |t: &::Token| list.contains_token(*t)), - ) -} - -/// Recognize a token that does not match the [pattern][ContainsToken] -/// -/// *Complete version*: Will return an error if there's not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error}; -/// # use winnow::prelude::*; -/// # use winnow::bytes::none_of; -/// assert_eq!(none_of::<_, _, Error<_>>("abc").parse_next("z"), Ok(("", 'z'))); -/// assert_eq!(none_of::<_, _, Error<_>>("ab").parse_next("a"), Err(ErrMode::Backtrack(Error::new("a", ErrorKind::Verify)))); -/// assert_eq!(none_of::<_, _, Error<_>>("a").parse_next(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Token)))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// # use winnow::bytes::none_of; -/// assert_eq!(none_of::<_, _, Error<_>>("abc").parse_next(Partial::new("z")), Ok((Partial::new(""), 'z'))); -/// assert_eq!(none_of::<_, _, Error<_>>("ab").parse_next(Partial::new("a")), Err(ErrMode::Backtrack(Error::new(Partial::new("a"), ErrorKind::Verify)))); -/// assert_eq!(none_of::<_, _, Error<_>>("a").parse_next(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn none_of>(list: T) -> impl Parser::Token, Error> -where - I: StreamIsPartial, - I: Stream, - ::Token: Copy, - T: ContainsToken<::Token>, -{ - trace( - "none_of", - any.verify(move |t: &::Token| !list.contains_token(*t)), - ) -} - -/// Recognize the longest input slice (if any) that matches the [pattern][ContainsToken] -/// -/// *Partial version*: will return a `ErrMode::Incomplete(Needed::new(1))` if the pattern reaches the end of the input. -/// -/// To recognize a series of tokens, use [`many0`][crate::multi::many0] to [`Accumulate`][crate::stream::Accumulate] into a `()` and then [`Parser::recognize`][crate::Parser::recognize]. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::bytes::take_while0; -/// use winnow::stream::AsChar; -/// -/// fn alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { -/// take_while0(AsChar::is_alpha).parse_next(s) -/// } -/// -/// assert_eq!(alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); -/// assert_eq!(alpha(b"12345"), Ok((&b"12345"[..], &b""[..]))); -/// assert_eq!(alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); -/// assert_eq!(alpha(b""), Ok((&b""[..], &b""[..]))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::bytes::take_while0; -/// use winnow::stream::AsChar; -/// -/// fn alpha(s: Partial<&[u8]>) -> IResult, &[u8]> { -/// take_while0(AsChar::is_alpha).parse_next(s) -/// } -/// -/// assert_eq!(alpha(Partial::new(b"latin123")), Ok((Partial::new(&b"123"[..]), &b"latin"[..]))); -/// assert_eq!(alpha(Partial::new(b"12345")), Ok((Partial::new(&b"12345"[..]), &b""[..]))); -/// assert_eq!(alpha(Partial::new(b"latin")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// assert_eq!(alpha(Partial::new(b"")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn take_while0>( - list: T, -) -> impl Parser::Slice, Error> -where - I: StreamIsPartial, - I: Stream, - T: ContainsToken<::Token>, -{ - trace("take_while0", move |i: I| { - if i.is_partial() { - streaming_take_while_internal(i, &list) - } else { - complete_take_while_internal(i, &list) - } - }) -} - -pub(crate) fn streaming_take_while_internal>( - i: I, - list: &T, -) -> IResult::Slice, Error> -where - I: Stream, - T: ContainsToken<::Token>, -{ - split_at_offset_partial(&i, |c| !list.contains_token(c)) -} - -pub(crate) fn complete_take_while_internal>( - i: I, - list: &T, -) -> IResult::Slice, Error> -where - I: Stream, - T: ContainsToken<::Token>, -{ - split_at_offset_complete(&i, |c| !list.contains_token(c)) -} - -/// Recognize the longest (at least 1) input slice that matches the [pattern][ContainsToken] -/// -/// It will return an `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Slice)))` if the pattern wasn't met. -/// -/// *Partial version* will return a `ErrMode::Incomplete(Needed::new(1))` or if the pattern reaches the end of the input. -/// -/// To recognize a series of tokens, use [`many1`][crate::multi::many1] to [`Accumulate`][crate::stream::Accumulate] into a `()` and then [`Parser::recognize`][crate::Parser::recognize]. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::bytes::take_while1; -/// use winnow::stream::AsChar; -/// -/// fn alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { -/// take_while1(AsChar::is_alpha).parse_next(s) -/// } -/// -/// assert_eq!(alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); -/// assert_eq!(alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); -/// assert_eq!(alpha(b"12345"), Err(ErrMode::Backtrack(Error::new(&b"12345"[..], ErrorKind::Slice)))); -/// -/// fn hex(s: &str) -> IResult<&str, &str> { -/// take_while1("1234567890ABCDEF").parse_next(s) -/// } -/// -/// assert_eq!(hex("123 and voila"), Ok((" and voila", "123"))); -/// assert_eq!(hex("DEADBEEF and others"), Ok((" and others", "DEADBEEF"))); -/// assert_eq!(hex("BADBABEsomething"), Ok(("something", "BADBABE"))); -/// assert_eq!(hex("D15EA5E"), Ok(("", "D15EA5E"))); -/// assert_eq!(hex(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::bytes::take_while1; -/// use winnow::stream::AsChar; -/// -/// fn alpha(s: Partial<&[u8]>) -> IResult, &[u8]> { -/// take_while1(AsChar::is_alpha).parse_next(s) -/// } -/// -/// assert_eq!(alpha(Partial::new(b"latin123")), Ok((Partial::new(&b"123"[..]), &b"latin"[..]))); -/// assert_eq!(alpha(Partial::new(b"latin")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// assert_eq!(alpha(Partial::new(b"12345")), Err(ErrMode::Backtrack(Error::new(Partial::new(&b"12345"[..]), ErrorKind::Slice)))); -/// -/// fn hex(s: Partial<&str>) -> IResult, &str> { -/// take_while1("1234567890ABCDEF").parse_next(s) -/// } -/// -/// assert_eq!(hex(Partial::new("123 and voila")), Ok((Partial::new(" and voila"), "123"))); -/// assert_eq!(hex(Partial::new("DEADBEEF and others")), Ok((Partial::new(" and others"), "DEADBEEF"))); -/// assert_eq!(hex(Partial::new("BADBABEsomething")), Ok((Partial::new("something"), "BADBABE"))); -/// assert_eq!(hex(Partial::new("D15EA5E")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// assert_eq!(hex(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -#[doc(alias = "is_a")] -pub fn take_while1>( - list: T, -) -> impl Parser::Slice, Error> -where - I: StreamIsPartial, - I: Stream, - T: ContainsToken<::Token>, -{ - trace("take_while1", move |i: I| { - if i.is_partial() { - streaming_take_while1_internal(i, &list) - } else { - complete_take_while1_internal(i, &list) - } - }) -} - -pub(crate) fn streaming_take_while1_internal>( - i: I, - list: &T, -) -> IResult::Slice, Error> -where - I: Stream, - T: ContainsToken<::Token>, -{ - let e: ErrorKind = ErrorKind::Slice; - split_at_offset1_partial(&i, |c| !list.contains_token(c), e) -} - -pub(crate) fn complete_take_while1_internal>( - i: I, - list: &T, -) -> IResult::Slice, Error> -where - I: Stream, - T: ContainsToken<::Token>, -{ - let e: ErrorKind = ErrorKind::Slice; - split_at_offset1_complete(&i, |c| !list.contains_token(c), e) -} - -/// Recognize the longest (m <= len <= n) input slice that matches the [pattern][ContainsToken] -/// -/// It will return an `ErrMode::Backtrack(Error::new(_, ErrorKind::Slice))` if the pattern wasn't met or is out -/// of range (m <= len <= n). -/// -/// *Partial version* will return a `ErrMode::Incomplete(Needed::new(1))` if the pattern reaches the end of the input or is too short. -/// -/// To recognize a series of tokens, use [`many_m_n`][crate::multi::many_m_n] to [`Accumulate`][crate::stream::Accumulate] into a `()` and then [`Parser::recognize`][crate::Parser::recognize]. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::bytes::take_while_m_n; -/// use winnow::stream::AsChar; -/// -/// fn short_alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { -/// take_while_m_n(3, 6, AsChar::is_alpha).parse_next(s) -/// } -/// -/// assert_eq!(short_alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); -/// assert_eq!(short_alpha(b"lengthy"), Ok((&b"y"[..], &b"length"[..]))); -/// assert_eq!(short_alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); -/// assert_eq!(short_alpha(b"ed"), Err(ErrMode::Backtrack(Error::new(&b"ed"[..], ErrorKind::Slice)))); -/// assert_eq!(short_alpha(b"12345"), Err(ErrMode::Backtrack(Error::new(&b"12345"[..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::bytes::take_while_m_n; -/// use winnow::stream::AsChar; -/// -/// fn short_alpha(s: Partial<&[u8]>) -> IResult, &[u8]> { -/// take_while_m_n(3, 6, AsChar::is_alpha).parse_next(s) -/// } -/// -/// assert_eq!(short_alpha(Partial::new(b"latin123")), Ok((Partial::new(&b"123"[..]), &b"latin"[..]))); -/// assert_eq!(short_alpha(Partial::new(b"lengthy")), Ok((Partial::new(&b"y"[..]), &b"length"[..]))); -/// assert_eq!(short_alpha(Partial::new(b"latin")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// assert_eq!(short_alpha(Partial::new(b"ed")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// assert_eq!(short_alpha(Partial::new(b"12345")), Err(ErrMode::Backtrack(Error::new(Partial::new(&b"12345"[..]), ErrorKind::Slice)))); -/// ``` -#[inline(always)] -pub fn take_while_m_n>( - m: usize, - n: usize, - list: T, -) -> impl Parser::Slice, Error> -where - I: StreamIsPartial, - I: Stream, - T: ContainsToken<::Token>, -{ - trace("take_while_m_n", move |i: I| { - if i.is_partial() { - streaming_take_while_m_n_internal(i, m, n, &list) - } else { - complete_take_while_m_n_internal(i, m, n, &list) - } - }) -} - -pub(crate) fn streaming_take_while_m_n_internal>( - input: I, - m: usize, - n: usize, - list: &T, -) -> IResult::Slice, Error> -where - I: Stream, - T: ContainsToken<::Token>, -{ - if n < m { - return Err(ErrMode::assert(input, "`m` should be <= `n`")); - } - - let mut final_count = 0; - for (processed, (offset, token)) in input.iter_offsets().enumerate() { - if !list.contains_token(token) { - if processed < m { - return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); - } else { - return Ok(input.next_slice(offset)); - } - } else { - if processed == n { - return Ok(input.next_slice(offset)); - } - final_count = processed + 1; - } - } - - if final_count == n { - Ok(input.next_slice(input.eof_offset())) - } else { - let needed = if m > input.eof_offset() { - m - input.eof_offset() - } else { - 1 - }; - Err(ErrMode::Incomplete(Needed::new(needed))) - } -} - -pub(crate) fn complete_take_while_m_n_internal>( - input: I, - m: usize, - n: usize, - list: &T, -) -> IResult::Slice, Error> -where - I: Stream, - T: ContainsToken<::Token>, -{ - if n < m { - return Err(ErrMode::assert(input, "`m` should be <= `n`")); - } - - let mut final_count = 0; - for (processed, (offset, token)) in input.iter_offsets().enumerate() { - if !list.contains_token(token) { - if processed < m { - return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); - } else { - return Ok(input.next_slice(offset)); - } - } else { - if processed == n { - return Ok(input.next_slice(offset)); - } - final_count = processed + 1; - } - } - - if m <= final_count { - Ok(input.next_slice(input.eof_offset())) - } else { - Err(ErrMode::from_error_kind(input, ErrorKind::Slice)) - } -} - -/// Recognize the longest input slice (if any) till a [pattern][ContainsToken] is met. -/// -/// *Partial version* will return a `ErrMode::Incomplete(Needed::new(1))` if the match reaches the -/// end of input or if there was not match. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::bytes::take_till0; -/// -/// fn till_colon(s: &str) -> IResult<&str, &str> { -/// take_till0(|c| c == ':').parse_next(s) -/// } -/// -/// assert_eq!(till_colon("latin:123"), Ok((":123", "latin"))); -/// assert_eq!(till_colon(":empty matched"), Ok((":empty matched", ""))); //allowed -/// assert_eq!(till_colon("12345"), Ok(("", "12345"))); -/// assert_eq!(till_colon(""), Ok(("", ""))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::bytes::take_till0; -/// -/// fn till_colon(s: Partial<&str>) -> IResult, &str> { -/// take_till0(|c| c == ':').parse_next(s) -/// } -/// -/// assert_eq!(till_colon(Partial::new("latin:123")), Ok((Partial::new(":123"), "latin"))); -/// assert_eq!(till_colon(Partial::new(":empty matched")), Ok((Partial::new(":empty matched"), ""))); //allowed -/// assert_eq!(till_colon(Partial::new("12345")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// assert_eq!(till_colon(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn take_till0>( - list: T, -) -> impl Parser::Slice, Error> -where - I: StreamIsPartial, - I: Stream, - T: ContainsToken<::Token>, -{ - trace("take_till0", move |i: I| { - if i.is_partial() { - streaming_take_till_internal(i, &list) - } else { - complete_take_till_internal(i, &list) - } - }) -} - -pub(crate) fn streaming_take_till_internal>( - i: I, - list: &T, -) -> IResult::Slice, Error> -where - I: Stream, - T: ContainsToken<::Token>, -{ - split_at_offset_partial(&i, |c| list.contains_token(c)) -} - -pub(crate) fn complete_take_till_internal>( - i: I, - list: &T, -) -> IResult::Slice, Error> -where - I: Stream, - T: ContainsToken<::Token>, -{ - split_at_offset_complete(&i, |c| list.contains_token(c)) -} - -/// Recognize the longest (at least 1) input slice till a [pattern][ContainsToken] is met. -/// -/// It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Slice)))` if the input is empty or the -/// predicate matches the first input. -/// -/// *Partial version* will return a `ErrMode::Incomplete(Needed::new(1))` if the match reaches the -/// end of input or if there was not match. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::bytes::take_till1; -/// -/// fn till_colon(s: &str) -> IResult<&str, &str> { -/// take_till1(|c| c == ':').parse_next(s) -/// } -/// -/// assert_eq!(till_colon("latin:123"), Ok((":123", "latin"))); -/// assert_eq!(till_colon(":empty matched"), Err(ErrMode::Backtrack(Error::new(":empty matched", ErrorKind::Slice)))); -/// assert_eq!(till_colon("12345"), Ok(("", "12345"))); -/// assert_eq!(till_colon(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); -/// -/// fn not_space(s: &str) -> IResult<&str, &str> { -/// take_till1(" \t\r\n").parse_next(s) -/// } -/// -/// assert_eq!(not_space("Hello, World!"), Ok((" World!", "Hello,"))); -/// assert_eq!(not_space("Sometimes\t"), Ok(("\t", "Sometimes"))); -/// assert_eq!(not_space("Nospace"), Ok(("", "Nospace"))); -/// assert_eq!(not_space(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::bytes::take_till1; -/// -/// fn till_colon(s: Partial<&str>) -> IResult, &str> { -/// take_till1(|c| c == ':').parse_next(s) -/// } -/// -/// assert_eq!(till_colon(Partial::new("latin:123")), Ok((Partial::new(":123"), "latin"))); -/// assert_eq!(till_colon(Partial::new(":empty matched")), Err(ErrMode::Backtrack(Error::new(Partial::new(":empty matched"), ErrorKind::Slice)))); -/// assert_eq!(till_colon(Partial::new("12345")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// assert_eq!(till_colon(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// -/// fn not_space(s: Partial<&str>) -> IResult, &str> { -/// take_till1(" \t\r\n").parse_next(s) -/// } -/// -/// assert_eq!(not_space(Partial::new("Hello, World!")), Ok((Partial::new(" World!"), "Hello,"))); -/// assert_eq!(not_space(Partial::new("Sometimes\t")), Ok((Partial::new("\t"), "Sometimes"))); -/// assert_eq!(not_space(Partial::new("Nospace")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// assert_eq!(not_space(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -#[doc(alias = "is_not")] -pub fn take_till1>( - list: T, -) -> impl Parser::Slice, Error> -where - I: StreamIsPartial, - I: Stream, - T: ContainsToken<::Token>, -{ - trace("take_till1", move |i: I| { - if i.is_partial() { - streaming_take_till1_internal(i, &list) - } else { - complete_take_till1_internal(i, &list) - } - }) -} - -pub(crate) fn streaming_take_till1_internal>( - i: I, - list: &T, -) -> IResult::Slice, Error> -where - I: Stream, - T: ContainsToken<::Token>, -{ - let e: ErrorKind = ErrorKind::Slice; - split_at_offset1_partial(&i, |c| list.contains_token(c), e) -} - -pub(crate) fn complete_take_till1_internal>( - i: I, - list: &T, -) -> IResult::Slice, Error> -where - I: Stream, - T: ContainsToken<::Token>, -{ - let e: ErrorKind = ErrorKind::Slice; - split_at_offset1_complete(&i, |c| list.contains_token(c), e) -} - -/// Recognize an input slice containing the first N input elements (I[..N]). -/// -/// *Complete version*: It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Slice)))` if the input is shorter than the argument. -/// -/// *Partial version*: if the input has less than N elements, `take` will -/// return a `ErrMode::Incomplete(Needed::new(M))` where M is the number of -/// additional bytes the parser would need to succeed. -/// It is well defined for `&[u8]` as the number of elements is the byte size, -/// but for types like `&str`, we cannot know how many bytes correspond for -/// the next few chars, so the result will be `ErrMode::Incomplete(Needed::Unknown)` -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::bytes::take; -/// -/// fn take6(s: &str) -> IResult<&str, &str> { -/// take(6usize).parse_next(s) -/// } -/// -/// assert_eq!(take6("1234567"), Ok(("7", "123456"))); -/// assert_eq!(take6("things"), Ok(("", "things"))); -/// assert_eq!(take6("short"), Err(ErrMode::Backtrack(Error::new("short", ErrorKind::Slice)))); -/// assert_eq!(take6(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); -/// ``` -/// -/// The units that are taken will depend on the input type. For example, for a -/// `&str` it will take a number of `char`'s, whereas for a `&[u8]` it will -/// take that many `u8`'s: -/// -/// ```rust -/// # use winnow::prelude::*; -/// use winnow::error::Error; -/// use winnow::bytes::take; -/// -/// assert_eq!(take::<_, _, Error<_>>(1usize).parse_next("💙"), Ok(("", "💙"))); -/// assert_eq!(take::<_, _, Error<_>>(1usize).parse_next("💙".as_bytes()), Ok((b"\x9F\x92\x99".as_ref(), b"\xF0".as_ref()))); -/// ``` -/// -/// ```rust -/// # use winnow::prelude::*; -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::Partial; -/// use winnow::bytes::take; -/// -/// fn take6(s: Partial<&str>) -> IResult, &str> { -/// take(6usize).parse_next(s) -/// } -/// -/// assert_eq!(take6(Partial::new("1234567")), Ok((Partial::new("7"), "123456"))); -/// assert_eq!(take6(Partial::new("things")), Ok((Partial::new(""), "things"))); -/// // `Unknown` as we don't know the number of bytes that `count` corresponds to -/// assert_eq!(take6(Partial::new("short")), Err(ErrMode::Incomplete(Needed::Unknown))); -/// ``` -#[inline(always)] -pub fn take>(count: C) -> impl Parser::Slice, Error> -where - I: StreamIsPartial, - I: Stream, - C: ToUsize, -{ - let c = count.to_usize(); - trace("take", move |i: I| { - if i.is_partial() { - streaming_take_internal(i, c) - } else { - complete_take_internal(i, c) - } - }) -} - -pub(crate) fn streaming_take_internal>( - i: I, - c: usize, -) -> IResult::Slice, Error> -where - I: Stream, -{ - match i.offset_at(c) { - Ok(offset) => Ok(i.next_slice(offset)), - Err(i) => Err(ErrMode::Incomplete(i)), - } -} - -pub(crate) fn complete_take_internal>( - i: I, - c: usize, -) -> IResult::Slice, Error> -where - I: Stream, -{ - match i.offset_at(c) { - Ok(offset) => Ok(i.next_slice(offset)), - Err(_needed) => Err(ErrMode::from_error_kind(i, ErrorKind::Slice)), - } -} - -/// Recognize the input slice up to the first occurrence of the literal. -/// -/// It doesn't consume the pattern. -/// -/// *Complete version*: It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Slice)))` -/// if the pattern wasn't met. -/// -/// *Partial version*: will return a `ErrMode::Incomplete(Needed::new(N))` if the input doesn't -/// contain the pattern or if the input is smaller than the pattern. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::bytes::take_until0; -/// -/// fn until_eof(s: &str) -> IResult<&str, &str> { -/// take_until0("eof").parse_next(s) -/// } -/// -/// assert_eq!(until_eof("hello, worldeof"), Ok(("eof", "hello, world"))); -/// assert_eq!(until_eof("hello, world"), Err(ErrMode::Backtrack(Error::new("hello, world", ErrorKind::Slice)))); -/// assert_eq!(until_eof(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); -/// assert_eq!(until_eof("1eof2eof"), Ok(("eof2eof", "1"))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::bytes::take_until0; -/// -/// fn until_eof(s: Partial<&str>) -> IResult, &str> { -/// take_until0("eof").parse_next(s) -/// } -/// -/// assert_eq!(until_eof(Partial::new("hello, worldeof")), Ok((Partial::new("eof"), "hello, world"))); -/// assert_eq!(until_eof(Partial::new("hello, world")), Err(ErrMode::Incomplete(Needed::Unknown))); -/// assert_eq!(until_eof(Partial::new("hello, worldeo")), Err(ErrMode::Incomplete(Needed::Unknown))); -/// assert_eq!(until_eof(Partial::new("1eof2eof")), Ok((Partial::new("eof2eof"), "1"))); -/// ``` -#[inline(always)] -pub fn take_until0>( - tag: T, -) -> impl Parser::Slice, Error> -where - I: StreamIsPartial, - I: Stream + FindSlice, - T: SliceLen + Clone, -{ - trace("take_until0", move |i: I| { - if i.is_partial() { - streaming_take_until_internal(i, tag.clone()) - } else { - complete_take_until_internal(i, tag.clone()) - } - }) -} - -pub(crate) fn streaming_take_until_internal>( - i: I, - t: T, -) -> IResult::Slice, Error> -where - I: Stream + FindSlice, - T: SliceLen, -{ - match i.find_slice(t) { - Some(offset) => Ok(i.next_slice(offset)), - None => Err(ErrMode::Incomplete(Needed::Unknown)), - } -} - -pub(crate) fn complete_take_until_internal>( - i: I, - t: T, -) -> IResult::Slice, Error> -where - I: Stream + FindSlice, - T: SliceLen, -{ - match i.find_slice(t) { - Some(offset) => Ok(i.next_slice(offset)), - None => Err(ErrMode::from_error_kind(i, ErrorKind::Slice)), - } -} - -/// Recognize the non empty input slice up to the first occurrence of the literal. -/// -/// It doesn't consume the pattern. -/// -/// *Complete version*: It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Slice)))` -/// if the pattern wasn't met. -/// -/// *Partial version*: will return a `ErrMode::Incomplete(Needed::new(N))` if the input doesn't -/// contain the pattern or if the input is smaller than the pattern. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::bytes::take_until1; -/// -/// fn until_eof(s: &str) -> IResult<&str, &str> { -/// take_until1("eof").parse_next(s) -/// } -/// -/// assert_eq!(until_eof("hello, worldeof"), Ok(("eof", "hello, world"))); -/// assert_eq!(until_eof("hello, world"), Err(ErrMode::Backtrack(Error::new("hello, world", ErrorKind::Slice)))); -/// assert_eq!(until_eof(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); -/// assert_eq!(until_eof("1eof2eof"), Ok(("eof2eof", "1"))); -/// assert_eq!(until_eof("eof"), Err(ErrMode::Backtrack(Error::new("eof", ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::bytes::take_until1; -/// -/// fn until_eof(s: Partial<&str>) -> IResult, &str> { -/// take_until1("eof").parse_next(s) -/// } -/// -/// assert_eq!(until_eof(Partial::new("hello, worldeof")), Ok((Partial::new("eof"), "hello, world"))); -/// assert_eq!(until_eof(Partial::new("hello, world")), Err(ErrMode::Incomplete(Needed::Unknown))); -/// assert_eq!(until_eof(Partial::new("hello, worldeo")), Err(ErrMode::Incomplete(Needed::Unknown))); -/// assert_eq!(until_eof(Partial::new("1eof2eof")), Ok((Partial::new("eof2eof"), "1"))); -/// assert_eq!(until_eof(Partial::new("eof")), Err(ErrMode::Backtrack(Error::new(Partial::new("eof"), ErrorKind::Slice)))); -/// ``` -#[inline(always)] -pub fn take_until1>( - tag: T, -) -> impl Parser::Slice, Error> -where - I: StreamIsPartial, - I: Stream + FindSlice, - T: SliceLen + Clone, -{ - trace("take_until1", move |i: I| { - if i.is_partial() { - streaming_take_until1_internal(i, tag.clone()) - } else { - complete_take_until1_internal(i, tag.clone()) - } - }) -} - -pub(crate) fn streaming_take_until1_internal>( - i: I, - t: T, -) -> IResult::Slice, Error> -where - I: Stream + FindSlice, - T: SliceLen, -{ - match i.find_slice(t) { - None => Err(ErrMode::Incomplete(Needed::Unknown)), - Some(0) => Err(ErrMode::from_error_kind(i, ErrorKind::Slice)), - Some(offset) => Ok(i.next_slice(offset)), - } -} - -pub(crate) fn complete_take_until1_internal>( - i: I, - t: T, -) -> IResult::Slice, Error> -where - I: Stream + FindSlice, - T: SliceLen, -{ - match i.find_slice(t) { - None | Some(0) => Err(ErrMode::from_error_kind(i, ErrorKind::Slice)), - Some(offset) => Ok(i.next_slice(offset)), - } -} diff --git a/vendor/winnow/src/bytes/tests.rs b/vendor/winnow/src/bytes/tests.rs deleted file mode 100644 index c2a1ceefd..000000000 --- a/vendor/winnow/src/bytes/tests.rs +++ /dev/null @@ -1,701 +0,0 @@ -use super::*; - -#[cfg(feature = "std")] -use proptest::prelude::*; - -use crate::bytes::tag; -use crate::error::ErrMode; -use crate::error::Error; -use crate::error::ErrorKind; -use crate::error::Needed; -use crate::multi::length_data; -use crate::sequence::delimited; -use crate::stream::AsChar; -use crate::IResult; -use crate::Parser; -use crate::Partial; - -#[test] -fn complete_take_while_m_n_utf8_all_matching() { - let result: IResult<&str, &str> = - take_while_m_n(1, 4, |c: char| c.is_alphabetic()).parse_next("øn"); - assert_eq!(result, Ok(("", "øn"))); -} - -#[test] -fn complete_take_while_m_n_utf8_all_matching_substring() { - let result: IResult<&str, &str> = - take_while_m_n(1, 1, |c: char| c.is_alphabetic()).parse_next("øn"); - assert_eq!(result, Ok(("n", "ø"))); -} - -#[cfg(feature = "std")] -fn model_complete_take_while_m_n( - m: usize, - n: usize, - valid: usize, - input: &str, -) -> IResult<&str, &str> { - if n < m { - Err(crate::error::ErrMode::from_error_kind( - input, - crate::error::ErrorKind::Slice, - )) - } else if m <= valid { - let offset = n.min(valid); - Ok((&input[offset..], &input[0..offset])) - } else { - Err(crate::error::ErrMode::from_error_kind( - input, - crate::error::ErrorKind::Slice, - )) - } -} - -#[cfg(feature = "std")] -proptest! { - #[test] - #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 - fn complete_take_while_m_n_bounds(m in 0..20usize, n in 0..20usize, valid in 0..20usize, invalid in 0..20usize) { - let input = format!("{:a>>(Partial::new("Ә")), - Ok((Partial::new(""), 'Ә')) - ); -} - -#[test] -fn partial_one_of_test() { - fn f(i: Partial<&[u8]>) -> IResult, u8> { - one_of("ab").parse_next(i) - } - - let a = &b"abcd"[..]; - assert_eq!(f(Partial::new(a)), Ok((Partial::new(&b"bcd"[..]), b'a'))); - - let b = &b"cde"[..]; - assert_eq!( - f(Partial::new(b)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(b), - ErrorKind::Verify - ))) - ); - - fn utf8(i: Partial<&str>) -> IResult, char> { - one_of("+\u{FF0B}").parse_next(i) - } - - assert!(utf8(Partial::new("+")).is_ok()); - assert!(utf8(Partial::new("\u{FF0B}")).is_ok()); -} - -#[test] -fn char_byteslice() { - fn f(i: Partial<&[u8]>) -> IResult, u8> { - 'c'.parse_next(i) - } - - let a = &b"abcd"[..]; - assert_eq!( - f(Partial::new(a)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(a), - ErrorKind::Verify - ))) - ); - - let b = &b"cde"[..]; - assert_eq!(f(Partial::new(b)), Ok((Partial::new(&b"de"[..]), b'c'))); -} - -#[test] -fn char_str() { - fn f(i: Partial<&str>) -> IResult, char> { - 'c'.parse_next(i) - } - - let a = "abcd"; - assert_eq!( - f(Partial::new(a)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(a), - ErrorKind::Verify - ))) - ); - - let b = "cde"; - assert_eq!(f(Partial::new(b)), Ok((Partial::new("de"), 'c'))); -} - -#[test] -fn partial_none_of_test() { - fn f(i: Partial<&[u8]>) -> IResult, u8> { - none_of("ab").parse_next(i) - } - - let a = &b"abcd"[..]; - assert_eq!( - f(Partial::new(a)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(a), - ErrorKind::Verify - ))) - ); - - let b = &b"cde"[..]; - assert_eq!(f(Partial::new(b)), Ok((Partial::new(&b"de"[..]), b'c'))); -} - -#[test] -fn partial_is_a() { - fn a_or_b(i: Partial<&[u8]>) -> IResult, &[u8]> { - take_while1("ab").parse_next(i) - } - - let a = Partial::new(&b"abcd"[..]); - assert_eq!(a_or_b(a), Ok((Partial::new(&b"cd"[..]), &b"ab"[..]))); - - let b = Partial::new(&b"bcde"[..]); - assert_eq!(a_or_b(b), Ok((Partial::new(&b"cde"[..]), &b"b"[..]))); - - let c = Partial::new(&b"cdef"[..]); - assert_eq!( - a_or_b(c), - Err(ErrMode::Backtrack(error_position!(c, ErrorKind::Slice))) - ); - - let d = Partial::new(&b"bacdef"[..]); - assert_eq!(a_or_b(d), Ok((Partial::new(&b"cdef"[..]), &b"ba"[..]))); -} - -#[test] -fn partial_is_not() { - fn a_or_b(i: Partial<&[u8]>) -> IResult, &[u8]> { - take_till1("ab").parse_next(i) - } - - let a = Partial::new(&b"cdab"[..]); - assert_eq!(a_or_b(a), Ok((Partial::new(&b"ab"[..]), &b"cd"[..]))); - - let b = Partial::new(&b"cbde"[..]); - assert_eq!(a_or_b(b), Ok((Partial::new(&b"bde"[..]), &b"c"[..]))); - - let c = Partial::new(&b"abab"[..]); - assert_eq!( - a_or_b(c), - Err(ErrMode::Backtrack(error_position!(c, ErrorKind::Slice))) - ); - - let d = Partial::new(&b"cdefba"[..]); - assert_eq!(a_or_b(d), Ok((Partial::new(&b"ba"[..]), &b"cdef"[..]))); - - let e = Partial::new(&b"e"[..]); - assert_eq!(a_or_b(e), Err(ErrMode::Incomplete(Needed::new(1)))); -} - -#[test] -fn partial_take_until_incomplete() { - fn y(i: Partial<&[u8]>) -> IResult, &[u8]> { - take_until0("end").parse_next(i) - } - assert_eq!( - y(Partial::new(&b"nd"[..])), - Err(ErrMode::Incomplete(Needed::Unknown)) - ); - assert_eq!( - y(Partial::new(&b"123"[..])), - Err(ErrMode::Incomplete(Needed::Unknown)) - ); - assert_eq!( - y(Partial::new(&b"123en"[..])), - Err(ErrMode::Incomplete(Needed::Unknown)) - ); -} - -#[test] -fn partial_take_until_incomplete_s() { - fn ys(i: Partial<&str>) -> IResult, &str> { - take_until0("end").parse_next(i) - } - assert_eq!( - ys(Partial::new("123en")), - Err(ErrMode::Incomplete(Needed::Unknown)) - ); -} - -#[test] -fn partial_recognize() { - use crate::character::{ - alpha1 as alpha, alphanumeric1 as alphanumeric, digit1 as digit, hex_digit1 as hex_digit, - multispace1 as multispace, oct_digit1 as oct_digit, space1 as space, - }; - - fn x(i: Partial<&[u8]>) -> IResult, &[u8]> { - delimited("") - .recognize() - .parse_next(i) - } - let r = x(Partial::new(&b" aaa"[..])); - assert_eq!(r, Ok((Partial::new(&b" aaa"[..]), &b""[..]))); - - let semicolon = &b";"[..]; - - fn ya(i: Partial<&[u8]>) -> IResult, &[u8]> { - alpha.recognize().parse_next(i) - } - let ra = ya(Partial::new(&b"abc;"[..])); - assert_eq!(ra, Ok((Partial::new(semicolon), &b"abc"[..]))); - - fn yd(i: Partial<&[u8]>) -> IResult, &[u8]> { - digit.recognize().parse_next(i) - } - let rd = yd(Partial::new(&b"123;"[..])); - assert_eq!(rd, Ok((Partial::new(semicolon), &b"123"[..]))); - - fn yhd(i: Partial<&[u8]>) -> IResult, &[u8]> { - hex_digit.recognize().parse_next(i) - } - let rhd = yhd(Partial::new(&b"123abcDEF;"[..])); - assert_eq!(rhd, Ok((Partial::new(semicolon), &b"123abcDEF"[..]))); - - fn yod(i: Partial<&[u8]>) -> IResult, &[u8]> { - oct_digit.recognize().parse_next(i) - } - let rod = yod(Partial::new(&b"1234567;"[..])); - assert_eq!(rod, Ok((Partial::new(semicolon), &b"1234567"[..]))); - - fn yan(i: Partial<&[u8]>) -> IResult, &[u8]> { - alphanumeric.recognize().parse_next(i) - } - let ran = yan(Partial::new(&b"123abc;"[..])); - assert_eq!(ran, Ok((Partial::new(semicolon), &b"123abc"[..]))); - - fn ys(i: Partial<&[u8]>) -> IResult, &[u8]> { - space.recognize().parse_next(i) - } - let rs = ys(Partial::new(&b" \t;"[..])); - assert_eq!(rs, Ok((Partial::new(semicolon), &b" \t"[..]))); - - fn yms(i: Partial<&[u8]>) -> IResult, &[u8]> { - multispace.recognize().parse_next(i) - } - let rms = yms(Partial::new(&b" \t\r\n;"[..])); - assert_eq!(rms, Ok((Partial::new(semicolon), &b" \t\r\n"[..]))); -} - -#[test] -fn partial_take_while0() { - fn f(i: Partial<&[u8]>) -> IResult, &[u8]> { - take_while0(AsChar::is_alpha).parse_next(i) - } - let a = &b""[..]; - let b = &b"abcd"[..]; - let c = &b"abcd123"[..]; - let d = &b"123"[..]; - - assert_eq!(f(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(1)))); - assert_eq!(f(Partial::new(b)), Err(ErrMode::Incomplete(Needed::new(1)))); - assert_eq!(f(Partial::new(c)), Ok((Partial::new(d), b))); - assert_eq!(f(Partial::new(d)), Ok((Partial::new(d), a))); -} - -#[test] -fn partial_take_while1() { - fn f(i: Partial<&[u8]>) -> IResult, &[u8]> { - take_while1(AsChar::is_alpha).parse_next(i) - } - let a = &b""[..]; - let b = &b"abcd"[..]; - let c = &b"abcd123"[..]; - let d = &b"123"[..]; - - assert_eq!(f(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(1)))); - assert_eq!(f(Partial::new(b)), Err(ErrMode::Incomplete(Needed::new(1)))); - assert_eq!(f(Partial::new(c)), Ok((Partial::new(&b"123"[..]), b))); - assert_eq!( - f(Partial::new(d)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(d), - ErrorKind::Slice - ))) - ); -} - -#[test] -fn partial_take_while_m_n() { - fn x(i: Partial<&[u8]>) -> IResult, &[u8]> { - take_while_m_n(2, 4, AsChar::is_alpha).parse_next(i) - } - let a = &b""[..]; - let b = &b"a"[..]; - let c = &b"abc"[..]; - let d = &b"abc123"[..]; - let e = &b"abcde"[..]; - let f = &b"123"[..]; - - assert_eq!(x(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(2)))); - assert_eq!(x(Partial::new(b)), Err(ErrMode::Incomplete(Needed::new(1)))); - assert_eq!(x(Partial::new(c)), Err(ErrMode::Incomplete(Needed::new(1)))); - assert_eq!(x(Partial::new(d)), Ok((Partial::new(&b"123"[..]), c))); - assert_eq!( - x(Partial::new(e)), - Ok((Partial::new(&b"e"[..]), &b"abcd"[..])) - ); - assert_eq!( - x(Partial::new(f)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(f), - ErrorKind::Slice - ))) - ); -} - -#[test] -fn partial_take_till0() { - fn f(i: Partial<&[u8]>) -> IResult, &[u8]> { - take_till0(AsChar::is_alpha).parse_next(i) - } - let a = &b""[..]; - let b = &b"abcd"[..]; - let c = &b"123abcd"[..]; - let d = &b"123"[..]; - - assert_eq!(f(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(1)))); - assert_eq!( - f(Partial::new(b)), - Ok((Partial::new(&b"abcd"[..]), &b""[..])) - ); - assert_eq!( - f(Partial::new(c)), - Ok((Partial::new(&b"abcd"[..]), &b"123"[..])) - ); - assert_eq!(f(Partial::new(d)), Err(ErrMode::Incomplete(Needed::new(1)))); -} - -#[test] -fn partial_take_till1() { - fn f(i: Partial<&[u8]>) -> IResult, &[u8]> { - take_till1(AsChar::is_alpha).parse_next(i) - } - let a = &b""[..]; - let b = &b"abcd"[..]; - let c = &b"123abcd"[..]; - let d = &b"123"[..]; - - assert_eq!(f(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(1)))); - assert_eq!( - f(Partial::new(b)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(b), - ErrorKind::Slice - ))) - ); - assert_eq!( - f(Partial::new(c)), - Ok((Partial::new(&b"abcd"[..]), &b"123"[..])) - ); - assert_eq!(f(Partial::new(d)), Err(ErrMode::Incomplete(Needed::new(1)))); -} - -#[test] -fn partial_take_while_utf8() { - fn f(i: Partial<&str>) -> IResult, &str> { - take_while0(|c| c != '點').parse_next(i) - } - - assert_eq!( - f(Partial::new("")), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - f(Partial::new("abcd")), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!(f(Partial::new("abcd點")), Ok((Partial::new("點"), "abcd"))); - assert_eq!( - f(Partial::new("abcd點a")), - Ok((Partial::new("點a"), "abcd")) - ); - - fn g(i: Partial<&str>) -> IResult, &str> { - take_while0(|c| c == '點').parse_next(i) - } - - assert_eq!( - g(Partial::new("")), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!(g(Partial::new("點abcd")), Ok((Partial::new("abcd"), "點"))); - assert_eq!( - g(Partial::new("點點點a")), - Ok((Partial::new("a"), "點點點")) - ); -} - -#[test] -fn partial_take_till0_utf8() { - fn f(i: Partial<&str>) -> IResult, &str> { - take_till0(|c| c == '點').parse_next(i) - } - - assert_eq!( - f(Partial::new("")), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - f(Partial::new("abcd")), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!(f(Partial::new("abcd點")), Ok((Partial::new("點"), "abcd"))); - assert_eq!( - f(Partial::new("abcd點a")), - Ok((Partial::new("點a"), "abcd")) - ); - - fn g(i: Partial<&str>) -> IResult, &str> { - take_till0(|c| c != '點').parse_next(i) - } - - assert_eq!( - g(Partial::new("")), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!(g(Partial::new("點abcd")), Ok((Partial::new("abcd"), "點"))); - assert_eq!( - g(Partial::new("點點點a")), - Ok((Partial::new("a"), "點點點")) - ); -} - -#[test] -fn partial_take_utf8() { - fn f(i: Partial<&str>) -> IResult, &str> { - take(3_usize).parse_next(i) - } - - assert_eq!( - f(Partial::new("")), - Err(ErrMode::Incomplete(Needed::Unknown)) - ); - assert_eq!( - f(Partial::new("ab")), - Err(ErrMode::Incomplete(Needed::Unknown)) - ); - assert_eq!( - f(Partial::new("點")), - Err(ErrMode::Incomplete(Needed::Unknown)) - ); - assert_eq!(f(Partial::new("ab點cd")), Ok((Partial::new("cd"), "ab點"))); - assert_eq!(f(Partial::new("a點bcd")), Ok((Partial::new("cd"), "a點b"))); - assert_eq!(f(Partial::new("a點b")), Ok((Partial::new(""), "a點b"))); - - fn g(i: Partial<&str>) -> IResult, &str> { - take_while0(|c| c == '點').parse_next(i) - } - - assert_eq!( - g(Partial::new("")), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!(g(Partial::new("點abcd")), Ok((Partial::new("abcd"), "點"))); - assert_eq!( - g(Partial::new("點點點a")), - Ok((Partial::new("a"), "點點點")) - ); -} - -#[test] -fn partial_take_while_m_n_utf8_fixed() { - fn parser(i: Partial<&str>) -> IResult, &str> { - take_while_m_n(1, 1, |c| c == 'A' || c == '😃').parse_next(i) - } - assert_eq!(parser(Partial::new("A!")), Ok((Partial::new("!"), "A"))); - assert_eq!(parser(Partial::new("😃!")), Ok((Partial::new("!"), "😃"))); -} - -#[test] -fn partial_take_while_m_n_utf8_range() { - fn parser(i: Partial<&str>) -> IResult, &str> { - take_while_m_n(1, 2, |c| c == 'A' || c == '😃').parse_next(i) - } - assert_eq!(parser(Partial::new("A!")), Ok((Partial::new("!"), "A"))); - assert_eq!(parser(Partial::new("😃!")), Ok((Partial::new("!"), "😃"))); -} - -#[test] -fn partial_take_while_m_n_utf8_full_match_fixed() { - fn parser(i: Partial<&str>) -> IResult, &str> { - take_while_m_n(1, 1, |c: char| c.is_alphabetic()).parse_next(i) - } - assert_eq!(parser(Partial::new("øn")), Ok((Partial::new("n"), "ø"))); -} - -#[test] -fn partial_take_while_m_n_utf8_full_match_range() { - fn parser(i: Partial<&str>) -> IResult, &str> { - take_while_m_n(1, 2, |c: char| c.is_alphabetic()).parse_next(i) - } - assert_eq!(parser(Partial::new("øn")), Ok((Partial::new(""), "øn"))); -} - -#[test] -#[cfg(feature = "std")] -fn partial_recognize_take_while0() { - fn x(i: Partial<&[u8]>) -> IResult, &[u8]> { - take_while0(AsChar::is_alphanum).parse_next(i) - } - fn y(i: Partial<&[u8]>) -> IResult, &[u8]> { - x.recognize().parse_next(i) - } - assert_eq!( - x(Partial::new(&b"ab."[..])), - Ok((Partial::new(&b"."[..]), &b"ab"[..])) - ); - assert_eq!( - y(Partial::new(&b"ab."[..])), - Ok((Partial::new(&b"."[..]), &b"ab"[..])) - ); -} - -#[test] -fn partial_length_bytes() { - use crate::number::le_u8; - - fn x(i: Partial<&[u8]>) -> IResult, &[u8]> { - length_data(le_u8).parse_next(i) - } - assert_eq!( - x(Partial::new(b"\x02..>>")), - Ok((Partial::new(&b">>"[..]), &b".."[..])) - ); - assert_eq!( - x(Partial::new(b"\x02..")), - Ok((Partial::new(&[][..]), &b".."[..])) - ); - assert_eq!( - x(Partial::new(b"\x02.")), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - x(Partial::new(b"\x02")), - Err(ErrMode::Incomplete(Needed::new(2))) - ); - - fn y(i: Partial<&[u8]>) -> IResult, &[u8]> { - let (i, _) = "magic".parse_next(i)?; - length_data(le_u8).parse_next(i) - } - assert_eq!( - y(Partial::new(b"magic\x02..>>")), - Ok((Partial::new(&b">>"[..]), &b".."[..])) - ); - assert_eq!( - y(Partial::new(b"magic\x02..")), - Ok((Partial::new(&[][..]), &b".."[..])) - ); - assert_eq!( - y(Partial::new(b"magic\x02.")), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - y(Partial::new(b"magic\x02")), - Err(ErrMode::Incomplete(Needed::new(2))) - ); -} - -#[cfg(feature = "alloc")] -#[test] -fn partial_case_insensitive() { - fn test(i: Partial<&[u8]>) -> IResult, &[u8]> { - tag_no_case("ABcd").parse_next(i) - } - assert_eq!( - test(Partial::new(&b"aBCdefgh"[..])), - Ok((Partial::new(&b"efgh"[..]), &b"aBCd"[..])) - ); - assert_eq!( - test(Partial::new(&b"abcdefgh"[..])), - Ok((Partial::new(&b"efgh"[..]), &b"abcd"[..])) - ); - assert_eq!( - test(Partial::new(&b"ABCDefgh"[..])), - Ok((Partial::new(&b"efgh"[..]), &b"ABCD"[..])) - ); - assert_eq!( - test(Partial::new(&b"ab"[..])), - Err(ErrMode::Incomplete(Needed::new(2))) - ); - assert_eq!( - test(Partial::new(&b"Hello"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"Hello"[..]), - ErrorKind::Tag - ))) - ); - assert_eq!( - test(Partial::new(&b"Hel"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"Hel"[..]), - ErrorKind::Tag - ))) - ); - - fn test2(i: Partial<&str>) -> IResult, &str> { - tag_no_case("ABcd").parse_next(i) - } - assert_eq!( - test2(Partial::new("aBCdefgh")), - Ok((Partial::new("efgh"), "aBCd")) - ); - assert_eq!( - test2(Partial::new("abcdefgh")), - Ok((Partial::new("efgh"), "abcd")) - ); - assert_eq!( - test2(Partial::new("ABCDefgh")), - Ok((Partial::new("efgh"), "ABCD")) - ); - assert_eq!( - test2(Partial::new("ab")), - Err(ErrMode::Incomplete(Needed::new(2))) - ); - assert_eq!( - test2(Partial::new("Hello")), - Err(ErrMode::Backtrack(error_position!( - Partial::new("Hello"), - ErrorKind::Tag - ))) - ); - assert_eq!( - test2(Partial::new("Hel")), - Err(ErrMode::Backtrack(error_position!( - Partial::new("Hel"), - ErrorKind::Tag - ))) - ); -} - -#[test] -fn partial_tag_fixed_size_array() { - fn test(i: Partial<&[u8]>) -> IResult, &[u8]> { - tag([0x42]).parse_next(i) - } - fn test2(i: Partial<&[u8]>) -> IResult, &[u8]> { - tag(&[0x42]).parse_next(i) - } - let input = Partial::new(&[0x42, 0x00][..]); - assert_eq!(test(input), Ok((Partial::new(&b"\x00"[..]), &b"\x42"[..]))); - assert_eq!(test2(input), Ok((Partial::new(&b"\x00"[..]), &b"\x42"[..]))); -} diff --git a/vendor/winnow/src/character.rs b/vendor/winnow/src/character.rs new file mode 100644 index 000000000..a2f685971 --- /dev/null +++ b/vendor/winnow/src/character.rs @@ -0,0 +1,342 @@ +//! Deprecated, see [`ascii`] +#![deprecated(since = "0.4.2", note = "Replaced with `ascii`")] + +use crate::ascii; +use crate::error::ParseError; +use crate::stream::Compare; +use crate::stream::ContainsToken; +use crate::stream::{AsBStr, AsChar, Offset, ParseSlice, Stream, StreamIsPartial}; +use crate::IResult; +use crate::Parser; + +/// Deprecated, replaced by [`ascii::crlf`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::crlf`")] +#[inline(always)] +pub fn crlf>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + I: Compare<&'static str>, +{ + ascii::crlf.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::not_line_ending`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::not_line_ending`")] +#[inline(always)] +pub fn not_line_ending>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream + AsBStr, + I: Compare<&'static str>, + ::Token: AsChar, +{ + ascii::not_line_ending.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::line_ending`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::line_ending`")] +#[inline(always)] +pub fn line_ending>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + I: Compare<&'static str>, +{ + ascii::line_ending.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::newline`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::newline`")] +#[inline(always)] +pub fn newline>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar + Copy, +{ + ascii::newline.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::tab`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::tab`")] +#[inline(always)] +pub fn tab>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar + Copy, +{ + ascii::tab.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::alpha0`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::alpha0`")] +#[inline(always)] +pub fn alpha0>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + ascii::alpha0.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::alpha1`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::alpha1`")] +#[inline(always)] +pub fn alpha1>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + ascii::alpha1.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::digit0`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::digit0`")] +#[inline(always)] +pub fn digit0>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + ascii::digit0.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::digit1`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::digit1`")] +#[inline(always)] +pub fn digit1>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + ascii::digit1.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::hex_digit0`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::hex_digit0`")] +#[inline(always)] +pub fn hex_digit0>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + ascii::hex_digit0.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::hex_digit1`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::hex_digit1`")] +#[inline(always)] +pub fn hex_digit1>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + ascii::hex_digit1.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::oct_digit0`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::oct_digit0`")] +#[inline(always)] +pub fn oct_digit0>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + ascii::oct_digit0.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::oct_digit1`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::oct_digit1`")] +#[inline(always)] +pub fn oct_digit1>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + ascii::oct_digit0.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::alphanumeric0`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::alphanumeric0`")] +#[inline(always)] +pub fn alphanumeric0>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + ascii::alphanumeric0.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::alphanumeric1`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::alphanumeric1`")] +#[inline(always)] +pub fn alphanumeric1>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar, +{ + ascii::alphanumeric1.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::space0`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::space0`")] +#[inline(always)] +pub fn space0>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar + Copy, +{ + ascii::space0.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::space1`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::space1`")] +#[inline(always)] +pub fn space1>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar + Copy, +{ + ascii::space1.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::multispace0`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::multispace0`")] +#[inline(always)] +pub fn multispace0>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar + Copy, +{ + ascii::multispace0.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::multispace1`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::multispace1`")] +#[inline(always)] +pub fn multispace1>(input: I) -> IResult::Slice, E> +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar + Copy, +{ + ascii::multispace1.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::dec_uint`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::dec_uint`")] +#[inline(always)] +pub fn dec_uint>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar + Copy, + O: Uint, +{ + ascii::dec_uint.parse_next(input) +} + +pub use ascii::Uint; + +/// Deprecated, replaced by [`ascii::dec_int`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::dec_int`")] +#[inline(always)] +pub fn dec_int>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Token: AsChar + Copy, + O: Int, +{ + ascii::dec_int.parse_next(input) +} + +pub use ascii::Int; + +/// Deprecated, replaced by [`ascii::hex_uint`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::hex_uint`")] +#[inline(always)] +pub fn hex_uint>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + O: HexUint, + ::Token: AsChar, + ::Slice: AsBStr, +{ + ascii::hex_uint.parse_next(input) +} + +pub use ascii::HexUint; + +/// Deprecated, replaced by [`ascii::float`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::float`")] +#[inline(always)] +pub fn float>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + I: Offset + Compare<&'static str>, + ::Slice: ParseSlice, + ::Token: AsChar + Copy, + ::IterOffsets: Clone, + I: AsBStr, + &'static str: ContainsToken<::Token>, +{ + ascii::float.parse_next(input) +} + +/// Deprecated, replaced by [`ascii::escaped`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::escaped`")] +#[inline(always)] +pub fn escaped<'a, I: 'a, Error, F, G, O1, O2>( + normal: F, + control_char: char, + escapable: G, +) -> impl Parser::Slice, Error> +where + I: StreamIsPartial, + I: Stream + Offset, + ::Token: crate::stream::AsChar, + F: Parser, + G: Parser, + Error: ParseError, +{ + ascii::escaped(normal, control_char, escapable) +} + +#[cfg(feature = "alloc")] +/// Deprecated, replaced by [`ascii::escaped_transform`] +#[deprecated(since = "0.4.2", note = "Replaced with `ascii::escaped_transform`")] +#[inline(always)] +pub fn escaped_transform( + normal: F, + control_char: char, + transform: G, +) -> impl Parser +where + I: StreamIsPartial, + I: Stream + Offset, + ::Token: crate::stream::AsChar, + Output: crate::stream::Accumulate<::Slice>, + F: Parser::Slice, Error>, + G: Parser::Slice, Error>, + Error: ParseError, +{ + ascii::escaped_transform(normal, control_char, transform) +} diff --git a/vendor/winnow/src/character/mod.rs b/vendor/winnow/src/character/mod.rs deleted file mode 100644 index 89cc9ec09..000000000 --- a/vendor/winnow/src/character/mod.rs +++ /dev/null @@ -1,1808 +0,0 @@ -//! Character specific parsers and combinators -//! -//! Functions recognizing specific characters - -#[cfg(test)] -mod tests; - -use crate::lib::std::ops::{Add, Shl}; - -use crate::branch::alt; -use crate::bytes::one_of; - -use crate::bytes::take_while0; -use crate::bytes::take_while1; -use crate::combinator::cut_err; -use crate::combinator::opt; -use crate::error::ParseError; -use crate::error::{ErrMode, ErrorKind, Needed}; -use crate::stream::ContainsToken; -use crate::stream::{AsBStr, AsChar, Offset, ParseSlice, Stream, StreamIsPartial}; -use crate::stream::{Compare, CompareResult}; -use crate::trace::trace; -use crate::IResult; -use crate::Parser; - -/// Recognizes the string "\r\n". -/// -/// *Complete version*: Will return an error if there's not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult}; -/// # use winnow::character::crlf; -/// fn parser(input: &str) -> IResult<&str, &str> { -/// crlf(input) -/// } -/// -/// assert_eq!(parser("\r\nc"), Ok(("c", "\r\n"))); -/// assert_eq!(parser("ab\r\nc"), Err(ErrMode::Backtrack(Error::new("ab\r\nc", ErrorKind::Tag)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::crlf; -/// assert_eq!(crlf::<_, Error<_>>(Partial::new("\r\nc")), Ok((Partial::new("c"), "\r\n"))); -/// assert_eq!(crlf::<_, Error<_>>(Partial::new("ab\r\nc")), Err(ErrMode::Backtrack(Error::new(Partial::new("ab\r\nc"), ErrorKind::Tag)))); -/// assert_eq!(crlf::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(2)))); -/// ``` -#[inline(always)] -pub fn crlf>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - I: Compare<&'static str>, -{ - trace("crlf", move |input: I| "\r\n".parse_next(input)).parse_next(input) -} - -/// Recognizes a string of any char except '\r\n' or '\n'. -/// -/// *Complete version*: Will return an error if there's not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; -/// # use winnow::character::not_line_ending; -/// fn parser(input: &str) -> IResult<&str, &str> { -/// not_line_ending(input) -/// } -/// -/// assert_eq!(parser("ab\r\nc"), Ok(("\r\nc", "ab"))); -/// assert_eq!(parser("ab\nc"), Ok(("\nc", "ab"))); -/// assert_eq!(parser("abc"), Ok(("", "abc"))); -/// assert_eq!(parser(""), Ok(("", ""))); -/// assert_eq!(parser("a\rb\nc"), Err(ErrMode::Backtrack(Error { input: "a\rb\nc", kind: ErrorKind::Tag }))); -/// assert_eq!(parser("a\rbc"), Err(ErrMode::Backtrack(Error { input: "a\rbc", kind: ErrorKind::Tag }))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::not_line_ending; -/// assert_eq!(not_line_ending::<_, Error<_>>(Partial::new("ab\r\nc")), Ok((Partial::new("\r\nc"), "ab"))); -/// assert_eq!(not_line_ending::<_, Error<_>>(Partial::new("abc")), Err(ErrMode::Incomplete(Needed::Unknown))); -/// assert_eq!(not_line_ending::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::Unknown))); -/// assert_eq!(not_line_ending::<_, Error<_>>(Partial::new("a\rb\nc")), Err(ErrMode::Backtrack(Error::new(Partial::new("a\rb\nc"), ErrorKind::Tag )))); -/// assert_eq!(not_line_ending::<_, Error<_>>(Partial::new("a\rbc")), Err(ErrMode::Backtrack(Error::new(Partial::new("a\rbc"), ErrorKind::Tag )))); -/// ``` -#[inline(always)] -pub fn not_line_ending>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream + AsBStr, - I: Compare<&'static str>, - ::Token: AsChar, -{ - trace("not_line_ending", move |input: I| { - if input.is_partial() { - streaming_not_line_ending(input) - } else { - complete_not_line_ending(input) - } - }) - .parse_next(input) -} - -pub(crate) fn streaming_not_line_ending>( - input: T, -) -> IResult::Slice, E> -where - T: Stream + AsBStr, - T: Compare<&'static str>, - ::Token: AsChar, -{ - match input.offset_for(|item| { - let c = item.as_char(); - c == '\r' || c == '\n' - }) { - None => Err(ErrMode::Incomplete(Needed::Unknown)), - Some(offset) => { - let (new_input, res) = input.next_slice(offset); - let bytes = new_input.as_bstr(); - let nth = bytes[0]; - if nth == b'\r' { - let comp = new_input.compare("\r\n"); - match comp { - //FIXME: calculate the right index - CompareResult::Ok => {} - CompareResult::Incomplete => { - return Err(ErrMode::Incomplete(Needed::Unknown)); - } - CompareResult::Error => { - let e: ErrorKind = ErrorKind::Tag; - return Err(ErrMode::from_error_kind(input, e)); - } - } - } - Ok((new_input, res)) - } - } -} - -pub(crate) fn complete_not_line_ending>( - input: T, -) -> IResult::Slice, E> -where - T: Stream + AsBStr, - T: Compare<&'static str>, - ::Token: AsChar, -{ - match input.offset_for(|item| { - let c = item.as_char(); - c == '\r' || c == '\n' - }) { - None => Ok(input.next_slice(input.eof_offset())), - Some(offset) => { - let (new_input, res) = input.next_slice(offset); - let bytes = new_input.as_bstr(); - let nth = bytes[0]; - if nth == b'\r' { - let comp = new_input.compare("\r\n"); - match comp { - //FIXME: calculate the right index - CompareResult::Ok => {} - CompareResult::Incomplete | CompareResult::Error => { - let e: ErrorKind = ErrorKind::Tag; - return Err(ErrMode::from_error_kind(input, e)); - } - } - } - Ok((new_input, res)) - } - } -} - -/// Recognizes an end of line (both '\n' and '\r\n'). -/// -/// *Complete version*: Will return an error if there's not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; -/// # use winnow::character::line_ending; -/// fn parser(input: &str) -> IResult<&str, &str> { -/// line_ending(input) -/// } -/// -/// assert_eq!(parser("\r\nc"), Ok(("c", "\r\n"))); -/// assert_eq!(parser("ab\r\nc"), Err(ErrMode::Backtrack(Error::new("ab\r\nc", ErrorKind::Tag)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::line_ending; -/// assert_eq!(line_ending::<_, Error<_>>(Partial::new("\r\nc")), Ok((Partial::new("c"), "\r\n"))); -/// assert_eq!(line_ending::<_, Error<_>>(Partial::new("ab\r\nc")), Err(ErrMode::Backtrack(Error::new(Partial::new("ab\r\nc"), ErrorKind::Tag)))); -/// assert_eq!(line_ending::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn line_ending>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - I: Compare<&'static str>, -{ - trace("line_ending", move |input: I| { - alt(("\n", "\r\n")).parse_next(input) - }) - .parse_next(input) -} - -/// Matches a newline character '\n'. -/// -/// *Complete version*: Will return an error if there's not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; -/// # use winnow::character::newline; -/// fn parser(input: &str) -> IResult<&str, char> { -/// newline(input) -/// } -/// -/// assert_eq!(parser("\nc"), Ok(("c", '\n'))); -/// assert_eq!(parser("\r\nc"), Err(ErrMode::Backtrack(Error::new("\r\nc", ErrorKind::Verify)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Token)))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::newline; -/// assert_eq!(newline::<_, Error<_>>(Partial::new("\nc")), Ok((Partial::new("c"), '\n'))); -/// assert_eq!(newline::<_, Error<_>>(Partial::new("\r\nc")), Err(ErrMode::Backtrack(Error::new(Partial::new("\r\nc"), ErrorKind::Verify)))); -/// assert_eq!(newline::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn newline>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar + Copy, -{ - trace("newline", move |input: I| { - '\n'.map(|c: ::Token| c.as_char()) - .parse_next(input) - }) - .parse_next(input) -} - -/// Matches a tab character '\t'. -/// -/// *Complete version*: Will return an error if there's not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; -/// # use winnow::character::tab; -/// fn parser(input: &str) -> IResult<&str, char> { -/// tab(input) -/// } -/// -/// assert_eq!(parser("\tc"), Ok(("c", '\t'))); -/// assert_eq!(parser("\r\nc"), Err(ErrMode::Backtrack(Error::new("\r\nc", ErrorKind::Verify)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Token)))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::tab; -/// assert_eq!(tab::<_, Error<_>>(Partial::new("\tc")), Ok((Partial::new("c"), '\t'))); -/// assert_eq!(tab::<_, Error<_>>(Partial::new("\r\nc")), Err(ErrMode::Backtrack(Error::new(Partial::new("\r\nc"), ErrorKind::Verify)))); -/// assert_eq!(tab::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn tab>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar + Copy, -{ - trace("tab", move |input: I| { - '\t'.map(|c: ::Token| c.as_char()) - .parse_next(input) - }) - .parse_next(input) -} - -/// Recognizes zero or more lowercase and uppercase ASCII alphabetic characters: a-z, A-Z -/// -/// *Complete version*: Will return the whole input if no terminating token is found (a non -/// alphabetic character). -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, -/// or if no terminating token is found (a non alphabetic character). -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::character::alpha0; -/// fn parser(input: &str) -> IResult<&str, &str> { -/// alpha0(input) -/// } -/// -/// assert_eq!(parser("ab1c"), Ok(("1c", "ab"))); -/// assert_eq!(parser("1c"), Ok(("1c", ""))); -/// assert_eq!(parser(""), Ok(("", ""))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::alpha0; -/// assert_eq!(alpha0::<_, Error<_>>(Partial::new("ab1c")), Ok((Partial::new("1c"), "ab"))); -/// assert_eq!(alpha0::<_, Error<_>>(Partial::new("1c")), Ok((Partial::new("1c"), ""))); -/// assert_eq!(alpha0::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn alpha0>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar, -{ - trace("alpha0", move |input: I| { - take_while0(|c: ::Token| c.is_alpha()).parse_next(input) - }) - .parse_next(input) -} - -/// Recognizes one or more lowercase and uppercase ASCII alphabetic characters: a-z, A-Z -/// -/// *Complete version*: Will return an error if there's not enough input data, -/// or the whole input if no terminating token is found (a non alphabetic character). -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, -/// or if no terminating token is found (a non alphabetic character). -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; -/// # use winnow::character::alpha1; -/// fn parser(input: &str) -> IResult<&str, &str> { -/// alpha1(input) -/// } -/// -/// assert_eq!(parser("aB1c"), Ok(("1c", "aB"))); -/// assert_eq!(parser("1c"), Err(ErrMode::Backtrack(Error::new("1c", ErrorKind::Slice)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::alpha1; -/// assert_eq!(alpha1::<_, Error<_>>(Partial::new("aB1c")), Ok((Partial::new("1c"), "aB"))); -/// assert_eq!(alpha1::<_, Error<_>>(Partial::new("1c")), Err(ErrMode::Backtrack(Error::new(Partial::new("1c"), ErrorKind::Slice)))); -/// assert_eq!(alpha1::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn alpha1>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar, -{ - trace("alpha1", move |input: I| { - take_while1(|c: ::Token| c.is_alpha()).parse_next(input) - }) - .parse_next(input) -} - -/// Recognizes zero or more ASCII numerical characters: 0-9 -/// -/// *Complete version*: Will return an error if there's not enough input data, -/// or the whole input if no terminating token is found (a non digit character). -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, -/// or if no terminating token is found (a non digit character). -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::character::digit0; -/// fn parser(input: &str) -> IResult<&str, &str> { -/// digit0(input) -/// } -/// -/// assert_eq!(parser("21c"), Ok(("c", "21"))); -/// assert_eq!(parser("21"), Ok(("", "21"))); -/// assert_eq!(parser("a21c"), Ok(("a21c", ""))); -/// assert_eq!(parser(""), Ok(("", ""))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::digit0; -/// assert_eq!(digit0::<_, Error<_>>(Partial::new("21c")), Ok((Partial::new("c"), "21"))); -/// assert_eq!(digit0::<_, Error<_>>(Partial::new("a21c")), Ok((Partial::new("a21c"), ""))); -/// assert_eq!(digit0::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn digit0>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar, -{ - trace("digit0", move |input: I| { - take_while0(|c: ::Token| c.is_dec_digit()).parse_next(input) - }) - .parse_next(input) -} - -/// Recognizes one or more ASCII numerical characters: 0-9 -/// -/// *Complete version*: Will return an error if there's not enough input data, -/// or the whole input if no terminating token is found (a non digit character). -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, -/// or if no terminating token is found (a non digit character). -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; -/// # use winnow::character::digit1; -/// fn parser(input: &str) -> IResult<&str, &str> { -/// digit1(input) -/// } -/// -/// assert_eq!(parser("21c"), Ok(("c", "21"))); -/// assert_eq!(parser("c1"), Err(ErrMode::Backtrack(Error::new("c1", ErrorKind::Slice)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::digit1; -/// assert_eq!(digit1::<_, Error<_>>(Partial::new("21c")), Ok((Partial::new("c"), "21"))); -/// assert_eq!(digit1::<_, Error<_>>(Partial::new("c1")), Err(ErrMode::Backtrack(Error::new(Partial::new("c1"), ErrorKind::Slice)))); -/// assert_eq!(digit1::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -/// -/// ## Parsing an integer -/// -/// You can use `digit1` in combination with [`Parser::map_res`][crate::Parser::map_res] to parse an integer: -/// -/// ``` -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed, Parser}; -/// # use winnow::character::digit1; -/// fn parser(input: &str) -> IResult<&str, u32> { -/// digit1.map_res(str::parse).parse_next(input) -/// } -/// -/// assert_eq!(parser("416"), Ok(("", 416))); -/// assert_eq!(parser("12b"), Ok(("b", 12))); -/// assert!(parser("b").is_err()); -/// ``` -#[inline(always)] -pub fn digit1>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar, -{ - trace("digit1", move |input: I| { - take_while1(|c: ::Token| c.is_dec_digit()).parse_next(input) - }) - .parse_next(input) -} - -/// Recognizes zero or more ASCII hexadecimal numerical characters: 0-9, A-F, a-f -/// -/// *Complete version*: Will return the whole input if no terminating token is found (a non hexadecimal digit character). -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, -/// or if no terminating token is found (a non hexadecimal digit character). -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::character::hex_digit0; -/// fn parser(input: &str) -> IResult<&str, &str> { -/// hex_digit0(input) -/// } -/// -/// assert_eq!(parser("21cZ"), Ok(("Z", "21c"))); -/// assert_eq!(parser("Z21c"), Ok(("Z21c", ""))); -/// assert_eq!(parser(""), Ok(("", ""))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::hex_digit0; -/// assert_eq!(hex_digit0::<_, Error<_>>(Partial::new("21cZ")), Ok((Partial::new("Z"), "21c"))); -/// assert_eq!(hex_digit0::<_, Error<_>>(Partial::new("Z21c")), Ok((Partial::new("Z21c"), ""))); -/// assert_eq!(hex_digit0::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn hex_digit0>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar, -{ - trace("hex_digit0", move |input: I| { - take_while0(|c: ::Token| c.is_hex_digit()).parse_next(input) - }) - .parse_next(input) -} - -/// Recognizes one or more ASCII hexadecimal numerical characters: 0-9, A-F, a-f -/// -/// *Complete version*: Will return an error if there's not enough input data, -/// or the whole input if no terminating token is found (a non hexadecimal digit character). -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, -/// or if no terminating token is found (a non hexadecimal digit character). -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; -/// # use winnow::character::hex_digit1; -/// fn parser(input: &str) -> IResult<&str, &str> { -/// hex_digit1(input) -/// } -/// -/// assert_eq!(parser("21cZ"), Ok(("Z", "21c"))); -/// assert_eq!(parser("H2"), Err(ErrMode::Backtrack(Error::new("H2", ErrorKind::Slice)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::hex_digit1; -/// assert_eq!(hex_digit1::<_, Error<_>>(Partial::new("21cZ")), Ok((Partial::new("Z"), "21c"))); -/// assert_eq!(hex_digit1::<_, Error<_>>(Partial::new("H2")), Err(ErrMode::Backtrack(Error::new(Partial::new("H2"), ErrorKind::Slice)))); -/// assert_eq!(hex_digit1::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn hex_digit1>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar, -{ - trace("hex_digit1", move |input: I| { - take_while1(|c: ::Token| c.is_hex_digit()).parse_next(input) - }) - .parse_next(input) -} - -/// Recognizes zero or more octal characters: 0-7 -/// -/// *Complete version*: Will return the whole input if no terminating token is found (a non octal -/// digit character). -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, -/// or if no terminating token is found (a non octal digit character). -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::character::oct_digit0; -/// fn parser(input: &str) -> IResult<&str, &str> { -/// oct_digit0(input) -/// } -/// -/// assert_eq!(parser("21cZ"), Ok(("cZ", "21"))); -/// assert_eq!(parser("Z21c"), Ok(("Z21c", ""))); -/// assert_eq!(parser(""), Ok(("", ""))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::oct_digit0; -/// assert_eq!(oct_digit0::<_, Error<_>>(Partial::new("21cZ")), Ok((Partial::new("cZ"), "21"))); -/// assert_eq!(oct_digit0::<_, Error<_>>(Partial::new("Z21c")), Ok((Partial::new("Z21c"), ""))); -/// assert_eq!(oct_digit0::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn oct_digit0>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar, -{ - trace("oct_digit0", move |input: I| { - take_while0(|c: ::Token| c.is_oct_digit()).parse_next(input) - }) - .parse_next(input) -} - -/// Recognizes one or more octal characters: 0-7 -/// -/// *Complete version*: Will return an error if there's not enough input data, -/// or the whole input if no terminating token is found (a non octal digit character). -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, -/// or if no terminating token is found (a non octal digit character). -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; -/// # use winnow::character::oct_digit1; -/// fn parser(input: &str) -> IResult<&str, &str> { -/// oct_digit1(input) -/// } -/// -/// assert_eq!(parser("21cZ"), Ok(("cZ", "21"))); -/// assert_eq!(parser("H2"), Err(ErrMode::Backtrack(Error::new("H2", ErrorKind::Slice)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::oct_digit1; -/// assert_eq!(oct_digit1::<_, Error<_>>(Partial::new("21cZ")), Ok((Partial::new("cZ"), "21"))); -/// assert_eq!(oct_digit1::<_, Error<_>>(Partial::new("H2")), Err(ErrMode::Backtrack(Error::new(Partial::new("H2"), ErrorKind::Slice)))); -/// assert_eq!(oct_digit1::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn oct_digit1>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar, -{ - trace("oct_digit0", move |input: I| { - take_while1(|c: ::Token| c.is_oct_digit()).parse_next(input) - }) - .parse_next(input) -} - -/// Recognizes zero or more ASCII numerical and alphabetic characters: 0-9, a-z, A-Z -/// -/// *Complete version*: Will return the whole input if no terminating token is found (a non -/// alphanumerical character). -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, -/// or if no terminating token is found (a non alphanumerical character). -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::character::alphanumeric0; -/// fn parser(input: &str) -> IResult<&str, &str> { -/// alphanumeric0(input) -/// } -/// -/// assert_eq!(parser("21cZ%1"), Ok(("%1", "21cZ"))); -/// assert_eq!(parser("&Z21c"), Ok(("&Z21c", ""))); -/// assert_eq!(parser(""), Ok(("", ""))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::alphanumeric0; -/// assert_eq!(alphanumeric0::<_, Error<_>>(Partial::new("21cZ%1")), Ok((Partial::new("%1"), "21cZ"))); -/// assert_eq!(alphanumeric0::<_, Error<_>>(Partial::new("&Z21c")), Ok((Partial::new("&Z21c"), ""))); -/// assert_eq!(alphanumeric0::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn alphanumeric0>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar, -{ - trace("alphanumeric0", move |input: I| { - take_while0(|c: ::Token| c.is_alphanum()).parse_next(input) - }) - .parse_next(input) -} - -/// Recognizes one or more ASCII numerical and alphabetic characters: 0-9, a-z, A-Z -/// -/// *Complete version*: Will return an error if there's not enough input data, -/// or the whole input if no terminating token is found (a non alphanumerical character). -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, -/// or if no terminating token is found (a non alphanumerical character). -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; -/// # use winnow::character::alphanumeric1; -/// fn parser(input: &str) -> IResult<&str, &str> { -/// alphanumeric1(input) -/// } -/// -/// assert_eq!(parser("21cZ%1"), Ok(("%1", "21cZ"))); -/// assert_eq!(parser("&H2"), Err(ErrMode::Backtrack(Error::new("&H2", ErrorKind::Slice)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::alphanumeric1; -/// assert_eq!(alphanumeric1::<_, Error<_>>(Partial::new("21cZ%1")), Ok((Partial::new("%1"), "21cZ"))); -/// assert_eq!(alphanumeric1::<_, Error<_>>(Partial::new("&H2")), Err(ErrMode::Backtrack(Error::new(Partial::new("&H2"), ErrorKind::Slice)))); -/// assert_eq!(alphanumeric1::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn alphanumeric1>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar, -{ - trace("alphanumeric1", move |input: I| { - take_while1(|c: ::Token| c.is_alphanum()).parse_next(input) - }) - .parse_next(input) -} - -/// Recognizes zero or more spaces and tabs. -/// -/// *Complete version*: Will return the whole input if no terminating token is found (a non space -/// character). -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, -/// or if no terminating token is found (a non space character). -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::space0; -/// assert_eq!(space0::<_, Error<_>>(Partial::new(" \t21c")), Ok((Partial::new("21c"), " \t"))); -/// assert_eq!(space0::<_, Error<_>>(Partial::new("Z21c")), Ok((Partial::new("Z21c"), ""))); -/// assert_eq!(space0::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn space0>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar + Copy, -{ - trace("space0", move |input: I| { - take_while0(|c: ::Token| { - let ch = c.as_char(); - matches!(ch, ' ' | '\t') - }) - .parse_next(input) - }) - .parse_next(input) -} - -/// Recognizes one or more spaces and tabs. -/// -/// *Complete version*: Will return an error if there's not enough input data, -/// or the whole input if no terminating token is found (a non space character). -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, -/// or if no terminating token is found (a non space character). -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; -/// # use winnow::character::space1; -/// fn parser(input: &str) -> IResult<&str, &str> { -/// space1(input) -/// } -/// -/// assert_eq!(parser(" \t21c"), Ok(("21c", " \t"))); -/// assert_eq!(parser("H2"), Err(ErrMode::Backtrack(Error::new("H2", ErrorKind::Slice)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::space1; -/// assert_eq!(space1::<_, Error<_>>(Partial::new(" \t21c")), Ok((Partial::new("21c"), " \t"))); -/// assert_eq!(space1::<_, Error<_>>(Partial::new("H2")), Err(ErrMode::Backtrack(Error::new(Partial::new("H2"), ErrorKind::Slice)))); -/// assert_eq!(space1::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn space1>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar + Copy, -{ - trace("space1", move |input: I| { - take_while1(|c: ::Token| { - let ch = c.as_char(); - matches!(ch, ' ' | '\t') - }) - .parse_next(input) - }) - .parse_next(input) -} - -/// Recognizes zero or more spaces, tabs, carriage returns and line feeds. -/// -/// *Complete version*: will return the whole input if no terminating token is found (a non space -/// character). -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, -/// or if no terminating token is found (a non space character). -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::character::multispace0; -/// fn parser(input: &str) -> IResult<&str, &str> { -/// multispace0(input) -/// } -/// -/// assert_eq!(parser(" \t\n\r21c"), Ok(("21c", " \t\n\r"))); -/// assert_eq!(parser("Z21c"), Ok(("Z21c", ""))); -/// assert_eq!(parser(""), Ok(("", ""))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::multispace0; -/// assert_eq!(multispace0::<_, Error<_>>(Partial::new(" \t\n\r21c")), Ok((Partial::new("21c"), " \t\n\r"))); -/// assert_eq!(multispace0::<_, Error<_>>(Partial::new("Z21c")), Ok((Partial::new("Z21c"), ""))); -/// assert_eq!(multispace0::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn multispace0>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar + Copy, -{ - trace("multispace0", move |input: I| { - take_while0(|c: ::Token| { - let ch = c.as_char(); - matches!(ch, ' ' | '\t' | '\r' | '\n') - }) - .parse_next(input) - }) - .parse_next(input) -} - -/// Recognizes one or more spaces, tabs, carriage returns and line feeds. -/// -/// *Complete version*: will return an error if there's not enough input data, -/// or the whole input if no terminating token is found (a non space character). -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data, -/// or if no terminating token is found (a non space character). -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, IResult, error::Needed}; -/// # use winnow::character::multispace1; -/// fn parser(input: &str) -> IResult<&str, &str> { -/// multispace1(input) -/// } -/// -/// assert_eq!(parser(" \t\n\r21c"), Ok(("21c", " \t\n\r"))); -/// assert_eq!(parser("H2"), Err(ErrMode::Backtrack(Error::new("H2", ErrorKind::Slice)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); -/// ``` -/// -/// ``` -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, error::Needed}; -/// # use winnow::Partial; -/// # use winnow::character::multispace1; -/// assert_eq!(multispace1::<_, Error<_>>(Partial::new(" \t\n\r21c")), Ok((Partial::new("21c"), " \t\n\r"))); -/// assert_eq!(multispace1::<_, Error<_>>(Partial::new("H2")), Err(ErrMode::Backtrack(Error::new(Partial::new("H2"), ErrorKind::Slice)))); -/// assert_eq!(multispace1::<_, Error<_>>(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn multispace1>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar + Copy, -{ - trace("multispace1", move |input: I| { - take_while1(|c: ::Token| { - let ch = c.as_char(); - matches!(ch, ' ' | '\t' | '\r' | '\n') - }) - .parse_next(input) - }) - .parse_next(input) -} - -/// Decode a decimal unsigned integer -/// -/// *Complete version*: can parse until the end of input. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. -#[doc(alias = "u8")] -#[doc(alias = "u16")] -#[doc(alias = "u32")] -#[doc(alias = "u64")] -#[doc(alias = "u128")] -pub fn dec_uint>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar + Copy, - O: Uint, -{ - trace("dec_uint", move |input: I| { - if input.eof_offset() == 0 { - if input.is_partial() { - return Err(ErrMode::Incomplete(Needed::new(1))); - } else { - return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); - } - } - - let mut value = O::default(); - for (offset, c) in input.iter_offsets() { - match c.as_char().to_digit(10) { - Some(d) => match value.checked_mul(10, sealed::SealedMarker).and_then(|v| { - let d = d as u8; - v.checked_add(d, sealed::SealedMarker) - }) { - None => return Err(ErrMode::from_error_kind(input, ErrorKind::Verify)), - Some(v) => value = v, - }, - None => { - if offset == 0 { - return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); - } else { - return Ok((input.next_slice(offset).0, value)); - } - } - } - } - - if input.is_partial() { - Err(ErrMode::Incomplete(Needed::new(1))) - } else { - Ok((input.next_slice(input.eof_offset()).0, value)) - } - }) - .parse_next(input) -} - -/// Metadata for parsing unsigned integers, see [`dec_uint`] -pub trait Uint: Default { - #[doc(hidden)] - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option; - #[doc(hidden)] - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option; -} - -impl Uint for u8 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) - } -} - -impl Uint for u16 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) - } -} - -impl Uint for u32 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) - } -} - -impl Uint for u64 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) - } -} - -impl Uint for u128 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) - } -} - -impl Uint for i8 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) - } -} - -impl Uint for i16 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) - } -} - -impl Uint for i32 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) - } -} - -impl Uint for i64 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) - } -} - -impl Uint for i128 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) - } -} - -/// Decode a decimal signed integer -/// -/// *Complete version*: can parse until the end of input. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. -#[doc(alias = "i8")] -#[doc(alias = "i16")] -#[doc(alias = "i32")] -#[doc(alias = "i64")] -#[doc(alias = "i128")] -pub fn dec_int>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Token: AsChar + Copy, - O: Int, -{ - trace("dec_int", move |input: I| { - fn sign(token: impl AsChar) -> bool { - let token = token.as_char(); - token == '+' || token == '-' - } - let (input, sign) = opt(crate::bytes::one_of(sign).map(AsChar::as_char)) - .map(|c| c != Some('-')) - .parse_next(input)?; - - if input.eof_offset() == 0 { - if input.is_partial() { - return Err(ErrMode::Incomplete(Needed::new(1))); - } else { - return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); - } - } - - let mut value = O::default(); - for (offset, c) in input.iter_offsets() { - match c.as_char().to_digit(10) { - Some(d) => match value.checked_mul(10, sealed::SealedMarker).and_then(|v| { - let d = d as u8; - if sign { - v.checked_add(d, sealed::SealedMarker) - } else { - v.checked_sub(d, sealed::SealedMarker) - } - }) { - None => return Err(ErrMode::from_error_kind(input, ErrorKind::Verify)), - Some(v) => value = v, - }, - None => { - if offset == 0 { - return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); - } else { - return Ok((input.next_slice(offset).0, value)); - } - } - } - } - - if input.is_partial() { - Err(ErrMode::Incomplete(Needed::new(1))) - } else { - Ok((input.next_slice(input.eof_offset()).0, value)) - } - }) - .parse_next(input) -} - -/// Metadata for parsing signed integers, see [`dec_int`] -pub trait Int: Uint { - #[doc(hidden)] - fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option; -} - -impl Int for i8 { - fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_sub(by as Self) - } -} - -impl Int for i16 { - fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_sub(by as Self) - } -} - -impl Int for i32 { - fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_sub(by as Self) - } -} - -impl Int for i64 { - fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_sub(by as Self) - } -} - -impl Int for i128 { - fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_sub(by as Self) - } -} - -/// Decode a variable-width hexadecimal integer. -/// -/// *Complete version*: Will parse until the end of input if it has fewer characters than the type -/// supports. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if end-of-input -/// is hit before a hard boundary (non-hex character, more characters than supported). -/// -/// # Example -/// -/// ```rust -/// # use winnow::prelude::*; -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error}; -/// use winnow::character::hex_uint; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], u32> { -/// hex_uint(s) -/// } -/// -/// assert_eq!(parser(&b"01AE"[..]), Ok((&b""[..], 0x01AE))); -/// assert_eq!(parser(&b"abc"[..]), Ok((&b""[..], 0x0ABC))); -/// assert_eq!(parser(&b"ggg"[..]), Err(ErrMode::Backtrack(Error::new(&b"ggg"[..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::prelude::*; -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::Partial; -/// use winnow::character::hex_uint; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, u32> { -/// hex_uint(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"01AE;"[..])), Ok((Partial::new(&b";"[..]), 0x01AE))); -/// assert_eq!(parser(Partial::new(&b"abc"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); -/// assert_eq!(parser(Partial::new(&b"ggg"[..])), Err(ErrMode::Backtrack(Error::new(Partial::new(&b"ggg"[..]), ErrorKind::Slice)))); -/// ``` -#[inline] -pub fn hex_uint>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - O: HexUint, - ::Token: AsChar, - ::Slice: AsBStr, -{ - trace("hex_uint", move |input: I| { - let invalid_offset = input - .offset_for(|c| { - let c = c.as_char(); - !"0123456789abcdefABCDEF".contains(c) - }) - .unwrap_or_else(|| input.eof_offset()); - let max_nibbles = O::max_nibbles(sealed::SealedMarker); - let max_offset = input.offset_at(max_nibbles); - let offset = match max_offset { - Ok(max_offset) => { - if max_offset < invalid_offset { - // Overflow - return Err(ErrMode::from_error_kind(input, ErrorKind::Verify)); - } else { - invalid_offset - } - } - Err(_) => { - if input.is_partial() && invalid_offset == input.eof_offset() { - // Only the next byte is guaranteed required - return Err(ErrMode::Incomplete(Needed::new(1))); - } else { - invalid_offset - } - } - }; - if offset == 0 { - // Must be at least one digit - return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); - } - let (remaining, parsed) = input.next_slice(offset); - - let mut res = O::default(); - for c in parsed.as_bstr() { - let nibble = *c as char; - let nibble = nibble.to_digit(16).unwrap_or(0) as u8; - let nibble = O::from(nibble); - res = (res << O::from(4)) + nibble; - } - - Ok((remaining, res)) - }) - .parse_next(input) -} - -/// Metadata for parsing hex numbers, see [`hex_uint`] -pub trait HexUint: - Default + Shl + Add + From -{ - #[doc(hidden)] - fn max_nibbles(_: sealed::SealedMarker) -> usize; -} - -impl HexUint for u8 { - #[inline(always)] - fn max_nibbles(_: sealed::SealedMarker) -> usize { - 2 - } -} - -impl HexUint for u16 { - #[inline(always)] - fn max_nibbles(_: sealed::SealedMarker) -> usize { - 4 - } -} - -impl HexUint for u32 { - #[inline(always)] - fn max_nibbles(_: sealed::SealedMarker) -> usize { - 8 - } -} - -impl HexUint for u64 { - #[inline(always)] - fn max_nibbles(_: sealed::SealedMarker) -> usize { - 16 - } -} - -impl HexUint for u128 { - #[inline(always)] - fn max_nibbles(_: sealed::SealedMarker) -> usize { - 32 - } -} - -/// Recognizes floating point number in text format and returns a f32 or f64. -/// -/// *Complete version*: Can parse until the end of input. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::prelude::*; -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::error::Needed::Size; -/// use winnow::character::float; -/// -/// fn parser(s: &str) -> IResult<&str, f64> { -/// float(s) -/// } -/// -/// assert_eq!(parser("11e-1"), Ok(("", 1.1))); -/// assert_eq!(parser("123E-02"), Ok(("", 1.23))); -/// assert_eq!(parser("123K-01"), Ok(("K-01", 123.0))); -/// assert_eq!(parser("abc"), Err(ErrMode::Backtrack(Error::new("abc", ErrorKind::Tag)))); -/// ``` -/// -/// ```rust -/// # use winnow::prelude::*; -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::error::Needed::Size; -/// # use winnow::Partial; -/// use winnow::character::float; -/// -/// fn parser(s: Partial<&str>) -> IResult, f64> { -/// float(s) -/// } -/// -/// assert_eq!(parser(Partial::new("11e-1 ")), Ok((Partial::new(" "), 1.1))); -/// assert_eq!(parser(Partial::new("11e-1")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// assert_eq!(parser(Partial::new("123E-02")), Err(ErrMode::Incomplete(Needed::new(1)))); -/// assert_eq!(parser(Partial::new("123K-01")), Ok((Partial::new("K-01"), 123.0))); -/// assert_eq!(parser(Partial::new("abc")), Err(ErrMode::Backtrack(Error::new(Partial::new("abc"), ErrorKind::Tag)))); -/// ``` -#[inline(always)] -#[doc(alias = "f32")] -#[doc(alias = "double")] -pub fn float>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - I: Offset + Compare<&'static str>, - ::Slice: ParseSlice, - ::Token: AsChar + Copy, - ::IterOffsets: Clone, - I: AsBStr, - &'static str: ContainsToken<::Token>, -{ - trace("float", move |input: I| { - let (i, s) = recognize_float_or_exceptions(input)?; - match s.parse_slice() { - Some(f) => Ok((i, f)), - None => Err(ErrMode::from_error_kind(i, ErrorKind::Verify)), - } - }) - .parse_next(input) -} - -fn recognize_float_or_exceptions>( - input: I, -) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - I: Offset + Compare<&'static str>, - ::Token: AsChar + Copy, - ::IterOffsets: Clone, - I: AsBStr, - &'static str: ContainsToken<::Token>, -{ - alt(( - recognize_float, - crate::bytes::tag_no_case("nan"), - crate::bytes::tag_no_case("inf"), - crate::bytes::tag_no_case("infinity"), - )) - .parse_next(input) -} - -fn recognize_float>(input: I) -> IResult::Slice, E> -where - I: StreamIsPartial, - I: Stream, - I: Offset + Compare<&'static str>, - ::Token: AsChar + Copy, - ::IterOffsets: Clone, - I: AsBStr, - &'static str: ContainsToken<::Token>, -{ - ( - opt(one_of("+-")), - alt(( - (digit1, opt(('.', opt(digit1)))).map(|_| ()), - ('.', digit1).map(|_| ()), - )), - opt((one_of("eE"), opt(one_of("+-")), cut_err(digit1))), - ) - .recognize() - .parse_next(input) -} - -/// Matches a byte string with escaped characters. -/// -/// * The first argument matches the normal characters (it must not accept the control character) -/// * The second argument is the control character (like `\` in most languages) -/// * The third argument matches the escaped characters -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed, IResult}; -/// # use winnow::character::digit1; -/// # use winnow::prelude::*; -/// use winnow::character::escaped; -/// use winnow::bytes::one_of; -/// -/// fn esc(s: &str) -> IResult<&str, &str> { -/// escaped(digit1, '\\', one_of(r#""n\"#)).parse_next(s) -/// } -/// -/// assert_eq!(esc("123;"), Ok((";", "123"))); -/// assert_eq!(esc(r#"12\"34;"#), Ok((";", r#"12\"34"#))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed, IResult}; -/// # use winnow::character::digit1; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::character::escaped; -/// use winnow::bytes::one_of; -/// -/// fn esc(s: Partial<&str>) -> IResult, &str> { -/// escaped(digit1, '\\', one_of("\"n\\")).parse_next(s) -/// } -/// -/// assert_eq!(esc(Partial::new("123;")), Ok((Partial::new(";"), "123"))); -/// assert_eq!(esc(Partial::new("12\\\"34;")), Ok((Partial::new(";"), "12\\\"34"))); -/// ``` -#[inline(always)] -pub fn escaped<'a, I: 'a, Error, F, G, O1, O2>( - mut normal: F, - control_char: char, - mut escapable: G, -) -> impl Parser::Slice, Error> -where - I: StreamIsPartial, - I: Stream + Offset, - ::Token: crate::stream::AsChar, - F: Parser, - G: Parser, - Error: ParseError, -{ - trace("escaped", move |input: I| { - if input.is_partial() { - streaming_escaped_internal(input, &mut normal, control_char, &mut escapable) - } else { - complete_escaped_internal(input, &mut normal, control_char, &mut escapable) - } - }) -} - -pub(crate) fn streaming_escaped_internal( - input: I, - normal: &mut F, - control_char: char, - escapable: &mut G, -) -> IResult::Slice, Error> -where - I: Stream + Offset, - ::Token: crate::stream::AsChar, - F: Parser, - G: Parser, - Error: ParseError, -{ - let mut i = input.clone(); - - while i.eof_offset() > 0 { - let current_len = i.eof_offset(); - - match normal.parse_next(i.clone()) { - Ok((i2, _)) => { - if i2.eof_offset() == 0 { - return Err(ErrMode::Incomplete(Needed::Unknown)); - } else if i2.eof_offset() == current_len { - let offset = input.offset_to(&i2); - return Ok(input.next_slice(offset)); - } else { - i = i2; - } - } - Err(ErrMode::Backtrack(_)) => { - if i.next_token().expect("eof_offset > 0").1.as_char() == control_char { - let next = control_char.len_utf8(); - match escapable.parse_next(i.next_slice(next).0) { - Ok((i2, _)) => { - if i2.eof_offset() == 0 { - return Err(ErrMode::Incomplete(Needed::Unknown)); - } else { - i = i2; - } - } - Err(e) => return Err(e), - } - } else { - let offset = input.offset_to(&i); - return Ok(input.next_slice(offset)); - } - } - Err(e) => { - return Err(e); - } - } - } - - Err(ErrMode::Incomplete(Needed::Unknown)) -} - -pub(crate) fn complete_escaped_internal<'a, I: 'a, Error, F, G, O1, O2>( - input: I, - normal: &mut F, - control_char: char, - escapable: &mut G, -) -> IResult::Slice, Error> -where - I: Stream + Offset, - ::Token: crate::stream::AsChar, - F: Parser, - G: Parser, - Error: ParseError, -{ - let mut i = input.clone(); - - while i.eof_offset() > 0 { - let current_len = i.eof_offset(); - - match normal.parse_next(i.clone()) { - Ok((i2, _)) => { - // return if we consumed everything or if the normal parser - // does not consume anything - if i2.eof_offset() == 0 { - return Ok(input.next_slice(input.eof_offset())); - } else if i2.eof_offset() == current_len { - let offset = input.offset_to(&i2); - return Ok(input.next_slice(offset)); - } else { - i = i2; - } - } - Err(ErrMode::Backtrack(_)) => { - if i.next_token().expect("eof_offset > 0").1.as_char() == control_char { - let next = control_char.len_utf8(); - match escapable.parse_next(i.next_slice(next).0) { - Ok((i2, _)) => { - if i2.eof_offset() == 0 { - return Ok(input.next_slice(input.eof_offset())); - } else { - i = i2; - } - } - Err(e) => return Err(e), - } - } else { - let offset = input.offset_to(&i); - return Ok(input.next_slice(offset)); - } - } - Err(e) => { - return Err(e); - } - } - } - - Ok(input.next_slice(input.eof_offset())) -} - -/// Matches a byte string with escaped characters. -/// -/// * The first argument matches the normal characters (it must not match the control character) -/// * The second argument is the control character (like `\` in most languages) -/// * The third argument matches the escaped characters and transforms them -/// -/// As an example, the chain `abc\tdef` could be `abc def` (it also consumes the control character) -/// -/// # Example -/// -/// ```rust -/// # use winnow::prelude::*; -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use std::str::from_utf8; -/// use winnow::bytes::tag; -/// use winnow::character::escaped_transform; -/// use winnow::character::alpha1; -/// use winnow::branch::alt; -/// -/// fn parser(input: &str) -> IResult<&str, String> { -/// escaped_transform( -/// alpha1, -/// '\\', -/// alt(( -/// "\\".value("\\"), -/// "\"".value("\""), -/// "n".value("\n"), -/// )) -/// ).parse_next(input) -/// } -/// -/// assert_eq!(parser("ab\\\"cd"), Ok(("", String::from("ab\"cd")))); -/// assert_eq!(parser("ab\\ncd"), Ok(("", String::from("ab\ncd")))); -/// ``` -/// -/// ``` -/// # use winnow::prelude::*; -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use std::str::from_utf8; -/// # use winnow::Partial; -/// use winnow::bytes::tag; -/// use winnow::character::escaped_transform; -/// use winnow::character::alpha1; -/// use winnow::branch::alt; -/// -/// fn parser(input: Partial<&str>) -> IResult, String> { -/// escaped_transform( -/// alpha1, -/// '\\', -/// alt(( -/// "\\".value("\\"), -/// "\"".value("\""), -/// "n".value("\n"), -/// )) -/// ).parse_next(input) -/// } -/// -/// assert_eq!(parser(Partial::new("ab\\\"cd\"")), Ok((Partial::new("\""), String::from("ab\"cd")))); -/// ``` -#[cfg(feature = "alloc")] -#[inline(always)] -pub fn escaped_transform( - mut normal: F, - control_char: char, - mut transform: G, -) -> impl Parser -where - I: StreamIsPartial, - I: Stream + Offset, - ::Token: crate::stream::AsChar, - Output: crate::stream::Accumulate<::Slice>, - F: Parser::Slice, Error>, - G: Parser::Slice, Error>, - Error: ParseError, -{ - trace("escaped_transform", move |input: I| { - if input.is_partial() { - streaming_escaped_transform_internal(input, &mut normal, control_char, &mut transform) - } else { - complete_escaped_transform_internal(input, &mut normal, control_char, &mut transform) - } - }) -} - -#[cfg(feature = "alloc")] -pub(crate) fn streaming_escaped_transform_internal( - input: I, - normal: &mut F, - control_char: char, - transform: &mut G, -) -> IResult -where - I: Stream + Offset, - ::Token: crate::stream::AsChar, - Output: crate::stream::Accumulate<::Slice>, - F: Parser::Slice, Error>, - G: Parser::Slice, Error>, - Error: ParseError, -{ - let mut offset = 0; - let mut res = Output::initial(Some(input.eof_offset())); - - let i = input.clone(); - - while offset < i.eof_offset() { - let current_len = i.eof_offset(); - let remainder = i.next_slice(offset).0; - match normal.parse_next(remainder.clone()) { - Ok((i2, o)) => { - res.accumulate(o); - if i2.eof_offset() == 0 { - return Err(ErrMode::Incomplete(Needed::Unknown)); - } else if i2.eof_offset() == current_len { - return Ok((remainder, res)); - } else { - offset = input.offset_to(&i2); - } - } - Err(ErrMode::Backtrack(_)) => { - if remainder.next_token().expect("eof_offset > 0").1.as_char() == control_char { - let next = offset + control_char.len_utf8(); - match transform.parse_next(i.next_slice(next).0) { - Ok((i2, o)) => { - res.accumulate(o); - if i2.eof_offset() == 0 { - return Err(ErrMode::Incomplete(Needed::Unknown)); - } else { - offset = input.offset_to(&i2); - } - } - Err(e) => return Err(e), - } - } else { - return Ok((remainder, res)); - } - } - Err(e) => return Err(e), - } - } - Err(ErrMode::Incomplete(Needed::Unknown)) -} - -#[cfg(feature = "alloc")] -pub(crate) fn complete_escaped_transform_internal( - input: I, - normal: &mut F, - control_char: char, - transform: &mut G, -) -> IResult -where - I: Stream + Offset, - ::Token: crate::stream::AsChar, - Output: crate::stream::Accumulate<::Slice>, - F: Parser::Slice, Error>, - G: Parser::Slice, Error>, - Error: ParseError, -{ - let mut offset = 0; - let mut res = Output::initial(Some(input.eof_offset())); - - let i = input.clone(); - - while offset < i.eof_offset() { - let current_len = i.eof_offset(); - let (remainder, _) = i.next_slice(offset); - match normal.parse_next(remainder.clone()) { - Ok((i2, o)) => { - res.accumulate(o); - if i2.eof_offset() == 0 { - return Ok((i.next_slice(i.eof_offset()).0, res)); - } else if i2.eof_offset() == current_len { - return Ok((remainder, res)); - } else { - offset = input.offset_to(&i2); - } - } - Err(ErrMode::Backtrack(_)) => { - if remainder.next_token().expect("eof_offset > 0").1.as_char() == control_char { - let next = offset + control_char.len_utf8(); - match transform.parse_next(i.next_slice(next).0) { - Ok((i2, o)) => { - res.accumulate(o); - if i2.eof_offset() == 0 { - return Ok((i.next_slice(i.eof_offset()).0, res)); - } else { - offset = input.offset_to(&i2); - } - } - Err(e) => return Err(e), - } - } else { - return Ok((remainder, res)); - } - } - Err(e) => return Err(e), - } - } - Ok((input.next_slice(offset).0, res)) -} - -mod sealed { - pub struct SealedMarker; -} diff --git a/vendor/winnow/src/character/tests.rs b/vendor/winnow/src/character/tests.rs deleted file mode 100644 index 95a63c303..000000000 --- a/vendor/winnow/src/character/tests.rs +++ /dev/null @@ -1,1496 +0,0 @@ -use super::*; - -mod complete { - use super::*; - use crate::branch::alt; - use crate::bytes::none_of; - use crate::bytes::one_of; - use crate::combinator::opt; - use crate::error::ErrMode; - use crate::error::Error; - use crate::error::ErrorKind; - use crate::stream::ParseSlice; - #[cfg(feature = "alloc")] - use crate::{lib::std::string::String, lib::std::vec::Vec}; - use proptest::prelude::*; - - macro_rules! assert_parse( - ($left: expr, $right: expr) => { - let res: $crate::IResult<_, _, Error<_>> = $left; - assert_eq!(res, $right); - }; - ); - - #[test] - fn character() { - let empty: &[u8] = b""; - let a: &[u8] = b"abcd"; - let b: &[u8] = b"1234"; - let c: &[u8] = b"a123"; - let d: &[u8] = "azé12".as_bytes(); - let e: &[u8] = b" "; - let f: &[u8] = b" ;"; - //assert_eq!(alpha1::<_, Error>(a), Err(ErrMode::Incomplete(Needed::Size(1)))); - assert_parse!(alpha1(a), Ok((empty, a))); - assert_eq!( - alpha1(b), - Err(ErrMode::Backtrack(Error::new(b, ErrorKind::Slice))) - ); - assert_eq!(alpha1::<_, Error<_>>(c), Ok((&c[1..], &b"a"[..]))); - assert_eq!(alpha1::<_, Error<_>>(d), Ok(("é12".as_bytes(), &b"az"[..]))); - assert_eq!( - digit1(a), - Err(ErrMode::Backtrack(Error::new(a, ErrorKind::Slice))) - ); - assert_eq!(digit1::<_, Error<_>>(b), Ok((empty, b))); - assert_eq!( - digit1(c), - Err(ErrMode::Backtrack(Error::new(c, ErrorKind::Slice))) - ); - assert_eq!( - digit1(d), - Err(ErrMode::Backtrack(Error::new(d, ErrorKind::Slice))) - ); - assert_eq!(hex_digit1::<_, Error<_>>(a), Ok((empty, a))); - assert_eq!(hex_digit1::<_, Error<_>>(b), Ok((empty, b))); - assert_eq!(hex_digit1::<_, Error<_>>(c), Ok((empty, c))); - assert_eq!( - hex_digit1::<_, Error<_>>(d), - Ok(("zé12".as_bytes(), &b"a"[..])) - ); - assert_eq!( - hex_digit1(e), - Err(ErrMode::Backtrack(Error::new(e, ErrorKind::Slice))) - ); - assert_eq!( - oct_digit1(a), - Err(ErrMode::Backtrack(Error::new(a, ErrorKind::Slice))) - ); - assert_eq!(oct_digit1::<_, Error<_>>(b), Ok((empty, b))); - assert_eq!( - oct_digit1(c), - Err(ErrMode::Backtrack(Error::new(c, ErrorKind::Slice))) - ); - assert_eq!( - oct_digit1(d), - Err(ErrMode::Backtrack(Error::new(d, ErrorKind::Slice))) - ); - assert_eq!(alphanumeric1::<_, Error<_>>(a), Ok((empty, a))); - //assert_eq!(fix_error!(b,(), alphanumeric), Ok((empty, b))); - assert_eq!(alphanumeric1::<_, Error<_>>(c), Ok((empty, c))); - assert_eq!( - alphanumeric1::<_, Error<_>>(d), - Ok(("é12".as_bytes(), &b"az"[..])) - ); - assert_eq!(space1::<_, Error<_>>(e), Ok((empty, e))); - assert_eq!(space1::<_, Error<_>>(f), Ok((&b";"[..], &b" "[..]))); - } - - #[cfg(feature = "alloc")] - #[test] - fn character_s() { - let empty = ""; - let a = "abcd"; - let b = "1234"; - let c = "a123"; - let d = "azé12"; - let e = " "; - assert_eq!(alpha1::<_, Error<_>>(a), Ok((empty, a))); - assert_eq!( - alpha1(b), - Err(ErrMode::Backtrack(Error::new(b, ErrorKind::Slice))) - ); - assert_eq!(alpha1::<_, Error<_>>(c), Ok((&c[1..], "a"))); - assert_eq!(alpha1::<_, Error<_>>(d), Ok(("é12", "az"))); - assert_eq!( - digit1(a), - Err(ErrMode::Backtrack(Error::new(a, ErrorKind::Slice))) - ); - assert_eq!(digit1::<_, Error<_>>(b), Ok((empty, b))); - assert_eq!( - digit1(c), - Err(ErrMode::Backtrack(Error::new(c, ErrorKind::Slice))) - ); - assert_eq!( - digit1(d), - Err(ErrMode::Backtrack(Error::new(d, ErrorKind::Slice))) - ); - assert_eq!(hex_digit1::<_, Error<_>>(a), Ok((empty, a))); - assert_eq!(hex_digit1::<_, Error<_>>(b), Ok((empty, b))); - assert_eq!(hex_digit1::<_, Error<_>>(c), Ok((empty, c))); - assert_eq!(hex_digit1::<_, Error<_>>(d), Ok(("zé12", "a"))); - assert_eq!( - hex_digit1(e), - Err(ErrMode::Backtrack(Error::new(e, ErrorKind::Slice))) - ); - assert_eq!( - oct_digit1(a), - Err(ErrMode::Backtrack(Error::new(a, ErrorKind::Slice))) - ); - assert_eq!(oct_digit1::<_, Error<_>>(b), Ok((empty, b))); - assert_eq!( - oct_digit1(c), - Err(ErrMode::Backtrack(Error::new(c, ErrorKind::Slice))) - ); - assert_eq!( - oct_digit1(d), - Err(ErrMode::Backtrack(Error::new(d, ErrorKind::Slice))) - ); - assert_eq!(alphanumeric1::<_, Error<_>>(a), Ok((empty, a))); - //assert_eq!(fix_error!(b,(), alphanumeric), Ok((empty, b))); - assert_eq!(alphanumeric1::<_, Error<_>>(c), Ok((empty, c))); - assert_eq!(alphanumeric1::<_, Error<_>>(d), Ok(("é12", "az"))); - assert_eq!(space1::<_, Error<_>>(e), Ok((empty, e))); - } - - use crate::stream::Offset; - #[test] - fn offset() { - let a = &b"abcd;"[..]; - let b = &b"1234;"[..]; - let c = &b"a123;"[..]; - let d = &b" \t;"[..]; - let e = &b" \t\r\n;"[..]; - let f = &b"123abcDEF;"[..]; - - match alpha1::<_, Error<_>>(a) { - Ok((i, _)) => { - assert_eq!(a.offset_to(i) + i.len(), a.len()); - } - _ => panic!("wrong return type in offset test for alpha"), - } - match digit1::<_, Error<_>>(b) { - Ok((i, _)) => { - assert_eq!(b.offset_to(i) + i.len(), b.len()); - } - _ => panic!("wrong return type in offset test for digit"), - } - match alphanumeric1::<_, Error<_>>(c) { - Ok((i, _)) => { - assert_eq!(c.offset_to(i) + i.len(), c.len()); - } - _ => panic!("wrong return type in offset test for alphanumeric"), - } - match space1::<_, Error<_>>(d) { - Ok((i, _)) => { - assert_eq!(d.offset_to(i) + i.len(), d.len()); - } - _ => panic!("wrong return type in offset test for space"), - } - match multispace1::<_, Error<_>>(e) { - Ok((i, _)) => { - assert_eq!(e.offset_to(i) + i.len(), e.len()); - } - _ => panic!("wrong return type in offset test for multispace"), - } - match hex_digit1::<_, Error<_>>(f) { - Ok((i, _)) => { - assert_eq!(f.offset_to(i) + i.len(), f.len()); - } - _ => panic!("wrong return type in offset test for hex_digit"), - } - match oct_digit1::<_, Error<_>>(f) { - Ok((i, _)) => { - assert_eq!(f.offset_to(i) + i.len(), f.len()); - } - _ => panic!("wrong return type in offset test for oct_digit"), - } - } - - #[test] - fn is_not_line_ending_bytes() { - let a: &[u8] = b"ab12cd\nefgh"; - assert_eq!( - not_line_ending::<_, Error<_>>(a), - Ok((&b"\nefgh"[..], &b"ab12cd"[..])) - ); - - let b: &[u8] = b"ab12cd\nefgh\nijkl"; - assert_eq!( - not_line_ending::<_, Error<_>>(b), - Ok((&b"\nefgh\nijkl"[..], &b"ab12cd"[..])) - ); - - let c: &[u8] = b"ab12cd\r\nefgh\nijkl"; - assert_eq!( - not_line_ending::<_, Error<_>>(c), - Ok((&b"\r\nefgh\nijkl"[..], &b"ab12cd"[..])) - ); - - let d: &[u8] = b"ab12cd"; - assert_eq!(not_line_ending::<_, Error<_>>(d), Ok((&[][..], d))); - } - - #[test] - fn is_not_line_ending_str() { - let f = "βèƒôřè\rÂßÇáƒƭèř"; - assert_eq!( - not_line_ending(f), - Err(ErrMode::Backtrack(Error::new(f, ErrorKind::Tag))) - ); - - let g2: &str = "ab12cd"; - assert_eq!(not_line_ending::<_, Error<_>>(g2), Ok(("", g2))); - } - - #[test] - fn hex_digit_test() { - let i = &b"0123456789abcdefABCDEF;"[..]; - assert_parse!(hex_digit1(i), Ok((&b";"[..], &i[..i.len() - 1]))); - - let i = &b"g"[..]; - assert_parse!( - hex_digit1(i), - Err(ErrMode::Backtrack(error_position!(i, ErrorKind::Slice))) - ); - - let i = &b"G"[..]; - assert_parse!( - hex_digit1(i), - Err(ErrMode::Backtrack(error_position!(i, ErrorKind::Slice))) - ); - - assert!(AsChar::is_hex_digit(b'0')); - assert!(AsChar::is_hex_digit(b'9')); - assert!(AsChar::is_hex_digit(b'a')); - assert!(AsChar::is_hex_digit(b'f')); - assert!(AsChar::is_hex_digit(b'A')); - assert!(AsChar::is_hex_digit(b'F')); - assert!(!AsChar::is_hex_digit(b'g')); - assert!(!AsChar::is_hex_digit(b'G')); - assert!(!AsChar::is_hex_digit(b'/')); - assert!(!AsChar::is_hex_digit(b':')); - assert!(!AsChar::is_hex_digit(b'@')); - assert!(!AsChar::is_hex_digit(b'\x60')); - } - - #[test] - fn oct_digit_test() { - let i = &b"01234567;"[..]; - assert_parse!(oct_digit1(i), Ok((&b";"[..], &i[..i.len() - 1]))); - - let i = &b"8"[..]; - assert_parse!( - oct_digit1(i), - Err(ErrMode::Backtrack(error_position!(i, ErrorKind::Slice))) - ); - - assert!(AsChar::is_oct_digit(b'0')); - assert!(AsChar::is_oct_digit(b'7')); - assert!(!AsChar::is_oct_digit(b'8')); - assert!(!AsChar::is_oct_digit(b'9')); - assert!(!AsChar::is_oct_digit(b'a')); - assert!(!AsChar::is_oct_digit(b'A')); - assert!(!AsChar::is_oct_digit(b'/')); - assert!(!AsChar::is_oct_digit(b':')); - assert!(!AsChar::is_oct_digit(b'@')); - assert!(!AsChar::is_oct_digit(b'\x60')); - } - - #[test] - fn full_line_windows() { - fn take_full_line(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> { - (not_line_ending, line_ending).parse_next(i) - } - let input = b"abc\r\n"; - let output = take_full_line(input); - assert_eq!(output, Ok((&b""[..], (&b"abc"[..], &b"\r\n"[..])))); - } - - #[test] - fn full_line_unix() { - fn take_full_line(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> { - (not_line_ending, line_ending).parse_next(i) - } - let input = b"abc\n"; - let output = take_full_line(input); - assert_eq!(output, Ok((&b""[..], (&b"abc"[..], &b"\n"[..])))); - } - - #[test] - fn check_windows_lineending() { - let input = b"\r\n"; - let output = line_ending(&input[..]); - assert_parse!(output, Ok((&b""[..], &b"\r\n"[..]))); - } - - #[test] - fn check_unix_lineending() { - let input = b"\n"; - let output = line_ending(&input[..]); - assert_parse!(output, Ok((&b""[..], &b"\n"[..]))); - } - - #[test] - fn cr_lf() { - assert_parse!(crlf(&b"\r\na"[..]), Ok((&b"a"[..], &b"\r\n"[..]))); - assert_parse!( - crlf(&b"\r"[..]), - Err(ErrMode::Backtrack(error_position!( - &b"\r"[..], - ErrorKind::Tag - ))) - ); - assert_parse!( - crlf(&b"\ra"[..]), - Err(ErrMode::Backtrack(error_position!( - &b"\ra"[..], - ErrorKind::Tag - ))) - ); - - assert_parse!(crlf("\r\na"), Ok(("a", "\r\n"))); - assert_parse!( - crlf("\r"), - Err(ErrMode::Backtrack(error_position!("\r", ErrorKind::Tag))) - ); - assert_parse!( - crlf("\ra"), - Err(ErrMode::Backtrack(error_position!("\ra", ErrorKind::Tag))) - ); - } - - #[test] - fn end_of_line() { - assert_parse!(line_ending(&b"\na"[..]), Ok((&b"a"[..], &b"\n"[..]))); - assert_parse!(line_ending(&b"\r\na"[..]), Ok((&b"a"[..], &b"\r\n"[..]))); - assert_parse!( - line_ending(&b"\r"[..]), - Err(ErrMode::Backtrack(error_position!( - &b"\r"[..], - ErrorKind::Tag - ))) - ); - assert_parse!( - line_ending(&b"\ra"[..]), - Err(ErrMode::Backtrack(error_position!( - &b"\ra"[..], - ErrorKind::Tag - ))) - ); - - assert_parse!(line_ending("\na"), Ok(("a", "\n"))); - assert_parse!(line_ending("\r\na"), Ok(("a", "\r\n"))); - assert_parse!( - line_ending("\r"), - Err(ErrMode::Backtrack(error_position!("\r", ErrorKind::Tag))) - ); - assert_parse!( - line_ending("\ra"), - Err(ErrMode::Backtrack(error_position!("\ra", ErrorKind::Tag))) - ); - } - - fn digit_to_i16(input: &str) -> IResult<&str, i16> { - let i = input; - let (i, opt_sign) = opt(alt(('+', '-'))).parse_next(i)?; - let sign = match opt_sign { - Some('+') | None => true, - Some('-') => false, - _ => unreachable!(), - }; - - let (i, s) = digit1::<_, crate::error::Error<_>>(i)?; - match s.parse_slice() { - Some(n) => { - if sign { - Ok((i, n)) - } else { - Ok((i, -n)) - } - } - None => Err(ErrMode::from_error_kind(i, ErrorKind::Verify)), - } - } - - fn digit_to_u32(i: &str) -> IResult<&str, u32> { - let (i, s) = digit1(i)?; - match s.parse_slice() { - Some(n) => Ok((i, n)), - None => Err(ErrMode::from_error_kind(i, ErrorKind::Verify)), - } - } - - proptest! { - #[test] - #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 - fn ints(s in "\\PC*") { - let res1 = digit_to_i16(&s); - let res2 = dec_int(s.as_str()); - assert_eq!(res1, res2); - } - - #[test] - #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 - fn uints(s in "\\PC*") { - let res1 = digit_to_u32(&s); - let res2 = dec_uint(s.as_str()); - assert_eq!(res1, res2); - } - } - - #[test] - fn hex_uint_tests() { - fn hex_u32(input: &[u8]) -> IResult<&[u8], u32> { - hex_uint(input) - } - - assert_parse!( - hex_u32(&b";"[..]), - Err(ErrMode::Backtrack(error_position!( - &b";"[..], - ErrorKind::Slice - ))) - ); - assert_parse!(hex_u32(&b"ff;"[..]), Ok((&b";"[..], 255))); - assert_parse!(hex_u32(&b"1be2;"[..]), Ok((&b";"[..], 7138))); - assert_parse!(hex_u32(&b"c5a31be2;"[..]), Ok((&b";"[..], 3_315_801_058))); - assert_parse!(hex_u32(&b"C5A31be2;"[..]), Ok((&b";"[..], 3_315_801_058))); - assert_parse!( - hex_u32(&b"00c5a31be2;"[..]), // overflow - Err(ErrMode::Backtrack(error_position!( - &b"00c5a31be2;"[..], - ErrorKind::Verify - ))) - ); - assert_parse!( - hex_u32(&b"c5a31be201;"[..]), // overflow - Err(ErrMode::Backtrack(error_position!( - &b"c5a31be201;"[..], - ErrorKind::Verify - ))) - ); - assert_parse!(hex_u32(&b"ffffffff;"[..]), Ok((&b";"[..], 4_294_967_295))); - assert_parse!( - hex_u32(&b"ffffffffffffffff;"[..]), // overflow - Err(ErrMode::Backtrack(error_position!( - &b"ffffffffffffffff;"[..], - ErrorKind::Verify - ))) - ); - assert_parse!( - hex_u32(&b"ffffffffffffffff"[..]), // overflow - Err(ErrMode::Backtrack(error_position!( - &b"ffffffffffffffff"[..], - ErrorKind::Verify - ))) - ); - assert_parse!(hex_u32(&b"0x1be2;"[..]), Ok((&b"x1be2;"[..], 0))); - assert_parse!(hex_u32(&b"12af"[..]), Ok((&b""[..], 0x12af))); - } - - #[test] - #[cfg(feature = "std")] - fn float_test() { - let mut test_cases = vec![ - "+3.14", - "3.14", - "-3.14", - "0", - "0.0", - "1.", - ".789", - "-.5", - "1e7", - "-1E-7", - ".3e-2", - "1.e4", - "1.2e4", - "12.34", - "-1.234E-12", - "-1.234e-12", - "0.00000000000000000087", - ]; - - for test in test_cases.drain(..) { - let expected32 = str::parse::(test).unwrap(); - let expected64 = str::parse::(test).unwrap(); - - println!("now parsing: {} -> {}", test, expected32); - - let larger = test.to_string(); - - assert_parse!(float(larger.as_bytes()), Ok((&b""[..], expected32))); - assert_parse!(float(&larger[..]), Ok(("", expected32))); - - assert_parse!(float(larger.as_bytes()), Ok((&b""[..], expected64))); - assert_parse!(float(&larger[..]), Ok(("", expected64))); - } - - let remaining_exponent = "-1.234E-"; - assert_parse!( - float::<_, f64, _>(remaining_exponent), - Err(ErrMode::Cut(Error { - input: "", - kind: ErrorKind::Slice - })) - ); - - let (_i, nan) = float::<_, f32, ()>("NaN").unwrap(); - assert!(nan.is_nan()); - - let (_i, inf) = float::<_, f32, ()>("inf").unwrap(); - assert!(inf.is_infinite()); - let (_i, inf) = float::<_, f32, ()>("infinite").unwrap(); - assert!(inf.is_infinite()); - } - - #[cfg(feature = "std")] - fn parse_f64(i: &str) -> IResult<&str, f64, ()> { - #[allow(deprecated)] // will just become `pub(crate)` later - match super::recognize_float_or_exceptions(i) { - Err(e) => Err(e), - Ok((i, s)) => { - if s.is_empty() { - return Err(ErrMode::Backtrack(())); - } - match s.parse_slice() { - Some(n) => Ok((i, n)), - None => Err(ErrMode::Backtrack(())), - } - } - } - } - - proptest! { - #[test] - #[cfg(feature = "std")] - #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 - fn floats(s in "\\PC*") { - println!("testing {}", s); - let res1 = parse_f64(&s); - let res2 = float::<_, f64, ()>(s.as_str()); - assert_eq!(res1, res2); - } - } - - // issue #1336 "escaped hangs if normal parser accepts empty" - #[test] - fn complete_escaped_hang() { - // issue #1336 "escaped hangs if normal parser accepts empty" - fn escaped_string(input: &str) -> IResult<&str, &str> { - use crate::bytes::one_of; - use crate::character::alpha0; - escaped(alpha0, '\\', one_of("n")).parse_next(input) - } - - escaped_string("7").unwrap(); - escaped_string("a7").unwrap(); - } - - #[test] - fn complete_escaped_hang_1118() { - // issue ##1118 escaped does not work with empty string - fn unquote(input: &str) -> IResult<&str, &str> { - use crate::bytes::one_of; - use crate::combinator::opt; - use crate::sequence::delimited; - - delimited( - '"', - escaped(opt(none_of(r#"\""#)), '\\', one_of(r#"\"rnt"#)), - '"', - ) - .parse_next(input) - } - - assert_eq!(unquote(r#""""#), Ok(("", ""))); - } - - #[cfg(feature = "alloc")] - #[allow(unused_variables)] - #[test] - fn complete_escaping() { - use crate::bytes::one_of; - use crate::character::{alpha1 as alpha, digit1 as digit}; - - fn esc(i: &[u8]) -> IResult<&[u8], &[u8]> { - escaped(alpha, '\\', one_of("\"n\\")).parse_next(i) - } - assert_eq!(esc(&b"abcd;"[..]), Ok((&b";"[..], &b"abcd"[..]))); - assert_eq!(esc(&b"ab\\\"cd;"[..]), Ok((&b";"[..], &b"ab\\\"cd"[..]))); - assert_eq!(esc(&b"\\\"abcd;"[..]), Ok((&b";"[..], &b"\\\"abcd"[..]))); - assert_eq!(esc(&b"\\n;"[..]), Ok((&b";"[..], &b"\\n"[..]))); - assert_eq!(esc(&b"ab\\\"12"[..]), Ok((&b"12"[..], &b"ab\\\""[..]))); - assert_eq!( - esc(&b"AB\\"[..]), - Err(ErrMode::Backtrack(error_position!( - &b""[..], - ErrorKind::Token - ))) - ); - assert_eq!( - esc(&b"AB\\A"[..]), - Err(ErrMode::Backtrack(error_node_position!( - &b"AB\\A"[..], - ErrorKind::Token, - error_position!(&b"A"[..], ErrorKind::Verify) - ))) - ); - - fn esc2(i: &[u8]) -> IResult<&[u8], &[u8]> { - escaped(digit, '\\', one_of("\"n\\")).parse_next(i) - } - assert_eq!(esc2(&b"12\\nnn34"[..]), Ok((&b"nn34"[..], &b"12\\n"[..]))); - } - - #[cfg(feature = "alloc")] - #[test] - fn complete_escaping_str() { - use crate::bytes::one_of; - use crate::character::{alpha1 as alpha, digit1 as digit}; - - fn esc(i: &str) -> IResult<&str, &str> { - escaped(alpha, '\\', one_of("\"n\\")).parse_next(i) - } - assert_eq!(esc("abcd;"), Ok((";", "abcd"))); - assert_eq!(esc("ab\\\"cd;"), Ok((";", "ab\\\"cd"))); - assert_eq!(esc("\\\"abcd;"), Ok((";", "\\\"abcd"))); - assert_eq!(esc("\\n;"), Ok((";", "\\n"))); - assert_eq!(esc("ab\\\"12"), Ok(("12", "ab\\\""))); - assert_eq!( - esc("AB\\"), - Err(ErrMode::Backtrack(error_position!("", ErrorKind::Token))) - ); - assert_eq!( - esc("AB\\A"), - Err(ErrMode::Backtrack(error_node_position!( - "AB\\A", - ErrorKind::Token, - error_position!("A", ErrorKind::Verify) - ))) - ); - - fn esc2(i: &str) -> IResult<&str, &str> { - escaped(digit, '\\', one_of("\"n\\")).parse_next(i) - } - assert_eq!(esc2("12\\nnn34"), Ok(("nn34", "12\\n"))); - - fn esc3(i: &str) -> IResult<&str, &str> { - escaped(alpha, '\u{241b}', one_of("\"n")).parse_next(i) - } - assert_eq!(esc3("ab␛ncd;"), Ok((";", "ab␛ncd"))); - } - - #[test] - fn test_escaped_error() { - fn esc(s: &str) -> IResult<&str, &str> { - use crate::character::digit1; - escaped(digit1, '\\', one_of("\"n\\")).parse_next(s) - } - - assert_eq!(esc("abcd"), Ok(("abcd", ""))); - } - - #[cfg(feature = "alloc")] - #[test] - fn complete_escape_transform() { - use crate::character::alpha1 as alpha; - - #[cfg(feature = "alloc")] - fn to_s(i: Vec) -> String { - String::from_utf8_lossy(&i).into_owned() - } - - fn esc(i: &[u8]) -> IResult<&[u8], String> { - escaped_transform( - alpha, - '\\', - alt(( - "\\".value(&b"\\"[..]), - "\"".value(&b"\""[..]), - "n".value(&b"\n"[..]), - )), - ) - .map(to_s) - .parse_next(i) - } - - assert_eq!(esc(&b"abcd;"[..]), Ok((&b";"[..], String::from("abcd")))); - assert_eq!( - esc(&b"ab\\\"cd;"[..]), - Ok((&b";"[..], String::from("ab\"cd"))) - ); - assert_eq!( - esc(&b"\\\"abcd;"[..]), - Ok((&b";"[..], String::from("\"abcd"))) - ); - assert_eq!(esc(&b"\\n;"[..]), Ok((&b";"[..], String::from("\n")))); - assert_eq!( - esc(&b"ab\\\"12"[..]), - Ok((&b"12"[..], String::from("ab\""))) - ); - assert_eq!( - esc(&b"AB\\"[..]), - Err(ErrMode::Backtrack(error_position!( - &b""[..], - ErrorKind::Tag - ))) - ); - assert_eq!( - esc(&b"AB\\A"[..]), - Err(ErrMode::Backtrack(error_node_position!( - &b"AB\\A"[..], - ErrorKind::Eof, - error_position!(&b"A"[..], ErrorKind::Tag) - ))) - ); - - fn esc2(i: &[u8]) -> IResult<&[u8], String> { - escaped_transform( - alpha, - '&', - alt(( - "egrave;".value("è".as_bytes()), - "agrave;".value("à".as_bytes()), - )), - ) - .map(to_s) - .parse_next(i) - } - assert_eq!( - esc2(&b"abèDEF;"[..]), - Ok((&b";"[..], String::from("abèDEF"))) - ); - assert_eq!( - esc2(&b"abèDàEF;"[..]), - Ok((&b";"[..], String::from("abèDàEF"))) - ); - } - - #[cfg(feature = "std")] - #[test] - fn complete_escape_transform_str() { - use crate::character::alpha1 as alpha; - - fn esc(i: &str) -> IResult<&str, String> { - escaped_transform( - alpha, - '\\', - alt(("\\".value("\\"), "\"".value("\""), "n".value("\n"))), - ) - .parse_next(i) - } - - assert_eq!(esc("abcd;"), Ok((";", String::from("abcd")))); - assert_eq!(esc("ab\\\"cd;"), Ok((";", String::from("ab\"cd")))); - assert_eq!(esc("\\\"abcd;"), Ok((";", String::from("\"abcd")))); - assert_eq!(esc("\\n;"), Ok((";", String::from("\n")))); - assert_eq!(esc("ab\\\"12"), Ok(("12", String::from("ab\"")))); - assert_eq!( - esc("AB\\"), - Err(ErrMode::Backtrack(error_position!("", ErrorKind::Tag))) - ); - assert_eq!( - esc("AB\\A"), - Err(ErrMode::Backtrack(error_node_position!( - "AB\\A", - ErrorKind::Eof, - error_position!("A", ErrorKind::Tag) - ))) - ); - - fn esc2(i: &str) -> IResult<&str, String> { - escaped_transform( - alpha, - '&', - alt(("egrave;".value("è"), "agrave;".value("à"))), - ) - .parse_next(i) - } - assert_eq!(esc2("abèDEF;"), Ok((";", String::from("abèDEF")))); - assert_eq!( - esc2("abèDàEF;"), - Ok((";", String::from("abèDàEF"))) - ); - - fn esc3(i: &str) -> IResult<&str, String> { - escaped_transform(alpha, '␛', alt(("0".value("\0"), "n".value("\n")))).parse_next(i) - } - assert_eq!(esc3("a␛0bc␛n"), Ok(("", String::from("a\0bc\n")))); - } - - #[test] - #[cfg(feature = "alloc")] - fn test_escaped_transform_error() { - fn esc_trans(s: &str) -> IResult<&str, String> { - use crate::character::digit1; - escaped_transform(digit1, '\\', "n").parse_next(s) - } - - assert_eq!(esc_trans("abcd"), Ok(("abcd", String::new()))); - } -} - -mod partial { - use super::*; - use crate::combinator::opt; - use crate::error::Error; - use crate::error::ErrorKind; - use crate::error::{ErrMode, Needed}; - use crate::stream::ParseSlice; - use crate::IResult; - use crate::Partial; - use proptest::prelude::*; - - macro_rules! assert_parse( - ($left: expr, $right: expr) => { - let res: $crate::IResult<_, _, Error<_>> = $left; - assert_eq!(res, $right); - }; - ); - - #[test] - fn character() { - let a: &[u8] = b"abcd"; - let b: &[u8] = b"1234"; - let c: &[u8] = b"a123"; - let d: &[u8] = "azé12".as_bytes(); - let e: &[u8] = b" "; - let f: &[u8] = b" ;"; - //assert_eq!(alpha1::<_, Error<_>>(a), Err(ErrMode::Incomplete(Needed::new(1)))); - assert_parse!( - alpha1(Partial::new(a)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - alpha1(Partial::new(b)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(b), - ErrorKind::Slice - ))) - ); - assert_eq!( - alpha1::<_, Error<_>>(Partial::new(c)), - Ok((Partial::new(&c[1..]), &b"a"[..])) - ); - assert_eq!( - alpha1::<_, Error<_>>(Partial::new(d)), - Ok((Partial::new("é12".as_bytes()), &b"az"[..])) - ); - assert_eq!( - digit1(Partial::new(a)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(a), - ErrorKind::Slice - ))) - ); - assert_eq!( - digit1::<_, Error<_>>(Partial::new(b)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - digit1(Partial::new(c)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(c), - ErrorKind::Slice - ))) - ); - assert_eq!( - digit1(Partial::new(d)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(d), - ErrorKind::Slice - ))) - ); - assert_eq!( - hex_digit1::<_, Error<_>>(Partial::new(a)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - hex_digit1::<_, Error<_>>(Partial::new(b)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - hex_digit1::<_, Error<_>>(Partial::new(c)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - hex_digit1::<_, Error<_>>(Partial::new(d)), - Ok((Partial::new("zé12".as_bytes()), &b"a"[..])) - ); - assert_eq!( - hex_digit1(Partial::new(e)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(e), - ErrorKind::Slice - ))) - ); - assert_eq!( - oct_digit1(Partial::new(a)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(a), - ErrorKind::Slice - ))) - ); - assert_eq!( - oct_digit1::<_, Error<_>>(Partial::new(b)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - oct_digit1(Partial::new(c)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(c), - ErrorKind::Slice - ))) - ); - assert_eq!( - oct_digit1(Partial::new(d)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(d), - ErrorKind::Slice - ))) - ); - assert_eq!( - alphanumeric1::<_, Error<_>>(Partial::new(a)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - //assert_eq!(fix_error!(b,(), alphanumeric1), Ok((empty, b))); - assert_eq!( - alphanumeric1::<_, Error<_>>(Partial::new(c)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - alphanumeric1::<_, Error<_>>(Partial::new(d)), - Ok((Partial::new("é12".as_bytes()), &b"az"[..])) - ); - assert_eq!( - space1::<_, Error<_>>(Partial::new(e)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - space1::<_, Error<_>>(Partial::new(f)), - Ok((Partial::new(&b";"[..]), &b" "[..])) - ); - } - - #[cfg(feature = "alloc")] - #[test] - fn character_s() { - let a = "abcd"; - let b = "1234"; - let c = "a123"; - let d = "azé12"; - let e = " "; - assert_eq!( - alpha1::<_, Error<_>>(Partial::new(a)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - alpha1(Partial::new(b)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(b), - ErrorKind::Slice - ))) - ); - assert_eq!( - alpha1::<_, Error<_>>(Partial::new(c)), - Ok((Partial::new(&c[1..]), "a")) - ); - assert_eq!( - alpha1::<_, Error<_>>(Partial::new(d)), - Ok((Partial::new("é12"), "az")) - ); - assert_eq!( - digit1(Partial::new(a)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(a), - ErrorKind::Slice - ))) - ); - assert_eq!( - digit1::<_, Error<_>>(Partial::new(b)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - digit1(Partial::new(c)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(c), - ErrorKind::Slice - ))) - ); - assert_eq!( - digit1(Partial::new(d)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(d), - ErrorKind::Slice - ))) - ); - assert_eq!( - hex_digit1::<_, Error<_>>(Partial::new(a)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - hex_digit1::<_, Error<_>>(Partial::new(b)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - hex_digit1::<_, Error<_>>(Partial::new(c)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - hex_digit1::<_, Error<_>>(Partial::new(d)), - Ok((Partial::new("zé12"), "a")) - ); - assert_eq!( - hex_digit1(Partial::new(e)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(e), - ErrorKind::Slice - ))) - ); - assert_eq!( - oct_digit1(Partial::new(a)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(a), - ErrorKind::Slice - ))) - ); - assert_eq!( - oct_digit1::<_, Error<_>>(Partial::new(b)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - oct_digit1(Partial::new(c)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(c), - ErrorKind::Slice - ))) - ); - assert_eq!( - oct_digit1(Partial::new(d)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(d), - ErrorKind::Slice - ))) - ); - assert_eq!( - alphanumeric1::<_, Error<_>>(Partial::new(a)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - //assert_eq!(fix_error!(b,(), alphanumeric1), Ok((empty, b))); - assert_eq!( - alphanumeric1::<_, Error<_>>(Partial::new(c)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - alphanumeric1::<_, Error<_>>(Partial::new(d)), - Ok((Partial::new("é12"), "az")) - ); - assert_eq!( - space1::<_, Error<_>>(Partial::new(e)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - } - - use crate::stream::Offset; - #[test] - fn offset() { - let a = &b"abcd;"[..]; - let b = &b"1234;"[..]; - let c = &b"a123;"[..]; - let d = &b" \t;"[..]; - let e = &b" \t\r\n;"[..]; - let f = &b"123abcDEF;"[..]; - - match alpha1::<_, Error<_>>(Partial::new(a)) { - Ok((i, _)) => { - let i = i.into_inner(); - assert_eq!(a.offset_to(i) + i.len(), a.len()); - } - _ => panic!("wrong return type in offset test for alpha"), - } - match digit1::<_, Error<_>>(Partial::new(b)) { - Ok((i, _)) => { - let i = i.into_inner(); - assert_eq!(b.offset_to(i) + i.len(), b.len()); - } - _ => panic!("wrong return type in offset test for digit"), - } - match alphanumeric1::<_, Error<_>>(Partial::new(c)) { - Ok((i, _)) => { - let i = i.into_inner(); - assert_eq!(c.offset_to(i) + i.len(), c.len()); - } - _ => panic!("wrong return type in offset test for alphanumeric"), - } - match space1::<_, Error<_>>(Partial::new(d)) { - Ok((i, _)) => { - let i = i.into_inner(); - assert_eq!(d.offset_to(i) + i.len(), d.len()); - } - _ => panic!("wrong return type in offset test for space"), - } - match multispace1::<_, Error<_>>(Partial::new(e)) { - Ok((i, _)) => { - let i = i.into_inner(); - assert_eq!(e.offset_to(i) + i.len(), e.len()); - } - _ => panic!("wrong return type in offset test for multispace"), - } - match hex_digit1::<_, Error<_>>(Partial::new(f)) { - Ok((i, _)) => { - let i = i.into_inner(); - assert_eq!(f.offset_to(i) + i.len(), f.len()); - } - _ => panic!("wrong return type in offset test for hex_digit"), - } - match oct_digit1::<_, Error<_>>(Partial::new(f)) { - Ok((i, _)) => { - let i = i.into_inner(); - assert_eq!(f.offset_to(i) + i.len(), f.len()); - } - _ => panic!("wrong return type in offset test for oct_digit"), - } - } - - #[test] - fn is_not_line_ending_bytes() { - let a: &[u8] = b"ab12cd\nefgh"; - assert_eq!( - not_line_ending::<_, Error<_>>(Partial::new(a)), - Ok((Partial::new(&b"\nefgh"[..]), &b"ab12cd"[..])) - ); - - let b: &[u8] = b"ab12cd\nefgh\nijkl"; - assert_eq!( - not_line_ending::<_, Error<_>>(Partial::new(b)), - Ok((Partial::new(&b"\nefgh\nijkl"[..]), &b"ab12cd"[..])) - ); - - let c: &[u8] = b"ab12cd\r\nefgh\nijkl"; - assert_eq!( - not_line_ending::<_, Error<_>>(Partial::new(c)), - Ok((Partial::new(&b"\r\nefgh\nijkl"[..]), &b"ab12cd"[..])) - ); - - let d: &[u8] = b"ab12cd"; - assert_eq!( - not_line_ending::<_, Error<_>>(Partial::new(d)), - Err(ErrMode::Incomplete(Needed::Unknown)) - ); - } - - #[test] - fn is_not_line_ending_str() { - let f = "βèƒôřè\rÂßÇáƒƭèř"; - assert_eq!( - not_line_ending(Partial::new(f)), - Err(ErrMode::Backtrack(Error::new( - Partial::new(f), - ErrorKind::Tag - ))) - ); - - let g2: &str = "ab12cd"; - assert_eq!( - not_line_ending::<_, Error<_>>(Partial::new(g2)), - Err(ErrMode::Incomplete(Needed::Unknown)) - ); - } - - #[test] - fn hex_digit_test() { - let i = &b"0123456789abcdefABCDEF;"[..]; - assert_parse!( - hex_digit1(Partial::new(i)), - Ok((Partial::new(&b";"[..]), &i[..i.len() - 1])) - ); - - let i = &b"g"[..]; - assert_parse!( - hex_digit1(Partial::new(i)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(i), - ErrorKind::Slice - ))) - ); - - let i = &b"G"[..]; - assert_parse!( - hex_digit1(Partial::new(i)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(i), - ErrorKind::Slice - ))) - ); - - assert!(AsChar::is_hex_digit(b'0')); - assert!(AsChar::is_hex_digit(b'9')); - assert!(AsChar::is_hex_digit(b'a')); - assert!(AsChar::is_hex_digit(b'f')); - assert!(AsChar::is_hex_digit(b'A')); - assert!(AsChar::is_hex_digit(b'F')); - assert!(!AsChar::is_hex_digit(b'g')); - assert!(!AsChar::is_hex_digit(b'G')); - assert!(!AsChar::is_hex_digit(b'/')); - assert!(!AsChar::is_hex_digit(b':')); - assert!(!AsChar::is_hex_digit(b'@')); - assert!(!AsChar::is_hex_digit(b'\x60')); - } - - #[test] - fn oct_digit_test() { - let i = &b"01234567;"[..]; - assert_parse!( - oct_digit1(Partial::new(i)), - Ok((Partial::new(&b";"[..]), &i[..i.len() - 1])) - ); - - let i = &b"8"[..]; - assert_parse!( - oct_digit1(Partial::new(i)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(i), - ErrorKind::Slice - ))) - ); - - assert!(AsChar::is_oct_digit(b'0')); - assert!(AsChar::is_oct_digit(b'7')); - assert!(!AsChar::is_oct_digit(b'8')); - assert!(!AsChar::is_oct_digit(b'9')); - assert!(!AsChar::is_oct_digit(b'a')); - assert!(!AsChar::is_oct_digit(b'A')); - assert!(!AsChar::is_oct_digit(b'/')); - assert!(!AsChar::is_oct_digit(b':')); - assert!(!AsChar::is_oct_digit(b'@')); - assert!(!AsChar::is_oct_digit(b'\x60')); - } - - #[test] - fn full_line_windows() { - #[allow(clippy::type_complexity)] - fn take_full_line(i: Partial<&[u8]>) -> IResult, (&[u8], &[u8])> { - (not_line_ending, line_ending).parse_next(i) - } - let input = b"abc\r\n"; - let output = take_full_line(Partial::new(input)); - assert_eq!( - output, - Ok((Partial::new(&b""[..]), (&b"abc"[..], &b"\r\n"[..]))) - ); - } - - #[test] - fn full_line_unix() { - #[allow(clippy::type_complexity)] - fn take_full_line(i: Partial<&[u8]>) -> IResult, (&[u8], &[u8])> { - (not_line_ending, line_ending).parse_next(i) - } - let input = b"abc\n"; - let output = take_full_line(Partial::new(input)); - assert_eq!( - output, - Ok((Partial::new(&b""[..]), (&b"abc"[..], &b"\n"[..]))) - ); - } - - #[test] - fn check_windows_lineending() { - let input = b"\r\n"; - let output = line_ending(Partial::new(&input[..])); - assert_parse!(output, Ok((Partial::new(&b""[..]), &b"\r\n"[..]))); - } - - #[test] - fn check_unix_lineending() { - let input = b"\n"; - let output = line_ending(Partial::new(&input[..])); - assert_parse!(output, Ok((Partial::new(&b""[..]), &b"\n"[..]))); - } - - #[test] - fn cr_lf() { - assert_parse!( - crlf(Partial::new(&b"\r\na"[..])), - Ok((Partial::new(&b"a"[..]), &b"\r\n"[..])) - ); - assert_parse!( - crlf(Partial::new(&b"\r"[..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_parse!( - crlf(Partial::new(&b"\ra"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"\ra"[..]), - ErrorKind::Tag - ))) - ); - - assert_parse!(crlf(Partial::new("\r\na")), Ok((Partial::new("a"), "\r\n"))); - assert_parse!( - crlf(Partial::new("\r")), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_parse!( - crlf(Partial::new("\ra")), - Err(ErrMode::Backtrack(error_position!( - Partial::new("\ra"), - ErrorKind::Tag - ))) - ); - } - - #[test] - fn end_of_line() { - assert_parse!( - line_ending(Partial::new(&b"\na"[..])), - Ok((Partial::new(&b"a"[..]), &b"\n"[..])) - ); - assert_parse!( - line_ending(Partial::new(&b"\r\na"[..])), - Ok((Partial::new(&b"a"[..]), &b"\r\n"[..])) - ); - assert_parse!( - line_ending(Partial::new(&b"\r"[..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_parse!( - line_ending(Partial::new(&b"\ra"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"\ra"[..]), - ErrorKind::Tag - ))) - ); - - assert_parse!( - line_ending(Partial::new("\na")), - Ok((Partial::new("a"), "\n")) - ); - assert_parse!( - line_ending(Partial::new("\r\na")), - Ok((Partial::new("a"), "\r\n")) - ); - assert_parse!( - line_ending(Partial::new("\r")), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_parse!( - line_ending(Partial::new("\ra")), - Err(ErrMode::Backtrack(error_position!( - Partial::new("\ra"), - ErrorKind::Tag - ))) - ); - } - - fn digit_to_i16(input: Partial<&str>) -> IResult, i16> { - let i = input; - let (i, opt_sign) = opt(one_of("+-")).parse_next(i)?; - let sign = match opt_sign { - Some('+') | None => true, - Some('-') => false, - _ => unreachable!(), - }; - - let (i, s) = digit1::<_, crate::error::Error<_>>(i)?; - match s.parse_slice() { - Some(n) => { - if sign { - Ok((i, n)) - } else { - Ok((i, -n)) - } - } - None => Err(ErrMode::from_error_kind(i, ErrorKind::Verify)), - } - } - - fn digit_to_u32(i: Partial<&str>) -> IResult, u32> { - let (i, s) = digit1(i)?; - match s.parse_slice() { - Some(n) => Ok((i, n)), - None => Err(ErrMode::from_error_kind(i, ErrorKind::Verify)), - } - } - - proptest! { - #[test] - #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 - fn ints(s in "\\PC*") { - let res1 = digit_to_i16(Partial::new(&s)); - let res2 = dec_int(Partial::new(s.as_str())); - assert_eq!(res1, res2); - } - - #[test] - #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 - fn uints(s in "\\PC*") { - let res1 = digit_to_u32(Partial::new(&s)); - let res2 = dec_uint(Partial::new(s.as_str())); - assert_eq!(res1, res2); - } - } - - #[test] - fn hex_uint_tests() { - fn hex_u32(input: Partial<&[u8]>) -> IResult, u32> { - hex_uint(input) - } - - assert_parse!( - hex_u32(Partial::new(&b";"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b";"[..]), - ErrorKind::Slice - ))) - ); - assert_parse!( - hex_u32(Partial::new(&b"ff;"[..])), - Ok((Partial::new(&b";"[..]), 255)) - ); - assert_parse!( - hex_u32(Partial::new(&b"1be2;"[..])), - Ok((Partial::new(&b";"[..]), 7138)) - ); - assert_parse!( - hex_u32(Partial::new(&b"c5a31be2;"[..])), - Ok((Partial::new(&b";"[..]), 3_315_801_058)) - ); - assert_parse!( - hex_u32(Partial::new(&b"C5A31be2;"[..])), - Ok((Partial::new(&b";"[..]), 3_315_801_058)) - ); - assert_parse!( - hex_u32(Partial::new(&b"00c5a31be2;"[..])), // overflow - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"00c5a31be2;"[..]), - ErrorKind::Verify - ))) - ); - assert_parse!( - hex_u32(Partial::new(&b"c5a31be201;"[..])), // overflow - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"c5a31be201;"[..]), - ErrorKind::Verify - ))) - ); - assert_parse!( - hex_u32(Partial::new(&b"ffffffff;"[..])), - Ok((Partial::new(&b";"[..]), 4_294_967_295)) - ); - assert_parse!( - hex_u32(Partial::new(&b"ffffffffffffffff;"[..])), // overflow - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"ffffffffffffffff;"[..]), - ErrorKind::Verify - ))) - ); - assert_parse!( - hex_u32(Partial::new(&b"ffffffffffffffff"[..])), // overflow - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"ffffffffffffffff"[..]), - ErrorKind::Verify - ))) - ); - assert_parse!( - hex_u32(Partial::new(&b"0x1be2;"[..])), - Ok((Partial::new(&b"x1be2;"[..]), 0)) - ); - assert_parse!( - hex_u32(Partial::new(&b"12af"[..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - } -} diff --git a/vendor/winnow/src/combinator/branch.rs b/vendor/winnow/src/combinator/branch.rs new file mode 100644 index 000000000..042b27d53 --- /dev/null +++ b/vendor/winnow/src/combinator/branch.rs @@ -0,0 +1,268 @@ +use crate::error::{ErrMode, ErrorKind, ParseError}; +use crate::stream::Stream; +use crate::trace::trace; +use crate::*; + +#[doc(inline)] +pub use crate::dispatch; + +/// Helper trait for the [alt()] combinator. +/// +/// This trait is implemented for tuples of up to 21 elements +pub trait Alt { + /// Tests each parser in the tuple and returns the result of the first one that succeeds + fn choice(&mut self, input: I) -> IResult; +} + +/// Pick the first successful parser +/// +/// For tight control over the error, add a final case using [`fail`][crate::combinator::fail]. +/// Alternatively, with a [custom error type][crate::_topic::error], it is possible to track all +/// errors or return the error of the parser that went the farthest in the input data. +/// +/// When the alternative cases have unique prefixes, [`dispatch`] can offer better performance. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::Error,error::ErrorKind, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::ascii::{alpha1, digit1}; +/// use winnow::combinator::alt; +/// # fn main() { +/// fn parser(input: &str) -> IResult<&str, &str> { +/// alt((alpha1, digit1)).parse_next(input) +/// }; +/// +/// // the first parser, alpha1, recognizes the input +/// assert_eq!(parser("abc"), Ok(("", "abc"))); +/// +/// // the first parser returns an error, so alt tries the second one +/// assert_eq!(parser("123456"), Ok(("", "123456"))); +/// +/// // both parsers failed, and with the default error type, alt will return the last error +/// assert_eq!(parser(" "), Err(ErrMode::Backtrack(Error::new(" ", ErrorKind::Slice)))); +/// # } +/// ``` +#[doc(alias = "choice")] +pub fn alt, List: Alt>( + mut l: List, +) -> impl Parser { + trace("alt", move |i: I| l.choice(i)) +} + +/// Helper trait for the [permutation()] combinator. +/// +/// This trait is implemented for tuples of up to 21 elements +pub trait Permutation { + /// Tries to apply all parsers in the tuple in various orders until all of them succeed + fn permutation(&mut self, input: I) -> IResult; +} + +/// Applies a list of parsers in any order. +/// +/// Permutation will succeed if all of the child parsers succeeded. +/// It takes as argument a tuple of parsers, and returns a +/// tuple of the parser results. +/// +/// ```rust +/// # use winnow::{error::ErrMode,error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::ascii::{alpha1, digit1}; +/// use winnow::combinator::permutation; +/// # fn main() { +/// fn parser(input: &str) -> IResult<&str, (&str, &str)> { +/// permutation((alpha1, digit1)).parse_next(input) +/// } +/// +/// // permutation recognizes alphabetic characters then digit +/// assert_eq!(parser("abc123"), Ok(("", ("abc", "123")))); +/// +/// // but also in inverse order +/// assert_eq!(parser("123abc"), Ok(("", ("abc", "123")))); +/// +/// // it will fail if one of the parsers failed +/// assert_eq!(parser("abc;"), Err(ErrMode::Backtrack(Error::new(";", ErrorKind::Slice)))); +/// # } +/// ``` +/// +/// The parsers are applied greedily: if there are multiple unapplied parsers +/// that could parse the next slice of input, the first one is used. +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}}; +/// # use winnow::prelude::*; +/// use winnow::combinator::permutation; +/// use winnow::token::any; +/// +/// fn parser(input: &str) -> IResult<&str, (char, char)> { +/// permutation((any, 'a')).parse_next(input) +/// } +/// +/// // any parses 'b', then char('a') parses 'a' +/// assert_eq!(parser("ba"), Ok(("", ('b', 'a')))); +/// +/// // any parses 'a', then char('a') fails on 'b', +/// // even though char('a') followed by any would succeed +/// assert_eq!(parser("ab"), Err(ErrMode::Backtrack(Error::new("b", ErrorKind::Verify)))); +/// ``` +/// +pub fn permutation, List: Permutation>( + mut l: List, +) -> impl Parser { + trace("permutation", move |i: I| l.permutation(i)) +} + +macro_rules! alt_trait( + ($first:ident $second:ident $($id: ident)+) => ( + alt_trait!(__impl $first $second; $($id)+); + ); + (__impl $($current:ident)*; $head:ident $($id: ident)+) => ( + alt_trait_impl!($($current)*); + + alt_trait!(__impl $($current)* $head; $($id)+); + ); + (__impl $($current:ident)*; $head:ident) => ( + alt_trait_impl!($($current)*); + alt_trait_impl!($($current)* $head); + ); +); + +macro_rules! alt_trait_impl( + ($($id:ident)+) => ( + impl< + I: Clone, Output, Error: ParseError, + $($id: Parser),+ + > Alt for ( $($id),+ ) { + + fn choice(&mut self, input: I) -> IResult { + match self.0.parse_next(input.clone()) { + Err(ErrMode::Backtrack(e)) => alt_trait_inner!(1, self, input, e, $($id)+), + res => res, + } + } + } + ); +); + +macro_rules! alt_trait_inner( + ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident $($id:ident)+) => ( + match $self.$it.parse_next($input.clone()) { + Err(ErrMode::Backtrack(e)) => { + let err = $err.or(e); + succ!($it, alt_trait_inner!($self, $input, err, $($id)+)) + } + res => res, + } + ); + ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident) => ( + Err(ErrMode::Backtrack($err.append($input, ErrorKind::Alt))) + ); +); + +alt_trait!(Alt2 Alt3 Alt4 Alt5 Alt6 Alt7 Alt8 Alt9 Alt10 Alt11 Alt12 Alt13 Alt14 Alt15 Alt16 Alt17 Alt18 Alt19 Alt20 Alt21 Alt22); + +// Manually implement Alt for (A,), the 1-tuple type +impl, A: Parser> Alt for (A,) { + fn choice(&mut self, input: I) -> IResult { + self.0.parse_next(input) + } +} + +macro_rules! permutation_trait( + ( + $name1:ident $ty1:ident $item1:ident + $name2:ident $ty2:ident $item2:ident + $($name3:ident $ty3:ident $item3:ident)* + ) => ( + permutation_trait!(__impl $name1 $ty1 $item1, $name2 $ty2 $item2; $($name3 $ty3 $item3)*); + ); + ( + __impl $($name:ident $ty:ident $item:ident),+; + $name1:ident $ty1:ident $item1:ident $($name2:ident $ty2:ident $item2:ident)* + ) => ( + permutation_trait_impl!($($name $ty $item),+); + permutation_trait!(__impl $($name $ty $item),+ , $name1 $ty1 $item1; $($name2 $ty2 $item2)*); + ); + (__impl $($name:ident $ty:ident $item:ident),+;) => ( + permutation_trait_impl!($($name $ty $item),+); + ); +); + +macro_rules! permutation_trait_impl( + ($($name:ident $ty:ident $item:ident),+) => ( + impl< + I: Clone, $($ty),+ , Error: ParseError, + $($name: Parser),+ + > Permutation for ( $($name),+ ) { + + fn permutation(&mut self, mut input: I) -> IResult { + let mut res = ($(Option::<$ty>::None),+); + + loop { + let mut err: Option = None; + permutation_trait_inner!(0, self, input, res, err, $($name)+); + + // If we reach here, every iterator has either been applied before, + // or errored on the remaining input + if let Some(err) = err { + // There are remaining parsers, and all errored on the remaining input + return Err(ErrMode::Backtrack(err.append(input, ErrorKind::Alt))); + } + + // All parsers were applied + match res { + ($(Some($item)),+) => return Ok((input, ($($item),+))), + _ => unreachable!(), + } + } + } + } + ); +); + +macro_rules! permutation_trait_inner( + ($it:tt, $self:expr, $input:ident, $res:expr, $err:expr, $head:ident $($id:ident)*) => ( + if $res.$it.is_none() { + match $self.$it.parse_next($input.clone()) { + Ok((i, o)) => { + $input = i; + $res.$it = Some(o); + continue; + } + Err(ErrMode::Backtrack(e)) => { + $err = Some(match $err { + Some(err) => err.or(e), + None => e, + }); + } + Err(e) => return Err(e), + }; + } + succ!($it, permutation_trait_inner!($self, $input, $res, $err, $($id)*)); + ); + ($it:tt, $self:expr, $input:ident, $res:expr, $err:expr,) => (); +); + +permutation_trait!( + P1 O1 o1 + P2 O2 o2 + P3 O3 o3 + P4 O4 o4 + P5 O5 o5 + P6 O6 o6 + P7 O7 o7 + P8 O8 o8 + P9 O9 o9 + P10 O10 o10 + P11 O11 o11 + P12 O12 o12 + P13 O13 o13 + P14 O14 o14 + P15 O15 o15 + P16 O16 o16 + P17 O17 o17 + P18 O18 o18 + P19 O19 o19 + P20 O20 o20 + P21 O21 o21 +); diff --git a/vendor/winnow/src/combinator/core.rs b/vendor/winnow/src/combinator/core.rs new file mode 100644 index 000000000..75551d7c5 --- /dev/null +++ b/vendor/winnow/src/combinator/core.rs @@ -0,0 +1,490 @@ +use crate::error::{ErrMode, ErrorKind, Needed, ParseError}; +use crate::stream::Stream; +use crate::trace::trace; +use crate::*; + +/// 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) +} + +/// 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::ascii::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::ascii::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::ascii::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) +} + +/// 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::ascii::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), + } + }) +} + +/// Transforms an [`ErrMode::Backtrack`] (recoverable) to [`ErrMode::Cut`] (unrecoverable) +/// +/// This commits the parse result, preventing alternative branch paths like with +/// [`winnow::combinator::alt`][crate::combinator::alt]. +/// +/// # Example +/// +/// Without `cut_err`: +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error}; +/// # use winnow::token::one_of; +/// # use winnow::ascii::digit1; +/// # use winnow::combinator::rest; +/// # use winnow::combinator::alt; +/// # use winnow::combinator::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::token::one_of; +/// # use winnow::ascii::digit1; +/// # use winnow::combinator::rest; +/// # use winnow::combinator::alt; +/// # use winnow::combinator::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::combinator::alt`][crate::combinator::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) +} + +/// Repeats the embedded parser, lazily returning the results +/// +/// 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, token::tag, ascii::alpha1, combinator::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::combinator::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) +} diff --git a/vendor/winnow/src/combinator/mod.rs b/vendor/winnow/src/combinator/mod.rs index 4276b06d3..d76ef8e5f 100644 --- a/vendor/winnow/src/combinator/mod.rs +++ b/vendor/winnow/src/combinator/mod.rs @@ -8,45 +8,41 @@ //! //! | 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| +//! | [`one_of`][crate::token::one_of] | `one_of("abc")` | `"abc"` | `Ok(("bc", 'a'))` |Matches one of the provided characters (works with non ASCII characters too)| +//! | [`none_of`][crate::token::none_of] | `none_of("abc")` | `"xyab"` | `Ok(("yab", 'x'))` |Matches anything but the provided characters| +//! | [`tag`][crate::token::tag] | `"hello"` | `"hello world"` | `Ok((" world", "hello"))` |Recognizes a specific suite of characters or bytes| +//! | [`tag_no_case`][crate::token::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::token::take] | `take(4)` | `"hello"` | `Ok(("o", "hell"))` |Takes a specific number of bytes or characters| +//! | [`take_while`][crate::token::take_while] | `take_while(0.., is_alphabetic)` | `"abc123"` | `Ok(("123", "abc"))` |Returns the longest list of bytes for which the provided pattern matches.| +//! | [`take_till0`][crate::token::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_while`: `take_till(f)` is equivalent to `take_while(0.., \|c\| !f(c))`| +//! | [`take_until0`][crate::token::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| +//! | [`alt`][crate::combinator::alt] | `alt(("ab", "cd"))` | `"cdef"` | `Ok(("ef", "cd"))` |Try a list of parsers and return the result of the first successful one| +//! | [`dispatch`][crate::combinator::dispatch] | \- | \- | \- | `match` for parsers | +//! | [`permutation`][crate::combinator::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")))` || +//! | [`delimited`] | `delimited(char('('), take(2), char(')'))` | `"(ab)cd"` | `Ok(("cd", "ab"))` || +//! | [`preceded`] | `preceded("ab", "XY")` | `"abXYZ"` | `Ok(("Z", "XY"))` || +//! | [`terminated`] | `terminated("ab", "XY")` | `"abXYZ"` | `Ok(("Z", "ab"))` || +//! | [`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| +//! | [`repeat`][crate::combinator::repeat] | `repeat(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| +//! | [`repeat_till0`][crate::combinator::repeat_till0] | `repeat_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::combinator::separated0] | `separated0("ab", ",")` | `"ab,ab,ab."` | `Ok((".", vec!["ab", "ab", "ab"]))` |`separated1` works like `separated0` but must returns at least one element| +//! | [`fold_repeat`][crate::combinator::fold_repeat] | `fold_repeat(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| //! //! ## Partial related //! @@ -61,7 +57,7 @@ //! - [`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::try_map`][Parser::try_map]: 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 @@ -89,33 +85,33 @@ //! //! ## 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` +//! - [`any`][crate::token::any]: Matches one token +//! - [`tab`][crate::ascii::tab]: Matches a tab character `\t` +//! - [`crlf`][crate::ascii::crlf]: Recognizes the string `\r\n` +//! - [`line_ending`][crate::ascii::line_ending]: Recognizes an end of line (both `\n` and `\r\n`) +//! - [`newline`][crate::ascii::newline]: Matches a newline character `\n` +//! - [`not_line_ending`][crate::ascii::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 +//! - [`alpha0`][crate::ascii::alpha0]: Recognizes zero or more lowercase and uppercase alphabetic characters: `[a-zA-Z]`. [`alpha1`][crate::ascii::alpha1] does the same but returns at least one character +//! - [`alphanumeric0`][crate::ascii::alphanumeric0]: Recognizes zero or more numerical and alphabetic characters: `[0-9a-zA-Z]`. [`alphanumeric1`][crate::ascii::alphanumeric1] does the same but returns at least one character +//! - [`space0`][crate::ascii::space0]: Recognizes zero or more spaces and tabs. [`space1`][crate::ascii::space1] does the same but returns at least one character +//! - [`multispace0`][crate::ascii::multispace0]: Recognizes zero or more spaces, tabs, carriage returns and line feeds. [`multispace1`][crate::ascii::multispace1] does the same but returns at least one character +//! - [`digit0`][crate::ascii::digit0]: Recognizes zero or more numerical characters: `[0-9]`. [`digit1`][crate::ascii::digit1] does the same but returns at least one character +//! - [`hex_digit0`][crate::ascii::hex_digit0]: Recognizes zero or more hexadecimal numerical characters: `[0-9A-Fa-f]`. [`hex_digit1`][crate::ascii::hex_digit1] does the same but returns at least one character +//! - [`oct_digit0`][crate::ascii::oct_digit0]: Recognizes zero or more octal characters: `[0-7]`. [`oct_digit1`][crate::ascii::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 +//! - [`float`][crate::ascii::float]: Parse a floating point number in a byte string +//! - [`dec_int`][crate::ascii::dec_uint]: Decode a variable-width, decimal signed integer +//! - [`dec_uint`][crate::ascii::dec_uint]: Decode a variable-width, decimal unsigned integer +//! - [`hex_uint`][crate::ascii::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 +//! - [`escaped`][crate::ascii::escaped]: Matches a byte string with escaped characters +//! - [`escaped_transform`][crate::ascii::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`: +//! Use these functions with a combinator like `take_while`: //! //! - [`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]` @@ -127,1345 +123,50 @@ //! //! ## 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 +//! - [`length_count`][crate::binary::length_count] Gets a number from the first parser, then applies the second parser that many times +//! - [`length_data`][crate::binary::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::binary::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 +//! - **configurable endianness:** [`i16`][crate::binary::i16], [`i32`][crate::binary::i32], +//! [`i64`][crate::binary::i64], [`u16`][crate::binary::u16], [`u32`][crate::binary::u32], +//! [`u64`][crate::binary::u64] are combinators that take as argument a +//! [`winnow::binary::Endianness`][crate::binary::Endianness], like this: `i16(endianness)`. If the +//! parameter is `winnow::binary::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 +//! - [`be_f32`][crate::binary::be_f32], [`be_f64`][crate::binary::be_f64]: Big endian floating point numbers +//! - [`le_f32`][crate::binary::le_f32], [`le_f64`][crate::binary::le_f64]: Little endian floating point numbers +//! - [`be_i8`][crate::binary::be_i8], [`be_i16`][crate::binary::be_i16], [`be_i24`][crate::binary::be_i24], [`be_i32`][crate::binary::be_i32], [`be_i64`][crate::binary::be_i64], [`be_i128`][crate::binary::be_i128]: Big endian signed integers +//! - [`be_u8`][crate::binary::be_u8], [`be_u16`][crate::binary::be_u16], [`be_u24`][crate::binary::be_u24], [`be_u32`][crate::binary::be_u32], [`be_u64`][crate::binary::be_u64], [`be_u128`][crate::binary::be_u128]: Big endian unsigned integers +//! - [`le_i8`][crate::binary::le_i8], [`le_i16`][crate::binary::le_i16], [`le_i24`][crate::binary::le_i24], [`le_i32`][crate::binary::le_i32], [`le_i64`][crate::binary::le_i64], [`le_i128`][crate::binary::le_i128]: Little endian signed integers +//! - [`le_u8`][crate::binary::le_u8], [`le_u16`][crate::binary::le_u16], [`le_u24`][crate::binary::le_u24], [`le_u32`][crate::binary::le_u32], [`le_u64`][crate::binary::le_u64], [`le_u128`][crate::binary::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 +//! - [`bits`][crate::binary::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::binary::bits::bytes]: Transforms its bits stream input back into a byte slice for the underlying parser +//! - [`take`][crate::binary::bits::take]: Take a set number of its +//! - [`tag`][crate::binary::bits::tag]: Check if a set number of bis matches a pattern +//! - [`bool`][crate::binary::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::*; +mod branch; +mod core; +mod multi; +mod parser; +mod sequence; #[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) -} +pub use self::branch::*; +pub use self::core::*; +pub use self::multi::*; +pub use self::parser::*; +pub use self::sequence::*; -/// 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) - } -} +#[allow(unused_imports)] +use crate::Parser; diff --git a/vendor/winnow/src/combinator/multi.rs b/vendor/winnow/src/combinator/multi.rs new file mode 100644 index 000000000..950432601 --- /dev/null +++ b/vendor/winnow/src/combinator/multi.rs @@ -0,0 +1,987 @@ +//! Combinators applying their child parser multiple times + +use crate::error::ErrMode; +use crate::error::ErrorKind; +use crate::error::ParseError; +use crate::stream::Accumulate; +use crate::stream::Range; +use crate::stream::Stream; +use crate::trace::trace; +use crate::IResult; +use crate::Parser; + +/// [`Accumulate`] the output of a parser into a container, like `Vec` +/// +/// This stops before `n` when the parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see +/// [`cut_err`][crate::combinator::cut_err]. +/// +/// # Arguments +/// * `m` The minimum number of iterations. +/// * `n` The maximum number of iterations. +/// * `f` The parser to apply. +/// +/// To recognize a series of tokens, [`Accumulate`] into a `()` and then [`Parser::recognize`]. +/// +/// **Warning:** If the parser passed to `repeat` accepts empty inputs +/// (like `alpha0` or `digit0`), `repeat` will return an error, +/// to prevent going into an infinite loop. +/// +/// # Example +/// +/// Zero or more reptitions: +/// ```rust +/// # #[cfg(feature = "std")] { +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::repeat; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// repeat(0.., "abc").parse_next(s) +/// } +/// +/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); +/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); +/// assert_eq!(parser("123123"), Ok(("123123", vec![]))); +/// assert_eq!(parser(""), Ok(("", vec![]))); +/// # } +/// ``` +/// +/// One or more reptitions: +/// ```rust +/// # #[cfg(feature = "std")] { +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::repeat; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// repeat(1.., "abc").parse_next(s) +/// } +/// +/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); +/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); +/// assert_eq!(parser("123123"), Err(ErrMode::Backtrack(Error::new("123123", ErrorKind::Tag)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); +/// # } +/// ``` +/// +/// Fixed number of repeitions: +/// ```rust +/// # #[cfg(feature = "std")] { +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::repeat; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// repeat(2, "abc").parse_next(s) +/// } +/// +/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); +/// assert_eq!(parser("abc123"), Err(ErrMode::Backtrack(Error::new("123", ErrorKind::Tag)))); +/// assert_eq!(parser("123123"), Err(ErrMode::Backtrack(Error::new("123123", ErrorKind::Tag)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); +/// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"]))); +/// # } +/// ``` +/// +/// Arbitrary reptitions: +/// ```rust +/// # #[cfg(feature = "std")] { +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::repeat; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// repeat(0..=2, "abc").parse_next(s) +/// } +/// +/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); +/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); +/// assert_eq!(parser("123123"), Ok(("123123", vec![]))); +/// assert_eq!(parser(""), Ok(("", vec![]))); +/// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"]))); +/// # } +/// ``` +#[doc(alias = "many0")] +#[doc(alias = "count")] +#[doc(alias = "many0_count")] +#[doc(alias = "many1")] +#[doc(alias = "many1_count")] +#[doc(alias = "many_m_n")] +#[doc(alias = "repeated")] +#[doc(alias = "skip_many")] +#[doc(alias = "skip_many1")] +#[inline(always)] +pub fn repeat(range: impl Into, mut f: F) -> impl Parser +where + I: Stream, + C: Accumulate, + F: Parser, + E: ParseError, +{ + let Range { + start_inclusive, + end_inclusive, + } = range.into(); + trace("repeat", move |i: I| { + match (start_inclusive, end_inclusive) { + (0, None) => repeat0_(&mut f, i), + (1, None) => repeat1_(&mut f, i), + (start, end) if Some(start) == end => repeat_n_(start, &mut f, i), + (start, end) => repeat_m_n_(start, end.unwrap_or(usize::MAX), &mut f, i), + } + }) +} + +/// Deprecated, replaced by [`repeat`] +#[deprecated(since = "0.4.6", note = "Replaced with `repeat`")] +#[inline(always)] +pub fn repeat0(f: F) -> impl Parser +where + I: Stream, + C: Accumulate, + F: Parser, + E: ParseError, +{ + repeat(0.., f) +} + +fn repeat0_(f: &mut F, mut i: I) -> IResult +where + I: Stream, + C: Accumulate, + F: Parser, + E: ParseError, +{ + let mut acc = C::initial(None); + loop { + let len = i.eof_offset(); + match f.parse_next(i.clone()) { + Err(ErrMode::Backtrack(_)) => return Ok((i, acc)), + Err(e) => return Err(e), + Ok((i1, o)) => { + // infinite loop check: the parser must always consume + if i1.eof_offset() == len { + return Err(ErrMode::assert(i, "`repeat` parsers must always consume")); + } + + i = i1; + acc.accumulate(o); + } + } + } +} + +/// Deprecated, replaced by [`repeat`] +#[deprecated(since = "0.4.6", note = "Replaced with `repeat`")] +#[inline(always)] +pub fn repeat1(f: F) -> impl Parser +where + I: Stream, + C: Accumulate, + F: Parser, + E: ParseError, +{ + repeat(1.., f) +} + +fn repeat1_(f: &mut F, mut i: I) -> IResult +where + I: Stream, + C: Accumulate, + F: Parser, + E: ParseError, +{ + match f.parse_next(i.clone()) { + Err(e) => Err(e.append(i, ErrorKind::Many)), + Ok((i1, o)) => { + let mut acc = C::initial(None); + acc.accumulate(o); + i = i1; + + loop { + let len = i.eof_offset(); + match f.parse_next(i.clone()) { + Err(ErrMode::Backtrack(_)) => return Ok((i, acc)), + Err(e) => return Err(e), + Ok((i1, o)) => { + // infinite loop check: the parser must always consume + if i1.eof_offset() == len { + return Err(ErrMode::assert(i, "`repeat` parsers must always consume")); + } + + i = i1; + acc.accumulate(o); + } + } + } + } + } +} + +/// [`Accumulate`] the output of parser `f` into a container, like `Vec`, until the parser `g` +/// produces a result. +/// +/// Returns a tuple of the results of `f` in a `Vec` and the result of `g`. +/// +/// `f` keeps going so long as `g` produces [`ErrMode::Backtrack`]. To instead chain an error up, see [`cut_err`][crate::combinator::cut_err]. +/// +/// To recognize a series of tokens, [`Accumulate`] into a `()` and then [`Parser::recognize`]. +/// +/// # Example +/// +/// ```rust +/// # #[cfg(feature = "std")] { +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::repeat_till0; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, (Vec<&str>, &str)> { +/// repeat_till0("abc", "end").parse_next(s) +/// }; +/// +/// assert_eq!(parser("abcabcend"), Ok(("", (vec!["abc", "abc"], "end")))); +/// assert_eq!(parser("abc123end"), Err(ErrMode::Backtrack(Error::new("123end", ErrorKind::Tag)))); +/// assert_eq!(parser("123123end"), Err(ErrMode::Backtrack(Error::new("123123end", ErrorKind::Tag)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); +/// assert_eq!(parser("abcendefg"), Ok(("efg", (vec!["abc"], "end")))); +/// # } +/// ``` +#[doc(alias = "many_till0")] +pub fn repeat_till0(mut f: F, mut g: G) -> impl Parser +where + I: Stream, + C: Accumulate, + F: Parser, + G: Parser, + E: ParseError, +{ + trace("repeat_till0", move |mut i: I| { + let mut res = C::initial(None); + loop { + let len = i.eof_offset(); + match g.parse_next(i.clone()) { + Ok((i1, o)) => return Ok((i1, (res, o))), + Err(ErrMode::Backtrack(_)) => { + match f.parse_next(i.clone()) { + Err(e) => return Err(e.append(i, ErrorKind::Many)), + Ok((i1, o)) => { + // infinite loop check: the parser must always consume + if i1.eof_offset() == len { + return Err(ErrMode::assert( + i, + "`repeat` parsers must always consume", + )); + } + + res.accumulate(o); + i = i1; + } + } + } + Err(e) => return Err(e), + } + } + }) +} + +/// [`Accumulate`] the output of a parser, interleaed with `sep` +/// +/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see +/// [`cut_err`][crate::combinator::cut_err]. +/// +/// # Arguments +/// * `parser` Parses the elements of the list. +/// * `sep` Parses the separator between list elements. +/// +/// # Example +/// +/// ```rust +/// # #[cfg(feature = "std")] { +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::separated0; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// separated0("abc", "|").parse_next(s) +/// } +/// +/// assert_eq!(parser("abc|abc|abc"), Ok(("", vec!["abc", "abc", "abc"]))); +/// assert_eq!(parser("abc123abc"), Ok(("123abc", vec!["abc"]))); +/// assert_eq!(parser("abc|def"), Ok(("|def", vec!["abc"]))); +/// assert_eq!(parser(""), Ok(("", vec![]))); +/// assert_eq!(parser("def|abc"), Ok(("def|abc", vec![]))); +/// # } +/// ``` +#[doc(alias = "sep_by")] +#[doc(alias = "separated_list0")] +pub fn separated0(mut parser: P, mut sep: S) -> impl Parser +where + I: Stream, + C: Accumulate, + P: Parser, + S: Parser, + E: ParseError, +{ + trace("separated0", move |mut i: I| { + let mut res = C::initial(None); + + match parser.parse_next(i.clone()) { + Err(ErrMode::Backtrack(_)) => return Ok((i, res)), + Err(e) => return Err(e), + Ok((i1, o)) => { + res.accumulate(o); + i = i1; + } + } + + loop { + let len = i.eof_offset(); + match sep.parse_next(i.clone()) { + Err(ErrMode::Backtrack(_)) => return Ok((i, res)), + Err(e) => return Err(e), + Ok((i1, _)) => { + // infinite loop check: the parser must always consume + if i1.eof_offset() == len { + return Err(ErrMode::assert(i, "sep parsers must always consume")); + } + + match parser.parse_next(i1.clone()) { + Err(ErrMode::Backtrack(_)) => return Ok((i, res)), + Err(e) => return Err(e), + Ok((i2, o)) => { + res.accumulate(o); + i = i2; + } + } + } + } + } + }) +} + +/// [`Accumulate`] the output of a parser, interleaed with `sep` +/// +/// Fails if the element parser does not produce at least one element.$ +/// +/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see +/// [`cut_err`][crate::combinator::cut_err]. +/// +/// # Arguments +/// * `sep` Parses the separator between list elements. +/// * `f` Parses the elements of the list. +/// +/// # Example +/// +/// ```rust +/// # #[cfg(feature = "std")] { +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::separated1; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// separated1("abc", "|").parse_next(s) +/// } +/// +/// assert_eq!(parser("abc|abc|abc"), Ok(("", vec!["abc", "abc", "abc"]))); +/// assert_eq!(parser("abc123abc"), Ok(("123abc", vec!["abc"]))); +/// assert_eq!(parser("abc|def"), Ok(("|def", vec!["abc"]))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); +/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(Error::new("def|abc", ErrorKind::Tag)))); +/// # } +/// ``` +#[doc(alias = "sep_by1")] +#[doc(alias = "separated_list1")] +pub fn separated1(mut parser: P, mut sep: S) -> impl Parser +where + I: Stream, + C: Accumulate, + P: Parser, + S: Parser, + E: ParseError, +{ + trace("separated1", move |mut i: I| { + let mut res = C::initial(None); + + // Parse the first element + match parser.parse_next(i.clone()) { + Err(e) => return Err(e), + Ok((i1, o)) => { + res.accumulate(o); + i = i1; + } + } + + loop { + let len = i.eof_offset(); + match sep.parse_next(i.clone()) { + Err(ErrMode::Backtrack(_)) => return Ok((i, res)), + Err(e) => return Err(e), + Ok((i1, _)) => { + // infinite loop check: the parser must always consume + if i1.eof_offset() == len { + return Err(ErrMode::assert(i, "sep parsers must always consume")); + } + + match parser.parse_next(i1.clone()) { + Err(ErrMode::Backtrack(_)) => return Ok((i, res)), + Err(e) => return Err(e), + Ok((i2, o)) => { + res.accumulate(o); + i = i2; + } + } + } + } + } + }) +} + +/// Alternates between two parsers, merging the results (left associative) +/// +/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see +/// [`cut_err`][crate::combinator::cut_err]. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::separated_foldl1; +/// use winnow::ascii::dec_int; +/// +/// fn parser(s: &str) -> IResult<&str, i32> { +/// separated_foldl1(dec_int, "-", |l, _, r| l - r).parse_next(s) +/// } +/// +/// assert_eq!(parser("9-3-5"), Ok(("", 1))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(Error::new("def|abc", ErrorKind::Slice)))); +/// ``` +pub fn separated_foldl1( + mut parser: P, + mut sep: S, + op: Op, +) -> impl Parser +where + I: Stream, + P: Parser, + S: Parser, + E: ParseError, + Op: Fn(O, O2, O) -> O, +{ + trace("separated_foldl1", move |i: I| { + let (mut i, mut ol) = parser.parse_next(i)?; + + loop { + let len = i.eof_offset(); + match sep.parse_next(i.clone()) { + Err(ErrMode::Backtrack(_)) => return Ok((i, ol)), + Err(e) => return Err(e), + Ok((i1, s)) => { + // infinite loop check: the parser must always consume + if i1.eof_offset() == len { + return Err(ErrMode::assert(i, "`repeat` parsers must always consume")); + } + + match parser.parse_next(i1.clone()) { + Err(ErrMode::Backtrack(_)) => return Ok((i, ol)), + Err(e) => return Err(e), + Ok((i2, or)) => { + ol = op(ol, s, or); + i = i2; + } + } + } + } + } + }) +} + +/// Alternates between two parsers, merging the results (right associative) +/// +/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see +/// [`cut_err`][crate::combinator::cut_err]. +/// +/// # Example +/// +/// ``` +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::separated_foldr1; +/// use winnow::ascii::dec_uint; +/// +/// fn parser(s: &str) -> IResult<&str, u32> { +/// separated_foldr1(dec_uint, "^", |l: u32, _, r: u32| l.pow(r)).parse_next(s) +/// } +/// +/// assert_eq!(parser("2^3^2"), Ok(("", 512))); +/// assert_eq!(parser("2"), Ok(("", 2))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(Error::new("def|abc", ErrorKind::Slice)))); +/// ``` +#[cfg(feature = "alloc")] +pub fn separated_foldr1( + mut parser: P, + mut sep: S, + op: Op, +) -> impl Parser +where + I: Stream, + P: Parser, + S: Parser, + E: ParseError, + Op: Fn(O, O2, O) -> O, +{ + trace("separated_foldr1", move |i: I| { + let (i, ol) = parser.parse_next(i)?; + let (i, all): (_, crate::lib::std::vec::Vec<(O2, O)>) = + repeat(0.., (sep.by_ref(), parser.by_ref())).parse_next(i)?; + if let Some((s, or)) = all + .into_iter() + .rev() + .reduce(|(sr, or), (sl, ol)| (sl, op(ol, sr, or))) + { + let merged = op(ol, s, or); + Ok((i, merged)) + } else { + Ok((i, ol)) + } + }) +} + +fn repeat_m_n_( + min: usize, + max: usize, + parse: &mut F, + mut input: I, +) -> IResult +where + I: Stream, + C: Accumulate, + F: Parser, + E: ParseError, +{ + if min > max { + return Err(ErrMode::Cut(E::from_error_kind(input, ErrorKind::Many))); + } + + let mut res = C::initial(Some(min)); + for count in 0..max { + let len = input.eof_offset(); + match parse.parse_next(input.clone()) { + Ok((tail, value)) => { + // infinite loop check: the parser must always consume + if tail.eof_offset() == len { + return Err(ErrMode::assert( + input, + "`repeat` parsers must always consume", + )); + } + + res.accumulate(value); + input = tail; + } + Err(ErrMode::Backtrack(e)) => { + if count < min { + return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many))); + } else { + return Ok((input, res)); + } + } + Err(e) => { + return Err(e); + } + } + } + + Ok((input, res)) +} + +/// Deprecated, replaced by [`repeat`] +#[deprecated(since = "0.4.6", note = "Replaced with `repeat`")] +#[inline(always)] +pub fn count(f: F, count: usize) -> impl Parser +where + I: Stream, + C: Accumulate, + F: Parser, + E: ParseError, +{ + repeat(count, f) +} + +fn repeat_n_(count: usize, f: &mut F, i: I) -> IResult +where + I: Stream, + C: Accumulate, + F: Parser, + E: ParseError, +{ + let mut input = i.clone(); + let mut res = C::initial(Some(count)); + + for _ in 0..count { + let input_ = input.clone(); + match f.parse_next(input_) { + Ok((i, o)) => { + res.accumulate(o); + input = i; + } + Err(e) => { + return Err(e.append(i, ErrorKind::Many)); + } + } + } + + Ok((input, res)) +} + +/// Repeats the embedded parser, filling the given slice with results. +/// +/// This parser fails if the input runs out before the given slice is full. +/// +/// # Arguments +/// * `f` The parser to apply. +/// * `buf` The slice to fill +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::fill; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, [&str; 2]> { +/// let mut buf = ["", ""]; +/// let (rest, ()) = fill("abc", &mut buf).parse_next(s)?; +/// Ok((rest, buf)) +/// } +/// +/// assert_eq!(parser("abcabc"), Ok(("", ["abc", "abc"]))); +/// assert_eq!(parser("abc123"), Err(ErrMode::Backtrack(Error::new("123", ErrorKind::Tag)))); +/// assert_eq!(parser("123123"), Err(ErrMode::Backtrack(Error::new("123123", ErrorKind::Tag)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); +/// assert_eq!(parser("abcabcabc"), Ok(("abc", ["abc", "abc"]))); +/// ``` +pub fn fill<'a, I, O, E, F>(mut f: F, buf: &'a mut [O]) -> impl Parser + 'a +where + I: Stream + 'a, + F: Parser + 'a, + E: ParseError + 'a, +{ + trace("fill", move |i: I| { + let mut input = i.clone(); + + for elem in buf.iter_mut() { + let input_ = input.clone(); + match f.parse_next(input_) { + Ok((i, o)) => { + *elem = o; + input = i; + } + Err(e) => { + return Err(e.append(i, ErrorKind::Many)); + } + } + } + + Ok((input, ())) + }) +} + +/// Repeats the embedded parser `m..=n` times, calling `g` to gather the results +/// +/// This stops before `n` when the parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see +/// [`cut_err`][crate::combinator::cut_err]. +/// +/// # Arguments +/// * `m` The minimum number of iterations. +/// * `n` The maximum number of iterations. +/// * `f` The parser to apply. +/// * `init` A function returning the initial value. +/// * `g` The function that combines a result of `f` with +/// the current accumulator. +/// +/// **Warning:** If the parser passed to `fold_repeat` accepts empty inputs +/// (like `alpha0` or `digit0`), `fold_repeat` will return an error, +/// to prevent going into an infinite loop. +/// +/// # Example +/// +/// Zero or more repetitions: +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::fold_repeat; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// fold_repeat( +/// 0.., +/// "abc", +/// Vec::new, +/// |mut acc: Vec<_>, item| { +/// acc.push(item); +/// acc +/// } +/// ).parse_next(s) +/// } +/// +/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); +/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); +/// assert_eq!(parser("123123"), Ok(("123123", vec![]))); +/// assert_eq!(parser(""), Ok(("", vec![]))); +/// ``` +/// +/// One or more repetitions: +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::fold_repeat; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// fold_repeat( +/// 1.., +/// "abc", +/// Vec::new, +/// |mut acc: Vec<_>, item| { +/// acc.push(item); +/// acc +/// } +/// ).parse_next(s) +/// } +/// +/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); +/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); +/// assert_eq!(parser("123123"), Err(ErrMode::Backtrack(Error::new("123123", ErrorKind::Many)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Many)))); +/// ``` +/// +/// Arbitrary number of repetitions: +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::fold_repeat; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// fold_repeat( +/// 0..=2, +/// "abc", +/// Vec::new, +/// |mut acc: Vec<_>, item| { +/// acc.push(item); +/// acc +/// } +/// ).parse_next(s) +/// } +/// +/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); +/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); +/// assert_eq!(parser("123123"), Ok(("123123", vec![]))); +/// assert_eq!(parser(""), Ok(("", vec![]))); +/// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"]))); +/// ``` +#[doc(alias = "fold_many0")] +#[doc(alias = "fold_many1")] +#[doc(alias = "fold_many_m_n")] +#[inline(always)] +pub fn fold_repeat( + range: impl Into, + mut f: F, + mut init: H, + mut g: G, +) -> impl Parser +where + I: Stream, + F: Parser, + G: FnMut(R, O) -> R, + H: FnMut() -> R, + E: ParseError, +{ + let Range { + start_inclusive, + end_inclusive, + } = range.into(); + trace("fold_repeat", move |i: I| { + match (start_inclusive, end_inclusive) { + (0, None) => fold_repeat0_(&mut f, &mut init, &mut g, i), + (1, None) => fold_repeat1_(&mut f, &mut init, &mut g, i), + (start, end) => fold_repeat_m_n_( + start, + end.unwrap_or(usize::MAX), + &mut f, + &mut init, + &mut g, + i, + ), + } + }) +} + +/// Deprecated, replaced by [`fold_repeat`] +#[deprecated(since = "0.4.6", note = "Replaced with `fold_repeat`")] +#[inline(always)] +pub fn fold_repeat0(mut f: F, mut init: H, mut g: G) -> impl Parser +where + I: Stream, + F: Parser, + G: FnMut(R, O) -> R, + H: FnMut() -> R, + E: ParseError, +{ + trace("fold_repeat0", move |i: I| { + fold_repeat0_(&mut f, &mut init, &mut g, i) + }) +} + +fn fold_repeat0_(f: &mut F, init: &mut H, g: &mut G, i: I) -> IResult +where + I: Stream, + F: Parser, + G: FnMut(R, O) -> R, + H: FnMut() -> R, + E: ParseError, +{ + let mut res = init(); + let mut input = i; + + loop { + let i_ = input.clone(); + let len = input.eof_offset(); + match f.parse_next(i_) { + Ok((i, o)) => { + // infinite loop check: the parser must always consume + if i.eof_offset() == len { + return Err(ErrMode::assert(i, "`repeat` parsers must always consume")); + } + + res = g(res, o); + input = i; + } + Err(ErrMode::Backtrack(_)) => { + return Ok((input, res)); + } + Err(e) => { + return Err(e); + } + } + } +} + +/// Deprecated, replaced by [`fold_repeat`] +#[deprecated(since = "0.4.6", note = "Replaced with `fold_repeat`")] +#[inline(always)] +pub fn fold_repeat1(mut f: F, mut init: H, mut g: G) -> impl Parser +where + I: Stream, + F: Parser, + G: FnMut(R, O) -> R, + H: FnMut() -> R, + E: ParseError, +{ + trace("fold_repeat1", move |i: I| { + fold_repeat1_(&mut f, &mut init, &mut g, i) + }) +} + +fn fold_repeat1_(f: &mut F, init: &mut H, g: &mut G, i: I) -> IResult +where + I: Stream, + F: Parser, + G: FnMut(R, O) -> R, + H: FnMut() -> R, + E: ParseError, +{ + let _i = i.clone(); + let init = init(); + match f.parse_next(_i) { + Err(ErrMode::Backtrack(_)) => Err(ErrMode::from_error_kind(i, ErrorKind::Many)), + Err(e) => Err(e), + Ok((i1, o1)) => { + let mut acc = g(init, o1); + let mut input = i1; + + loop { + let _input = input.clone(); + let len = input.eof_offset(); + match f.parse_next(_input) { + Err(ErrMode::Backtrack(_)) => { + break; + } + Err(e) => return Err(e), + Ok((i, o)) => { + // infinite loop check: the parser must always consume + if i.eof_offset() == len { + return Err(ErrMode::assert(i, "`repeat` parsers must always consume")); + } + + acc = g(acc, o); + input = i; + } + } + } + + Ok((input, acc)) + } + } +} + +fn fold_repeat_m_n_( + min: usize, + max: usize, + parse: &mut F, + init: &mut H, + fold: &mut G, + mut input: I, +) -> IResult +where + I: Stream, + F: Parser, + G: FnMut(R, O) -> R, + H: FnMut() -> R, + E: ParseError, +{ + if min > max { + return Err(ErrMode::Cut(E::from_error_kind(input, ErrorKind::Many))); + } + + let mut acc = init(); + for count in 0..max { + let len = input.eof_offset(); + match parse.parse_next(input.clone()) { + Ok((tail, value)) => { + // infinite loop check: the parser must always consume + if tail.eof_offset() == len { + return Err(ErrMode::assert( + input, + "`repeat` parsers must always consume", + )); + } + + acc = fold(acc, value); + input = tail; + } + //FInputXMError: handle failure properly + Err(ErrMode::Backtrack(err)) => { + if count < min { + return Err(ErrMode::Backtrack(err.append(input, ErrorKind::Many))); + } else { + break; + } + } + Err(e) => return Err(e), + } + } + + Ok((input, acc)) +} diff --git a/vendor/winnow/src/combinator/parser.rs b/vendor/winnow/src/combinator/parser.rs new file mode 100644 index 000000000..12b223a2e --- /dev/null +++ b/vendor/winnow/src/combinator/parser.rs @@ -0,0 +1,827 @@ +use crate::error::{ContextError, ErrMode, ErrorKind, FromExternalError, 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::*; + +/// 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))), + } + } +} + +#[deprecated(since = "0.4.2", note = "Replaced with `TryMap`")] +pub use TryMap as MapRes; + +/// Implementation of [`Parser::try_map`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct TryMap +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 TryMap +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 TryMap +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) + } +} + +/// 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, ())) + } +} + +/// 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))) + }) + } +} + +/// 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)), + } + } +} + +/// 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/sequence.rs b/vendor/winnow/src/combinator/sequence.rs new file mode 100644 index 000000000..89c29a548 --- /dev/null +++ b/vendor/winnow/src/combinator/sequence.rs @@ -0,0 +1,164 @@ +use crate::error::ParseError; +use crate::stream::Stream; +use crate::trace::trace; +use crate::*; + +/// Sequence two parsers, only returning the output from the second. +/// +/// # Arguments +/// * `first` The opening parser. +/// * `second` The second parser to get object. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::combinator::preceded; +/// use winnow::token::tag; +/// +/// let mut parser = preceded("abc", "efg"); +/// +/// assert_eq!(parser.parse_next("abcefg"), Ok(("", "efg"))); +/// assert_eq!(parser.parse_next("abcefghij"), Ok(("hij", "efg"))); +/// assert_eq!(parser.parse_next(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); +/// assert_eq!(parser.parse_next("123"), Err(ErrMode::Backtrack(Error::new("123", ErrorKind::Tag)))); +/// ``` +#[doc(alias = "ignore_then")] +pub fn preceded, F, G>( + mut first: F, + mut second: G, +) -> impl Parser +where + I: Stream, + F: Parser, + G: Parser, +{ + trace("preceded", move |input: I| { + let (input, _) = first.parse_next(input)?; + second.parse_next(input) + }) +} + +/// Sequence two parsers, only returning the output of the first. +/// +/// # Arguments +/// * `first` The first parser to apply. +/// * `second` The second parser to match an object. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::error::Needed::Size; +/// use winnow::combinator::terminated; +/// use winnow::token::tag; +/// +/// let mut parser = terminated("abc", "efg"); +/// +/// assert_eq!(parser.parse_next("abcefg"), Ok(("", "abc"))); +/// assert_eq!(parser.parse_next("abcefghij"), Ok(("hij", "abc"))); +/// assert_eq!(parser.parse_next(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); +/// assert_eq!(parser.parse_next("123"), Err(ErrMode::Backtrack(Error::new("123", ErrorKind::Tag)))); +/// ``` +#[doc(alias = "then_ignore")] +pub fn terminated, F, G>( + mut first: F, + mut second: G, +) -> impl Parser +where + I: Stream, + F: Parser, + G: Parser, +{ + trace("terminated", move |input: I| { + let (input, o1) = first.parse_next(input)?; + second.parse_next(input).map(|(i, _)| (i, o1)) + }) +} + +/// Sequence three parsers, only returning the values of the first and third. +/// +/// # Arguments +/// * `first` The first parser to apply. +/// * `sep` The separator parser to apply. +/// * `second` The second parser to apply. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::error::Needed::Size; +/// # use winnow::prelude::*; +/// use winnow::combinator::separated_pair; +/// use winnow::token::tag; +/// +/// let mut parser = separated_pair("abc", "|", "efg"); +/// +/// assert_eq!(parser.parse_next("abc|efg"), Ok(("", ("abc", "efg")))); +/// assert_eq!(parser.parse_next("abc|efghij"), Ok(("hij", ("abc", "efg")))); +/// assert_eq!(parser.parse_next(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); +/// assert_eq!(parser.parse_next("123"), Err(ErrMode::Backtrack(Error::new("123", ErrorKind::Tag)))); +/// ``` +pub fn separated_pair, F, G, H>( + mut first: F, + mut sep: G, + mut second: H, +) -> impl Parser +where + I: Stream, + F: Parser, + G: Parser, + H: Parser, +{ + trace("separated_pair", move |input: I| { + let (input, o1) = first.parse_next(input)?; + let (input, _) = sep.parse_next(input)?; + second.parse_next(input).map(|(i, o2)| (i, (o1, o2))) + }) +} + +/// Sequence three parsers, only returning the output of the second. +/// +/// # Arguments +/// * `first` The first parser to apply and discard. +/// * `second` The second parser to apply. +/// * `third` The third parser to apply and discard. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::error::Needed::Size; +/// # use winnow::prelude::*; +/// use winnow::combinator::delimited; +/// use winnow::token::tag; +/// +/// let mut parser = delimited("(", "abc", ")"); +/// +/// assert_eq!(parser.parse_next("(abc)"), Ok(("", "abc"))); +/// assert_eq!(parser.parse_next("(abc)def"), Ok(("def", "abc"))); +/// assert_eq!(parser.parse_next(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); +/// assert_eq!(parser.parse_next("123"), Err(ErrMode::Backtrack(Error::new("123", ErrorKind::Tag)))); +/// ``` +#[doc(alias = "between")] +#[doc(alias = "padded")] +pub fn delimited, F, G, H>( + mut first: F, + mut second: G, + mut third: H, +) -> impl Parser +where + I: Stream, + F: Parser, + G: Parser, + H: Parser, +{ + trace("delimited", move |input: I| { + let (input, _) = first.parse_next(input)?; + let (input, o2) = second.parse_next(input)?; + third.parse_next(input).map(|(i, _)| (i, o2)) + }) +} diff --git a/vendor/winnow/src/combinator/tests.rs b/vendor/winnow/src/combinator/tests.rs index 4286286ae..cdb787760 100644 --- a/vendor/winnow/src/combinator/tests.rs +++ b/vendor/winnow/src/combinator/tests.rs @@ -1,19 +1,22 @@ use super::*; -use crate::bytes::take; +use crate::ascii::digit1 as digit; +use crate::binary::u16; +use crate::binary::u8; +use crate::binary::Endianness; 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::token::take; use crate::IResult; use crate::Parser; use crate::Partial; +#[cfg(feature = "alloc")] +use crate::lib::std::vec::Vec; + macro_rules! assert_parse( ($left: expr, $right: expr) => { let res: $crate::IResult<_, _, Error<_>> = $left; @@ -98,7 +101,7 @@ struct CustomError; #[allow(dead_code)] fn custom_error(input: &[u8]) -> IResult<&[u8], &[u8], CustomError> { //fix_error!(input, CustomError<_>, alphanumeric) - crate::character::alphanumeric1(input) + crate::ascii::alphanumeric1(input) } #[test] @@ -112,7 +115,7 @@ fn test_parser_flat_map() { #[allow(dead_code)] fn test_closure_compiles_195(input: &[u8]) -> IResult<&[u8], ()> { - u8.flat_map(|num| count(u16(Endianness::Big), num as usize)) + u8.flat_map(|num| repeat(num as usize, u16(Endianness::Big))) .parse_next(input) } @@ -146,8 +149,8 @@ fn test_parser_map_parser() { #[test] #[cfg(feature = "std")] fn test_parser_into() { - use crate::bytes::take; use crate::error::Error; + use crate::token::take; let mut parser = take::<_, _, Error<_>>(3u8).output_into(); let result: IResult<&[u8], Vec> = parser.parse_next(&b"abcdefg"[..]); @@ -226,7 +229,7 @@ fn not_test() { #[test] fn test_parser_verify() { - use crate::bytes::take; + use crate::token::take; fn test(i: Partial<&[u8]>) -> IResult, &[u8]> { take(5u8) @@ -253,7 +256,7 @@ fn test_parser_verify() { #[test] #[allow(unused)] fn test_parser_verify_ref() { - use crate::bytes::take; + use crate::token::take; let mut parser1 = take(3u8).verify(|s: &[u8]| s == &b"abc"[..]); @@ -270,7 +273,7 @@ fn test_parser_verify_ref() { ); fn parser2(i: &[u8]) -> IResult<&[u8], u32> { - crate::number::be_u32 + crate::binary::be_u32 .verify(|val: &u32| *val < 3) .parse_next(i) } @@ -279,7 +282,7 @@ fn test_parser_verify_ref() { #[test] #[cfg(feature = "alloc")] fn test_parser_verify_alloc() { - use crate::bytes::take; + use crate::token::take; let mut parser1 = take(3u8) .map(|s: &[u8]| s.to_vec()) .verify(|s: &[u8]| s == &b"abc"[..]); @@ -317,3 +320,948 @@ fn fail_test() { })) ); } + +#[test] +fn complete() { + fn err_test(i: &[u8]) -> IResult<&[u8], &[u8]> { + let (i, _) = "ijkl".parse_next(i)?; + "mnop".parse_next(i) + } + let a = &b"ijklmn"[..]; + + let res_a = err_test(a); + assert_eq!( + res_a, + Err(ErrMode::Backtrack(error_position!( + &b"mn"[..], + ErrorKind::Tag + ))) + ); +} + +#[test] +fn separated_pair_test() { + #[allow(clippy::type_complexity)] + fn sep_pair_abc_def(i: Partial<&[u8]>) -> IResult, (&[u8], &[u8])> { + separated_pair("abc", ",", "def").parse_next(i) + } + + assert_eq!( + sep_pair_abc_def(Partial::new(&b"abc,defghijkl"[..])), + Ok((Partial::new(&b"ghijkl"[..]), (&b"abc"[..], &b"def"[..]))) + ); + assert_eq!( + sep_pair_abc_def(Partial::new(&b"ab"[..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + sep_pair_abc_def(Partial::new(&b"abc,d"[..])), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_eq!( + sep_pair_abc_def(Partial::new(&b"xxx"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxx"[..]), + ErrorKind::Tag + ))) + ); + assert_eq!( + sep_pair_abc_def(Partial::new(&b"xxx,def"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxx,def"[..]), + ErrorKind::Tag + ))) + ); + assert_eq!( + sep_pair_abc_def(Partial::new(&b"abc,xxx"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxx"[..]), + ErrorKind::Tag + ))) + ); +} + +#[test] +fn preceded_test() { + fn preceded_abcd_efgh(i: Partial<&[u8]>) -> IResult, &[u8]> { + preceded("abcd", "efgh").parse_next(i) + } + + assert_eq!( + preceded_abcd_efgh(Partial::new(&b"abcdefghijkl"[..])), + Ok((Partial::new(&b"ijkl"[..]), &b"efgh"[..])) + ); + assert_eq!( + preceded_abcd_efgh(Partial::new(&b"ab"[..])), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_eq!( + preceded_abcd_efgh(Partial::new(&b"abcde"[..])), + Err(ErrMode::Incomplete(Needed::new(3))) + ); + assert_eq!( + preceded_abcd_efgh(Partial::new(&b"xxx"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxx"[..]), + ErrorKind::Tag + ))) + ); + assert_eq!( + preceded_abcd_efgh(Partial::new(&b"xxxxdef"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxxxdef"[..]), + ErrorKind::Tag + ))) + ); + assert_eq!( + preceded_abcd_efgh(Partial::new(&b"abcdxxx"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxx"[..]), + ErrorKind::Tag + ))) + ); +} + +#[test] +fn terminated_test() { + fn terminated_abcd_efgh(i: Partial<&[u8]>) -> IResult, &[u8]> { + terminated("abcd", "efgh").parse_next(i) + } + + assert_eq!( + terminated_abcd_efgh(Partial::new(&b"abcdefghijkl"[..])), + Ok((Partial::new(&b"ijkl"[..]), &b"abcd"[..])) + ); + assert_eq!( + terminated_abcd_efgh(Partial::new(&b"ab"[..])), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_eq!( + terminated_abcd_efgh(Partial::new(&b"abcde"[..])), + Err(ErrMode::Incomplete(Needed::new(3))) + ); + assert_eq!( + terminated_abcd_efgh(Partial::new(&b"xxx"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxx"[..]), + ErrorKind::Tag + ))) + ); + assert_eq!( + terminated_abcd_efgh(Partial::new(&b"xxxxdef"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxxxdef"[..]), + ErrorKind::Tag + ))) + ); + assert_eq!( + terminated_abcd_efgh(Partial::new(&b"abcdxxxx"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxxx"[..]), + ErrorKind::Tag + ))) + ); +} + +#[test] +fn delimited_test() { + fn delimited_abc_def_ghi(i: Partial<&[u8]>) -> IResult, &[u8]> { + delimited("abc", "def", "ghi").parse_next(i) + } + + assert_eq!( + delimited_abc_def_ghi(Partial::new(&b"abcdefghijkl"[..])), + Ok((Partial::new(&b"jkl"[..]), &b"def"[..])) + ); + assert_eq!( + delimited_abc_def_ghi(Partial::new(&b"ab"[..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + delimited_abc_def_ghi(Partial::new(&b"abcde"[..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + delimited_abc_def_ghi(Partial::new(&b"abcdefgh"[..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + delimited_abc_def_ghi(Partial::new(&b"xxx"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxx"[..]), + ErrorKind::Tag + ))) + ); + assert_eq!( + delimited_abc_def_ghi(Partial::new(&b"xxxdefghi"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxxdefghi"[..]), + ErrorKind::Tag + ),)) + ); + assert_eq!( + delimited_abc_def_ghi(Partial::new(&b"abcxxxghi"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxxghi"[..]), + ErrorKind::Tag + ))) + ); + assert_eq!( + delimited_abc_def_ghi(Partial::new(&b"abcdefxxx"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxx"[..]), + ErrorKind::Tag + ))) + ); +} + +#[cfg(feature = "alloc")] +#[test] +fn alt_test() { + #[cfg(feature = "alloc")] + use crate::{ + error::ParseError, + lib::std::{ + fmt::Debug, + string::{String, ToString}, + }, + }; + + #[cfg(feature = "alloc")] + #[derive(Debug, Clone, Eq, PartialEq)] + pub struct ErrorStr(String); + + #[cfg(feature = "alloc")] + impl From for ErrorStr { + fn from(i: u32) -> Self { + ErrorStr(format!("custom error code: {}", i)) + } + } + + #[cfg(feature = "alloc")] + impl<'a> From<&'a str> for ErrorStr { + fn from(i: &'a str) -> Self { + ErrorStr(format!("custom error message: {}", i)) + } + } + + #[cfg(feature = "alloc")] + impl ParseError for ErrorStr { + fn from_error_kind(input: I, kind: ErrorKind) -> Self { + ErrorStr(format!("custom error message: ({:?}, {:?})", input, kind)) + } + + fn append(self, input: I, kind: ErrorKind) -> Self { + ErrorStr(format!( + "custom error message: ({:?}, {:?}) - {:?}", + input, kind, self + )) + } + } + + fn work(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { + Ok((&b""[..], input)) + } + + #[allow(unused_variables)] + fn dont_work(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { + Err(ErrMode::Backtrack(ErrorStr("abcd".to_string()))) + } + + fn work2(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { + Ok((input, &b""[..])) + } + + fn alt1(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { + alt((dont_work, dont_work)).parse_next(i) + } + fn alt2(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { + alt((dont_work, work)).parse_next(i) + } + fn alt3(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { + alt((dont_work, dont_work, work2, dont_work)).parse_next(i) + } + //named!(alt1, alt!(dont_work | dont_work)); + //named!(alt2, alt!(dont_work | work)); + //named!(alt3, alt!(dont_work | dont_work | work2 | dont_work)); + + let a = &b"abcd"[..]; + assert_eq!( + alt1(a), + Err(ErrMode::Backtrack(error_node_position!( + a, + ErrorKind::Alt, + ErrorStr("abcd".to_string()) + ))) + ); + assert_eq!(alt2(a), Ok((&b""[..], a))); + assert_eq!(alt3(a), Ok((a, &b""[..]))); + + fn alt4(i: &[u8]) -> IResult<&[u8], &[u8]> { + alt(("abcd", "efgh")).parse_next(i) + } + let b = &b"efgh"[..]; + assert_eq!(alt4(a), Ok((&b""[..], a))); + assert_eq!(alt4(b), Ok((&b""[..], b))); +} + +#[test] +fn alt_incomplete() { + fn alt1(i: Partial<&[u8]>) -> IResult, &[u8]> { + alt(("a", "bc", "def")).parse_next(i) + } + + let a = &b""[..]; + assert_eq!( + alt1(Partial::new(a)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + let a = &b"b"[..]; + assert_eq!( + alt1(Partial::new(a)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + let a = &b"bcd"[..]; + assert_eq!( + alt1(Partial::new(a)), + Ok((Partial::new(&b"d"[..]), &b"bc"[..])) + ); + let a = &b"cde"[..]; + assert_eq!( + alt1(Partial::new(a)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(a), + ErrorKind::Tag + ))) + ); + let a = &b"de"[..]; + assert_eq!( + alt1(Partial::new(a)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + let a = &b"defg"[..]; + assert_eq!( + alt1(Partial::new(a)), + Ok((Partial::new(&b"g"[..]), &b"def"[..])) + ); +} + +#[test] +fn permutation_test() { + #[allow(clippy::type_complexity)] + fn perm(i: Partial<&[u8]>) -> IResult, (&[u8], &[u8], &[u8])> { + permutation(("abcd", "efg", "hi")).parse_next(i) + } + + let expected = (&b"abcd"[..], &b"efg"[..], &b"hi"[..]); + + let a = &b"abcdefghijk"[..]; + assert_eq!( + perm(Partial::new(a)), + Ok((Partial::new(&b"jk"[..]), expected)) + ); + let b = &b"efgabcdhijk"[..]; + assert_eq!( + perm(Partial::new(b)), + Ok((Partial::new(&b"jk"[..]), expected)) + ); + let c = &b"hiefgabcdjk"[..]; + assert_eq!( + perm(Partial::new(c)), + Ok((Partial::new(&b"jk"[..]), expected)) + ); + + let d = &b"efgxyzabcdefghi"[..]; + assert_eq!( + perm(Partial::new(d)), + Err(ErrMode::Backtrack(error_node_position!( + Partial::new(&b"efgxyzabcdefghi"[..]), + ErrorKind::Alt, + error_position!(Partial::new(&b"xyzabcdefghi"[..]), ErrorKind::Tag) + ))) + ); + + let e = &b"efgabc"[..]; + assert_eq!( + perm(Partial::new(e)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn separated0_test() { + fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { + separated0("abcd", ",").parse_next(i) + } + fn multi_empty(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { + separated0("", ",").parse_next(i) + } + fn multi_longsep(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { + separated0("abcd", "..").parse_next(i) + } + + let a = &b"abcdef"[..]; + let b = &b"abcd,abcdef"[..]; + let c = &b"azerty"[..]; + let d = &b",,abc"[..]; + let e = &b"abcd,abcd,ef"[..]; + let f = &b"abc"[..]; + let g = &b"abcd."[..]; + let h = &b"abcd,abc"[..]; + + let res1 = vec![&b"abcd"[..]]; + assert_eq!(multi(Partial::new(a)), Ok((Partial::new(&b"ef"[..]), res1))); + let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; + assert_eq!(multi(Partial::new(b)), Ok((Partial::new(&b"ef"[..]), res2))); + assert_eq!( + multi(Partial::new(c)), + Ok((Partial::new(&b"azerty"[..]), Vec::new())) + ); + let res3 = vec![&b""[..], &b""[..], &b""[..]]; + assert_eq!( + multi_empty(Partial::new(d)), + Ok((Partial::new(&b"abc"[..]), res3)) + ); + let res4 = vec![&b"abcd"[..], &b"abcd"[..]]; + assert_eq!( + multi(Partial::new(e)), + Ok((Partial::new(&b",ef"[..]), res4)) + ); + + assert_eq!( + multi(Partial::new(f)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + multi_longsep(Partial::new(g)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + multi(Partial::new(h)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +#[cfg_attr(debug_assertions, should_panic)] +fn separated0_empty_sep_test() { + fn empty_sep(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { + separated0("abc", "").parse_next(i) + } + + let i = &b"abcabc"[..]; + + let i_err_pos = &i[3..]; + assert_eq!( + empty_sep(Partial::new(i)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(i_err_pos), + ErrorKind::Assert + ))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn separated1_test() { + fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { + separated1("abcd", ",").parse_next(i) + } + fn multi_longsep(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { + separated1("abcd", "..").parse_next(i) + } + + let a = &b"abcdef"[..]; + let b = &b"abcd,abcdef"[..]; + let c = &b"azerty"[..]; + let d = &b"abcd,abcd,ef"[..]; + + let f = &b"abc"[..]; + let g = &b"abcd."[..]; + let h = &b"abcd,abc"[..]; + + let res1 = vec![&b"abcd"[..]]; + assert_eq!(multi(Partial::new(a)), Ok((Partial::new(&b"ef"[..]), res1))); + let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; + assert_eq!(multi(Partial::new(b)), Ok((Partial::new(&b"ef"[..]), res2))); + assert_eq!( + multi(Partial::new(c)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(c), + ErrorKind::Tag + ))) + ); + let res3 = vec![&b"abcd"[..], &b"abcd"[..]]; + assert_eq!( + multi(Partial::new(d)), + Ok((Partial::new(&b",ef"[..]), res3)) + ); + + assert_eq!( + multi(Partial::new(f)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + multi_longsep(Partial::new(g)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + multi(Partial::new(h)), + Err(ErrMode::Incomplete(Needed::new(1))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn repeat0_test() { + fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { + repeat(0.., "abcd").parse_next(i) + } + + assert_eq!( + multi(Partial::new(&b"abcdef"[..])), + Ok((Partial::new(&b"ef"[..]), vec![&b"abcd"[..]])) + ); + assert_eq!( + multi(Partial::new(&b"abcdabcdefgh"[..])), + Ok((Partial::new(&b"efgh"[..]), vec![&b"abcd"[..], &b"abcd"[..]])) + ); + assert_eq!( + multi(Partial::new(&b"azerty"[..])), + Ok((Partial::new(&b"azerty"[..]), Vec::new())) + ); + assert_eq!( + multi(Partial::new(&b"abcdab"[..])), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_eq!( + multi(Partial::new(&b"abcd"[..])), + Err(ErrMode::Incomplete(Needed::new(4))) + ); + assert_eq!( + multi(Partial::new(&b""[..])), + Err(ErrMode::Incomplete(Needed::new(4))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +#[cfg_attr(debug_assertions, should_panic)] +fn repeat0_empty_test() { + fn multi_empty(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { + repeat(0.., "").parse_next(i) + } + + assert_eq!( + multi_empty(Partial::new(&b"abcdef"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"abcdef"[..]), + ErrorKind::Assert + ))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn repeat1_test() { + fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { + repeat(1.., "abcd").parse_next(i) + } + + let a = &b"abcdef"[..]; + let b = &b"abcdabcdefgh"[..]; + let c = &b"azerty"[..]; + let d = &b"abcdab"[..]; + + let res1 = vec![&b"abcd"[..]]; + assert_eq!(multi(Partial::new(a)), Ok((Partial::new(&b"ef"[..]), res1))); + let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; + assert_eq!( + multi(Partial::new(b)), + Ok((Partial::new(&b"efgh"[..]), res2)) + ); + assert_eq!( + multi(Partial::new(c)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(c), + ErrorKind::Tag + ))) + ); + assert_eq!( + multi(Partial::new(d)), + Err(ErrMode::Incomplete(Needed::new(2))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn repeat_till_test() { + #[allow(clippy::type_complexity)] + fn multi(i: &[u8]) -> IResult<&[u8], (Vec<&[u8]>, &[u8])> { + repeat_till0("abcd", "efgh").parse_next(i) + } + + let a = b"abcdabcdefghabcd"; + let b = b"efghabcd"; + let c = b"azerty"; + + let res_a = (vec![&b"abcd"[..], &b"abcd"[..]], &b"efgh"[..]); + let res_b: (Vec<&[u8]>, &[u8]) = (Vec::new(), &b"efgh"[..]); + assert_eq!(multi(&a[..]), Ok((&b"abcd"[..], res_a))); + assert_eq!(multi(&b[..]), Ok((&b"abcd"[..], res_b))); + assert_eq!( + multi(&c[..]), + Err(ErrMode::Backtrack(error_node_position!( + &c[..], + ErrorKind::Many, + error_position!(&c[..], ErrorKind::Tag) + ))) + ); +} + +#[test] +#[cfg(feature = "std")] +fn infinite_many() { + fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> { + println!("input: {:?}", input); + Err(ErrMode::Backtrack(error_position!(input, ErrorKind::Tag))) + } + + // should not go into an infinite loop + fn multi0(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + repeat(0.., tst).parse_next(i) + } + let a = &b"abcdef"[..]; + assert_eq!(multi0(a), Ok((a, Vec::new()))); + + fn multi1(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + repeat(1.., tst).parse_next(i) + } + let a = &b"abcdef"[..]; + assert_eq!( + multi1(a), + Err(ErrMode::Backtrack(error_position!(a, ErrorKind::Tag))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn repeat_test() { + fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { + repeat(2..=4, "Abcd").parse_next(i) + } + + let a = &b"Abcdef"[..]; + let b = &b"AbcdAbcdefgh"[..]; + let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; + let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..]; + let e = &b"AbcdAb"[..]; + + assert_eq!( + multi(Partial::new(a)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"ef"[..]), + ErrorKind::Tag + ))) + ); + let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; + assert_eq!( + multi(Partial::new(b)), + Ok((Partial::new(&b"efgh"[..]), res1)) + ); + let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; + assert_eq!( + multi(Partial::new(c)), + Ok((Partial::new(&b"efgh"[..]), res2)) + ); + let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; + assert_eq!( + multi(Partial::new(d)), + Ok((Partial::new(&b"Abcdefgh"[..]), res3)) + ); + assert_eq!( + multi(Partial::new(e)), + Err(ErrMode::Incomplete(Needed::new(2))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn count_test() { + const TIMES: usize = 2; + fn cnt_2(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { + repeat(TIMES, "abc").parse_next(i) + } + + assert_eq!( + cnt_2(Partial::new(&b"abcabcabcdef"[..])), + Ok((Partial::new(&b"abcdef"[..]), vec![&b"abc"[..], &b"abc"[..]])) + ); + assert_eq!( + cnt_2(Partial::new(&b"ab"[..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + cnt_2(Partial::new(&b"abcab"[..])), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + cnt_2(Partial::new(&b"xxx"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxx"[..]), + ErrorKind::Tag + ))) + ); + assert_eq!( + cnt_2(Partial::new(&b"xxxabcabcdef"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxxabcabcdef"[..]), + ErrorKind::Tag + ))) + ); + assert_eq!( + cnt_2(Partial::new(&b"abcxxxabcdef"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"xxxabcdef"[..]), + ErrorKind::Tag + ))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn count_zero() { + const TIMES: usize = 0; + fn counter_2(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + repeat(TIMES, "abc").parse_next(i) + } + + let done = &b"abcabcabcdef"[..]; + let parsed_done = Vec::new(); + let rest = done; + let incomplete_1 = &b"ab"[..]; + let parsed_incompl_1 = Vec::new(); + let incomplete_2 = &b"abcab"[..]; + let parsed_incompl_2 = Vec::new(); + let error = &b"xxx"[..]; + let error_remain = &b"xxx"[..]; + let parsed_err = Vec::new(); + let error_1 = &b"xxxabcabcdef"[..]; + let parsed_err_1 = Vec::new(); + let error_1_remain = &b"xxxabcabcdef"[..]; + let error_2 = &b"abcxxxabcdef"[..]; + let parsed_err_2 = Vec::new(); + let error_2_remain = &b"abcxxxabcdef"[..]; + + assert_eq!(counter_2(done), Ok((rest, parsed_done))); + assert_eq!( + counter_2(incomplete_1), + Ok((incomplete_1, parsed_incompl_1)) + ); + assert_eq!( + counter_2(incomplete_2), + Ok((incomplete_2, parsed_incompl_2)) + ); + assert_eq!(counter_2(error), Ok((error_remain, parsed_err))); + assert_eq!(counter_2(error_1), Ok((error_1_remain, parsed_err_1))); + assert_eq!(counter_2(error_2), Ok((error_2_remain, parsed_err_2))); +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct NilError; + +impl From<(I, ErrorKind)> for NilError { + fn from(_: (I, ErrorKind)) -> Self { + NilError + } +} + +impl ParseError for NilError { + fn from_error_kind(_: I, _: ErrorKind) -> NilError { + NilError + } + fn append(self, _: I, _: ErrorKind) -> NilError { + NilError + } +} + +#[test] +#[cfg(feature = "alloc")] +fn fold_repeat0_test() { + fn fold_into_vec(mut acc: Vec, item: T) -> Vec { + acc.push(item); + acc + } + fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { + fold_repeat(0.., "abcd", Vec::new, fold_into_vec).parse_next(i) + } + + assert_eq!( + multi(Partial::new(&b"abcdef"[..])), + Ok((Partial::new(&b"ef"[..]), vec![&b"abcd"[..]])) + ); + assert_eq!( + multi(Partial::new(&b"abcdabcdefgh"[..])), + Ok((Partial::new(&b"efgh"[..]), vec![&b"abcd"[..], &b"abcd"[..]])) + ); + assert_eq!( + multi(Partial::new(&b"azerty"[..])), + Ok((Partial::new(&b"azerty"[..]), Vec::new())) + ); + assert_eq!( + multi(Partial::new(&b"abcdab"[..])), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_eq!( + multi(Partial::new(&b"abcd"[..])), + Err(ErrMode::Incomplete(Needed::new(4))) + ); + assert_eq!( + multi(Partial::new(&b""[..])), + Err(ErrMode::Incomplete(Needed::new(4))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +#[cfg_attr(debug_assertions, should_panic)] +fn fold_repeat0_empty_test() { + fn fold_into_vec(mut acc: Vec, item: T) -> Vec { + acc.push(item); + acc + } + fn multi_empty(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { + fold_repeat(0.., "", Vec::new, fold_into_vec).parse_next(i) + } + + assert_eq!( + multi_empty(Partial::new(&b"abcdef"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"abcdef"[..]), + ErrorKind::Assert + ))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn fold_repeat1_test() { + fn fold_into_vec(mut acc: Vec, item: T) -> Vec { + acc.push(item); + acc + } + fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { + fold_repeat(1.., "abcd", Vec::new, fold_into_vec).parse_next(i) + } + + let a = &b"abcdef"[..]; + let b = &b"abcdabcdefgh"[..]; + let c = &b"azerty"[..]; + let d = &b"abcdab"[..]; + + let res1 = vec![&b"abcd"[..]]; + assert_eq!(multi(Partial::new(a)), Ok((Partial::new(&b"ef"[..]), res1))); + let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; + assert_eq!( + multi(Partial::new(b)), + Ok((Partial::new(&b"efgh"[..]), res2)) + ); + assert_eq!( + multi(Partial::new(c)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(c), + ErrorKind::Many + ))) + ); + assert_eq!( + multi(Partial::new(d)), + Err(ErrMode::Incomplete(Needed::new(2))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn fold_repeat_test() { + fn fold_into_vec(mut acc: Vec, item: T) -> Vec { + acc.push(item); + acc + } + fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { + fold_repeat(2..=4, "Abcd", Vec::new, fold_into_vec).parse_next(i) + } + + let a = &b"Abcdef"[..]; + let b = &b"AbcdAbcdefgh"[..]; + let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; + let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..]; + let e = &b"AbcdAb"[..]; + + assert_eq!( + multi(Partial::new(a)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"ef"[..]), + ErrorKind::Tag + ))) + ); + let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; + assert_eq!( + multi(Partial::new(b)), + Ok((Partial::new(&b"efgh"[..]), res1)) + ); + let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; + assert_eq!( + multi(Partial::new(c)), + Ok((Partial::new(&b"efgh"[..]), res2)) + ); + let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; + assert_eq!( + multi(Partial::new(d)), + Ok((Partial::new(&b"Abcdefgh"[..]), res3)) + ); + assert_eq!( + multi(Partial::new(e)), + Err(ErrMode::Incomplete(Needed::new(2))) + ); +} + +#[test] +fn repeat0_count_test() { + fn count0_nums(i: &[u8]) -> IResult<&[u8], usize> { + repeat(0.., (digit, ",")).parse_next(i) + } + + assert_eq!(count0_nums(&b"123,junk"[..]), Ok((&b"junk"[..], 1))); + + assert_eq!(count0_nums(&b"123,45,junk"[..]), Ok((&b"junk"[..], 2))); + + assert_eq!( + count0_nums(&b"1,2,3,4,5,6,7,8,9,0,junk"[..]), + Ok((&b"junk"[..], 10)) + ); + + assert_eq!(count0_nums(&b"hello"[..]), Ok((&b"hello"[..], 0))); +} + +#[test] +fn repeat1_count_test() { + fn count1_nums(i: &[u8]) -> IResult<&[u8], usize> { + repeat(1.., (digit, ",")).parse_next(i) + } + + assert_eq!(count1_nums(&b"123,45,junk"[..]), Ok((&b"junk"[..], 2))); + + assert_eq!( + count1_nums(&b"1,2,3,4,5,6,7,8,9,0,junk"[..]), + Ok((&b"junk"[..], 10)) + ); + + assert_eq!( + count1_nums(&b"hello"[..]), + Err(ErrMode::Backtrack(error_position!( + &b"hello"[..], + ErrorKind::Slice + ))) + ); +} diff --git a/vendor/winnow/src/error.rs b/vendor/winnow/src/error.rs index b49b0560a..c92228621 100644 --- a/vendor/winnow/src/error.rs +++ b/vendor/winnow/src/error.rs @@ -58,10 +58,10 @@ pub trait FinishIResult { /// /// # Example /// - #[cfg_attr(not(feature = "std"), doc = "```ignore")] - #[cfg_attr(feature = "std", doc = "```")] + /// ```rust + /// # #[cfg(feature = "std")] { /// use winnow::prelude::*; - /// use winnow::character::hex_uint; + /// use winnow::ascii::hex_uint; /// use winnow::error::Error; /// /// struct Hex(u64); @@ -69,6 +69,7 @@ pub trait FinishIResult { /// fn parse(value: &str) -> Result> { /// hex_uint.map(Hex).parse_next(value).finish().map_err(Error::into_owned) /// } + /// # } /// ``` #[deprecated(since = "0.4.0", note = "Replaced with `Parser::parse`")] fn finish(self) -> Result; @@ -176,7 +177,7 @@ pub enum ErrMode { /// The parser failed with a recoverable error (the default). /// /// For example, a parser for json values might include a - /// [`dec_uint`][crate::character::dec_uint] as one case in an [`alt`][crate::branch::alt] + /// [`dec_uint`][crate::ascii::dec_uint] as one case in an [`alt`][crate::combinator::alt] /// combiantor. If it fails, the next case should be tried. Backtrack(E), /// The parser had an unrecoverable error. @@ -185,7 +186,7 @@ pub enum ErrMode { /// other branches. You can use [`cut_err()`][crate::combinator::cut_err] combinator to switch /// from `ErrMode::Backtrack` to `ErrMode::Cut`. /// - /// For example, one case in an [`alt`][crate::branch::alt] combinator found a unique prefix + /// For example, one case in an [`alt`][crate::combinator::alt] combinator found a unique prefix /// and you want any further errors parsing the case to be reported to the user. Cut(E), } @@ -335,7 +336,7 @@ pub trait ParseError: Sized { /// Combines errors from two different parse branches. /// - /// For example, this would be used by [`alt`][crate::branch::alt] to report the error from + /// For example, this would be used by [`alt`][crate::combinator::alt] to report the error from /// each case. fn or(self, other: Self) -> Self { other @@ -357,7 +358,7 @@ pub trait ContextError: Sized { /// Create a new error with an external error, from [`std::str::FromStr`] /// -/// This trait is required by the [`Parser::map_res`] combinator. +/// This trait is required by the [`Parser::try_map`] combinator. pub trait FromExternalError { /// Like [`ParseError::from_error_kind`] but also include an external error. fn from_external_error(input: I, kind: ErrorKind, e: E) -> Self; @@ -374,7 +375,7 @@ pub trait ErrorConvert { /// This is a low-overhead error that only provides basic information. For less overhead, see /// `()`. Fore more information, see [`VerboseError`]. ///:w -/// **Note:** [context][Parser::context] and inner errors (like from [`Parser::map_res`]) will be +/// **Note:** [context][Parser::context] and inner errors (like from [`Parser::try_map`]) will be /// dropped. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct Error { @@ -472,7 +473,7 @@ impl ErrorConvert<()> for () { /// [`convert_error`] provides an example of how to render this for end-users. /// /// **Note:** This will only capture the last failed branch for combinators like -/// [`alt`][crate::branch::alt]. +/// [`alt`][crate::combinator::alt]. #[cfg(feature = "alloc")] #[derive(Clone, Debug, Eq, PartialEq)] pub struct VerboseError { diff --git a/vendor/winnow/src/lib.rs b/vendor/winnow/src/lib.rs index ddbc8f812..3b6066230 100644 --- a/vendor/winnow/src/lib.rs +++ b/vendor/winnow/src/lib.rs @@ -24,7 +24,7 @@ //! - Resilient maintainership, including //! - Willing to break compatibility rather than batching up breaking changes in large releases //! - Leverage feature flags to keep one active branch -//! - We will support the last 6 months of rust releases (MSRV, currently 1.60) +//! - We will support the last 6 months of rust releases (MSRV, currently 1.64.0) //! //! See also [Special Topic: Why winnow?][crate::_topic::why] //! @@ -48,7 +48,7 @@ #![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(docsrs, feature(extended_key_value_attributes))] #![cfg_attr(not(feature = "std"), no_std)] -#![deny(missing_docs)] +#![warn(missing_docs)] // BEGIN - Embark standard lints v6 for Rust 1.55+ // do not change or add/remove here, but one can add exceptions after this section // for more info see: @@ -199,6 +199,8 @@ mod parser; pub mod stream; +pub mod ascii; +pub mod binary; pub mod bits; pub mod branch; pub mod bytes; @@ -207,6 +209,7 @@ pub mod combinator; pub mod multi; pub mod number; pub mod sequence; +pub mod token; pub mod trace; #[cfg(feature = "unstable-doc")] @@ -227,7 +230,7 @@ pub mod _tutorial; /// /// fn parse_data(input: &str) -> IResult<&str, u64> { /// // ... -/// # winnow::character::dec_uint(input) +/// # winnow::ascii::dec_uint(input) /// } /// /// fn main() { diff --git a/vendor/winnow/src/macros.rs b/vendor/winnow/src/macros.rs index bec67c1a3..8a38ef25c 100644 --- a/vendor/winnow/src/macros.rs +++ b/vendor/winnow/src/macros.rs @@ -1,7 +1,7 @@ /// `match` for parsers /// /// When parsers have unique prefixes to test for, this offers better performance over -/// [`alt`][crate::branch::alt] though it might be at the cost of duplicating parts of your grammar +/// [`alt`][crate::combinator::alt] though it might be at the cost of duplicating parts of your grammar /// if you needed to [`peek`][crate::combinator::peek]. /// /// For tight control over the error in a catch-all case, use [`fail`][crate::combinator::fail]. @@ -10,10 +10,10 @@ /// /// ```rust /// use winnow::prelude::*; -/// use winnow::branch::dispatch; -/// # use winnow::bytes::any; +/// use winnow::combinator::dispatch; +/// # use winnow::token::any; /// # use winnow::combinator::peek; -/// # use winnow::sequence::preceded; +/// # use winnow::combinator::preceded; /// # use winnow::combinator::success; /// # use winnow::combinator::fail; /// diff --git a/vendor/winnow/src/multi.rs b/vendor/winnow/src/multi.rs new file mode 100644 index 000000000..3e92f70be --- /dev/null +++ b/vendor/winnow/src/multi.rs @@ -0,0 +1,124 @@ +//! Deprecated, see [`combinator`] +#![deprecated(since = "0.4.2", note = "Replaced with `combinator`")] + +use crate::binary; +use crate::combinator; +use crate::error::ParseError; +use crate::stream::Accumulate; +use crate::stream::Stream; +use crate::Parser; + +/// Deprecated, replaced by [`combinator::repeat`] +#[deprecated(since = "0.4.2", note = "Replaced with `combinator::repeat`")] +#[inline(always)] +pub fn many0(f: F) -> impl Parser +where + I: Stream, + C: Accumulate, + F: Parser, + E: ParseError, +{ + combinator::repeat(0.., f) +} + +/// Deprecated, replaced by [`combinator::repeat`] +#[deprecated(since = "0.4.2", note = "Replaced with `combinator::repeat`")] +#[inline(always)] +pub fn many1(f: F) -> impl Parser +where + I: Stream, + C: Accumulate, + F: Parser, + E: ParseError, +{ + combinator::repeat(1.., f) +} + +/// Deprecated, replaced by [`combinator::repeat_till0`] +#[deprecated(since = "0.4.2", note = "Replaced with `combinator::repeat_till0`")] +#[inline(always)] +pub fn many_till0(f: F, g: G) -> impl Parser +where + I: Stream, + C: Accumulate, + F: Parser, + G: Parser, + E: ParseError, +{ + combinator::repeat_till0(f, g) +} + +pub use combinator::separated0; +pub use combinator::separated1; +pub use combinator::separated_foldl1; +#[cfg(feature = "alloc")] +pub use combinator::separated_foldr1; + +/// Deprecated, replaced by [`combinator::repeat`] +#[deprecated(since = "0.4.2", note = "Replaced with `combinator::repeat`")] +#[inline(always)] +pub fn many_m_n(min: usize, max: usize, parse: F) -> impl Parser +where + I: Stream, + C: Accumulate, + F: Parser, + E: ParseError, +{ + combinator::repeat(min..=max, parse) +} + +#[allow(deprecated)] +pub use combinator::count; +pub use combinator::fill; + +/// Deprecated, replaced by [`combinator::fold_repeat`] +#[deprecated(since = "0.4.2", note = "Replaced with `combinator::fold_repeat`")] +#[inline(always)] +pub fn fold_many0(f: F, init: H, g: G) -> impl Parser +where + I: Stream, + F: Parser, + G: FnMut(R, O) -> R, + H: FnMut() -> R, + E: ParseError, +{ + combinator::fold_repeat(0.., f, init, g) +} + +/// Deprecated, replaced by [`combinator::fold_repeat`] +#[deprecated(since = "0.4.2", note = "Replaced with `combinator::fold_repeat`")] +#[inline(always)] +pub fn fold_many1(f: F, init: H, g: G) -> impl Parser +where + I: Stream, + F: Parser, + G: FnMut(R, O) -> R, + H: FnMut() -> R, + E: ParseError, +{ + combinator::fold_repeat(1.., f, init, g) +} + +/// Deprecated, replaced by [`combinator::fold_repeat`] +#[deprecated(since = "0.4.2", note = "Replaced with `combinator::fold_repeat`")] +#[inline(always)] +pub fn fold_many_m_n( + min: usize, + max: usize, + parse: F, + init: H, + fold: G, +) -> impl Parser +where + I: Stream, + F: Parser, + G: FnMut(R, O) -> R, + H: FnMut() -> R, + E: ParseError, +{ + combinator::fold_repeat(min..=max, parse, init, fold) +} + +pub use binary::length_count; +pub use binary::length_data; +pub use binary::length_value; diff --git a/vendor/winnow/src/multi/mod.rs b/vendor/winnow/src/multi/mod.rs deleted file mode 100644 index 1c3aed7ba..000000000 --- a/vendor/winnow/src/multi/mod.rs +++ /dev/null @@ -1,1065 +0,0 @@ -//! Combinators applying their child parser multiple times - -#[cfg(test)] -mod tests; - -use crate::error::ErrMode; -use crate::error::ErrorKind; -use crate::error::ParseError; -use crate::stream::Accumulate; -use crate::stream::{Stream, StreamIsPartial, ToUsize, UpdateSlice}; -use crate::trace::trace; -use crate::Parser; - -/// [`Accumulate`] the output of a parser into a container, like `Vec` -/// -/// This stops on [`ErrMode::Backtrack`]. To instead chain an error up, see -/// [`cut_err`][crate::combinator::cut_err]. -/// -/// To recognize a series of tokens, [`Accumulate`] into a `()` and then [`Parser::recognize`]. -/// -/// **Warning:** if the parser passed in accepts empty inputs (like `alpha0` or `digit0`), `many0` will -/// return an error, to prevent going into an infinite loop -/// -/// # Example -/// -#[cfg_attr(not(feature = "std"), doc = "```ignore")] -#[cfg_attr(feature = "std", doc = "```")] -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::multi::many0; -/// use winnow::bytes::tag; -/// -/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { -/// many0("abc").parse_next(s) -/// } -/// -/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); -/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); -/// assert_eq!(parser("123123"), Ok(("123123", vec![]))); -/// assert_eq!(parser(""), Ok(("", vec![]))); -/// ``` -#[doc(alias = "skip_many")] -#[doc(alias = "repeated")] -#[doc(alias = "many0_count")] -pub fn many0(mut f: F) -> impl Parser -where - I: Stream, - C: Accumulate, - F: Parser, - E: ParseError, -{ - trace("many0", move |mut i: I| { - let mut acc = C::initial(None); - loop { - let len = i.eof_offset(); - match f.parse_next(i.clone()) { - Err(ErrMode::Backtrack(_)) => return Ok((i, acc)), - Err(e) => return Err(e), - Ok((i1, o)) => { - // infinite loop check: the parser must always consume - if i1.eof_offset() == len { - return Err(ErrMode::assert(i, "many parsers must always consume")); - } - - i = i1; - acc.accumulate(o); - } - } - } - }) -} - -/// [`Accumulate`] the output of a parser into a container, like `Vec` -/// -/// -/// This stops on [`ErrMode::Backtrack`] if there is at least one result. To instead chain an error up, -/// see [`cut_err`][crate::combinator::cut_err]. -/// -/// # Arguments -/// * `f` The parser to apply. -/// -/// To recognize a series of tokens, [`Accumulate`] into a `()` and then [`Parser::recognize`]. -/// -/// **Warning:** If the parser passed to `many1` accepts empty inputs -/// (like `alpha0` or `digit0`), `many1` will return an error, -/// to prevent going into an infinite loop. -/// -/// # Example -/// -#[cfg_attr(not(feature = "std"), doc = "```ignore")] -#[cfg_attr(feature = "std", doc = "```")] -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::multi::many1; -/// use winnow::bytes::tag; -/// -/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { -/// many1("abc").parse_next(s) -/// } -/// -/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); -/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); -/// assert_eq!(parser("123123"), Err(ErrMode::Backtrack(Error::new("123123", ErrorKind::Tag)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); -/// ``` -#[doc(alias = "skip_many1")] -#[doc(alias = "repeated")] -#[doc(alias = "many1_count")] -pub fn many1(mut f: F) -> impl Parser -where - I: Stream, - C: Accumulate, - F: Parser, - E: ParseError, -{ - trace("many1", move |mut i: I| match f.parse_next(i.clone()) { - Err(e) => Err(e.append(i, ErrorKind::Many)), - Ok((i1, o)) => { - let mut acc = C::initial(None); - acc.accumulate(o); - i = i1; - - loop { - let len = i.eof_offset(); - match f.parse_next(i.clone()) { - Err(ErrMode::Backtrack(_)) => return Ok((i, acc)), - Err(e) => return Err(e), - Ok((i1, o)) => { - // infinite loop check: the parser must always consume - if i1.eof_offset() == len { - return Err(ErrMode::assert(i, "many parsers must always consume")); - } - - i = i1; - acc.accumulate(o); - } - } - } - } - }) -} - -/// Applies the parser `f` until the parser `g` produces a result. -/// -/// Returns a tuple of the results of `f` in a `Vec` and the result of `g`. -/// -/// `f` keeps going so long as `g` produces [`ErrMode::Backtrack`]. To instead chain an error up, see [`cut_err`][crate::combinator::cut_err]. -/// -/// To recognize a series of tokens, [`Accumulate`] into a `()` and then [`Parser::recognize`]. -/// -/// # Example -/// -#[cfg_attr(not(feature = "std"), doc = "```ignore")] -#[cfg_attr(feature = "std", doc = "```")] -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::multi::many_till0; -/// use winnow::bytes::tag; -/// -/// fn parser(s: &str) -> IResult<&str, (Vec<&str>, &str)> { -/// many_till0("abc", "end").parse_next(s) -/// }; -/// -/// assert_eq!(parser("abcabcend"), Ok(("", (vec!["abc", "abc"], "end")))); -/// assert_eq!(parser("abc123end"), Err(ErrMode::Backtrack(Error::new("123end", ErrorKind::Tag)))); -/// assert_eq!(parser("123123end"), Err(ErrMode::Backtrack(Error::new("123123end", ErrorKind::Tag)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); -/// assert_eq!(parser("abcendefg"), Ok(("efg", (vec!["abc"], "end")))); -/// ``` -pub fn many_till0(mut f: F, mut g: G) -> impl Parser -where - I: Stream, - C: Accumulate, - F: Parser, - G: Parser, - E: ParseError, -{ - trace("many_till0", move |mut i: I| { - let mut res = C::initial(None); - loop { - let len = i.eof_offset(); - match g.parse_next(i.clone()) { - Ok((i1, o)) => return Ok((i1, (res, o))), - Err(ErrMode::Backtrack(_)) => { - match f.parse_next(i.clone()) { - Err(e) => return Err(e.append(i, ErrorKind::Many)), - Ok((i1, o)) => { - // infinite loop check: the parser must always consume - if i1.eof_offset() == len { - return Err(ErrMode::assert(i, "many parsers must always consume")); - } - - res.accumulate(o); - i = i1; - } - } - } - Err(e) => return Err(e), - } - } - }) -} - -/// Alternates between two parsers to produce a list of elements. -/// -/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see -/// [`cut_err`][crate::combinator::cut_err]. -/// -/// # Arguments -/// * `parser` Parses the elements of the list. -/// * `sep` Parses the separator between list elements. -/// -/// # Example -/// -#[cfg_attr(not(feature = "std"), doc = "```ignore")] -#[cfg_attr(feature = "std", doc = "```")] -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::multi::separated0; -/// use winnow::bytes::tag; -/// -/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { -/// separated0("abc", "|").parse_next(s) -/// } -/// -/// assert_eq!(parser("abc|abc|abc"), Ok(("", vec!["abc", "abc", "abc"]))); -/// assert_eq!(parser("abc123abc"), Ok(("123abc", vec!["abc"]))); -/// assert_eq!(parser("abc|def"), Ok(("|def", vec!["abc"]))); -/// assert_eq!(parser(""), Ok(("", vec![]))); -/// assert_eq!(parser("def|abc"), Ok(("def|abc", vec![]))); -/// ``` -#[doc(alias = "sep_by")] -#[doc(alias = "separated_list0")] -pub fn separated0(mut parser: P, mut sep: S) -> impl Parser -where - I: Stream, - C: Accumulate, - P: Parser, - S: Parser, - E: ParseError, -{ - trace("separated0", move |mut i: I| { - let mut res = C::initial(None); - - match parser.parse_next(i.clone()) { - Err(ErrMode::Backtrack(_)) => return Ok((i, res)), - Err(e) => return Err(e), - Ok((i1, o)) => { - res.accumulate(o); - i = i1; - } - } - - loop { - let len = i.eof_offset(); - match sep.parse_next(i.clone()) { - Err(ErrMode::Backtrack(_)) => return Ok((i, res)), - Err(e) => return Err(e), - Ok((i1, _)) => { - // infinite loop check: the parser must always consume - if i1.eof_offset() == len { - return Err(ErrMode::assert(i, "sep parsers must always consume")); - } - - match parser.parse_next(i1.clone()) { - Err(ErrMode::Backtrack(_)) => return Ok((i, res)), - Err(e) => return Err(e), - Ok((i2, o)) => { - res.accumulate(o); - i = i2; - } - } - } - } - } - }) -} - -/// Alternates between two parsers to produce a list of elements until [`ErrMode::Backtrack`]. -/// -/// Fails if the element parser does not produce at least one element.$ -/// -/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see -/// [`cut_err`][crate::combinator::cut_err]. -/// -/// # Arguments -/// * `sep` Parses the separator between list elements. -/// * `f` Parses the elements of the list. -/// -/// # Example -/// -#[cfg_attr(not(feature = "std"), doc = "```ignore")] -#[cfg_attr(feature = "std", doc = "```")] -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::multi::separated1; -/// use winnow::bytes::tag; -/// -/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { -/// separated1("abc", "|").parse_next(s) -/// } -/// -/// assert_eq!(parser("abc|abc|abc"), Ok(("", vec!["abc", "abc", "abc"]))); -/// assert_eq!(parser("abc123abc"), Ok(("123abc", vec!["abc"]))); -/// assert_eq!(parser("abc|def"), Ok(("|def", vec!["abc"]))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); -/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(Error::new("def|abc", ErrorKind::Tag)))); -/// ``` -#[doc(alias = "sep_by1")] -#[doc(alias = "separated_list1")] -pub fn separated1(mut parser: P, mut sep: S) -> impl Parser -where - I: Stream, - C: Accumulate, - P: Parser, - S: Parser, - E: ParseError, -{ - trace("separated1", move |mut i: I| { - let mut res = C::initial(None); - - // Parse the first element - match parser.parse_next(i.clone()) { - Err(e) => return Err(e), - Ok((i1, o)) => { - res.accumulate(o); - i = i1; - } - } - - loop { - let len = i.eof_offset(); - match sep.parse_next(i.clone()) { - Err(ErrMode::Backtrack(_)) => return Ok((i, res)), - Err(e) => return Err(e), - Ok((i1, _)) => { - // infinite loop check: the parser must always consume - if i1.eof_offset() == len { - return Err(ErrMode::assert(i, "sep parsers must always consume")); - } - - match parser.parse_next(i1.clone()) { - Err(ErrMode::Backtrack(_)) => return Ok((i, res)), - Err(e) => return Err(e), - Ok((i2, o)) => { - res.accumulate(o); - i = i2; - } - } - } - } - } - }) -} - -/// Alternates between two parsers, merging the results (left associative) -/// -/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see -/// [`cut_err`][crate::combinator::cut_err]. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::multi::separated_foldl1; -/// use winnow::character::dec_int; -/// -/// fn parser(s: &str) -> IResult<&str, i32> { -/// separated_foldl1(dec_int, "-", |l, _, r| l - r).parse_next(s) -/// } -/// -/// assert_eq!(parser("9-3-5"), Ok(("", 1))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); -/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(Error::new("def|abc", ErrorKind::Slice)))); -/// ``` -pub fn separated_foldl1( - mut parser: P, - mut sep: S, - op: Op, -) -> impl Parser -where - I: Stream, - P: Parser, - S: Parser, - E: ParseError, - Op: Fn(O, O2, O) -> O, -{ - trace("separated_foldl1", move |i: I| { - let (mut i, mut ol) = parser.parse_next(i)?; - - loop { - let len = i.eof_offset(); - match sep.parse_next(i.clone()) { - Err(ErrMode::Backtrack(_)) => return Ok((i, ol)), - Err(e) => return Err(e), - Ok((i1, s)) => { - // infinite loop check: the parser must always consume - if i1.eof_offset() == len { - return Err(ErrMode::assert(i, "many parsers must always consume")); - } - - match parser.parse_next(i1.clone()) { - Err(ErrMode::Backtrack(_)) => return Ok((i, ol)), - Err(e) => return Err(e), - Ok((i2, or)) => { - ol = op(ol, s, or); - i = i2; - } - } - } - } - } - }) -} - -/// Alternates between two parsers, merging the results (right associative) -/// -/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see -/// [`cut_err`][crate::combinator::cut_err]. -/// -/// # Example -/// -/// ``` -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::multi::separated_foldr1; -/// use winnow::character::dec_uint; -/// -/// fn parser(s: &str) -> IResult<&str, u32> { -/// separated_foldr1(dec_uint, "^", |l: u32, _, r: u32| l.pow(r)).parse_next(s) -/// } -/// -/// assert_eq!(parser("2^3^2"), Ok(("", 512))); -/// assert_eq!(parser("2"), Ok(("", 2))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); -/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(Error::new("def|abc", ErrorKind::Slice)))); -/// ``` -#[cfg(feature = "alloc")] -pub fn separated_foldr1( - mut parser: P, - mut sep: S, - op: Op, -) -> impl Parser -where - I: Stream, - P: Parser, - S: Parser, - E: ParseError, - Op: Fn(O, O2, O) -> O, -{ - trace("separated_foldr1", move |i: I| { - let (i, ol) = parser.parse_next(i)?; - let (i, all): (_, crate::lib::std::vec::Vec<(O2, O)>) = - many0((sep.by_ref(), parser.by_ref())).parse_next(i)?; - if let Some((s, or)) = all - .into_iter() - .rev() - .reduce(|(sr, or), (sl, ol)| (sl, op(ol, sr, or))) - { - let merged = op(ol, s, or); - Ok((i, merged)) - } else { - Ok((i, ol)) - } - }) -} - -/// Repeats the embedded parser `m..=n` times -/// -/// This stops before `n` when the parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see -/// [`cut_err`][crate::combinator::cut_err]. -/// -/// # Arguments -/// * `m` The minimum number of iterations. -/// * `n` The maximum number of iterations. -/// * `f` The parser to apply. -/// -/// To recognize a series of tokens, [`Accumulate`] into a `()` and then [`Parser::recognize`]. -/// -/// **Warning:** If the parser passed to `many1` accepts empty inputs -/// (like `alpha0` or `digit0`), `many1` will return an error, -/// to prevent going into an infinite loop. -/// -/// # Example -/// -#[cfg_attr(not(feature = "std"), doc = "```ignore")] -#[cfg_attr(feature = "std", doc = "```")] -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::multi::many_m_n; -/// use winnow::bytes::tag; -/// -/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { -/// many_m_n(0, 2, "abc").parse_next(s) -/// } -/// -/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); -/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); -/// assert_eq!(parser("123123"), Ok(("123123", vec![]))); -/// assert_eq!(parser(""), Ok(("", vec![]))); -/// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"]))); -/// ``` -#[doc(alias = "repeated")] -pub fn many_m_n(min: usize, max: usize, mut parse: F) -> impl Parser -where - I: Stream, - C: Accumulate, - F: Parser, - E: ParseError, -{ - trace("many_m_n", move |mut input: I| { - if min > max { - return Err(ErrMode::Cut(E::from_error_kind(input, ErrorKind::Many))); - } - - let mut res = C::initial(Some(min)); - for count in 0..max { - let len = input.eof_offset(); - match parse.parse_next(input.clone()) { - Ok((tail, value)) => { - // infinite loop check: the parser must always consume - if tail.eof_offset() == len { - return Err(ErrMode::assert(input, "many parsers must always consume")); - } - - res.accumulate(value); - input = tail; - } - Err(ErrMode::Backtrack(e)) => { - if count < min { - return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many))); - } else { - return Ok((input, res)); - } - } - Err(e) => { - return Err(e); - } - } - } - - Ok((input, res)) - }) -} - -/// [`Accumulate`] the output of a parser into a container, like `Vec` -/// -/// # Arguments -/// * `f` The parser to apply. -/// * `count` How often to apply the parser. -/// -/// To recognize a series of tokens, [`Accumulate`] into a `()` and then [`Parser::recognize`]. -/// -/// # Example -/// -#[cfg_attr(not(feature = "std"), doc = "```ignore")] -#[cfg_attr(feature = "std", doc = "```")] -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::multi::count; -/// use winnow::bytes::tag; -/// -/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { -/// count("abc", 2).parse_next(s) -/// } -/// -/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); -/// assert_eq!(parser("abc123"), Err(ErrMode::Backtrack(Error::new("123", ErrorKind::Tag)))); -/// assert_eq!(parser("123123"), Err(ErrMode::Backtrack(Error::new("123123", ErrorKind::Tag)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); -/// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"]))); -/// ``` -#[doc(alias = "skip_counskip_count")] -pub fn count(mut f: F, count: usize) -> impl Parser -where - I: Stream, - C: Accumulate, - F: Parser, - E: ParseError, -{ - trace("count", move |i: I| { - let mut input = i.clone(); - let mut res = C::initial(Some(count)); - - for _ in 0..count { - let input_ = input.clone(); - match f.parse_next(input_) { - Ok((i, o)) => { - res.accumulate(o); - input = i; - } - Err(e) => { - return Err(e.append(i, ErrorKind::Many)); - } - } - } - - Ok((input, res)) - }) -} - -/// Runs the embedded parser repeatedly, filling the given slice with results. -/// -/// This parser fails if the input runs out before the given slice is full. -/// -/// # Arguments -/// * `f` The parser to apply. -/// * `buf` The slice to fill -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::multi::fill; -/// use winnow::bytes::tag; -/// -/// fn parser(s: &str) -> IResult<&str, [&str; 2]> { -/// let mut buf = ["", ""]; -/// let (rest, ()) = fill("abc", &mut buf).parse_next(s)?; -/// Ok((rest, buf)) -/// } -/// -/// assert_eq!(parser("abcabc"), Ok(("", ["abc", "abc"]))); -/// assert_eq!(parser("abc123"), Err(ErrMode::Backtrack(Error::new("123", ErrorKind::Tag)))); -/// assert_eq!(parser("123123"), Err(ErrMode::Backtrack(Error::new("123123", ErrorKind::Tag)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); -/// assert_eq!(parser("abcabcabc"), Ok(("abc", ["abc", "abc"]))); -/// ``` -pub fn fill<'a, I, O, E, F>(mut f: F, buf: &'a mut [O]) -> impl Parser + 'a -where - I: Stream + 'a, - F: Parser + 'a, - E: ParseError + 'a, -{ - trace("fill", move |i: I| { - let mut input = i.clone(); - - for elem in buf.iter_mut() { - let input_ = input.clone(); - match f.parse_next(input_) { - Ok((i, o)) => { - *elem = o; - input = i; - } - Err(e) => { - return Err(e.append(i, ErrorKind::Many)); - } - } - } - - Ok((input, ())) - }) -} - -/// Repeats the embedded parser, calling `g` to gather the results. -/// -/// This stops on [`ErrMode::Backtrack`]. To instead chain an error up, see -/// [`cut_err`][crate::combinator::cut_err]. -/// -/// # Arguments -/// * `f` The parser to apply. -/// * `init` A function returning the initial value. -/// * `g` The function that combines a result of `f` with -/// the current accumulator. -/// -/// **Warning:** if the parser passed in accepts empty inputs (like `alpha0` or `digit0`), `many0` will -/// return an error, to prevent going into an infinite loop -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::multi::fold_many0; -/// use winnow::bytes::tag; -/// -/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { -/// fold_many0( -/// "abc", -/// Vec::new, -/// |mut acc: Vec<_>, item| { -/// acc.push(item); -/// acc -/// } -/// ).parse_next(s) -/// } -/// -/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); -/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); -/// assert_eq!(parser("123123"), Ok(("123123", vec![]))); -/// assert_eq!(parser(""), Ok(("", vec![]))); -/// ``` -pub fn fold_many0(mut f: F, mut init: H, mut g: G) -> impl Parser -where - I: Stream, - F: Parser, - G: FnMut(R, O) -> R, - H: FnMut() -> R, - E: ParseError, -{ - trace("fold_many0", move |i: I| { - let mut res = init(); - let mut input = i; - - loop { - let i_ = input.clone(); - let len = input.eof_offset(); - match f.parse_next(i_) { - Ok((i, o)) => { - // infinite loop check: the parser must always consume - if i.eof_offset() == len { - return Err(ErrMode::assert(i, "many parsers must always consume")); - } - - res = g(res, o); - input = i; - } - Err(ErrMode::Backtrack(_)) => { - return Ok((input, res)); - } - Err(e) => { - return Err(e); - } - } - } - }) -} - -/// Repeats the embedded parser, calling `g` to gather the results. -/// -/// This stops on [`ErrMode::Backtrack`] if there is at least one result. To instead chain an error up, -/// see [`cut_err`][crate::combinator::cut_err]. -/// -/// # Arguments -/// * `f` The parser to apply. -/// * `init` A function returning the initial value. -/// * `g` The function that combines a result of `f` with -/// the current accumulator. -/// -/// **Warning:** If the parser passed to `many1` accepts empty inputs -/// (like `alpha0` or `digit0`), `many1` will return an error, -/// to prevent going into an infinite loop. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::multi::fold_many1; -/// use winnow::bytes::tag; -/// -/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { -/// fold_many1( -/// "abc", -/// Vec::new, -/// |mut acc: Vec<_>, item| { -/// acc.push(item); -/// acc -/// } -/// ).parse_next(s) -/// } -/// -/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); -/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); -/// assert_eq!(parser("123123"), Err(ErrMode::Backtrack(Error::new("123123", ErrorKind::Many)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Many)))); -/// ``` -pub fn fold_many1(mut f: F, mut init: H, mut g: G) -> impl Parser -where - I: Stream, - F: Parser, - G: FnMut(R, O) -> R, - H: FnMut() -> R, - E: ParseError, -{ - trace("fold_many1", move |i: I| { - let _i = i.clone(); - let init = init(); - match f.parse_next(_i) { - Err(ErrMode::Backtrack(_)) => Err(ErrMode::from_error_kind(i, ErrorKind::Many)), - Err(e) => Err(e), - Ok((i1, o1)) => { - let mut acc = g(init, o1); - let mut input = i1; - - loop { - let _input = input.clone(); - let len = input.eof_offset(); - match f.parse_next(_input) { - Err(ErrMode::Backtrack(_)) => { - break; - } - Err(e) => return Err(e), - Ok((i, o)) => { - // infinite loop check: the parser must always consume - if i.eof_offset() == len { - return Err(ErrMode::assert(i, "many parsers must always consume")); - } - - acc = g(acc, o); - input = i; - } - } - } - - Ok((input, acc)) - } - } - }) -} - -/// Repeats the embedded parser `m..=n` times, calling `g` to gather the results -/// -/// This stops before `n` when the parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see -/// [`cut_err`][crate::combinator::cut_err]. -/// -/// # Arguments -/// * `m` The minimum number of iterations. -/// * `n` The maximum number of iterations. -/// * `f` The parser to apply. -/// * `init` A function returning the initial value. -/// * `g` The function that combines a result of `f` with -/// the current accumulator. -/// -/// **Warning:** If the parser passed to `many1` accepts empty inputs -/// (like `alpha0` or `digit0`), `many1` will return an error, -/// to prevent going into an infinite loop. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::multi::fold_many_m_n; -/// use winnow::bytes::tag; -/// -/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { -/// fold_many_m_n( -/// 0, -/// 2, -/// "abc", -/// Vec::new, -/// |mut acc: Vec<_>, item| { -/// acc.push(item); -/// acc -/// } -/// ).parse_next(s) -/// } -/// -/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); -/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); -/// assert_eq!(parser("123123"), Ok(("123123", vec![]))); -/// assert_eq!(parser(""), Ok(("", vec![]))); -/// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"]))); -/// ``` -pub fn fold_many_m_n( - min: usize, - max: usize, - mut parse: F, - mut init: H, - mut fold: G, -) -> impl Parser -where - I: Stream, - F: Parser, - G: FnMut(R, O) -> R, - H: FnMut() -> R, - E: ParseError, -{ - trace("fold_many_m_n", move |mut input: I| { - if min > max { - return Err(ErrMode::Cut(E::from_error_kind(input, ErrorKind::Many))); - } - - let mut acc = init(); - for count in 0..max { - let len = input.eof_offset(); - match parse.parse_next(input.clone()) { - Ok((tail, value)) => { - // infinite loop check: the parser must always consume - if tail.eof_offset() == len { - return Err(ErrMode::assert(input, "many parsers must always consume")); - } - - acc = fold(acc, value); - input = tail; - } - //FInputXMError: handle failure properly - Err(ErrMode::Backtrack(err)) => { - if count < min { - return Err(ErrMode::Backtrack(err.append(input, ErrorKind::Many))); - } else { - break; - } - } - Err(e) => return Err(e), - } - } - - Ok((input, acc)) - }) -} - -/// Gets a number from the parser and returns a -/// subslice of the input of that size. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Arguments -/// * `f` The parser to apply. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed, stream::Partial}; -/// # use winnow::prelude::*; -/// use winnow::Bytes; -/// use winnow::number::be_u16; -/// use winnow::multi::length_data; -/// use winnow::bytes::tag; -/// -/// type Stream<'i> = Partial<&'i Bytes>; -/// -/// fn stream(b: &[u8]) -> Stream<'_> { -/// Partial::new(Bytes::new(b)) -/// } -/// -/// fn parser(s: Stream<'_>) -> IResult, &[u8]> { -/// length_data(be_u16).parse_next(s) -/// } -/// -/// assert_eq!(parser(stream(b"\x00\x03abcefg")), Ok((stream(&b"efg"[..]), &b"abc"[..]))); -/// assert_eq!(parser(stream(b"\x00\x03a")), Err(ErrMode::Incomplete(Needed::new(2)))); -/// ``` -pub fn length_data(mut f: F) -> impl Parser::Slice, E> -where - I: StreamIsPartial, - I: Stream, - N: ToUsize, - F: Parser, - E: ParseError, -{ - trace("length_data", move |i: I| { - let (i, length) = f.parse_next(i)?; - - crate::bytes::take(length).parse_next(i) - }) -} - -/// 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. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Arguments -/// * `f` The parser to apply. -/// * `g` The parser to apply on the subslice. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed, stream::{Partial, StreamIsPartial}}; -/// # use winnow::prelude::*; -/// use winnow::Bytes; -/// use winnow::number::be_u16; -/// use winnow::multi::length_value; -/// use winnow::bytes::tag; -/// -/// type Stream<'i> = Partial<&'i Bytes>; -/// -/// fn stream(b: &[u8]) -> Stream<'_> { -/// Partial::new(Bytes::new(b)) -/// } -/// -/// fn complete_stream(b: &[u8]) -> Stream<'_> { -/// let mut p = Partial::new(Bytes::new(b)); -/// let _ = p.complete(); -/// p -/// } -/// -/// fn parser(s: Stream<'_>) -> IResult, &[u8]> { -/// length_value(be_u16, "abc").parse_next(s) -/// } -/// -/// assert_eq!(parser(stream(b"\x00\x03abcefg")), Ok((stream(&b"efg"[..]), &b"abc"[..]))); -/// assert_eq!(parser(stream(b"\x00\x03123123")), Err(ErrMode::Backtrack(Error::new(complete_stream(&b"123"[..]), ErrorKind::Tag)))); -/// assert_eq!(parser(stream(b"\x00\x03a")), Err(ErrMode::Incomplete(Needed::new(2)))); -/// ``` -pub fn length_value(mut f: F, mut g: G) -> impl Parser -where - I: StreamIsPartial, - I: Stream + UpdateSlice, - N: ToUsize, - F: Parser, - G: Parser, - E: ParseError, -{ - trace("length_value", move |i: I| { - let (i, data) = length_data(f.by_ref()).parse_next(i)?; - let mut data = I::update_slice(i.clone(), data); - let _ = data.complete(); - let (_, o) = g.by_ref().complete_err().parse_next(data)?; - Ok((i, o)) - }) -} - -/// Gets a number from the first parser, -/// then applies the second parser that many times. -/// -/// # Arguments -/// * `f` The parser to apply to obtain the count. -/// * `g` The parser to apply repeatedly. -/// -/// # Example -/// -#[cfg_attr(not(feature = "std"), doc = "```ignore")] -#[cfg_attr(feature = "std", doc = "```")] -/// # use winnow::prelude::*; -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::Bytes; -/// use winnow::number::u8; -/// use winnow::multi::length_count; -/// use winnow::bytes::tag; -/// -/// type Stream<'i> = &'i Bytes; -/// -/// fn stream(b: &[u8]) -> Stream<'_> { -/// Bytes::new(b) -/// } -/// -/// fn parser(s: Stream<'_>) -> IResult, Vec<&[u8]>> { -/// length_count(u8.map(|i| { -/// println!("got number: {}", i); -/// i -/// }), "abc").parse_next(s) -/// } -/// -/// assert_eq!(parser(stream(b"\x02abcabcabc")), Ok((stream(b"abc"), vec![&b"abc"[..], &b"abc"[..]]))); -/// assert_eq!(parser(stream(b"\x03123123123")), Err(ErrMode::Backtrack(Error::new(stream(b"123123123"), ErrorKind::Tag)))); -/// ``` -pub fn length_count(mut f: F, mut g: G) -> impl Parser -where - I: Stream, - N: ToUsize, - C: Accumulate, - F: Parser, - G: Parser, - E: ParseError, -{ - trace("length_count", move |i: I| { - let (i, n) = f.parse_next(i)?; - let n = n.to_usize(); - count(g.by_ref(), n).parse_next(i) - }) -} diff --git a/vendor/winnow/src/multi/tests.rs b/vendor/winnow/src/multi/tests.rs deleted file mode 100644 index 1977ff9c1..000000000 --- a/vendor/winnow/src/multi/tests.rs +++ /dev/null @@ -1,743 +0,0 @@ -use super::{length_data, length_value, many0, many1}; -use crate::Parser; -use crate::Partial; -use crate::{ - character::digit1 as digit, - error::{ErrMode, ErrorKind, Needed, ParseError}, - lib::std::str::{self, FromStr}, - number::{be_u16, be_u8}, - IResult, -}; -#[cfg(feature = "alloc")] -use crate::{ - lib::std::vec::Vec, - multi::{ - count, fold_many0, fold_many1, fold_many_m_n, length_count, many_m_n, many_till0, - separated0, separated1, - }, -}; - -#[test] -#[cfg(feature = "alloc")] -fn separated0_test() { - fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - separated0("abcd", ",").parse_next(i) - } - fn multi_empty(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - separated0("", ",").parse_next(i) - } - fn multi_longsep(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - separated0("abcd", "..").parse_next(i) - } - - let a = &b"abcdef"[..]; - let b = &b"abcd,abcdef"[..]; - let c = &b"azerty"[..]; - let d = &b",,abc"[..]; - let e = &b"abcd,abcd,ef"[..]; - let f = &b"abc"[..]; - let g = &b"abcd."[..]; - let h = &b"abcd,abc"[..]; - - let res1 = vec![&b"abcd"[..]]; - assert_eq!(multi(Partial::new(a)), Ok((Partial::new(&b"ef"[..]), res1))); - let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; - assert_eq!(multi(Partial::new(b)), Ok((Partial::new(&b"ef"[..]), res2))); - assert_eq!( - multi(Partial::new(c)), - Ok((Partial::new(&b"azerty"[..]), Vec::new())) - ); - let res3 = vec![&b""[..], &b""[..], &b""[..]]; - assert_eq!( - multi_empty(Partial::new(d)), - Ok((Partial::new(&b"abc"[..]), res3)) - ); - let res4 = vec![&b"abcd"[..], &b"abcd"[..]]; - assert_eq!( - multi(Partial::new(e)), - Ok((Partial::new(&b",ef"[..]), res4)) - ); - - assert_eq!( - multi(Partial::new(f)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - multi_longsep(Partial::new(g)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - multi(Partial::new(h)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); -} - -#[test] -#[cfg(feature = "alloc")] -#[cfg_attr(debug_assertions, should_panic)] -fn separated0_empty_sep_test() { - fn empty_sep(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - separated0("abc", "").parse_next(i) - } - - let i = &b"abcabc"[..]; - - let i_err_pos = &i[3..]; - assert_eq!( - empty_sep(Partial::new(i)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(i_err_pos), - ErrorKind::Assert - ))) - ); -} - -#[test] -#[cfg(feature = "alloc")] -fn separated1_test() { - fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - separated1("abcd", ",").parse_next(i) - } - fn multi_longsep(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - separated1("abcd", "..").parse_next(i) - } - - let a = &b"abcdef"[..]; - let b = &b"abcd,abcdef"[..]; - let c = &b"azerty"[..]; - let d = &b"abcd,abcd,ef"[..]; - - let f = &b"abc"[..]; - let g = &b"abcd."[..]; - let h = &b"abcd,abc"[..]; - - let res1 = vec![&b"abcd"[..]]; - assert_eq!(multi(Partial::new(a)), Ok((Partial::new(&b"ef"[..]), res1))); - let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; - assert_eq!(multi(Partial::new(b)), Ok((Partial::new(&b"ef"[..]), res2))); - assert_eq!( - multi(Partial::new(c)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(c), - ErrorKind::Tag - ))) - ); - let res3 = vec![&b"abcd"[..], &b"abcd"[..]]; - assert_eq!( - multi(Partial::new(d)), - Ok((Partial::new(&b",ef"[..]), res3)) - ); - - assert_eq!( - multi(Partial::new(f)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - multi_longsep(Partial::new(g)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - multi(Partial::new(h)), - Err(ErrMode::Incomplete(Needed::new(1))) - ); -} - -#[test] -#[cfg(feature = "alloc")] -fn many0_test() { - fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - many0("abcd").parse_next(i) - } - - assert_eq!( - multi(Partial::new(&b"abcdef"[..])), - Ok((Partial::new(&b"ef"[..]), vec![&b"abcd"[..]])) - ); - assert_eq!( - multi(Partial::new(&b"abcdabcdefgh"[..])), - Ok((Partial::new(&b"efgh"[..]), vec![&b"abcd"[..], &b"abcd"[..]])) - ); - assert_eq!( - multi(Partial::new(&b"azerty"[..])), - Ok((Partial::new(&b"azerty"[..]), Vec::new())) - ); - assert_eq!( - multi(Partial::new(&b"abcdab"[..])), - Err(ErrMode::Incomplete(Needed::new(2))) - ); - assert_eq!( - multi(Partial::new(&b"abcd"[..])), - Err(ErrMode::Incomplete(Needed::new(4))) - ); - assert_eq!( - multi(Partial::new(&b""[..])), - Err(ErrMode::Incomplete(Needed::new(4))) - ); -} - -#[test] -#[cfg(feature = "alloc")] -#[cfg_attr(debug_assertions, should_panic)] -fn many0_empty_test() { - fn multi_empty(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - many0("").parse_next(i) - } - - assert_eq!( - multi_empty(Partial::new(&b"abcdef"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"abcdef"[..]), - ErrorKind::Assert - ))) - ); -} - -#[test] -#[cfg(feature = "alloc")] -fn many1_test() { - fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - many1("abcd").parse_next(i) - } - - let a = &b"abcdef"[..]; - let b = &b"abcdabcdefgh"[..]; - let c = &b"azerty"[..]; - let d = &b"abcdab"[..]; - - let res1 = vec![&b"abcd"[..]]; - assert_eq!(multi(Partial::new(a)), Ok((Partial::new(&b"ef"[..]), res1))); - let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; - assert_eq!( - multi(Partial::new(b)), - Ok((Partial::new(&b"efgh"[..]), res2)) - ); - assert_eq!( - multi(Partial::new(c)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(c), - ErrorKind::Tag - ))) - ); - assert_eq!( - multi(Partial::new(d)), - Err(ErrMode::Incomplete(Needed::new(2))) - ); -} - -#[test] -#[cfg(feature = "alloc")] -fn many_till_test() { - #[allow(clippy::type_complexity)] - fn multi(i: &[u8]) -> IResult<&[u8], (Vec<&[u8]>, &[u8])> { - many_till0("abcd", "efgh").parse_next(i) - } - - let a = b"abcdabcdefghabcd"; - let b = b"efghabcd"; - let c = b"azerty"; - - let res_a = (vec![&b"abcd"[..], &b"abcd"[..]], &b"efgh"[..]); - let res_b: (Vec<&[u8]>, &[u8]) = (Vec::new(), &b"efgh"[..]); - assert_eq!(multi(&a[..]), Ok((&b"abcd"[..], res_a))); - assert_eq!(multi(&b[..]), Ok((&b"abcd"[..], res_b))); - assert_eq!( - multi(&c[..]), - Err(ErrMode::Backtrack(error_node_position!( - &c[..], - ErrorKind::Many, - error_position!(&c[..], ErrorKind::Tag) - ))) - ); -} - -#[test] -#[cfg(feature = "std")] -fn infinite_many() { - fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> { - println!("input: {:?}", input); - Err(ErrMode::Backtrack(error_position!(input, ErrorKind::Tag))) - } - - // should not go into an infinite loop - fn multi0(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - many0(tst).parse_next(i) - } - let a = &b"abcdef"[..]; - assert_eq!(multi0(a), Ok((a, Vec::new()))); - - fn multi1(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - many1(tst).parse_next(i) - } - let a = &b"abcdef"[..]; - assert_eq!( - multi1(a), - Err(ErrMode::Backtrack(error_position!(a, ErrorKind::Tag))) - ); -} - -#[test] -#[cfg(feature = "alloc")] -fn many_m_n_test() { - fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - many_m_n(2, 4, "Abcd").parse_next(i) - } - - let a = &b"Abcdef"[..]; - let b = &b"AbcdAbcdefgh"[..]; - let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; - let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..]; - let e = &b"AbcdAb"[..]; - - assert_eq!( - multi(Partial::new(a)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"ef"[..]), - ErrorKind::Tag - ))) - ); - let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; - assert_eq!( - multi(Partial::new(b)), - Ok((Partial::new(&b"efgh"[..]), res1)) - ); - let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; - assert_eq!( - multi(Partial::new(c)), - Ok((Partial::new(&b"efgh"[..]), res2)) - ); - let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; - assert_eq!( - multi(Partial::new(d)), - Ok((Partial::new(&b"Abcdefgh"[..]), res3)) - ); - assert_eq!( - multi(Partial::new(e)), - Err(ErrMode::Incomplete(Needed::new(2))) - ); -} - -#[test] -#[cfg(feature = "alloc")] -fn count_test() { - const TIMES: usize = 2; - fn cnt_2(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - count("abc", TIMES).parse_next(i) - } - - assert_eq!( - cnt_2(Partial::new(&b"abcabcabcdef"[..])), - Ok((Partial::new(&b"abcdef"[..]), vec![&b"abc"[..], &b"abc"[..]])) - ); - assert_eq!( - cnt_2(Partial::new(&b"ab"[..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - cnt_2(Partial::new(&b"abcab"[..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - cnt_2(Partial::new(&b"xxx"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxx"[..]), - ErrorKind::Tag - ))) - ); - assert_eq!( - cnt_2(Partial::new(&b"xxxabcabcdef"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxxabcabcdef"[..]), - ErrorKind::Tag - ))) - ); - assert_eq!( - cnt_2(Partial::new(&b"abcxxxabcdef"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxxabcdef"[..]), - ErrorKind::Tag - ))) - ); -} - -#[test] -#[cfg(feature = "alloc")] -fn count_zero() { - const TIMES: usize = 0; - fn counter_2(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - count("abc", TIMES).parse_next(i) - } - - let done = &b"abcabcabcdef"[..]; - let parsed_done = Vec::new(); - let rest = done; - let incomplete_1 = &b"ab"[..]; - let parsed_incompl_1 = Vec::new(); - let incomplete_2 = &b"abcab"[..]; - let parsed_incompl_2 = Vec::new(); - let error = &b"xxx"[..]; - let error_remain = &b"xxx"[..]; - let parsed_err = Vec::new(); - let error_1 = &b"xxxabcabcdef"[..]; - let parsed_err_1 = Vec::new(); - let error_1_remain = &b"xxxabcabcdef"[..]; - let error_2 = &b"abcxxxabcdef"[..]; - let parsed_err_2 = Vec::new(); - let error_2_remain = &b"abcxxxabcdef"[..]; - - assert_eq!(counter_2(done), Ok((rest, parsed_done))); - assert_eq!( - counter_2(incomplete_1), - Ok((incomplete_1, parsed_incompl_1)) - ); - assert_eq!( - counter_2(incomplete_2), - Ok((incomplete_2, parsed_incompl_2)) - ); - assert_eq!(counter_2(error), Ok((error_remain, parsed_err))); - assert_eq!(counter_2(error_1), Ok((error_1_remain, parsed_err_1))); - assert_eq!(counter_2(error_2), Ok((error_2_remain, parsed_err_2))); -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct NilError; - -impl From<(I, ErrorKind)> for NilError { - fn from(_: (I, ErrorKind)) -> Self { - NilError - } -} - -impl ParseError for NilError { - fn from_error_kind(_: I, _: ErrorKind) -> NilError { - NilError - } - fn append(self, _: I, _: ErrorKind) -> NilError { - NilError - } -} - -#[test] -#[cfg(feature = "alloc")] -fn length_count_test() { - fn number(i: Partial<&[u8]>) -> IResult, u32> { - digit - .map_res(str::from_utf8) - .map_res(FromStr::from_str) - .parse_next(i) - } - - fn cnt(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - length_count(number, "abc").parse_next(i) - } - - assert_eq!( - cnt(Partial::new(&b"2abcabcabcdef"[..])), - Ok((Partial::new(&b"abcdef"[..]), vec![&b"abc"[..], &b"abc"[..]])) - ); - assert_eq!( - cnt(Partial::new(&b"2ab"[..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - cnt(Partial::new(&b"3abcab"[..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - cnt(Partial::new(&b"xxx"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxx"[..]), - ErrorKind::Slice - ))) - ); - assert_eq!( - cnt(Partial::new(&b"2abcxxx"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxx"[..]), - ErrorKind::Tag - ))) - ); -} - -#[test] -fn length_data_test() { - fn number(i: Partial<&[u8]>) -> IResult, u32> { - digit - .map_res(str::from_utf8) - .map_res(FromStr::from_str) - .parse_next(i) - } - - fn take(i: Partial<&[u8]>) -> IResult, &[u8]> { - length_data(number).parse_next(i) - } - - assert_eq!( - take(Partial::new(&b"6abcabcabcdef"[..])), - Ok((Partial::new(&b"abcdef"[..]), &b"abcabc"[..])) - ); - assert_eq!( - take(Partial::new(&b"3ab"[..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - take(Partial::new(&b"xxx"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxx"[..]), - ErrorKind::Slice - ))) - ); - assert_eq!( - take(Partial::new(&b"2abcxxx"[..])), - Ok((Partial::new(&b"cxxx"[..]), &b"ab"[..])) - ); -} - -#[test] -fn length_value_test() { - use crate::stream::StreamIsPartial; - - fn length_value_1(i: Partial<&[u8]>) -> IResult, u16> { - length_value(be_u8, be_u16).parse_next(i) - } - fn length_value_2(i: Partial<&[u8]>) -> IResult, (u8, u8)> { - length_value(be_u8, (be_u8, be_u8)).parse_next(i) - } - - let mut empty_complete = Partial::new(&b""[..]); - let _ = empty_complete.complete(); - - let i1 = [0, 5, 6]; - assert_eq!( - length_value_1(Partial::new(&i1)), - Err(ErrMode::Backtrack(error_position!( - empty_complete, - ErrorKind::Slice - ))) - ); - assert_eq!( - length_value_2(Partial::new(&i1)), - Err(ErrMode::Backtrack(error_position!( - empty_complete, - ErrorKind::Token - ))) - ); - - let i2 = [1, 5, 6, 3]; - { - let mut middle_complete = Partial::new(&i2[1..2]); - let _ = middle_complete.complete(); - assert_eq!( - length_value_1(Partial::new(&i2)), - Err(ErrMode::Backtrack(error_position!( - middle_complete, - ErrorKind::Slice - ))) - ); - assert_eq!( - length_value_2(Partial::new(&i2)), - Err(ErrMode::Backtrack(error_position!( - empty_complete, - ErrorKind::Token - ))) - ); - } - - let i3 = [2, 5, 6, 3, 4, 5, 7]; - assert_eq!( - length_value_1(Partial::new(&i3)), - Ok((Partial::new(&i3[3..]), 1286)) - ); - assert_eq!( - length_value_2(Partial::new(&i3)), - Ok((Partial::new(&i3[3..]), (5, 6))) - ); - - let i4 = [3, 5, 6, 3, 4, 5]; - assert_eq!( - length_value_1(Partial::new(&i4)), - Ok((Partial::new(&i4[4..]), 1286)) - ); - assert_eq!( - length_value_2(Partial::new(&i4)), - Ok((Partial::new(&i4[4..]), (5, 6))) - ); -} - -#[test] -#[cfg(feature = "alloc")] -fn fold_many0_test() { - fn fold_into_vec(mut acc: Vec, item: T) -> Vec { - acc.push(item); - acc - } - fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - fold_many0("abcd", Vec::new, fold_into_vec).parse_next(i) - } - - assert_eq!( - multi(Partial::new(&b"abcdef"[..])), - Ok((Partial::new(&b"ef"[..]), vec![&b"abcd"[..]])) - ); - assert_eq!( - multi(Partial::new(&b"abcdabcdefgh"[..])), - Ok((Partial::new(&b"efgh"[..]), vec![&b"abcd"[..], &b"abcd"[..]])) - ); - assert_eq!( - multi(Partial::new(&b"azerty"[..])), - Ok((Partial::new(&b"azerty"[..]), Vec::new())) - ); - assert_eq!( - multi(Partial::new(&b"abcdab"[..])), - Err(ErrMode::Incomplete(Needed::new(2))) - ); - assert_eq!( - multi(Partial::new(&b"abcd"[..])), - Err(ErrMode::Incomplete(Needed::new(4))) - ); - assert_eq!( - multi(Partial::new(&b""[..])), - Err(ErrMode::Incomplete(Needed::new(4))) - ); -} - -#[test] -#[cfg(feature = "alloc")] -#[cfg_attr(debug_assertions, should_panic)] -fn fold_many0_empty_test() { - fn fold_into_vec(mut acc: Vec, item: T) -> Vec { - acc.push(item); - acc - } - fn multi_empty(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - fold_many0("", Vec::new, fold_into_vec).parse_next(i) - } - - assert_eq!( - multi_empty(Partial::new(&b"abcdef"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"abcdef"[..]), - ErrorKind::Assert - ))) - ); -} - -#[test] -#[cfg(feature = "alloc")] -fn fold_many1_test() { - fn fold_into_vec(mut acc: Vec, item: T) -> Vec { - acc.push(item); - acc - } - fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - fold_many1("abcd", Vec::new, fold_into_vec).parse_next(i) - } - - let a = &b"abcdef"[..]; - let b = &b"abcdabcdefgh"[..]; - let c = &b"azerty"[..]; - let d = &b"abcdab"[..]; - - let res1 = vec![&b"abcd"[..]]; - assert_eq!(multi(Partial::new(a)), Ok((Partial::new(&b"ef"[..]), res1))); - let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; - assert_eq!( - multi(Partial::new(b)), - Ok((Partial::new(&b"efgh"[..]), res2)) - ); - assert_eq!( - multi(Partial::new(c)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(c), - ErrorKind::Many - ))) - ); - assert_eq!( - multi(Partial::new(d)), - Err(ErrMode::Incomplete(Needed::new(2))) - ); -} - -#[test] -#[cfg(feature = "alloc")] -fn fold_many_m_n_test() { - fn fold_into_vec(mut acc: Vec, item: T) -> Vec { - acc.push(item); - acc - } - fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - fold_many_m_n(2, 4, "Abcd", Vec::new, fold_into_vec).parse_next(i) - } - - let a = &b"Abcdef"[..]; - let b = &b"AbcdAbcdefgh"[..]; - let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; - let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..]; - let e = &b"AbcdAb"[..]; - - assert_eq!( - multi(Partial::new(a)), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"ef"[..]), - ErrorKind::Tag - ))) - ); - let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; - assert_eq!( - multi(Partial::new(b)), - Ok((Partial::new(&b"efgh"[..]), res1)) - ); - let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; - assert_eq!( - multi(Partial::new(c)), - Ok((Partial::new(&b"efgh"[..]), res2)) - ); - let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; - assert_eq!( - multi(Partial::new(d)), - Ok((Partial::new(&b"Abcdefgh"[..]), res3)) - ); - assert_eq!( - multi(Partial::new(e)), - Err(ErrMode::Incomplete(Needed::new(2))) - ); -} - -#[test] -fn many0_count_test() { - fn count0_nums(i: &[u8]) -> IResult<&[u8], usize> { - many0((digit, ",")).parse_next(i) - } - - assert_eq!(count0_nums(&b"123,junk"[..]), Ok((&b"junk"[..], 1))); - - assert_eq!(count0_nums(&b"123,45,junk"[..]), Ok((&b"junk"[..], 2))); - - assert_eq!( - count0_nums(&b"1,2,3,4,5,6,7,8,9,0,junk"[..]), - Ok((&b"junk"[..], 10)) - ); - - assert_eq!(count0_nums(&b"hello"[..]), Ok((&b"hello"[..], 0))); -} - -#[test] -fn many1_count_test() { - fn count1_nums(i: &[u8]) -> IResult<&[u8], usize> { - many1((digit, ",")).parse_next(i) - } - - assert_eq!(count1_nums(&b"123,45,junk"[..]), Ok((&b"junk"[..], 2))); - - assert_eq!( - count1_nums(&b"1,2,3,4,5,6,7,8,9,0,junk"[..]), - Ok((&b"junk"[..], 10)) - ); - - assert_eq!( - count1_nums(&b"hello"[..]), - Err(ErrMode::Backtrack(error_position!( - &b"hello"[..], - ErrorKind::Slice - ))) - ); -} diff --git a/vendor/winnow/src/number.rs b/vendor/winnow/src/number.rs new file mode 100644 index 000000000..2aa8da425 --- /dev/null +++ b/vendor/winnow/src/number.rs @@ -0,0 +1,509 @@ +//! Deprecated, see [`binary`] +#![deprecated(since = "0.4.2", note = "Replaced with `binary`")] +#![allow(clippy::match_same_arms)] + +use crate::binary; +use crate::error::ParseError; +use crate::stream::{AsBytes, Stream, StreamIsPartial}; +use crate::IResult; +use crate::Parser; + +pub use binary::Endianness; + +/// Deprecated, see [`binary::be_u8`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::be_u8`")] +#[inline(always)] +pub fn be_u8>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, +{ + binary::be_u8(input) +} + +/// Deprecated, see [`binary::be_u16`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::be_u16`")] +#[inline(always)] +pub fn be_u16>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::be_u16(input) +} + +/// Deprecated, see [`binary::be_u24`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::be_u24`")] +#[inline(always)] +pub fn be_u24>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::be_u24(input) +} + +/// Deprecated, see [`binary::be_u32`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::be_u32`")] +#[inline(always)] +pub fn be_u32>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::be_u32(input) +} + +/// Deprecated, see [`binary::be_u64`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::be_u64`")] +#[inline(always)] +pub fn be_u64>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::be_u64(input) +} + +/// Deprecated, see [`binary::be_u128`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::be_u128`")] +#[inline(always)] +pub fn be_u128>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::be_u128(input) +} + +/// Deprecated, see [`binary::be_i8`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::be_i8`")] +#[inline(always)] +pub fn be_i8>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, +{ + binary::be_i8(input) +} + +/// Deprecated, see [`binary::be_i16`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::be_i16`")] +#[inline(always)] +pub fn be_i16>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::be_i16(input) +} + +/// Deprecated, see [`binary::be_i24`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::be_i24`")] +#[inline(always)] +pub fn be_i24>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::be_i24(input) +} + +/// Deprecated, see [`binary::be_i32`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::be_i32`")] +#[inline(always)] +pub fn be_i32>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::be_i32(input) +} + +/// Deprecated, see [`binary::be_i64`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::be_i64`")] +#[inline(always)] +pub fn be_i64>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::be_i64(input) +} + +/// Deprecated, see [`binary::be_i128`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::be_i128`")] +#[inline(always)] +pub fn be_i128>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::be_i128(input) +} + +/// Deprecated, see [`binary::le_u8`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::le_u8`")] +#[inline(always)] +pub fn le_u8>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, +{ + binary::le_u8(input) +} + +/// Deprecated, see [`binary::le_u16`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::le_u16`")] +#[inline(always)] +pub fn le_u16>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::le_u16(input) +} + +/// Deprecated, see [`binary::le_u24`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::le_u24`")] +#[inline(always)] +pub fn le_u24>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::le_u24(input) +} + +/// Deprecated, see [`binary::le_u32`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::le_u32`")] +#[inline(always)] +pub fn le_u32>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::le_u32(input) +} + +/// Deprecated, see [`binary::le_u64`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::le_u64`")] +#[inline(always)] +pub fn le_u64>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::le_u64(input) +} + +/// Deprecated, see [`binary::le_u128`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::le_u128`")] +#[inline(always)] +pub fn le_u128>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::le_u128(input) +} + +/// Deprecated, see [`binary::le_i8`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::le_i8`")] +#[inline(always)] +pub fn le_i8>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, +{ + binary::le_i8(input) +} + +/// Deprecated, see [`binary::le_i16`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::le_i16`")] +#[inline(always)] +pub fn le_i16>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::le_i16(input) +} + +/// Deprecated, see [`binary::le_i24`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::le_i24`")] +#[inline(always)] +pub fn le_i24>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::le_i24(input) +} + +/// Deprecated, see [`binary::le_i32`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::le_i32`")] +#[inline(always)] +pub fn le_i32>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::le_i32(input) +} + +/// Deprecated, see [`binary::le_i64`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::le_i64`")] +#[inline(always)] +pub fn le_i64>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::le_i64(input) +} + +/// Deprecated, see [`binary::le_i128`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::le_i128`")] +#[inline(always)] +pub fn le_i128>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::le_i128(input) +} + +/// Deprecated, see [`binary::u8`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::u8`")] +#[inline(always)] +pub fn u8>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, +{ + binary::u8.parse_next(input) +} + +/// Deprecated, see [`binary::u16`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::u16`")] +#[inline(always)] +pub fn u16>(endian: crate::number::Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::u16(endian) +} + +/// Deprecated, see [`binary::u24`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::u24`")] +#[inline(always)] +pub fn u24>(endian: crate::number::Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::u24(endian) +} + +/// Deprecated, see [`binary::u32`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::u32`")] +#[inline(always)] +pub fn u32>(endian: crate::number::Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::u32(endian) +} + +/// Deprecated, see [`binary::u64`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::u64`")] +#[inline(always)] +pub fn u64>(endian: crate::number::Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::u64(endian) +} + +/// Deprecated, see [`binary::u128`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::u128`")] +#[inline(always)] +pub fn u128>(endian: crate::number::Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::u128(endian) +} + +/// Deprecated, see [`binary::i8`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::i8`")] +#[inline(always)] +pub fn i8>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, +{ + binary::i8.parse_next(input) +} + +/// Deprecated, see [`binary::i16`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::i16`")] +#[inline(always)] +pub fn i16>(endian: crate::number::Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::i16(endian) +} + +/// Deprecated, see [`binary::i24`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::i24`")] +#[inline(always)] +pub fn i24>(endian: crate::number::Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::i24(endian) +} + +/// Deprecated, see [`binary::i32`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::i32`")] +#[inline(always)] +pub fn i32>(endian: crate::number::Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::i32(endian) +} + +/// Deprecated, see [`binary::i64`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::i64`")] +#[inline(always)] +pub fn i64>(endian: crate::number::Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::i64(endian) +} + +/// Deprecated, see [`binary::i128`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::i128`")] +#[inline(always)] +pub fn i128>(endian: crate::number::Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::i128(endian) +} + +/// Deprecated, see [`binary::be_f32`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::be_f32`")] +#[inline(always)] +pub fn be_f32>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::be_f32(input) +} + +/// Deprecated, see [`binary::be_f64`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::be_f64`")] +#[inline(always)] +pub fn be_f64>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::be_f64(input) +} + +/// Deprecated, see [`binary::le_f32`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::le_f32`")] +#[inline(always)] +pub fn le_f32>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::le_f32(input) +} + +/// Deprecated, see [`binary::le_f64`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::le_f64`")] +#[inline(always)] +pub fn le_f64>(input: I) -> IResult +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::le_f64(input) +} + +/// Deprecated, see [`binary::f32`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::f32`")] +#[inline(always)] +pub fn f32>(endian: crate::number::Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::f32(endian) +} + +/// Deprecated, see [`binary::f64`] +#[deprecated(since = "0.4.2", note = "Replaced with `binary::f64`")] +#[inline(always)] +pub fn f64>(endian: crate::number::Endianness) -> impl Parser +where + I: StreamIsPartial, + I: Stream, + ::Slice: AsBytes, +{ + binary::f64(endian) +} diff --git a/vendor/winnow/src/number/mod.rs b/vendor/winnow/src/number/mod.rs deleted file mode 100644 index 1554ac729..000000000 --- a/vendor/winnow/src/number/mod.rs +++ /dev/null @@ -1,2388 +0,0 @@ -//! Parsers recognizing numbers - -#![allow(clippy::match_same_arms)] - -#[cfg(test)] -mod tests; - -use crate::bytes::take; -use crate::error::ErrMode; -use crate::error::ErrorKind; -use crate::error::Needed; -use crate::error::ParseError; -use crate::lib::std::ops::{Add, Shl}; -use crate::stream::{AsBytes, Stream, StreamIsPartial}; -use crate::trace::trace; -use crate::IResult; -use crate::Parser; - -/// Configurable endianness -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum Endianness { - /// Big endian - Big, - /// Little endian - Little, - /// Will match the host's endianness - Native, -} - -/// Recognizes an unsigned 1 byte integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::be_u8; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], u8> { -/// be_u8.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"\x03abcefg"[..], 0x00))); -/// assert_eq!(parser(&b""[..]), Err(ErrMode::Backtrack(Error::new(&[][..], ErrorKind::Token)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::be_u8; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, u8> { -/// be_u8.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01abcd"[..])), Ok((Partial::new(&b"\x01abcd"[..]), 0x00))); -/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn be_u8>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, -{ - u8(input) -} - -/// Recognizes a big endian unsigned 2 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::be_u16; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], u16> { -/// be_u16.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"abcefg"[..], 0x0003))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::be_u16; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, u16> { -/// be_u16.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x0001))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn be_u16>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("be_u16", move |input: I| be_uint(input, 2)).parse_next(input) -} - -/// Recognizes a big endian unsigned 3 byte integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::be_u24; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], u32> { -/// be_u24.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03\x05abcefg"[..]), Ok((&b"abcefg"[..], 0x000305))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::be_u24; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, u32> { -/// be_u24.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x000102))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(2)))); -/// ``` -#[inline(always)] -pub fn be_u24>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("be_u23", move |input: I| be_uint(input, 3)).parse_next(input) -} - -/// Recognizes a big endian unsigned 4 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::be_u32; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], u32> { -/// be_u32.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03\x05\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x00030507))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::be_u32; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, u32> { -/// be_u32.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x00010203))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(3)))); -/// ``` -#[inline(always)] -pub fn be_u32>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("be_u32", move |input: I| be_uint(input, 4)).parse_next(input) -} - -/// Recognizes a big endian unsigned 8 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::be_u64; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], u64> { -/// be_u64.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x0001020304050607))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::be_u64; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, u64> { -/// be_u64.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x0001020304050607))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(7)))); -/// ``` -#[inline(always)] -pub fn be_u64>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("be_u64", move |input: I| be_uint(input, 8)).parse_next(input) -} - -/// Recognizes a big endian unsigned 16 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::be_u128; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], u128> { -/// be_u128.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x00010203040506070001020304050607))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::be_u128; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, u128> { -/// be_u128.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x00010203040506070809101112131415))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(15)))); -/// ``` -#[inline(always)] -pub fn be_u128>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("be_u128", move |input: I| be_uint(input, 16)).parse_next(input) -} - -#[inline] -fn be_uint>(input: I, bound: usize) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, - Uint: Default + Shl + Add + From, -{ - debug_assert_ne!(bound, 1, "to_be_uint needs extra work to avoid overflow"); - take(bound) - .map(|n: ::Slice| to_be_uint(n.as_bytes())) - .parse_next(input) -} - -#[inline] -fn to_be_uint(number: &[u8]) -> Uint -where - Uint: Default + Shl + Add + From, -{ - let mut res = Uint::default(); - for byte in number.iter().copied() { - res = (res << 8) + byte.into(); - } - - res -} - -/// Recognizes a signed 1 byte integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::be_i8; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], i8> { -/// be_i8.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"\x03abcefg"[..], 0x00))); -/// assert_eq!(parser(&b""[..]), Err(ErrMode::Backtrack(Error::new(&[][..], ErrorKind::Token)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::be_i8; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, i8> { -/// be_i8.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01abcd"[..])), Ok((Partial::new(&b"\x01abcd"[..]), 0x00))); -/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn be_i8>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, -{ - i8(input) -} - -/// Recognizes a big endian signed 2 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::be_i16; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], i16> { -/// be_i16.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"abcefg"[..], 0x0003))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::be_i16; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, i16> { -/// be_i16.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x0001))); -/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(2)))); -/// ``` -#[inline(always)] -pub fn be_i16>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("be_i16", move |input: I| { - be_uint::<_, u16, _>(input, 2).map(|(i, n)| (i, n as i16)) - }) - .parse_next(input) -} - -/// Recognizes a big endian signed 3 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::be_i24; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], i32> { -/// be_i24.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03\x05abcefg"[..]), Ok((&b"abcefg"[..], 0x000305))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::be_i24; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, i32> { -/// be_i24.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x000102))); -/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(3)))); -/// ``` -#[inline(always)] -pub fn be_i24>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("be_i24", move |input: I| { - be_uint::<_, u32, _>(input, 3).map(|(i, n)| { - // Same as the unsigned version but we need to sign-extend manually here - let n = if n & 0x80_00_00 != 0 { - (n | 0xff_00_00_00) as i32 - } else { - n as i32 - }; - (i, n) - }) - }) - .parse_next(input) -} - -/// Recognizes a big endian signed 4 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::be_i32; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], i32> { -/// be_i32.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03\x05\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x00030507))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::be_i32; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, i32> { -/// be_i32.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x00010203))); -/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(4)))); -/// ``` -#[inline(always)] -pub fn be_i32>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("be_i32", move |input: I| { - be_uint::<_, u32, _>(input, 4).map(|(i, n)| (i, n as i32)) - }) - .parse_next(input) -} - -/// Recognizes a big endian signed 8 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::be_i64; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], i64> { -/// be_i64.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x0001020304050607))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::be_i64; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, i64> { -/// be_i64.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x0001020304050607))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(7)))); -/// ``` -#[inline(always)] -pub fn be_i64>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("be_i64", move |input: I| { - be_uint::<_, u64, _>(input, 8).map(|(i, n)| (i, n as i64)) - }) - .parse_next(input) -} - -/// Recognizes a big endian signed 16 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::be_i128; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], i128> { -/// be_i128.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x00010203040506070001020304050607))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::be_i128; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, i128> { -/// be_i128.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x00010203040506070809101112131415))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(15)))); -/// ``` -#[inline(always)] -pub fn be_i128>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("be_i128", move |input: I| { - be_uint::<_, u128, _>(input, 16).map(|(i, n)| (i, n as i128)) - }) - .parse_next(input) -} - -/// Recognizes an unsigned 1 byte integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::le_u8; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], u8> { -/// le_u8.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"\x03abcefg"[..], 0x00))); -/// assert_eq!(parser(&b""[..]), Err(ErrMode::Backtrack(Error::new(&[][..], ErrorKind::Token)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::le_u8; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, u8> { -/// le_u8.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01abcd"[..])), Ok((Partial::new(&b"\x01abcd"[..]), 0x00))); -/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn le_u8>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, -{ - u8(input) -} - -/// Recognizes a little endian unsigned 2 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::le_u16; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], u16> { -/// le_u16.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"abcefg"[..], 0x0300))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::le_u16; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, u16> { -/// le_u16::<_, Error<_>>.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x0100))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn le_u16>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("le_u16", move |input: I| le_uint(input, 2)).parse_next(input) -} - -/// Recognizes a little endian unsigned 3 byte integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::le_u24; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], u32> { -/// le_u24.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03\x05abcefg"[..]), Ok((&b"abcefg"[..], 0x050300))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::le_u24; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, u32> { -/// le_u24::<_, Error<_>>.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x020100))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(2)))); -/// ``` -#[inline(always)] -pub fn le_u24>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("le_u24", move |input: I| le_uint(input, 3)).parse_next(input) -} - -/// Recognizes a little endian unsigned 4 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::le_u32; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], u32> { -/// le_u32.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03\x05\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x07050300))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::le_u32; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, u32> { -/// le_u32::<_, Error<_>>.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x03020100))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(3)))); -/// ``` -#[inline(always)] -pub fn le_u32>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("le_u32", move |input: I| le_uint(input, 4)).parse_next(input) -} - -/// Recognizes a little endian unsigned 8 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::le_u64; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], u64> { -/// le_u64.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x0706050403020100))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::le_u64; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, u64> { -/// le_u64::<_, Error<_>>.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x0706050403020100))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(7)))); -/// ``` -#[inline(always)] -pub fn le_u64>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("le_u64", move |input: I| le_uint(input, 8)).parse_next(input) -} - -/// Recognizes a little endian unsigned 16 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::le_u128; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], u128> { -/// le_u128.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x07060504030201000706050403020100))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::le_u128; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, u128> { -/// le_u128::<_, Error<_>>.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x15141312111009080706050403020100))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(15)))); -/// ``` -#[inline(always)] -pub fn le_u128>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("le_u128", move |input: I| le_uint(input, 16)).parse_next(input) -} - -#[inline] -fn le_uint>(input: I, bound: usize) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, - Uint: Default + Shl + Add + From, -{ - take(bound) - .map(|n: ::Slice| to_le_uint(n.as_bytes())) - .parse_next(input) -} - -#[inline] -fn to_le_uint(number: &[u8]) -> Uint -where - Uint: Default + Shl + Add + From, -{ - let mut res = Uint::default(); - for (index, byte) in number.iter_offsets() { - res = res + (Uint::from(byte) << (8 * index as u8)); - } - - res -} - -/// Recognizes a signed 1 byte integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::le_i8; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], i8> { -/// le_i8.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"\x03abcefg"[..], 0x00))); -/// assert_eq!(parser(&b""[..]), Err(ErrMode::Backtrack(Error::new(&[][..], ErrorKind::Token)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::le_i8; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, i8> { -/// le_i8.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01abcd"[..])), Ok((Partial::new(&b"\x01abcd"[..]), 0x00))); -/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn le_i8>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, -{ - i8(input) -} - -/// Recognizes a little endian signed 2 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::le_i16; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], i16> { -/// le_i16.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"abcefg"[..], 0x0300))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::le_i16; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, i16> { -/// le_i16::<_, Error<_>>.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x0100))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn le_i16>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("le_i16", move |input: I| { - le_uint::<_, u16, _>(input, 2).map(|(i, n)| (i, n as i16)) - }) - .parse_next(input) -} - -/// Recognizes a little endian signed 3 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::le_i24; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], i32> { -/// le_i24.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03\x05abcefg"[..]), Ok((&b"abcefg"[..], 0x050300))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::le_i24; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, i32> { -/// le_i24::<_, Error<_>>.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x020100))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(2)))); -/// ``` -#[inline(always)] -pub fn le_i24>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("le_i24", move |input: I| { - le_uint::<_, u32, _>(input, 3).map(|(i, n)| { - // Same as the unsigned version but we need to sign-extend manually here - let n = if n & 0x80_00_00 != 0 { - (n | 0xff_00_00_00) as i32 - } else { - n as i32 - }; - (i, n) - }) - }) - .parse_next(input) -} - -/// Recognizes a little endian signed 4 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::le_i32; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], i32> { -/// le_i32.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03\x05\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x07050300))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::le_i32; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, i32> { -/// le_i32::<_, Error<_>>.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x03020100))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(3)))); -/// ``` -#[inline(always)] -pub fn le_i32>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("le_i32", move |input: I| { - le_uint::<_, u32, _>(input, 4).map(|(i, n)| (i, n as i32)) - }) - .parse_next(input) -} - -/// Recognizes a little endian signed 8 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::le_i64; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], i64> { -/// le_i64.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x0706050403020100))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::le_i64; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, i64> { -/// le_i64::<_, Error<_>>.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x0706050403020100))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(7)))); -/// ``` -#[inline(always)] -pub fn le_i64>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("le_i64", move |input: I| { - le_uint::<_, u64, _>(input, 8).map(|(i, n)| (i, n as i64)) - }) - .parse_next(input) -} - -/// Recognizes a little endian signed 16 bytes integer. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::le_i128; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], i128> { -/// le_i128.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x07060504030201000706050403020100))); -/// assert_eq!(parser(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::le_i128; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, i128> { -/// le_i128::<_, Error<_>>.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15abcd"[..])), Ok((Partial::new(&b"abcd"[..]), 0x15141312111009080706050403020100))); -/// assert_eq!(parser(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(15)))); -/// ``` -#[inline(always)] -pub fn le_i128>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("le_i128", move |input: I| { - le_uint::<_, u128, _>(input, 16).map(|(i, n)| (i, n as i128)) - }) - .parse_next(input) -} - -/// Recognizes an unsigned 1 byte integer -/// -/// **Note:** that endianness does not apply to 1 byte numbers. -/// -/// *Complete version*: returns an error if there is not enough input data -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::u8; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], u8> { -/// u8.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"\x03abcefg"[..], 0x00))); -/// assert_eq!(parser(&b""[..]), Err(ErrMode::Backtrack(Error::new(&[][..], ErrorKind::Token)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// # use winnow::Partial; -/// use winnow::number::u8; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, u8> { -/// u8::<_, Error<_>>.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x03abcefg"[..])), Ok((Partial::new(&b"\x03abcefg"[..]), 0x00))); -/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn u8>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, -{ - trace("u8", move |input: I| { - if input.is_partial() { - streaming_u8(input) - } else { - complete_u8(input) - } - }) - .parse_next(input) -} - -#[inline] -pub(crate) fn streaming_u8>(input: I) -> IResult -where - I: Stream, -{ - input - .next_token() - .ok_or_else(|| ErrMode::Incomplete(Needed::new(1))) -} - -pub(crate) fn complete_u8>(input: I) -> IResult -where - I: Stream, -{ - input - .next_token() - .ok_or_else(|| ErrMode::Backtrack(E::from_error_kind(input, ErrorKind::Token))) -} - -/// Recognizes an unsigned 2 bytes integer -/// -/// If the parameter is `winnow::number::Endianness::Big`, parse a big endian u16 integer, -/// otherwise if `winnow::number::Endianness::Little` parse a little endian u16 integer. -/// -/// *Complete version*: returns an error if there is not enough input data -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::u16; -/// -/// let be_u16 = |s| { -/// u16(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_u16(&b"\x00\x03abcefg"[..]), Ok((&b"abcefg"[..], 0x0003))); -/// assert_eq!(be_u16(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// -/// let le_u16 = |s| { -/// u16(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_u16(&b"\x00\x03abcefg"[..]), Ok((&b"abcefg"[..], 0x0300))); -/// assert_eq!(le_u16(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// # use winnow::Partial; -/// use winnow::number::u16; -/// -/// let be_u16 = |s| { -/// u16::<_, Error<_>>(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_u16(Partial::new(&b"\x00\x03abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x0003))); -/// assert_eq!(be_u16(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); -/// -/// let le_u16 = |s| { -/// u16::<_, Error<_>>(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_u16(Partial::new(&b"\x00\x03abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x0300))); -/// assert_eq!(le_u16(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn u16>(endian: crate::number::Endianness) -> impl Parser -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - move |input: I| { - match endian { - crate::number::Endianness::Big => be_u16, - crate::number::Endianness::Little => le_u16, - #[cfg(target_endian = "big")] - crate::number::Endianness::Native => be_u16, - #[cfg(target_endian = "little")] - crate::number::Endianness::Native => le_u16, - } - }(input) -} - -/// Recognizes an unsigned 3 byte integer -/// -/// If the parameter is `winnow::number::Endianness::Big`, parse a big endian u24 integer, -/// otherwise if `winnow::number::Endianness::Little` parse a little endian u24 integer. -/// -/// *Complete version*: returns an error if there is not enough input data -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::u24; -/// -/// let be_u24 = |s| { -/// u24(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_u24(&b"\x00\x03\x05abcefg"[..]), Ok((&b"abcefg"[..], 0x000305))); -/// assert_eq!(be_u24(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// -/// let le_u24 = |s| { -/// u24(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_u24(&b"\x00\x03\x05abcefg"[..]), Ok((&b"abcefg"[..], 0x050300))); -/// assert_eq!(le_u24(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// # use winnow::Partial; -/// use winnow::number::u24; -/// -/// let be_u24 = |s| { -/// u24::<_,Error<_>>(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_u24(Partial::new(&b"\x00\x03\x05abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x000305))); -/// assert_eq!(be_u24(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(2)))); -/// -/// let le_u24 = |s| { -/// u24::<_, Error<_>>(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_u24(Partial::new(&b"\x00\x03\x05abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x050300))); -/// assert_eq!(le_u24(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(2)))); -/// ``` -#[inline(always)] -pub fn u24>(endian: crate::number::Endianness) -> impl Parser -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - move |input: I| { - match endian { - crate::number::Endianness::Big => be_u24, - crate::number::Endianness::Little => le_u24, - #[cfg(target_endian = "big")] - crate::number::Endianness::Native => be_u24, - #[cfg(target_endian = "little")] - crate::number::Endianness::Native => le_u24, - } - }(input) -} - -/// Recognizes an unsigned 4 byte integer -/// -/// If the parameter is `winnow::number::Endianness::Big`, parse a big endian u32 integer, -/// otherwise if `winnow::number::Endianness::Little` parse a little endian u32 integer. -/// -/// *Complete version*: returns an error if there is not enough input data -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::u32; -/// -/// let be_u32 = |s| { -/// u32(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_u32(&b"\x00\x03\x05\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x00030507))); -/// assert_eq!(be_u32(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// -/// let le_u32 = |s| { -/// u32(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_u32(&b"\x00\x03\x05\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x07050300))); -/// assert_eq!(le_u32(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// # use winnow::Partial; -/// use winnow::number::u32; -/// -/// let be_u32 = |s| { -/// u32::<_, Error<_>>(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_u32(Partial::new(&b"\x00\x03\x05\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x00030507))); -/// assert_eq!(be_u32(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(3)))); -/// -/// let le_u32 = |s| { -/// u32::<_, Error<_>>(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_u32(Partial::new(&b"\x00\x03\x05\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x07050300))); -/// assert_eq!(le_u32(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(3)))); -/// ``` -#[inline(always)] -pub fn u32>(endian: crate::number::Endianness) -> impl Parser -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - move |input: I| { - match endian { - crate::number::Endianness::Big => be_u32, - crate::number::Endianness::Little => le_u32, - #[cfg(target_endian = "big")] - crate::number::Endianness::Native => be_u32, - #[cfg(target_endian = "little")] - crate::number::Endianness::Native => le_u32, - } - }(input) -} - -/// Recognizes an unsigned 8 byte integer -/// -/// If the parameter is `winnow::number::Endianness::Big`, parse a big endian u64 integer, -/// otherwise if `winnow::number::Endianness::Little` parse a little endian u64 integer. -/// -/// *Complete version*: returns an error if there is not enough input data -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::u64; -/// -/// let be_u64 = |s| { -/// u64(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_u64(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x0001020304050607))); -/// assert_eq!(be_u64(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// -/// let le_u64 = |s| { -/// u64(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_u64(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x0706050403020100))); -/// assert_eq!(le_u64(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// # use winnow::Partial; -/// use winnow::number::u64; -/// -/// let be_u64 = |s| { -/// u64::<_, Error<_>>(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_u64(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x0001020304050607))); -/// assert_eq!(be_u64(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(7)))); -/// -/// let le_u64 = |s| { -/// u64::<_, Error<_>>(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_u64(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x0706050403020100))); -/// assert_eq!(le_u64(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(7)))); -/// ``` -#[inline(always)] -pub fn u64>(endian: crate::number::Endianness) -> impl Parser -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - move |input: I| { - match endian { - crate::number::Endianness::Big => be_u64, - crate::number::Endianness::Little => le_u64, - #[cfg(target_endian = "big")] - crate::number::Endianness::Native => be_u64, - #[cfg(target_endian = "little")] - crate::number::Endianness::Native => le_u64, - } - }(input) -} - -/// Recognizes an unsigned 16 byte integer -/// -/// If the parameter is `winnow::number::Endianness::Big`, parse a big endian u128 integer, -/// otherwise if `winnow::number::Endianness::Little` parse a little endian u128 integer. -/// -/// *Complete version*: returns an error if there is not enough input data -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::u128; -/// -/// let be_u128 = |s| { -/// u128(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_u128(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x00010203040506070001020304050607))); -/// assert_eq!(be_u128(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// -/// let le_u128 = |s| { -/// u128(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_u128(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x07060504030201000706050403020100))); -/// assert_eq!(le_u128(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// # use winnow::Partial; -/// use winnow::number::u128; -/// -/// let be_u128 = |s| { -/// u128::<_, Error<_>>(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_u128(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x00010203040506070001020304050607))); -/// assert_eq!(be_u128(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(15)))); -/// -/// let le_u128 = |s| { -/// u128::<_, Error<_>>(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_u128(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x07060504030201000706050403020100))); -/// assert_eq!(le_u128(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(15)))); -/// ``` -#[inline(always)] -pub fn u128>(endian: crate::number::Endianness) -> impl Parser -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - move |input: I| { - match endian { - crate::number::Endianness::Big => be_u128, - crate::number::Endianness::Little => le_u128, - #[cfg(target_endian = "big")] - crate::number::Endianness::Native => be_u128, - #[cfg(target_endian = "little")] - crate::number::Endianness::Native => le_u128, - } - }(input) -} - -/// Recognizes a signed 1 byte integer -/// -/// **Note:** that endianness does not apply to 1 byte numbers. -/// -/// *Complete version*: returns an error if there is not enough input data -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::i8; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], i8> { -/// i8.parse_next(s) -/// } -/// -/// assert_eq!(parser(&b"\x00\x03abcefg"[..]), Ok((&b"\x03abcefg"[..], 0x00))); -/// assert_eq!(parser(&b""[..]), Err(ErrMode::Backtrack(Error::new(&[][..], ErrorKind::Token)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// # use winnow::Partial; -/// use winnow::number::i8; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, i8> { -/// i8.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&b"\x00\x03abcefg"[..])), Ok((Partial::new(&b"\x03abcefg"[..]), 0x00))); -/// assert_eq!(parser(Partial::new(&b""[..])), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn i8>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, -{ - trace("i8", move |input: I| { - if input.is_partial() { - streaming_u8(input) - } else { - complete_u8(input) - } - .map(|(i, n)| (i, n as i8)) - }) - .parse_next(input) -} - -/// Recognizes a signed 2 byte integer -/// -/// If the parameter is `winnow::number::Endianness::Big`, parse a big endian i16 integer, -/// otherwise if `winnow::number::Endianness::Little` parse a little endian i16 integer. -/// -/// *Complete version*: returns an error if there is not enough input data -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::i16; -/// -/// let be_i16 = |s| { -/// i16(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_i16(&b"\x00\x03abcefg"[..]), Ok((&b"abcefg"[..], 0x0003))); -/// assert_eq!(be_i16(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// -/// let le_i16 = |s| { -/// i16(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_i16(&b"\x00\x03abcefg"[..]), Ok((&b"abcefg"[..], 0x0300))); -/// assert_eq!(le_i16(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// # use winnow::Partial; -/// use winnow::number::i16; -/// -/// let be_i16 = |s| { -/// i16::<_, Error<_>>(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_i16(Partial::new(&b"\x00\x03abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x0003))); -/// assert_eq!(be_i16(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); -/// -/// let le_i16 = |s| { -/// i16::<_, Error<_>>(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_i16(Partial::new(&b"\x00\x03abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x0300))); -/// assert_eq!(le_i16(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn i16>(endian: crate::number::Endianness) -> impl Parser -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - move |input: I| { - match endian { - crate::number::Endianness::Big => be_i16, - crate::number::Endianness::Little => le_i16, - #[cfg(target_endian = "big")] - crate::number::Endianness::Native => be_i16, - #[cfg(target_endian = "little")] - crate::number::Endianness::Native => le_i16, - } - }(input) -} - -/// Recognizes a signed 3 byte integer -/// -/// If the parameter is `winnow::number::Endianness::Big`, parse a big endian i24 integer, -/// otherwise if `winnow::number::Endianness::Little` parse a little endian i24 integer. -/// -/// *Complete version*: returns an error if there is not enough input data -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::i24; -/// -/// let be_i24 = |s| { -/// i24(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_i24(&b"\x00\x03\x05abcefg"[..]), Ok((&b"abcefg"[..], 0x000305))); -/// assert_eq!(be_i24(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// -/// let le_i24 = |s| { -/// i24(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_i24(&b"\x00\x03\x05abcefg"[..]), Ok((&b"abcefg"[..], 0x050300))); -/// assert_eq!(le_i24(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// # use winnow::Partial; -/// use winnow::number::i24; -/// -/// let be_i24 = |s| { -/// i24::<_, Error<_>>(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_i24(Partial::new(&b"\x00\x03\x05abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x000305))); -/// assert_eq!(be_i24(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(2)))); -/// -/// let le_i24 = |s| { -/// i24::<_, Error<_>>(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_i24(Partial::new(&b"\x00\x03\x05abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x050300))); -/// assert_eq!(le_i24(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(2)))); -/// ``` -#[inline(always)] -pub fn i24>(endian: crate::number::Endianness) -> impl Parser -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - move |input: I| { - match endian { - crate::number::Endianness::Big => be_i24, - crate::number::Endianness::Little => le_i24, - #[cfg(target_endian = "big")] - crate::number::Endianness::Native => be_i24, - #[cfg(target_endian = "little")] - crate::number::Endianness::Native => le_i24, - } - }(input) -} - -/// Recognizes a signed 4 byte integer -/// -/// If the parameter is `winnow::number::Endianness::Big`, parse a big endian i32 integer, -/// otherwise if `winnow::number::Endianness::Little` parse a little endian i32 integer. -/// -/// *Complete version*: returns an error if there is not enough input data -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::i32; -/// -/// let be_i32 = |s| { -/// i32(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_i32(&b"\x00\x03\x05\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x00030507))); -/// assert_eq!(be_i32(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// -/// let le_i32 = |s| { -/// i32(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_i32(&b"\x00\x03\x05\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x07050300))); -/// assert_eq!(le_i32(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// # use winnow::Partial; -/// use winnow::number::i32; -/// -/// let be_i32 = |s| { -/// i32::<_, Error<_>>(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_i32(Partial::new(&b"\x00\x03\x05\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x00030507))); -/// assert_eq!(be_i32(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(3)))); -/// -/// let le_i32 = |s| { -/// i32::<_, Error<_>>(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_i32(Partial::new(&b"\x00\x03\x05\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x07050300))); -/// assert_eq!(le_i32(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(3)))); -/// ``` -#[inline(always)] -pub fn i32>(endian: crate::number::Endianness) -> impl Parser -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - move |input: I| { - match endian { - crate::number::Endianness::Big => be_i32, - crate::number::Endianness::Little => le_i32, - #[cfg(target_endian = "big")] - crate::number::Endianness::Native => be_i32, - #[cfg(target_endian = "little")] - crate::number::Endianness::Native => le_i32, - } - }(input) -} - -/// Recognizes a signed 8 byte integer -/// -/// If the parameter is `winnow::number::Endianness::Big`, parse a big endian i64 integer, -/// otherwise if `winnow::number::Endianness::Little` parse a little endian i64 integer. -/// -/// *Complete version*: returns an error if there is not enough input data -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::i64; -/// -/// let be_i64 = |s| { -/// i64(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_i64(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x0001020304050607))); -/// assert_eq!(be_i64(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// -/// let le_i64 = |s| { -/// i64(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_i64(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x0706050403020100))); -/// assert_eq!(le_i64(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// # use winnow::Partial; -/// use winnow::number::i64; -/// -/// let be_i64 = |s| { -/// i64::<_, Error<_>>(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_i64(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x0001020304050607))); -/// assert_eq!(be_i64(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(7)))); -/// -/// let le_i64 = |s| { -/// i64::<_, Error<_>>(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_i64(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x0706050403020100))); -/// assert_eq!(le_i64(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(7)))); -/// ``` -#[inline(always)] -pub fn i64>(endian: crate::number::Endianness) -> impl Parser -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - move |input: I| { - match endian { - crate::number::Endianness::Big => be_i64, - crate::number::Endianness::Little => le_i64, - #[cfg(target_endian = "big")] - crate::number::Endianness::Native => be_i64, - #[cfg(target_endian = "little")] - crate::number::Endianness::Native => le_i64, - } - }(input) -} - -/// Recognizes a signed 16 byte integer -/// -/// If the parameter is `winnow::number::Endianness::Big`, parse a big endian i128 integer, -/// otherwise if `winnow::number::Endianness::Little` parse a little endian i128 integer. -/// -/// *Complete version*: returns an error if there is not enough input data -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::i128; -/// -/// let be_i128 = |s| { -/// i128(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_i128(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x00010203040506070001020304050607))); -/// assert_eq!(be_i128(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// -/// let le_i128 = |s| { -/// i128(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_i128(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..]), Ok((&b"abcefg"[..], 0x07060504030201000706050403020100))); -/// assert_eq!(le_i128(&b"\x01"[..]), Err(ErrMode::Backtrack(Error::new(&[0x01][..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// # use winnow::Partial; -/// use winnow::number::i128; -/// -/// let be_i128 = |s| { -/// i128::<_, Error<_>>(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_i128(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x00010203040506070001020304050607))); -/// assert_eq!(be_i128(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(15)))); -/// -/// let le_i128 = |s| { -/// i128::<_, Error<_>>(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_i128(Partial::new(&b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07abcefg"[..])), Ok((Partial::new(&b"abcefg"[..]), 0x07060504030201000706050403020100))); -/// assert_eq!(le_i128(Partial::new(&b"\x01"[..])), Err(ErrMode::Incomplete(Needed::new(15)))); -/// ``` -#[inline(always)] -pub fn i128>(endian: crate::number::Endianness) -> impl Parser -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - move |input: I| { - match endian { - crate::number::Endianness::Big => be_i128, - crate::number::Endianness::Little => le_i128, - #[cfg(target_endian = "big")] - crate::number::Endianness::Native => be_i128, - #[cfg(target_endian = "little")] - crate::number::Endianness::Native => le_i128, - } - }(input) -} - -/// Recognizes a big endian 4 bytes floating point number. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::be_f32; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], f32> { -/// be_f32.parse_next(s) -/// } -/// -/// assert_eq!(parser(&[0x41, 0x48, 0x00, 0x00][..]), Ok((&b""[..], 12.5))); -/// assert_eq!(parser(&b"abc"[..]), Err(ErrMode::Backtrack(Error::new(&b"abc"[..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::be_f32; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, f32> { -/// be_f32.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&[0x40, 0x29, 0x00, 0x00][..])), Ok((Partial::new(&b""[..]), 2.640625))); -/// assert_eq!(parser(Partial::new(&[0x01][..])), Err(ErrMode::Incomplete(Needed::new(3)))); -/// ``` -#[inline(always)] -pub fn be_f32>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("be_f32", move |input: I| { - be_uint::<_, u32, _>(input, 4).map(|(i, n)| (i, f32::from_bits(n))) - }) - .parse_next(input) -} - -/// Recognizes a big endian 8 bytes floating point number. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::be_f64; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], f64> { -/// be_f64.parse_next(s) -/// } -/// -/// assert_eq!(parser(&[0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]), Ok((&b""[..], 12.5))); -/// assert_eq!(parser(&b"abc"[..]), Err(ErrMode::Backtrack(Error::new(&b"abc"[..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::be_f64; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, f64> { -/// be_f64::<_, Error<_>>.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&[0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..])), Ok((Partial::new(&b""[..]), 12.5))); -/// assert_eq!(parser(Partial::new(&[0x01][..])), Err(ErrMode::Incomplete(Needed::new(7)))); -/// ``` -#[inline(always)] -pub fn be_f64>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("be_f64", move |input: I| { - be_uint::<_, u64, _>(input, 8).map(|(i, n)| (i, f64::from_bits(n))) - }) - .parse_next(input) -} - -/// Recognizes a little endian 4 bytes floating point number. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::le_f32; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], f32> { -/// le_f32.parse_next(s) -/// } -/// -/// assert_eq!(parser(&[0x00, 0x00, 0x48, 0x41][..]), Ok((&b""[..], 12.5))); -/// assert_eq!(parser(&b"abc"[..]), Err(ErrMode::Backtrack(Error::new(&b"abc"[..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::le_f32; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, f32> { -/// le_f32::<_, Error<_>>.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&[0x00, 0x00, 0x48, 0x41][..])), Ok((Partial::new(&b""[..]), 12.5))); -/// assert_eq!(parser(Partial::new(&[0x01][..])), Err(ErrMode::Incomplete(Needed::new(3)))); -/// ``` -#[inline(always)] -pub fn le_f32>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("le_f32", move |input: I| { - le_uint::<_, u32, _>(input, 4).map(|(i, n)| (i, f32::from_bits(n))) - }) - .parse_next(input) -} - -/// Recognizes a little endian 8 bytes floating point number. -/// -/// *Complete version*: Returns an error if there is not enough input data. -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::le_f64; -/// -/// fn parser(s: &[u8]) -> IResult<&[u8], f64> { -/// le_f64.parse_next(s) -/// } -/// -/// assert_eq!(parser(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40][..]), Ok((&b""[..], 12.5))); -/// assert_eq!(parser(&b"abc"[..]), Err(ErrMode::Backtrack(Error::new(&b"abc"[..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::Partial; -/// use winnow::number::le_f64; -/// -/// fn parser(s: Partial<&[u8]>) -> IResult, f64> { -/// le_f64::<_, Error<_>>.parse_next(s) -/// } -/// -/// assert_eq!(parser(Partial::new(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x41][..])), Ok((Partial::new(&b""[..]), 3145728.0))); -/// assert_eq!(parser(Partial::new(&[0x01][..])), Err(ErrMode::Incomplete(Needed::new(7)))); -/// ``` -#[inline(always)] -pub fn le_f64>(input: I) -> IResult -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - trace("be_f64", move |input: I| { - le_uint::<_, u64, _>(input, 8).map(|(i, n)| (i, f64::from_bits(n))) - }) - .parse_next(input) -} - -/// Recognizes a 4 byte floating point number -/// -/// If the parameter is `winnow::number::Endianness::Big`, parse a big endian f32 float, -/// otherwise if `winnow::number::Endianness::Little` parse a little endian f32 float. -/// -/// *Complete version*: returns an error if there is not enough input data -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::f32; -/// -/// let be_f32 = |s| { -/// f32(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_f32(&[0x41, 0x48, 0x00, 0x00][..]), Ok((&b""[..], 12.5))); -/// assert_eq!(be_f32(&b"abc"[..]), Err(ErrMode::Backtrack(Error::new(&b"abc"[..], ErrorKind::Slice)))); -/// -/// let le_f32 = |s| { -/// f32(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_f32(&[0x00, 0x00, 0x48, 0x41][..]), Ok((&b""[..], 12.5))); -/// assert_eq!(le_f32(&b"abc"[..]), Err(ErrMode::Backtrack(Error::new(&b"abc"[..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// # use winnow::Partial; -/// use winnow::number::f32; -/// -/// let be_f32 = |s| { -/// f32::<_, Error<_>>(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_f32(Partial::new(&[0x41, 0x48, 0x00, 0x00][..])), Ok((Partial::new(&b""[..]), 12.5))); -/// assert_eq!(be_f32(Partial::new(&b"abc"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); -/// -/// let le_f32 = |s| { -/// f32::<_, Error<_>>(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_f32(Partial::new(&[0x00, 0x00, 0x48, 0x41][..])), Ok((Partial::new(&b""[..]), 12.5))); -/// assert_eq!(le_f32(Partial::new(&b"abc"[..])), Err(ErrMode::Incomplete(Needed::new(1)))); -/// ``` -#[inline(always)] -pub fn f32>(endian: crate::number::Endianness) -> impl Parser -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - move |input: I| { - match endian { - crate::number::Endianness::Big => be_f32, - crate::number::Endianness::Little => le_f32, - #[cfg(target_endian = "big")] - crate::number::Endianness::Native => be_f32, - #[cfg(target_endian = "little")] - crate::number::Endianness::Native => le_f32, - } - }(input) -} - -/// Recognizes an 8 byte floating point number -/// -/// If the parameter is `winnow::number::Endianness::Big`, parse a big endian f64 float, -/// otherwise if `winnow::number::Endianness::Little` parse a little endian f64 float. -/// -/// *Complete version*: returns an error if there is not enough input data -/// -/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there is not enough data. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::number::f64; -/// -/// let be_f64 = |s| { -/// f64(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_f64(&[0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]), Ok((&b""[..], 12.5))); -/// assert_eq!(be_f64(&b"abc"[..]), Err(ErrMode::Backtrack(Error::new(&b"abc"[..], ErrorKind::Slice)))); -/// -/// let le_f64 = |s| { -/// f64(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_f64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40][..]), Ok((&b""[..], 12.5))); -/// assert_eq!(le_f64(&b"abc"[..]), Err(ErrMode::Backtrack(Error::new(&b"abc"[..], ErrorKind::Slice)))); -/// ``` -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// # use winnow::Partial; -/// use winnow::number::f64; -/// -/// let be_f64 = |s| { -/// f64::<_, Error<_>>(winnow::number::Endianness::Big).parse_next(s) -/// }; -/// -/// assert_eq!(be_f64(Partial::new(&[0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..])), Ok((Partial::new(&b""[..]), 12.5))); -/// assert_eq!(be_f64(Partial::new(&b"abc"[..])), Err(ErrMode::Incomplete(Needed::new(5)))); -/// -/// let le_f64 = |s| { -/// f64::<_, Error<_>>(winnow::number::Endianness::Little).parse_next(s) -/// }; -/// -/// assert_eq!(le_f64(Partial::new(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40][..])), Ok((Partial::new(&b""[..]), 12.5))); -/// assert_eq!(le_f64(Partial::new(&b"abc"[..])), Err(ErrMode::Incomplete(Needed::new(5)))); -/// ``` -#[inline(always)] -pub fn f64>(endian: crate::number::Endianness) -> impl Parser -where - I: StreamIsPartial, - I: Stream, - ::Slice: AsBytes, -{ - move |input: I| { - match endian { - crate::number::Endianness::Big => be_f64, - crate::number::Endianness::Little => le_f64, - #[cfg(target_endian = "big")] - crate::number::Endianness::Native => be_f64, - #[cfg(target_endian = "little")] - crate::number::Endianness::Native => le_f64, - } - }(input) -} diff --git a/vendor/winnow/src/number/tests.rs b/vendor/winnow/src/number/tests.rs deleted file mode 100644 index bbfeb239e..000000000 --- a/vendor/winnow/src/number/tests.rs +++ /dev/null @@ -1,1058 +0,0 @@ -use super::*; - -mod complete { - use super::*; - use crate::error::Error; - - macro_rules! assert_parse( - ($left: expr, $right: expr) => { - let res: $crate::IResult<_, _, Error<_>> = $left; - assert_eq!(res, $right); - }; - ); - - #[test] - fn i8_tests() { - assert_parse!(i8(&[0x00][..]), Ok((&b""[..], 0))); - assert_parse!(i8(&[0x7f][..]), Ok((&b""[..], 127))); - assert_parse!(i8(&[0xff][..]), Ok((&b""[..], -1))); - assert_parse!(i8(&[0x80][..]), Ok((&b""[..], -128))); - } - - #[test] - fn be_i8_tests() { - assert_parse!(be_i8(&[0x00][..]), Ok((&b""[..], 0))); - assert_parse!(be_i8(&[0x7f][..]), Ok((&b""[..], 127))); - assert_parse!(be_i8(&[0xff][..]), Ok((&b""[..], -1))); - assert_parse!(be_i8(&[0x80][..]), Ok((&b""[..], -128))); - } - - #[test] - fn be_i16_tests() { - assert_parse!(be_i16(&[0x00, 0x00][..]), Ok((&b""[..], 0))); - assert_parse!(be_i16(&[0x7f, 0xff][..]), Ok((&b""[..], 32_767_i16))); - assert_parse!(be_i16(&[0xff, 0xff][..]), Ok((&b""[..], -1))); - assert_parse!(be_i16(&[0x80, 0x00][..]), Ok((&b""[..], -32_768_i16))); - } - - #[test] - fn be_u24_tests() { - assert_parse!(be_u24(&[0x00, 0x00, 0x00][..]), Ok((&b""[..], 0))); - assert_parse!(be_u24(&[0x00, 0xFF, 0xFF][..]), Ok((&b""[..], 65_535_u32))); - assert_parse!( - be_u24(&[0x12, 0x34, 0x56][..]), - Ok((&b""[..], 1_193_046_u32)) - ); - } - - #[test] - fn be_i24_tests() { - assert_parse!(be_i24(&[0xFF, 0xFF, 0xFF][..]), Ok((&b""[..], -1_i32))); - assert_parse!(be_i24(&[0xFF, 0x00, 0x00][..]), Ok((&b""[..], -65_536_i32))); - assert_parse!( - be_i24(&[0xED, 0xCB, 0xAA][..]), - Ok((&b""[..], -1_193_046_i32)) - ); - } - - #[test] - fn be_i32_tests() { - assert_parse!(be_i32(&[0x00, 0x00, 0x00, 0x00][..]), Ok((&b""[..], 0))); - assert_parse!( - be_i32(&[0x7f, 0xff, 0xff, 0xff][..]), - Ok((&b""[..], 2_147_483_647_i32)) - ); - assert_parse!(be_i32(&[0xff, 0xff, 0xff, 0xff][..]), Ok((&b""[..], -1))); - assert_parse!( - be_i32(&[0x80, 0x00, 0x00, 0x00][..]), - Ok((&b""[..], -2_147_483_648_i32)) - ); - } - - #[test] - fn be_i64_tests() { - assert_parse!( - be_i64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]), - Ok((&b""[..], 0)) - ); - assert_parse!( - be_i64(&[0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff][..]), - Ok((&b""[..], 9_223_372_036_854_775_807_i64)) - ); - assert_parse!( - be_i64(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff][..]), - Ok((&b""[..], -1)) - ); - assert_parse!( - be_i64(&[0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]), - Ok((&b""[..], -9_223_372_036_854_775_808_i64)) - ); - } - - #[test] - fn be_i128_tests() { - assert_parse!( - be_i128( - &[ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00 - ][..] - ), - Ok((&b""[..], 0)) - ); - assert_parse!( - be_i128( - &[ - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff - ][..] - ), - Ok(( - &b""[..], - 170_141_183_460_469_231_731_687_303_715_884_105_727_i128 - )) - ); - assert_parse!( - be_i128( - &[ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff - ][..] - ), - Ok((&b""[..], -1)) - ); - assert_parse!( - be_i128( - &[ - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00 - ][..] - ), - Ok(( - &b""[..], - -170_141_183_460_469_231_731_687_303_715_884_105_728_i128 - )) - ); - } - - #[test] - fn le_i8_tests() { - assert_parse!(le_i8(&[0x00][..]), Ok((&b""[..], 0))); - assert_parse!(le_i8(&[0x7f][..]), Ok((&b""[..], 127))); - assert_parse!(le_i8(&[0xff][..]), Ok((&b""[..], -1))); - assert_parse!(le_i8(&[0x80][..]), Ok((&b""[..], -128))); - } - - #[test] - fn le_i16_tests() { - assert_parse!(le_i16(&[0x00, 0x00][..]), Ok((&b""[..], 0))); - assert_parse!(le_i16(&[0xff, 0x7f][..]), Ok((&b""[..], 32_767_i16))); - assert_parse!(le_i16(&[0xff, 0xff][..]), Ok((&b""[..], -1))); - assert_parse!(le_i16(&[0x00, 0x80][..]), Ok((&b""[..], -32_768_i16))); - } - - #[test] - fn le_u24_tests() { - assert_parse!(le_u24(&[0x00, 0x00, 0x00][..]), Ok((&b""[..], 0))); - assert_parse!(le_u24(&[0xFF, 0xFF, 0x00][..]), Ok((&b""[..], 65_535_u32))); - assert_parse!( - le_u24(&[0x56, 0x34, 0x12][..]), - Ok((&b""[..], 1_193_046_u32)) - ); - } - - #[test] - fn le_i24_tests() { - assert_parse!(le_i24(&[0xFF, 0xFF, 0xFF][..]), Ok((&b""[..], -1_i32))); - assert_parse!(le_i24(&[0x00, 0x00, 0xFF][..]), Ok((&b""[..], -65_536_i32))); - assert_parse!( - le_i24(&[0xAA, 0xCB, 0xED][..]), - Ok((&b""[..], -1_193_046_i32)) - ); - } - - #[test] - fn le_i32_tests() { - assert_parse!(le_i32(&[0x00, 0x00, 0x00, 0x00][..]), Ok((&b""[..], 0))); - assert_parse!( - le_i32(&[0xff, 0xff, 0xff, 0x7f][..]), - Ok((&b""[..], 2_147_483_647_i32)) - ); - assert_parse!(le_i32(&[0xff, 0xff, 0xff, 0xff][..]), Ok((&b""[..], -1))); - assert_parse!( - le_i32(&[0x00, 0x00, 0x00, 0x80][..]), - Ok((&b""[..], -2_147_483_648_i32)) - ); - } - - #[test] - fn le_i64_tests() { - assert_parse!( - le_i64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]), - Ok((&b""[..], 0)) - ); - assert_parse!( - le_i64(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f][..]), - Ok((&b""[..], 9_223_372_036_854_775_807_i64)) - ); - assert_parse!( - le_i64(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff][..]), - Ok((&b""[..], -1)) - ); - assert_parse!( - le_i64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80][..]), - Ok((&b""[..], -9_223_372_036_854_775_808_i64)) - ); - } - - #[test] - fn le_i128_tests() { - assert_parse!( - le_i128( - &[ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00 - ][..] - ), - Ok((&b""[..], 0)) - ); - assert_parse!( - le_i128( - &[ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x7f - ][..] - ), - Ok(( - &b""[..], - 170_141_183_460_469_231_731_687_303_715_884_105_727_i128 - )) - ); - assert_parse!( - le_i128( - &[ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff - ][..] - ), - Ok((&b""[..], -1)) - ); - assert_parse!( - le_i128( - &[ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x80 - ][..] - ), - Ok(( - &b""[..], - -170_141_183_460_469_231_731_687_303_715_884_105_728_i128 - )) - ); - } - - #[test] - fn be_f32_tests() { - assert_parse!(be_f32(&[0x00, 0x00, 0x00, 0x00][..]), Ok((&b""[..], 0_f32))); - assert_parse!( - be_f32(&[0x4d, 0x31, 0x1f, 0xd8][..]), - Ok((&b""[..], 185_728_380_f32)) - ); - } - - #[test] - fn be_f64_tests() { - assert_parse!( - be_f64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]), - Ok((&b""[..], 0_f64)) - ); - assert_parse!( - be_f64(&[0x41, 0xa6, 0x23, 0xfb, 0x10, 0x00, 0x00, 0x00][..]), - Ok((&b""[..], 185_728_392_f64)) - ); - } - - #[test] - fn le_f32_tests() { - assert_parse!(le_f32(&[0x00, 0x00, 0x00, 0x00][..]), Ok((&b""[..], 0_f32))); - assert_parse!( - le_f32(&[0xd8, 0x1f, 0x31, 0x4d][..]), - Ok((&b""[..], 185_728_380_f32)) - ); - } - - #[test] - fn le_f64_tests() { - assert_parse!( - le_f64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]), - Ok((&b""[..], 0_f64)) - ); - assert_parse!( - le_f64(&[0x00, 0x00, 0x00, 0x10, 0xfb, 0x23, 0xa6, 0x41][..]), - Ok((&b""[..], 185_728_392_f64)) - ); - } - - #[test] - fn configurable_endianness() { - use crate::number::Endianness; - - fn be_tst16(i: &[u8]) -> IResult<&[u8], u16> { - u16(Endianness::Big).parse_next(i) - } - fn le_tst16(i: &[u8]) -> IResult<&[u8], u16> { - u16(Endianness::Little).parse_next(i) - } - assert_eq!(be_tst16(&[0x80, 0x00]), Ok((&b""[..], 32_768_u16))); - assert_eq!(le_tst16(&[0x80, 0x00]), Ok((&b""[..], 128_u16))); - - fn be_tst32(i: &[u8]) -> IResult<&[u8], u32> { - u32(Endianness::Big).parse_next(i) - } - fn le_tst32(i: &[u8]) -> IResult<&[u8], u32> { - u32(Endianness::Little).parse_next(i) - } - assert_eq!( - be_tst32(&[0x12, 0x00, 0x60, 0x00]), - Ok((&b""[..], 302_014_464_u32)) - ); - assert_eq!( - le_tst32(&[0x12, 0x00, 0x60, 0x00]), - Ok((&b""[..], 6_291_474_u32)) - ); - - fn be_tst64(i: &[u8]) -> IResult<&[u8], u64> { - u64(Endianness::Big).parse_next(i) - } - fn le_tst64(i: &[u8]) -> IResult<&[u8], u64> { - u64(Endianness::Little).parse_next(i) - } - assert_eq!( - be_tst64(&[0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]), - Ok((&b""[..], 1_297_142_246_100_992_000_u64)) - ); - assert_eq!( - le_tst64(&[0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]), - Ok((&b""[..], 36_028_874_334_666_770_u64)) - ); - - fn be_tsti16(i: &[u8]) -> IResult<&[u8], i16> { - i16(Endianness::Big).parse_next(i) - } - fn le_tsti16(i: &[u8]) -> IResult<&[u8], i16> { - i16(Endianness::Little).parse_next(i) - } - assert_eq!(be_tsti16(&[0x00, 0x80]), Ok((&b""[..], 128_i16))); - assert_eq!(le_tsti16(&[0x00, 0x80]), Ok((&b""[..], -32_768_i16))); - - fn be_tsti32(i: &[u8]) -> IResult<&[u8], i32> { - i32(Endianness::Big).parse_next(i) - } - fn le_tsti32(i: &[u8]) -> IResult<&[u8], i32> { - i32(Endianness::Little).parse_next(i) - } - assert_eq!( - be_tsti32(&[0x00, 0x12, 0x60, 0x00]), - Ok((&b""[..], 1_204_224_i32)) - ); - assert_eq!( - le_tsti32(&[0x00, 0x12, 0x60, 0x00]), - Ok((&b""[..], 6_296_064_i32)) - ); - - fn be_tsti64(i: &[u8]) -> IResult<&[u8], i64> { - i64(Endianness::Big).parse_next(i) - } - fn le_tsti64(i: &[u8]) -> IResult<&[u8], i64> { - i64(Endianness::Little).parse_next(i) - } - assert_eq!( - be_tsti64(&[0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]), - Ok((&b""[..], 71_881_672_479_506_432_i64)) - ); - assert_eq!( - le_tsti64(&[0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]), - Ok((&b""[..], 36_028_874_334_732_032_i64)) - ); - } -} - -mod partial { - use super::*; - use crate::error::ErrMode; - use crate::error::Error; - use crate::error::Needed; - use crate::Partial; - - macro_rules! assert_parse( - ($left: expr, $right: expr) => { - let res: $crate::IResult<_, _, Error<_>> = $left; - assert_eq!(res, $right); - }; - ); - - #[test] - fn i8_tests() { - assert_parse!( - be_i8(Partial::new(&[0x00][..])), - Ok((Partial::new(&b""[..]), 0)) - ); - assert_parse!( - be_i8(Partial::new(&[0x7f][..])), - Ok((Partial::new(&b""[..]), 127)) - ); - assert_parse!( - be_i8(Partial::new(&[0xff][..])), - Ok((Partial::new(&b""[..]), -1)) - ); - assert_parse!( - be_i8(Partial::new(&[0x80][..])), - Ok((Partial::new(&b""[..]), -128)) - ); - assert_parse!( - be_i8(Partial::new(&[][..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - } - - #[test] - fn i16_tests() { - assert_parse!( - be_i16(Partial::new(&[0x00, 0x00][..])), - Ok((Partial::new(&b""[..]), 0)) - ); - assert_parse!( - be_i16(Partial::new(&[0x7f, 0xff][..])), - Ok((Partial::new(&b""[..]), 32_767_i16)) - ); - assert_parse!( - be_i16(Partial::new(&[0xff, 0xff][..])), - Ok((Partial::new(&b""[..]), -1)) - ); - assert_parse!( - be_i16(Partial::new(&[0x80, 0x00][..])), - Ok((Partial::new(&b""[..]), -32_768_i16)) - ); - assert_parse!( - be_i16(Partial::new(&[][..])), - Err(ErrMode::Incomplete(Needed::new(2))) - ); - assert_parse!( - be_i16(Partial::new(&[0x00][..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - } - - #[test] - fn u24_tests() { - assert_parse!( - be_u24(Partial::new(&[0x00, 0x00, 0x00][..])), - Ok((Partial::new(&b""[..]), 0)) - ); - assert_parse!( - be_u24(Partial::new(&[0x00, 0xFF, 0xFF][..])), - Ok((Partial::new(&b""[..]), 65_535_u32)) - ); - assert_parse!( - be_u24(Partial::new(&[0x12, 0x34, 0x56][..])), - Ok((Partial::new(&b""[..]), 1_193_046_u32)) - ); - assert_parse!( - be_u24(Partial::new(&[][..])), - Err(ErrMode::Incomplete(Needed::new(3))) - ); - assert_parse!( - be_u24(Partial::new(&[0x00][..])), - Err(ErrMode::Incomplete(Needed::new(2))) - ); - assert_parse!( - be_u24(Partial::new(&[0x00, 0x00][..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - } - - #[test] - fn i24_tests() { - assert_parse!( - be_i24(Partial::new(&[0xFF, 0xFF, 0xFF][..])), - Ok((Partial::new(&b""[..]), -1_i32)) - ); - assert_parse!( - be_i24(Partial::new(&[0xFF, 0x00, 0x00][..])), - Ok((Partial::new(&b""[..]), -65_536_i32)) - ); - assert_parse!( - be_i24(Partial::new(&[0xED, 0xCB, 0xAA][..])), - Ok((Partial::new(&b""[..]), -1_193_046_i32)) - ); - assert_parse!( - be_i24(Partial::new(&[][..])), - Err(ErrMode::Incomplete(Needed::new(3))) - ); - assert_parse!( - be_i24(Partial::new(&[0x00][..])), - Err(ErrMode::Incomplete(Needed::new(2))) - ); - assert_parse!( - be_i24(Partial::new(&[0x00, 0x00][..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - } - - #[test] - fn i32_tests() { - assert_parse!( - be_i32(Partial::new(&[0x00, 0x00, 0x00, 0x00][..])), - Ok((Partial::new(&b""[..]), 0)) - ); - assert_parse!( - be_i32(Partial::new(&[0x7f, 0xff, 0xff, 0xff][..])), - Ok((Partial::new(&b""[..]), 2_147_483_647_i32)) - ); - assert_parse!( - be_i32(Partial::new(&[0xff, 0xff, 0xff, 0xff][..])), - Ok((Partial::new(&b""[..]), -1)) - ); - assert_parse!( - be_i32(Partial::new(&[0x80, 0x00, 0x00, 0x00][..])), - Ok((Partial::new(&b""[..]), -2_147_483_648_i32)) - ); - assert_parse!( - be_i32(Partial::new(&[][..])), - Err(ErrMode::Incomplete(Needed::new(4))) - ); - assert_parse!( - be_i32(Partial::new(&[0x00][..])), - Err(ErrMode::Incomplete(Needed::new(3))) - ); - assert_parse!( - be_i32(Partial::new(&[0x00, 0x00][..])), - Err(ErrMode::Incomplete(Needed::new(2))) - ); - assert_parse!( - be_i32(Partial::new(&[0x00, 0x00, 0x00][..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - } - - #[test] - fn i64_tests() { - assert_parse!( - be_i64(Partial::new( - &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] - )), - Ok((Partial::new(&b""[..]), 0)) - ); - assert_parse!( - be_i64(Partial::new( - &[0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff][..] - )), - Ok((Partial::new(&b""[..]), 9_223_372_036_854_775_807_i64)) - ); - assert_parse!( - be_i64(Partial::new( - &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff][..] - )), - Ok((Partial::new(&b""[..]), -1)) - ); - assert_parse!( - be_i64(Partial::new( - &[0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] - )), - Ok((Partial::new(&b""[..]), -9_223_372_036_854_775_808_i64)) - ); - assert_parse!( - be_i64(Partial::new(&[][..])), - Err(ErrMode::Incomplete(Needed::new(8))) - ); - assert_parse!( - be_i64(Partial::new(&[0x00][..])), - Err(ErrMode::Incomplete(Needed::new(7))) - ); - assert_parse!( - be_i64(Partial::new(&[0x00, 0x00][..])), - Err(ErrMode::Incomplete(Needed::new(6))) - ); - assert_parse!( - be_i64(Partial::new(&[0x00, 0x00, 0x00][..])), - Err(ErrMode::Incomplete(Needed::new(5))) - ); - assert_parse!( - be_i64(Partial::new(&[0x00, 0x00, 0x00, 0x00][..])), - Err(ErrMode::Incomplete(Needed::new(4))) - ); - assert_parse!( - be_i64(Partial::new(&[0x00, 0x00, 0x00, 0x00, 0x00][..])), - Err(ErrMode::Incomplete(Needed::new(3))) - ); - assert_parse!( - be_i64(Partial::new(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..])), - Err(ErrMode::Incomplete(Needed::new(2))) - ); - assert_parse!( - be_i64(Partial::new( - &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] - )), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - } - - #[test] - fn i128_tests() { - assert_parse!( - be_i128(Partial::new( - &[ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00 - ][..] - )), - Ok((Partial::new(&b""[..]), 0)) - ); - assert_parse!( - be_i128(Partial::new( - &[ - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff - ][..] - )), - Ok(( - Partial::new(&b""[..]), - 170_141_183_460_469_231_731_687_303_715_884_105_727_i128 - )) - ); - assert_parse!( - be_i128(Partial::new( - &[ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff - ][..] - )), - Ok((Partial::new(&b""[..]), -1)) - ); - assert_parse!( - be_i128(Partial::new( - &[ - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00 - ][..] - )), - Ok(( - Partial::new(&b""[..]), - -170_141_183_460_469_231_731_687_303_715_884_105_728_i128 - )) - ); - assert_parse!( - be_i128(Partial::new(&[][..])), - Err(ErrMode::Incomplete(Needed::new(16))) - ); - assert_parse!( - be_i128(Partial::new(&[0x00][..])), - Err(ErrMode::Incomplete(Needed::new(15))) - ); - assert_parse!( - be_i128(Partial::new(&[0x00, 0x00][..])), - Err(ErrMode::Incomplete(Needed::new(14))) - ); - assert_parse!( - be_i128(Partial::new(&[0x00, 0x00, 0x00][..])), - Err(ErrMode::Incomplete(Needed::new(13))) - ); - assert_parse!( - be_i128(Partial::new(&[0x00, 0x00, 0x00, 0x00][..])), - Err(ErrMode::Incomplete(Needed::new(12))) - ); - assert_parse!( - be_i128(Partial::new(&[0x00, 0x00, 0x00, 0x00, 0x00][..])), - Err(ErrMode::Incomplete(Needed::new(11))) - ); - assert_parse!( - be_i128(Partial::new(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..])), - Err(ErrMode::Incomplete(Needed::new(10))) - ); - assert_parse!( - be_i128(Partial::new( - &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] - )), - Err(ErrMode::Incomplete(Needed::new(9))) - ); - assert_parse!( - be_i128(Partial::new( - &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] - )), - Err(ErrMode::Incomplete(Needed::new(8))) - ); - assert_parse!( - be_i128(Partial::new( - &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] - )), - Err(ErrMode::Incomplete(Needed::new(7))) - ); - assert_parse!( - be_i128(Partial::new( - &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] - )), - Err(ErrMode::Incomplete(Needed::new(6))) - ); - assert_parse!( - be_i128(Partial::new( - &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] - )), - Err(ErrMode::Incomplete(Needed::new(5))) - ); - assert_parse!( - be_i128(Partial::new( - &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] - )), - Err(ErrMode::Incomplete(Needed::new(4))) - ); - assert_parse!( - be_i128(Partial::new( - &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] - )), - Err(ErrMode::Incomplete(Needed::new(3))) - ); - assert_parse!( - be_i128(Partial::new( - &[ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00 - ][..] - )), - Err(ErrMode::Incomplete(Needed::new(2))) - ); - assert_parse!( - be_i128(Partial::new( - &[ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 - ][..] - )), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - } - - #[test] - fn le_i8_tests() { - assert_parse!( - le_i8(Partial::new(&[0x00][..])), - Ok((Partial::new(&b""[..]), 0)) - ); - assert_parse!( - le_i8(Partial::new(&[0x7f][..])), - Ok((Partial::new(&b""[..]), 127)) - ); - assert_parse!( - le_i8(Partial::new(&[0xff][..])), - Ok((Partial::new(&b""[..]), -1)) - ); - assert_parse!( - le_i8(Partial::new(&[0x80][..])), - Ok((Partial::new(&b""[..]), -128)) - ); - } - - #[test] - fn le_i16_tests() { - assert_parse!( - le_i16(Partial::new(&[0x00, 0x00][..])), - Ok((Partial::new(&b""[..]), 0)) - ); - assert_parse!( - le_i16(Partial::new(&[0xff, 0x7f][..])), - Ok((Partial::new(&b""[..]), 32_767_i16)) - ); - assert_parse!( - le_i16(Partial::new(&[0xff, 0xff][..])), - Ok((Partial::new(&b""[..]), -1)) - ); - assert_parse!( - le_i16(Partial::new(&[0x00, 0x80][..])), - Ok((Partial::new(&b""[..]), -32_768_i16)) - ); - } - - #[test] - fn le_u24_tests() { - assert_parse!( - le_u24(Partial::new(&[0x00, 0x00, 0x00][..])), - Ok((Partial::new(&b""[..]), 0)) - ); - assert_parse!( - le_u24(Partial::new(&[0xFF, 0xFF, 0x00][..])), - Ok((Partial::new(&b""[..]), 65_535_u32)) - ); - assert_parse!( - le_u24(Partial::new(&[0x56, 0x34, 0x12][..])), - Ok((Partial::new(&b""[..]), 1_193_046_u32)) - ); - } - - #[test] - fn le_i24_tests() { - assert_parse!( - le_i24(Partial::new(&[0xFF, 0xFF, 0xFF][..])), - Ok((Partial::new(&b""[..]), -1_i32)) - ); - assert_parse!( - le_i24(Partial::new(&[0x00, 0x00, 0xFF][..])), - Ok((Partial::new(&b""[..]), -65_536_i32)) - ); - assert_parse!( - le_i24(Partial::new(&[0xAA, 0xCB, 0xED][..])), - Ok((Partial::new(&b""[..]), -1_193_046_i32)) - ); - } - - #[test] - fn le_i32_tests() { - assert_parse!( - le_i32(Partial::new(&[0x00, 0x00, 0x00, 0x00][..])), - Ok((Partial::new(&b""[..]), 0)) - ); - assert_parse!( - le_i32(Partial::new(&[0xff, 0xff, 0xff, 0x7f][..])), - Ok((Partial::new(&b""[..]), 2_147_483_647_i32)) - ); - assert_parse!( - le_i32(Partial::new(&[0xff, 0xff, 0xff, 0xff][..])), - Ok((Partial::new(&b""[..]), -1)) - ); - assert_parse!( - le_i32(Partial::new(&[0x00, 0x00, 0x00, 0x80][..])), - Ok((Partial::new(&b""[..]), -2_147_483_648_i32)) - ); - } - - #[test] - fn le_i64_tests() { - assert_parse!( - le_i64(Partial::new( - &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] - )), - Ok((Partial::new(&b""[..]), 0)) - ); - assert_parse!( - le_i64(Partial::new( - &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f][..] - )), - Ok((Partial::new(&b""[..]), 9_223_372_036_854_775_807_i64)) - ); - assert_parse!( - le_i64(Partial::new( - &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff][..] - )), - Ok((Partial::new(&b""[..]), -1)) - ); - assert_parse!( - le_i64(Partial::new( - &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80][..] - )), - Ok((Partial::new(&b""[..]), -9_223_372_036_854_775_808_i64)) - ); - } - - #[test] - fn le_i128_tests() { - assert_parse!( - le_i128(Partial::new( - &[ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00 - ][..] - )), - Ok((Partial::new(&b""[..]), 0)) - ); - assert_parse!( - le_i128(Partial::new( - &[ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x7f - ][..] - )), - Ok(( - Partial::new(&b""[..]), - 170_141_183_460_469_231_731_687_303_715_884_105_727_i128 - )) - ); - assert_parse!( - le_i128(Partial::new( - &[ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff - ][..] - )), - Ok((Partial::new(&b""[..]), -1)) - ); - assert_parse!( - le_i128(Partial::new( - &[ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x80 - ][..] - )), - Ok(( - Partial::new(&b""[..]), - -170_141_183_460_469_231_731_687_303_715_884_105_728_i128 - )) - ); - } - - #[test] - fn be_f32_tests() { - assert_parse!( - be_f32(Partial::new(&[0x00, 0x00, 0x00, 0x00][..])), - Ok((Partial::new(&b""[..]), 0_f32)) - ); - assert_parse!( - be_f32(Partial::new(&[0x4d, 0x31, 0x1f, 0xd8][..])), - Ok((Partial::new(&b""[..]), 185_728_380_f32)) - ); - } - - #[test] - fn be_f64_tests() { - assert_parse!( - be_f64(Partial::new( - &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] - )), - Ok((Partial::new(&b""[..]), 0_f64)) - ); - assert_parse!( - be_f64(Partial::new( - &[0x41, 0xa6, 0x23, 0xfb, 0x10, 0x00, 0x00, 0x00][..] - )), - Ok((Partial::new(&b""[..]), 185_728_392_f64)) - ); - } - - #[test] - fn le_f32_tests() { - assert_parse!( - le_f32(Partial::new(&[0x00, 0x00, 0x00, 0x00][..])), - Ok((Partial::new(&b""[..]), 0_f32)) - ); - assert_parse!( - le_f32(Partial::new(&[0xd8, 0x1f, 0x31, 0x4d][..])), - Ok((Partial::new(&b""[..]), 185_728_380_f32)) - ); - } - - #[test] - fn le_f64_tests() { - assert_parse!( - le_f64(Partial::new( - &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..] - )), - Ok((Partial::new(&b""[..]), 0_f64)) - ); - assert_parse!( - le_f64(Partial::new( - &[0x00, 0x00, 0x00, 0x10, 0xfb, 0x23, 0xa6, 0x41][..] - )), - Ok((Partial::new(&b""[..]), 185_728_392_f64)) - ); - } - - #[test] - fn configurable_endianness() { - use crate::number::Endianness; - - fn be_tst16(i: Partial<&[u8]>) -> IResult, u16> { - u16(Endianness::Big).parse_next(i) - } - fn le_tst16(i: Partial<&[u8]>) -> IResult, u16> { - u16(Endianness::Little).parse_next(i) - } - assert_eq!( - be_tst16(Partial::new(&[0x80, 0x00])), - Ok((Partial::new(&b""[..]), 32_768_u16)) - ); - assert_eq!( - le_tst16(Partial::new(&[0x80, 0x00])), - Ok((Partial::new(&b""[..]), 128_u16)) - ); - - fn be_tst32(i: Partial<&[u8]>) -> IResult, u32> { - u32(Endianness::Big).parse_next(i) - } - fn le_tst32(i: Partial<&[u8]>) -> IResult, u32> { - u32(Endianness::Little).parse_next(i) - } - assert_eq!( - be_tst32(Partial::new(&[0x12, 0x00, 0x60, 0x00])), - Ok((Partial::new(&b""[..]), 302_014_464_u32)) - ); - assert_eq!( - le_tst32(Partial::new(&[0x12, 0x00, 0x60, 0x00])), - Ok((Partial::new(&b""[..]), 6_291_474_u32)) - ); - - fn be_tst64(i: Partial<&[u8]>) -> IResult, u64> { - u64(Endianness::Big).parse_next(i) - } - fn le_tst64(i: Partial<&[u8]>) -> IResult, u64> { - u64(Endianness::Little).parse_next(i) - } - assert_eq!( - be_tst64(Partial::new(&[ - 0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00 - ])), - Ok((Partial::new(&b""[..]), 1_297_142_246_100_992_000_u64)) - ); - assert_eq!( - le_tst64(Partial::new(&[ - 0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00 - ])), - Ok((Partial::new(&b""[..]), 36_028_874_334_666_770_u64)) - ); - - fn be_tsti16(i: Partial<&[u8]>) -> IResult, i16> { - i16(Endianness::Big).parse_next(i) - } - fn le_tsti16(i: Partial<&[u8]>) -> IResult, i16> { - i16(Endianness::Little).parse_next(i) - } - assert_eq!( - be_tsti16(Partial::new(&[0x00, 0x80])), - Ok((Partial::new(&b""[..]), 128_i16)) - ); - assert_eq!( - le_tsti16(Partial::new(&[0x00, 0x80])), - Ok((Partial::new(&b""[..]), -32_768_i16)) - ); - - fn be_tsti32(i: Partial<&[u8]>) -> IResult, i32> { - i32(Endianness::Big).parse_next(i) - } - fn le_tsti32(i: Partial<&[u8]>) -> IResult, i32> { - i32(Endianness::Little).parse_next(i) - } - assert_eq!( - be_tsti32(Partial::new(&[0x00, 0x12, 0x60, 0x00])), - Ok((Partial::new(&b""[..]), 1_204_224_i32)) - ); - assert_eq!( - le_tsti32(Partial::new(&[0x00, 0x12, 0x60, 0x00])), - Ok((Partial::new(&b""[..]), 6_296_064_i32)) - ); - - fn be_tsti64(i: Partial<&[u8]>) -> IResult, i64> { - i64(Endianness::Big).parse_next(i) - } - fn le_tsti64(i: Partial<&[u8]>) -> IResult, i64> { - i64(Endianness::Little).parse_next(i) - } - assert_eq!( - be_tsti64(Partial::new(&[ - 0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00 - ])), - Ok((Partial::new(&b""[..]), 71_881_672_479_506_432_i64)) - ); - assert_eq!( - le_tsti64(Partial::new(&[ - 0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00 - ])), - Ok((Partial::new(&b""[..]), 36_028_874_334_732_032_i64)) - ); - } -} diff --git a/vendor/winnow/src/parser.rs b/vendor/winnow/src/parser.rs index 264159094..15d892864 100644 --- a/vendor/winnow/src/parser.rs +++ b/vendor/winnow/src/parser.rs @@ -36,10 +36,11 @@ use crate::stream::{AsChar, Compare, Location, Offset, ParseSlice, Stream, Strea /// ``` /// /// Additionally, some basic types implement `Parser` as well, including -/// - `u8` and `char`, see [`winnow::bytes::one_of`][crate::bytes::one_of] -/// - `&[u8]` and `&str`, see [`winnow::bytes::tag`][crate::bytes::tag] +/// - `u8` and `char`, see [`winnow::token::one_of`][crate::token::one_of] +/// - `&[u8]` and `&str`, see [`winnow::token::tag`][crate::token::tag] pub trait Parser { /// Parse all of `input`, generating `O` from it + #[inline] fn parse(&mut self, input: I) -> Result where I: Stream, @@ -65,14 +66,14 @@ pub trait Parser { /// # Example /// /// Because parsers are `FnMut`, they can be called multiple times. This prevents moving `f` - /// into [`length_data`][crate::multi::length_data] and `g` into + /// into [`length_data`][crate::binary::length_data] and `g` into /// [`Parser::complete_err`]: /// ```rust,compile_fail /// # use winnow::prelude::*; /// # use winnow::IResult; /// # use winnow::Parser; /// # use winnow::error::ParseError; - /// # use winnow::multi::length_data; + /// # use winnow::binary::length_data; /// pub fn length_value<'i, O, E: ParseError<&'i [u8]>>( /// mut f: impl Parser<&'i [u8], usize, E>, /// mut g: impl Parser<&'i [u8], O, E> @@ -91,7 +92,7 @@ pub trait Parser { /// # use winnow::IResult; /// # use winnow::Parser; /// # use winnow::error::ParseError; - /// # use winnow::multi::length_data; + /// # use winnow::binary::length_data; /// pub fn length_value<'i, O, E: ParseError<&'i [u8]>>( /// mut f: impl Parser<&'i [u8], usize, E>, /// mut g: impl Parser<&'i [u8], O, E> @@ -116,7 +117,7 @@ pub trait Parser { /// /// ```rust /// # use winnow::{error::ErrMode,error::ErrorKind, error::Error, IResult, Parser}; - /// use winnow::character::alpha1; + /// use winnow::ascii::alpha1; /// # fn main() { /// /// let mut parser = alpha1.value(1234); @@ -140,7 +141,7 @@ pub trait Parser { /// /// ```rust /// # use winnow::{error::ErrMode,error::ErrorKind, error::Error, IResult, Parser}; - /// use winnow::character::alpha1; + /// use winnow::ascii::alpha1; /// # fn main() { /// /// let mut parser = alpha1.void(); @@ -163,7 +164,7 @@ pub trait Parser { /// ```rust /// # use winnow::IResult; /// # use winnow::Parser; - /// use winnow::character::alpha1; + /// use winnow::ascii::alpha1; /// # fn main() { /// /// fn parser1(i: &str) -> IResult<&str, &str> { @@ -191,8 +192,8 @@ pub trait Parser { /// /// ```rust /// # use winnow::{error::ErrMode,error::ErrorKind, error::Error, IResult, Parser}; - /// use winnow::character::{alpha1}; - /// use winnow::sequence::separated_pair; + /// use winnow::ascii::{alpha1}; + /// use winnow::combinator::separated_pair; /// # fn main() { /// /// let mut parser = separated_pair(alpha1, ',', alpha1).recognize(); @@ -225,9 +226,9 @@ pub trait Parser { /// ```rust /// # use winnow::prelude::*; /// # use winnow::{error::ErrMode,error::ErrorKind, error::Error, IResult}; - /// use winnow::character::{alpha1}; - /// use winnow::bytes::tag; - /// use winnow::sequence::separated_pair; + /// use winnow::ascii::{alpha1}; + /// use winnow::token::tag; + /// use winnow::combinator::separated_pair; /// /// fn inner_parser(input: &str) -> IResult<&str, bool> { /// "1234".value(true).parse_next(input) @@ -266,8 +267,8 @@ pub trait Parser { /// # use winnow::prelude::*; /// # use winnow::{error::ErrMode,error::ErrorKind, error::Error, stream::Stream}; /// use winnow::stream::Located; - /// use winnow::character::alpha1; - /// use winnow::sequence::separated_pair; + /// use winnow::ascii::alpha1; + /// use winnow::combinator::separated_pair; /// /// let mut parser = separated_pair(alpha1.span(), ',', alpha1.span()); /// @@ -298,9 +299,9 @@ pub trait Parser { /// # use winnow::prelude::*; /// # use winnow::{error::ErrMode,error::ErrorKind, error::Error, IResult, stream::Stream}; /// use winnow::stream::Located; - /// use winnow::character::alpha1; - /// use winnow::bytes::tag; - /// use winnow::sequence::separated_pair; + /// use winnow::ascii::alpha1; + /// use winnow::token::tag; + /// use winnow::combinator::separated_pair; /// /// fn inner_parser(input: Located<&str>) -> IResult, bool> { /// "1234".value(true).parse_next(input) @@ -336,7 +337,7 @@ pub trait Parser { /// /// ```rust /// use winnow::{error::ErrMode,error::ErrorKind, error::Error, IResult,Parser}; - /// use winnow::character::digit1; + /// use winnow::ascii::digit1; /// # fn main() { /// /// let mut parser = digit1.map(|s: &str| s.len()); @@ -362,10 +363,10 @@ pub trait Parser { /// /// ```rust /// # use winnow::{error::ErrMode,error::ErrorKind, error::Error, IResult, Parser}; - /// use winnow::character::digit1; + /// use winnow::ascii::digit1; /// # fn main() { /// - /// let mut parse = digit1.map_res(|s: &str| s.parse::()); + /// let mut parse = digit1.try_map(|s: &str| s.parse::()); /// /// // the parser will convert the result of digit1 to a number /// assert_eq!(parse.parse_next("123"), Ok(("", 123))); @@ -377,6 +378,18 @@ pub trait Parser { /// assert_eq!(parse.parse_next("123456"), Err(ErrMode::Backtrack(Error::new("123456", ErrorKind::Verify)))); /// # } /// ``` + fn try_map(self, map: G) -> TryMap + where + Self: core::marker::Sized, + G: FnMut(O) -> Result, + I: Clone, + E: FromExternalError, + { + TryMap::new(self, map) + } + + /// Deprecated, see [`Parser::try_map`] + #[deprecated(since = "0.4.2", note = "Replaced with `Parser::try_map`")] fn map_res(self, map: G) -> MapRes where Self: core::marker::Sized, @@ -384,7 +397,7 @@ pub trait Parser { I: Clone, E: FromExternalError, { - MapRes::new(self, map) + self.try_map(map) } /// Apply both [`Parser::verify`] and [`Parser::map`]. @@ -393,7 +406,7 @@ pub trait Parser { /// /// ```rust /// # use winnow::{error::ErrMode,error::ErrorKind, error::Error, IResult, Parser}; - /// use winnow::character::digit1; + /// use winnow::ascii::digit1; /// # fn main() { /// /// let mut parse = digit1.verify_map(|s: &str| s.parse::().ok()); @@ -427,8 +440,8 @@ pub trait Parser { /// /// ```rust /// # use winnow::{error::ErrMode,error::ErrorKind, error::Error, IResult, Parser}; - /// use winnow::bytes::take; - /// use winnow::number::u8; + /// use winnow::token::take; + /// use winnow::binary::u8; /// /// fn length_data(input: &[u8]) -> IResult<&[u8], &[u8]> { /// u8.flat_map(take).parse_next(input) @@ -441,8 +454,8 @@ pub trait Parser { /// which is the same as /// ```rust /// # use winnow::{error::ErrMode,error::ErrorKind, error::Error, IResult, Parser}; - /// use winnow::bytes::take; - /// use winnow::number::u8; + /// use winnow::token::take; + /// use winnow::binary::u8; /// /// fn length_data(input: &[u8]) -> IResult<&[u8], &[u8]> { /// let (input, length) = u8.parse_next(input)?; @@ -468,8 +481,8 @@ pub trait Parser { /// /// ```rust /// # use winnow::{error::ErrMode,error::ErrorKind, error::Error, IResult, Parser}; - /// use winnow::character::digit1; - /// use winnow::bytes::take; + /// use winnow::ascii::digit1; + /// use winnow::token::take; /// # fn main() { /// /// let mut digits = take(5u8).and_then(digit1); @@ -495,7 +508,7 @@ pub trait Parser { /// ```rust /// # use winnow::prelude::*; /// use winnow::{error::ErrMode,error::ErrorKind, error::Error, IResult,Parser}; - /// use winnow::character::digit1; + /// use winnow::ascii::digit1; /// /// fn parser(input: &str) -> IResult<&str, u64> { /// digit1.parse_to().parse_next(input) @@ -527,7 +540,7 @@ pub trait Parser { /// /// ```rust /// # use winnow::{error::ErrMode,error::ErrorKind, error::Error, IResult, Parser}; - /// # use winnow::character::alpha1; + /// # use winnow::ascii::alpha1; /// # fn main() { /// /// let mut parser = alpha1.verify(|s: &str| s.len() == 4); @@ -572,7 +585,7 @@ pub trait Parser { /// /// ```rust /// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, IResult, stream::Partial, Parser}; - /// # use winnow::bytes::take; + /// # use winnow::token::take; /// # fn main() { /// /// let mut parser = take(5u8).complete_err(); @@ -602,12 +615,13 @@ impl<'a, I, O, E, F> Parser for F where F: FnMut(I) -> IResult + 'a, { + #[inline(always)] fn parse_next(&mut self, i: I) -> IResult { self(i) } } -/// This is a shortcut for [`one_of`][crate::bytes::one_of]. +/// This is a shortcut for [`one_of`][crate::token::one_of]. /// /// # Example /// @@ -628,12 +642,13 @@ where I: Stream, E: ParseError, { + #[inline(always)] fn parse_next(&mut self, i: I) -> IResult { - crate::bytes::one_of(*self).parse_next(i) + crate::token::one_of(*self).parse_next(i) } } -/// This is a shortcut for [`one_of`][crate::bytes::one_of]. +/// This is a shortcut for [`one_of`][crate::token::one_of]. /// /// # Example /// @@ -655,19 +670,20 @@ where ::Token: AsChar + Copy, E: ParseError, { + #[inline(always)] fn parse_next(&mut self, i: I) -> IResult::Token, E> { - crate::bytes::one_of(*self).parse_next(i) + crate::token::one_of(*self).parse_next(i) } } -/// This is a shortcut for [`tag`][crate::bytes::tag]. +/// This is a shortcut for [`tag`][crate::token::tag]. /// /// # Example /// ```rust /// # use winnow::prelude::*; /// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::branch::alt; -/// # use winnow::bytes::take; +/// # use winnow::combinator::alt; +/// # use winnow::token::take; /// /// fn parser(s: &[u8]) -> IResult<&[u8], &[u8]> { /// alt((&"Hello"[..], take(5usize))).parse_next(s) @@ -683,19 +699,20 @@ where I: Compare<&'s [u8]> + StreamIsPartial, I: Stream, { + #[inline(always)] fn parse_next(&mut self, i: I) -> IResult::Slice, E> { - crate::bytes::tag(*self).parse_next(i) + crate::token::tag(*self).parse_next(i) } } -/// This is a shortcut for [`tag`][crate::bytes::tag]. +/// This is a shortcut for [`tag`][crate::token::tag]. /// /// # Example /// ```rust /// # use winnow::prelude::*; /// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::branch::alt; -/// # use winnow::bytes::take; +/// # use winnow::combinator::alt; +/// # use winnow::token::take; /// /// fn parser(s: &[u8]) -> IResult<&[u8], &[u8]> { /// alt((b"Hello", take(5usize))).parse_next(s) @@ -711,19 +728,20 @@ where I: Compare<&'s [u8; N]> + StreamIsPartial, I: Stream, { + #[inline(always)] fn parse_next(&mut self, i: I) -> IResult::Slice, E> { - crate::bytes::tag(*self).parse_next(i) + crate::token::tag(*self).parse_next(i) } } -/// This is a shortcut for [`tag`][crate::bytes::tag]. +/// This is a shortcut for [`tag`][crate::token::tag]. /// /// # Example /// ```rust /// # use winnow::prelude::*; /// # use winnow::{error::ErrMode, error::{Error, ErrorKind}}; -/// # use winnow::branch::alt; -/// # use winnow::bytes::take; +/// # use winnow::combinator::alt; +/// # use winnow::token::take; /// /// fn parser(s: &str) -> IResult<&str, &str> { /// alt(("Hello", take(5usize))).parse_next(s) @@ -739,12 +757,14 @@ where I: Compare<&'s str> + StreamIsPartial, I: Stream, { + #[inline(always)] fn parse_next(&mut self, i: I) -> IResult::Slice, E> { - crate::bytes::tag(*self).parse_next(i) + crate::token::tag(*self).parse_next(i) } } impl> Parser for () { + #[inline(always)] fn parse_next(&mut self, i: I) -> IResult { Ok((i, ())) } @@ -757,6 +777,7 @@ macro_rules! impl_parser_for_tuple { where $($parser: Parser),+ { + #[inline(always)] fn parse_next(&mut self, i: I) -> IResult { let ($(ref mut $parser),+,) = *self; @@ -810,6 +831,7 @@ use alloc::boxed::Box; #[cfg(feature = "alloc")] impl<'a, I, O, E> Parser for Box + 'a> { + #[inline(always)] fn parse_next(&mut self, input: I) -> IResult { (**self).parse_next(input) } @@ -818,12 +840,12 @@ impl<'a, I, O, E> Parser for Box + 'a> { #[cfg(test)] mod tests { use super::*; - use crate::bytes::take; + use crate::binary::be_u16; use crate::error::ErrMode; use crate::error::Error; use crate::error::ErrorKind; use crate::error::Needed; - use crate::number::be_u16; + use crate::token::take; use crate::Partial; #[doc(hidden)] @@ -852,7 +874,7 @@ mod tests { #[test] fn single_element_tuples() { - use crate::character::alpha1; + use crate::ascii::alpha1; use crate::error::ErrorKind; let mut parser = (alpha1,); diff --git a/vendor/winnow/src/sequence.rs b/vendor/winnow/src/sequence.rs new file mode 100644 index 000000000..2d7af28e9 --- /dev/null +++ b/vendor/winnow/src/sequence.rs @@ -0,0 +1,9 @@ +//! Deprecated, see [`combinator`] +#![deprecated(since = "0.4.2", note = "Replaced with `combinator`")] + +use crate::combinator; + +pub use combinator::delimited; +pub use combinator::preceded; +pub use combinator::separated_pair; +pub use combinator::terminated; diff --git a/vendor/winnow/src/sequence/mod.rs b/vendor/winnow/src/sequence/mod.rs deleted file mode 100644 index 68f772384..000000000 --- a/vendor/winnow/src/sequence/mod.rs +++ /dev/null @@ -1,169 +0,0 @@ -//! Combinators applying parsers in sequence - -#[cfg(test)] -mod tests; - -use crate::error::ParseError; -use crate::stream::Stream; -use crate::trace::trace; -use crate::Parser; - -/// Apply two parsers, only returning the output from the second. -/// -/// # Arguments -/// * `first` The opening parser. -/// * `second` The second parser to get object. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::sequence::preceded; -/// use winnow::bytes::tag; -/// -/// let mut parser = preceded("abc", "efg"); -/// -/// assert_eq!(parser.parse_next("abcefg"), Ok(("", "efg"))); -/// assert_eq!(parser.parse_next("abcefghij"), Ok(("hij", "efg"))); -/// assert_eq!(parser.parse_next(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); -/// assert_eq!(parser.parse_next("123"), Err(ErrMode::Backtrack(Error::new("123", ErrorKind::Tag)))); -/// ``` -#[doc(alias = "ignore_then")] -pub fn preceded, F, G>( - mut first: F, - mut second: G, -) -> impl Parser -where - I: Stream, - F: Parser, - G: Parser, -{ - trace("preceded", move |input: I| { - let (input, _) = first.parse_next(input)?; - second.parse_next(input) - }) -} - -/// Apply two parsers, only returning the output of the first. -/// -/// # Arguments -/// * `first` The first parser to apply. -/// * `second` The second parser to match an object. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::prelude::*; -/// # use winnow::error::Needed::Size; -/// use winnow::sequence::terminated; -/// use winnow::bytes::tag; -/// -/// let mut parser = terminated("abc", "efg"); -/// -/// assert_eq!(parser.parse_next("abcefg"), Ok(("", "abc"))); -/// assert_eq!(parser.parse_next("abcefghij"), Ok(("hij", "abc"))); -/// assert_eq!(parser.parse_next(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); -/// assert_eq!(parser.parse_next("123"), Err(ErrMode::Backtrack(Error::new("123", ErrorKind::Tag)))); -/// ``` -#[doc(alias = "then_ignore")] -pub fn terminated, F, G>( - mut first: F, - mut second: G, -) -> impl Parser -where - I: Stream, - F: Parser, - G: Parser, -{ - trace("terminated", move |input: I| { - let (input, o1) = first.parse_next(input)?; - second.parse_next(input).map(|(i, _)| (i, o1)) - }) -} - -/// Apply three parsers, only returning the values of the first and third. -/// -/// # Arguments -/// * `first` The first parser to apply. -/// * `sep` The separator parser to apply. -/// * `second` The second parser to apply. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::error::Needed::Size; -/// # use winnow::prelude::*; -/// use winnow::sequence::separated_pair; -/// use winnow::bytes::tag; -/// -/// let mut parser = separated_pair("abc", "|", "efg"); -/// -/// assert_eq!(parser.parse_next("abc|efg"), Ok(("", ("abc", "efg")))); -/// assert_eq!(parser.parse_next("abc|efghij"), Ok(("hij", ("abc", "efg")))); -/// assert_eq!(parser.parse_next(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); -/// assert_eq!(parser.parse_next("123"), Err(ErrMode::Backtrack(Error::new("123", ErrorKind::Tag)))); -/// ``` -pub fn separated_pair, F, G, H>( - mut first: F, - mut sep: G, - mut second: H, -) -> impl Parser -where - I: Stream, - F: Parser, - G: Parser, - H: Parser, -{ - trace("separated_pair", move |input: I| { - let (input, o1) = first.parse_next(input)?; - let (input, _) = sep.parse_next(input)?; - second.parse_next(input).map(|(i, o2)| (i, (o1, o2))) - }) -} - -/// Apply three parsers, only returning the output of the second. -/// -/// # Arguments -/// * `first` The first parser to apply and discard. -/// * `second` The second parser to apply. -/// * `third` The third parser to apply and discard. -/// -/// # Example -/// -/// ```rust -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; -/// # use winnow::error::Needed::Size; -/// # use winnow::prelude::*; -/// use winnow::sequence::delimited; -/// use winnow::bytes::tag; -/// -/// let mut parser = delimited("(", "abc", ")"); -/// -/// assert_eq!(parser.parse_next("(abc)"), Ok(("", "abc"))); -/// assert_eq!(parser.parse_next("(abc)def"), Ok(("def", "abc"))); -/// assert_eq!(parser.parse_next(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); -/// assert_eq!(parser.parse_next("123"), Err(ErrMode::Backtrack(Error::new("123", ErrorKind::Tag)))); -/// ``` -#[doc(alias = "between")] -#[doc(alias = "padded")] -pub fn delimited, F, G, H>( - mut first: F, - mut second: G, - mut third: H, -) -> impl Parser -where - I: Stream, - F: Parser, - G: Parser, - H: Parser, -{ - trace("delimited", move |input: I| { - let (input, _) = first.parse_next(input)?; - let (input, o2) = second.parse_next(input)?; - third.parse_next(input).map(|(i, _)| (i, o2)) - }) -} diff --git a/vendor/winnow/src/sequence/tests.rs b/vendor/winnow/src/sequence/tests.rs deleted file mode 100644 index 77fa75df6..000000000 --- a/vendor/winnow/src/sequence/tests.rs +++ /dev/null @@ -1,211 +0,0 @@ -use super::*; - -use crate::error::{ErrMode, ErrorKind, Needed}; -use crate::IResult; -use crate::Partial; - -#[derive(PartialEq, Eq, Debug)] -struct B { - a: u8, - b: u8, -} - -#[derive(PartialEq, Eq, Debug)] -struct C { - a: u8, - b: Option, -} - -#[test] -fn complete() { - fn err_test(i: &[u8]) -> IResult<&[u8], &[u8]> { - let (i, _) = "ijkl".parse_next(i)?; - "mnop".parse_next(i) - } - let a = &b"ijklmn"[..]; - - let res_a = err_test(a); - assert_eq!( - res_a, - Err(ErrMode::Backtrack(error_position!( - &b"mn"[..], - ErrorKind::Tag - ))) - ); -} - -#[test] -fn separated_pair_test() { - #[allow(clippy::type_complexity)] - fn sep_pair_abc_def(i: Partial<&[u8]>) -> IResult, (&[u8], &[u8])> { - separated_pair("abc", ",", "def").parse_next(i) - } - - assert_eq!( - sep_pair_abc_def(Partial::new(&b"abc,defghijkl"[..])), - Ok((Partial::new(&b"ghijkl"[..]), (&b"abc"[..], &b"def"[..]))) - ); - assert_eq!( - sep_pair_abc_def(Partial::new(&b"ab"[..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - sep_pair_abc_def(Partial::new(&b"abc,d"[..])), - Err(ErrMode::Incomplete(Needed::new(2))) - ); - assert_eq!( - sep_pair_abc_def(Partial::new(&b"xxx"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxx"[..]), - ErrorKind::Tag - ))) - ); - assert_eq!( - sep_pair_abc_def(Partial::new(&b"xxx,def"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxx,def"[..]), - ErrorKind::Tag - ))) - ); - assert_eq!( - sep_pair_abc_def(Partial::new(&b"abc,xxx"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxx"[..]), - ErrorKind::Tag - ))) - ); -} - -#[test] -fn preceded_test() { - fn preceded_abcd_efgh(i: Partial<&[u8]>) -> IResult, &[u8]> { - preceded("abcd", "efgh").parse_next(i) - } - - assert_eq!( - preceded_abcd_efgh(Partial::new(&b"abcdefghijkl"[..])), - Ok((Partial::new(&b"ijkl"[..]), &b"efgh"[..])) - ); - assert_eq!( - preceded_abcd_efgh(Partial::new(&b"ab"[..])), - Err(ErrMode::Incomplete(Needed::new(2))) - ); - assert_eq!( - preceded_abcd_efgh(Partial::new(&b"abcde"[..])), - Err(ErrMode::Incomplete(Needed::new(3))) - ); - assert_eq!( - preceded_abcd_efgh(Partial::new(&b"xxx"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxx"[..]), - ErrorKind::Tag - ))) - ); - assert_eq!( - preceded_abcd_efgh(Partial::new(&b"xxxxdef"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxxxdef"[..]), - ErrorKind::Tag - ))) - ); - assert_eq!( - preceded_abcd_efgh(Partial::new(&b"abcdxxx"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxx"[..]), - ErrorKind::Tag - ))) - ); -} - -#[test] -fn terminated_test() { - fn terminated_abcd_efgh(i: Partial<&[u8]>) -> IResult, &[u8]> { - terminated("abcd", "efgh").parse_next(i) - } - - assert_eq!( - terminated_abcd_efgh(Partial::new(&b"abcdefghijkl"[..])), - Ok((Partial::new(&b"ijkl"[..]), &b"abcd"[..])) - ); - assert_eq!( - terminated_abcd_efgh(Partial::new(&b"ab"[..])), - Err(ErrMode::Incomplete(Needed::new(2))) - ); - assert_eq!( - terminated_abcd_efgh(Partial::new(&b"abcde"[..])), - Err(ErrMode::Incomplete(Needed::new(3))) - ); - assert_eq!( - terminated_abcd_efgh(Partial::new(&b"xxx"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxx"[..]), - ErrorKind::Tag - ))) - ); - assert_eq!( - terminated_abcd_efgh(Partial::new(&b"xxxxdef"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxxxdef"[..]), - ErrorKind::Tag - ))) - ); - assert_eq!( - terminated_abcd_efgh(Partial::new(&b"abcdxxxx"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxxx"[..]), - ErrorKind::Tag - ))) - ); -} - -#[test] -fn delimited_test() { - fn delimited_abc_def_ghi(i: Partial<&[u8]>) -> IResult, &[u8]> { - delimited("abc", "def", "ghi").parse_next(i) - } - - assert_eq!( - delimited_abc_def_ghi(Partial::new(&b"abcdefghijkl"[..])), - Ok((Partial::new(&b"jkl"[..]), &b"def"[..])) - ); - assert_eq!( - delimited_abc_def_ghi(Partial::new(&b"ab"[..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - delimited_abc_def_ghi(Partial::new(&b"abcde"[..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - delimited_abc_def_ghi(Partial::new(&b"abcdefgh"[..])), - Err(ErrMode::Incomplete(Needed::new(1))) - ); - assert_eq!( - delimited_abc_def_ghi(Partial::new(&b"xxx"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxx"[..]), - ErrorKind::Tag - ))) - ); - assert_eq!( - delimited_abc_def_ghi(Partial::new(&b"xxxdefghi"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxxdefghi"[..]), - ErrorKind::Tag - ),)) - ); - assert_eq!( - delimited_abc_def_ghi(Partial::new(&b"abcxxxghi"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxxghi"[..]), - ErrorKind::Tag - ))) - ); - assert_eq!( - delimited_abc_def_ghi(Partial::new(&b"abcdefxxx"[..])), - Err(ErrMode::Backtrack(error_position!( - Partial::new(&b"xxx"[..]), - ErrorKind::Tag - ))) - ); -} diff --git a/vendor/winnow/src/stream/mod.rs b/vendor/winnow/src/stream/mod.rs index 019975a72..3d7a41e09 100644 --- a/vendor/winnow/src/stream/mod.rs +++ b/vendor/winnow/src/stream/mod.rs @@ -13,9 +13,6 @@ use core::num::NonZeroUsize; use crate::error::{ErrMode, ErrorKind, Needed, ParseError}; use crate::lib::std::iter::{Cloned, Enumerate}; -use crate::lib::std::ops::{ - Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, -}; use crate::lib::std::slice::Iter; use crate::lib::std::str::from_utf8; use crate::lib::std::str::CharIndices; @@ -145,7 +142,7 @@ impl crate::lib::std::fmt::Display for Located /// # use std::cell::Cell; /// # use winnow::prelude::*; /// # use winnow::stream::Stateful; -/// # use winnow::character::alpha1; +/// # use winnow::ascii::alpha1; /// # type Error = (); /// /// #[derive(Clone, Debug)] @@ -221,15 +218,15 @@ impl crate::lib::std::fmt::Display for Stat /// Here is how it works in practice: /// /// ```rust -/// # use winnow::{IResult, error::ErrMode, error::Needed, error::{Error, ErrorKind}, bytes, character, stream::Partial}; +/// # use winnow::{IResult, error::ErrMode, error::Needed, error::{Error, ErrorKind}, token, ascii, stream::Partial}; /// # use winnow::prelude::*; /// /// fn take_partial(i: Partial<&[u8]>) -> IResult, &[u8]> { -/// bytes::take(4u8).parse_next(i) +/// token::take(4u8).parse_next(i) /// } /// /// fn take_complete(i: &[u8]) -> IResult<&[u8], &[u8]> { -/// bytes::take(4u8).parse_next(i) +/// token::take(4u8).parse_next(i) /// } /// /// // both parsers will take 4 bytes as expected @@ -245,11 +242,11 @@ impl crate::lib::std::fmt::Display for Stat /// /// // the alpha0 function recognizes 0 or more alphabetic characters /// fn alpha0_partial(i: Partial<&str>) -> IResult, &str> { -/// character::alpha0(i) +/// ascii::alpha0(i) /// } /// /// fn alpha0_complete(i: &str) -> IResult<&str, &str> { -/// character::alpha0(i) +/// ascii::alpha0(i) /// } /// /// // if there's a clear limit to the recognized characters, both parsers work the same way @@ -708,7 +705,7 @@ where } } -/// Iterator for [bit][crate::bits] stream (`(I, usize)`) +/// Iterator for [bit][crate::binary::bits] stream (`(I, usize)`) pub struct BitOffsets { i: (I, usize), o: usize, @@ -1747,6 +1744,123 @@ where } } +/// A range bounded inclusively for counting parses performed +#[derive(PartialEq, Eq)] +pub struct Range { + pub(crate) start_inclusive: usize, + pub(crate) end_inclusive: Option, +} + +impl Range { + #[inline(always)] + fn raw(start_inclusive: usize, end_inclusive: Option) -> Self { + Self { + start_inclusive, + end_inclusive, + } + } +} + +impl crate::lib::std::ops::RangeBounds for Range { + #[inline(always)] + fn start_bound(&self) -> crate::lib::std::ops::Bound<&usize> { + crate::lib::std::ops::Bound::Included(&self.start_inclusive) + } + + #[inline(always)] + fn end_bound(&self) -> crate::lib::std::ops::Bound<&usize> { + if let Some(end_inclusive) = &self.end_inclusive { + crate::lib::std::ops::Bound::Included(end_inclusive) + } else { + crate::lib::std::ops::Bound::Unbounded + } + } +} + +impl From for Range { + #[inline(always)] + fn from(fixed: usize) -> Self { + (fixed..=fixed).into() + } +} + +impl From> for Range { + #[inline(always)] + fn from(range: crate::lib::std::ops::Range) -> Self { + let start_inclusive = range.start; + let end_inclusive = Some(range.end.saturating_sub(1)); + Self::raw(start_inclusive, end_inclusive) + } +} + +impl From for Range { + #[inline(always)] + fn from(_: crate::lib::std::ops::RangeFull) -> Self { + let start_inclusive = 0; + let end_inclusive = None; + Self::raw(start_inclusive, end_inclusive) + } +} + +impl From> for Range { + #[inline(always)] + fn from(range: crate::lib::std::ops::RangeFrom) -> Self { + let start_inclusive = range.start; + let end_inclusive = None; + Self::raw(start_inclusive, end_inclusive) + } +} + +impl From> for Range { + #[inline(always)] + fn from(range: crate::lib::std::ops::RangeTo) -> Self { + let start_inclusive = 0; + let end_inclusive = Some(range.end.saturating_sub(1)); + Self::raw(start_inclusive, end_inclusive) + } +} + +impl From> for Range { + #[inline(always)] + fn from(range: crate::lib::std::ops::RangeInclusive) -> Self { + let start_inclusive = *range.start(); + let end_inclusive = Some(*range.end()); + Self::raw(start_inclusive, end_inclusive) + } +} + +impl From> for Range { + #[inline(always)] + fn from(range: crate::lib::std::ops::RangeToInclusive) -> Self { + let start_inclusive = 0; + let end_inclusive = Some(range.end); + Self::raw(start_inclusive, end_inclusive) + } +} + +impl crate::lib::std::fmt::Display for Range { + fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result { + self.start_inclusive.fmt(f)?; + match self.end_inclusive { + Some(e) if e == self.start_inclusive => {} + Some(e) => { + "..=".fmt(f)?; + e.fmt(f)?; + } + None => { + "..".fmt(f)?; + } + } + Ok(()) + } +} + +impl crate::lib::std::fmt::Debug for Range { + fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result { + write!(f, "{self}") + } +} + /// Abstracts something which can extend an `Extend`. /// Used to build modified input slices in `escaped_transform` pub trait Accumulate: Sized { @@ -2006,6 +2120,7 @@ impl AsChar for u8 { fn is_space(self) -> bool { self == b' ' || self == b'\t' } + #[inline] fn is_newline(self) -> bool { self == b'\n' } @@ -2043,6 +2158,7 @@ impl<'a> AsChar for &'a u8 { fn is_space(self) -> bool { *self == b' ' || *self == b'\t' } + #[inline] fn is_newline(self) -> bool { *self == b'\n' } @@ -2081,6 +2197,7 @@ impl AsChar for char { fn is_space(self) -> bool { self == ' ' || self == '\t' } + #[inline] fn is_newline(self) -> bool { self == '\n' } @@ -2119,6 +2236,7 @@ impl<'a> AsChar for &'a char { fn is_space(self) -> bool { *self == ' ' || *self == '\t' } + #[inline] fn is_newline(self) -> bool { *self == '\n' } @@ -2140,9 +2258,9 @@ impl<'a> AsChar for &'a char { /// ``` /// # use winnow::prelude::*; /// # use winnow::{error::ErrMode, error::ErrorKind, error::Error}; -/// # use winnow::bytes::take_while1; +/// # use winnow::token::take_while; /// fn hex_digit1(input: &str) -> IResult<&str, &str> { -/// take_while1(('a'..='f', 'A'..='F', '0'..='9')).parse_next(input) +/// take_while(1.., ('a'..='f', 'A'..='F', '0'..='9')).parse_next(input) /// } /// /// assert_eq!(hex_digit1("21cZ"), Ok(("Z", "21c"))); @@ -2196,7 +2314,7 @@ impl bool> ContainsToken for F { } } -impl ContainsToken for Range { +impl ContainsToken for crate::lib::std::ops::Range { #[inline(always)] fn contains_token(&self, token: C1) -> bool { let start = self.start.clone().as_char(); @@ -2205,7 +2323,9 @@ impl ContainsToken for Range { } } -impl ContainsToken for RangeInclusive { +impl ContainsToken + for crate::lib::std::ops::RangeInclusive +{ #[inline(always)] fn contains_token(&self, token: C1) -> bool { let start = self.start().clone().as_char(); @@ -2214,7 +2334,7 @@ impl ContainsToken for RangeInclusive { } } -impl ContainsToken for RangeFrom { +impl ContainsToken for crate::lib::std::ops::RangeFrom { #[inline(always)] fn contains_token(&self, token: C1) -> bool { let start = self.start.clone().as_char(); @@ -2222,7 +2342,7 @@ impl ContainsToken for RangeFrom { } } -impl ContainsToken for RangeTo { +impl ContainsToken for crate::lib::std::ops::RangeTo { #[inline(always)] fn contains_token(&self, token: C1) -> bool { let end = self.end.clone().as_char(); @@ -2230,7 +2350,9 @@ impl ContainsToken for RangeTo { } } -impl ContainsToken for RangeToInclusive { +impl ContainsToken + for crate::lib::std::ops::RangeToInclusive +{ #[inline(always)] fn contains_token(&self, token: C1) -> bool { let end = self.end.clone().as_char(); @@ -2238,7 +2360,7 @@ impl ContainsToken for RangeToInclusive } } -impl ContainsToken for RangeFull { +impl ContainsToken for crate::lib::std::ops::RangeFull { #[inline(always)] fn contains_token(&self, _token: C1) -> bool { true diff --git a/vendor/winnow/src/token/mod.rs b/vendor/winnow/src/token/mod.rs new file mode 100644 index 000000000..6f99dfa8d --- /dev/null +++ b/vendor/winnow/src/token/mod.rs @@ -0,0 +1,1009 @@ +//! Parsers extracting tokens from the stream + +#[cfg(test)] +mod tests; + +use crate::error::ErrMode; +use crate::error::ErrorKind; +use crate::error::Needed; +use crate::error::ParseError; +use crate::lib::std::result::Result::Ok; +use crate::stream::Range; +use crate::stream::{ + split_at_offset1_complete, split_at_offset1_partial, split_at_offset_complete, + split_at_offset_partial, Compare, CompareResult, ContainsToken, FindSlice, SliceLen, Stream, +}; +use crate::stream::{StreamIsPartial, ToUsize}; +use crate::trace::trace; +use crate::IResult; +use crate::Parser; + +/// Matches one token +/// +/// *Complete version*: Will return an error if there's not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{token::any, error::ErrMode, error::{Error, ErrorKind}}; +/// # use winnow::prelude::*; +/// fn parser(input: &str) -> IResult<&str, char> { +/// any.parse_next(input) +/// } +/// +/// assert_eq!(parser("abc"), Ok(("bc",'a'))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Token)))); +/// ``` +/// +/// ```rust +/// # use winnow::{token::any, error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// assert_eq!(any::<_, Error<_>>.parse_next(Partial::new("abc")), Ok((Partial::new("bc"),'a'))); +/// assert_eq!(any::<_, Error<_>>.parse_next(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +#[doc(alias = "token")] +pub fn any>(input: I) -> IResult::Token, E> +where + I: StreamIsPartial, + I: Stream, +{ + trace("any", move |input: I| { + if ::is_partial_supported() { + any_::<_, _, true>(input) + } else { + any_::<_, _, true>(input) + } + }) + .parse_next(input) +} + +fn any_, const PARTIAL: bool>(input: I) -> IResult::Token, E> +where + I: StreamIsPartial, + I: Stream, +{ + input.next_token().ok_or_else(|| { + if PARTIAL && input.is_partial() { + ErrMode::Incomplete(Needed::new(1)) + } else { + ErrMode::from_error_kind(input, ErrorKind::Token) + } + }) +} + +/// Recognizes a literal +/// +/// The input data will be compared to the tag combinator's argument and will return the part of +/// the input that matches the argument +/// +/// It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Tag)))` if the input doesn't match the pattern +/// +/// **Note:** [`Parser`][crate::Parser] is implemented for strings and byte strings as a convenience (complete +/// only) +/// +/// # Example +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, &str> { +/// "Hello".parse_next(s) +/// } +/// +/// assert_eq!(parser("Hello, World!"), Ok((", World!", "Hello"))); +/// assert_eq!(parser("Something"), Err(ErrMode::Backtrack(Error::new("Something", ErrorKind::Tag)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); +/// ``` +/// +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::Partial; +/// use winnow::token::tag; +/// +/// fn parser(s: Partial<&str>) -> IResult, &str> { +/// "Hello".parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new("Hello, World!")), Ok((Partial::new(", World!"), "Hello"))); +/// assert_eq!(parser(Partial::new("Something")), Err(ErrMode::Backtrack(Error::new(Partial::new("Something"), ErrorKind::Tag)))); +/// assert_eq!(parser(Partial::new("S")), Err(ErrMode::Backtrack(Error::new(Partial::new("S"), ErrorKind::Tag)))); +/// assert_eq!(parser(Partial::new("H")), Err(ErrMode::Incomplete(Needed::new(4)))); +/// ``` +#[inline(always)] +#[doc(alias = "literal")] +#[doc(alias = "bytes")] +#[doc(alias = "just")] +pub fn tag>(tag: T) -> impl Parser::Slice, Error> +where + I: StreamIsPartial, + I: Stream + Compare, + T: SliceLen + Clone, +{ + trace("tag", move |i: I| { + let t = tag.clone(); + if ::is_partial_supported() { + tag_::<_, _, _, true>(i, t) + } else { + tag_::<_, _, _, false>(i, t) + } + }) +} + +fn tag_, const PARTIAL: bool>( + i: I, + t: T, +) -> IResult::Slice, Error> +where + I: StreamIsPartial, + I: Stream + Compare, + T: SliceLen, +{ + let tag_len = t.slice_len(); + match i.compare(t) { + CompareResult::Ok => Ok(i.next_slice(tag_len)), + CompareResult::Incomplete if PARTIAL && i.is_partial() => { + Err(ErrMode::Incomplete(Needed::new(tag_len - i.eof_offset()))) + } + CompareResult::Incomplete | CompareResult::Error => { + let e: ErrorKind = ErrorKind::Tag; + Err(ErrMode::from_error_kind(i, e)) + } + } +} + +/// Recognizes a case insensitive literal. +/// +/// The input data will be compared to the tag combinator's argument and will return the part of +/// the input that matches the argument with no regard to case. +/// +/// It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Tag)))` if the input doesn't match the pattern. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::tag_no_case; +/// +/// fn parser(s: &str) -> IResult<&str, &str> { +/// tag_no_case("hello").parse_next(s) +/// } +/// +/// assert_eq!(parser("Hello, World!"), Ok((", World!", "Hello"))); +/// assert_eq!(parser("hello, World!"), Ok((", World!", "hello"))); +/// assert_eq!(parser("HeLlO, World!"), Ok((", World!", "HeLlO"))); +/// assert_eq!(parser("Something"), Err(ErrMode::Backtrack(Error::new("Something", ErrorKind::Tag)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::tag_no_case; +/// +/// fn parser(s: Partial<&str>) -> IResult, &str> { +/// tag_no_case("hello").parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new("Hello, World!")), Ok((Partial::new(", World!"), "Hello"))); +/// assert_eq!(parser(Partial::new("hello, World!")), Ok((Partial::new(", World!"), "hello"))); +/// assert_eq!(parser(Partial::new("HeLlO, World!")), Ok((Partial::new(", World!"), "HeLlO"))); +/// assert_eq!(parser(Partial::new("Something")), Err(ErrMode::Backtrack(Error::new(Partial::new("Something"), ErrorKind::Tag)))); +/// assert_eq!(parser(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(5)))); +/// ``` +#[inline(always)] +#[doc(alias = "literal")] +#[doc(alias = "bytes")] +#[doc(alias = "just")] +pub fn tag_no_case>( + tag: T, +) -> impl Parser::Slice, Error> +where + I: StreamIsPartial, + I: Stream + Compare, + T: SliceLen + Clone, +{ + trace("tag_no_case", move |i: I| { + let t = tag.clone(); + if ::is_partial_supported() { + tag_no_case_::<_, _, _, true>(i, t) + } else { + tag_no_case_::<_, _, _, false>(i, t) + } + }) +} + +fn tag_no_case_, const PARTIAL: bool>( + i: I, + t: T, +) -> IResult::Slice, Error> +where + I: StreamIsPartial, + I: Stream + Compare, + T: SliceLen, +{ + let tag_len = t.slice_len(); + + match (i).compare_no_case(t) { + CompareResult::Ok => Ok(i.next_slice(tag_len)), + CompareResult::Incomplete if PARTIAL && i.is_partial() => { + Err(ErrMode::Incomplete(Needed::new(tag_len - i.eof_offset()))) + } + CompareResult::Incomplete | CompareResult::Error => { + let e: ErrorKind = ErrorKind::Tag; + Err(ErrMode::from_error_kind(i, e)) + } + } +} + +/// Recognize a token that matches the [pattern][ContainsToken] +/// +/// **Note:** [`Parser`][crate::Parser] is implemented as a convenience (complete +/// only) for +/// - `u8` +/// - `char` +/// +/// *Complete version*: Will return an error if there's not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error}; +/// # use winnow::token::one_of; +/// assert_eq!(one_of::<_, _, Error<_>>("abc").parse_next("b"), Ok(("", 'b'))); +/// assert_eq!(one_of::<_, _, Error<_>>("a").parse_next("bc"), Err(ErrMode::Backtrack(Error::new("bc", ErrorKind::Verify)))); +/// assert_eq!(one_of::<_, _, Error<_>>("a").parse_next(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Token)))); +/// +/// fn parser_fn(i: &str) -> IResult<&str, char> { +/// one_of(|c| c == 'a' || c == 'b').parse_next(i) +/// } +/// assert_eq!(parser_fn("abc"), Ok(("bc", 'a'))); +/// assert_eq!(parser_fn("cd"), Err(ErrMode::Backtrack(Error::new("cd", ErrorKind::Verify)))); +/// assert_eq!(parser_fn(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Token)))); +/// ``` +/// +/// ``` +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::token::one_of; +/// assert_eq!(one_of::<_, _, Error<_>>("abc").parse_next(Partial::new("b")), Ok((Partial::new(""), 'b'))); +/// assert_eq!(one_of::<_, _, Error<_>>("a").parse_next(Partial::new("bc")), Err(ErrMode::Backtrack(Error::new(Partial::new("bc"), ErrorKind::Verify)))); +/// assert_eq!(one_of::<_, _, Error<_>>("a").parse_next(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// +/// fn parser_fn(i: Partial<&str>) -> IResult, char> { +/// one_of(|c| c == 'a' || c == 'b').parse_next(i) +/// } +/// assert_eq!(parser_fn(Partial::new("abc")), Ok((Partial::new("bc"), 'a'))); +/// assert_eq!(parser_fn(Partial::new("cd")), Err(ErrMode::Backtrack(Error::new(Partial::new("cd"), ErrorKind::Verify)))); +/// assert_eq!(parser_fn(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +#[doc(alias = "char")] +#[doc(alias = "token")] +#[doc(alias = "satisfy")] +pub fn one_of>(list: T) -> impl Parser::Token, Error> +where + I: StreamIsPartial, + I: Stream, + ::Token: Copy, + T: ContainsToken<::Token>, +{ + trace( + "one_of", + any.verify(move |t: &::Token| list.contains_token(*t)), + ) +} + +/// Recognize a token that does not match the [pattern][ContainsToken] +/// +/// *Complete version*: Will return an error if there's not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error}; +/// # use winnow::prelude::*; +/// # use winnow::token::none_of; +/// assert_eq!(none_of::<_, _, Error<_>>("abc").parse_next("z"), Ok(("", 'z'))); +/// assert_eq!(none_of::<_, _, Error<_>>("ab").parse_next("a"), Err(ErrMode::Backtrack(Error::new("a", ErrorKind::Verify)))); +/// assert_eq!(none_of::<_, _, Error<_>>("a").parse_next(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Token)))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// # use winnow::token::none_of; +/// assert_eq!(none_of::<_, _, Error<_>>("abc").parse_next(Partial::new("z")), Ok((Partial::new(""), 'z'))); +/// assert_eq!(none_of::<_, _, Error<_>>("ab").parse_next(Partial::new("a")), Err(ErrMode::Backtrack(Error::new(Partial::new("a"), ErrorKind::Verify)))); +/// assert_eq!(none_of::<_, _, Error<_>>("a").parse_next(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn none_of>(list: T) -> impl Parser::Token, Error> +where + I: StreamIsPartial, + I: Stream, + ::Token: Copy, + T: ContainsToken<::Token>, +{ + trace( + "none_of", + any.verify(move |t: &::Token| !list.contains_token(*t)), + ) +} + +/// Recognize the longest (m <= len <= n) input slice that matches the [pattern][ContainsToken] +/// +/// It will return an `ErrMode::Backtrack(Error::new(_, ErrorKind::Slice))` if the pattern wasn't met or is out +/// of range (m <= len <= n). +/// +/// *Partial version* will return a `ErrMode::Incomplete(Needed::new(1))` if the pattern reaches the end of the input or is too short. +/// +/// To recognize a series of tokens, use [`repeat`][crate::combinator::repeat] to [`Accumulate`][crate::stream::Accumulate] into a `()` and then [`Parser::recognize`][crate::Parser::recognize]. +/// +/// # Example +/// +/// Zero or more tokens: +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::take_while; +/// use winnow::stream::AsChar; +/// +/// fn alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { +/// take_while(0.., AsChar::is_alpha).parse_next(s) +/// } +/// +/// assert_eq!(alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); +/// assert_eq!(alpha(b"12345"), Ok((&b"12345"[..], &b""[..]))); +/// assert_eq!(alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); +/// assert_eq!(alpha(b""), Ok((&b""[..], &b""[..]))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::take_while; +/// use winnow::stream::AsChar; +/// +/// fn alpha(s: Partial<&[u8]>) -> IResult, &[u8]> { +/// take_while(0.., AsChar::is_alpha).parse_next(s) +/// } +/// +/// assert_eq!(alpha(Partial::new(b"latin123")), Ok((Partial::new(&b"123"[..]), &b"latin"[..]))); +/// assert_eq!(alpha(Partial::new(b"12345")), Ok((Partial::new(&b"12345"[..]), &b""[..]))); +/// assert_eq!(alpha(Partial::new(b"latin")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(alpha(Partial::new(b"")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +/// +/// One or more tokens: +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::take_while; +/// use winnow::stream::AsChar; +/// +/// fn alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { +/// take_while(1.., AsChar::is_alpha).parse_next(s) +/// } +/// +/// assert_eq!(alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); +/// assert_eq!(alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); +/// assert_eq!(alpha(b"12345"), Err(ErrMode::Backtrack(Error::new(&b"12345"[..], ErrorKind::Slice)))); +/// +/// fn hex(s: &str) -> IResult<&str, &str> { +/// take_while(1.., "1234567890ABCDEF").parse_next(s) +/// } +/// +/// assert_eq!(hex("123 and voila"), Ok((" and voila", "123"))); +/// assert_eq!(hex("DEADBEEF and others"), Ok((" and others", "DEADBEEF"))); +/// assert_eq!(hex("BADBABEsomething"), Ok(("something", "BADBABE"))); +/// assert_eq!(hex("D15EA5E"), Ok(("", "D15EA5E"))); +/// assert_eq!(hex(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::take_while; +/// use winnow::stream::AsChar; +/// +/// fn alpha(s: Partial<&[u8]>) -> IResult, &[u8]> { +/// take_while(1.., AsChar::is_alpha).parse_next(s) +/// } +/// +/// assert_eq!(alpha(Partial::new(b"latin123")), Ok((Partial::new(&b"123"[..]), &b"latin"[..]))); +/// assert_eq!(alpha(Partial::new(b"latin")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(alpha(Partial::new(b"12345")), Err(ErrMode::Backtrack(Error::new(Partial::new(&b"12345"[..]), ErrorKind::Slice)))); +/// +/// fn hex(s: Partial<&str>) -> IResult, &str> { +/// take_while(1.., "1234567890ABCDEF").parse_next(s) +/// } +/// +/// assert_eq!(hex(Partial::new("123 and voila")), Ok((Partial::new(" and voila"), "123"))); +/// assert_eq!(hex(Partial::new("DEADBEEF and others")), Ok((Partial::new(" and others"), "DEADBEEF"))); +/// assert_eq!(hex(Partial::new("BADBABEsomething")), Ok((Partial::new("something"), "BADBABE"))); +/// assert_eq!(hex(Partial::new("D15EA5E")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(hex(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +/// +/// Arbitrary amount of tokens: +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::take_while; +/// use winnow::stream::AsChar; +/// +/// fn short_alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { +/// take_while(3..=6, AsChar::is_alpha).parse_next(s) +/// } +/// +/// assert_eq!(short_alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); +/// assert_eq!(short_alpha(b"lengthy"), Ok((&b"y"[..], &b"length"[..]))); +/// assert_eq!(short_alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); +/// assert_eq!(short_alpha(b"ed"), Err(ErrMode::Backtrack(Error::new(&b"ed"[..], ErrorKind::Slice)))); +/// assert_eq!(short_alpha(b"12345"), Err(ErrMode::Backtrack(Error::new(&b"12345"[..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::take_while; +/// use winnow::stream::AsChar; +/// +/// fn short_alpha(s: Partial<&[u8]>) -> IResult, &[u8]> { +/// take_while(3..=6, AsChar::is_alpha).parse_next(s) +/// } +/// +/// assert_eq!(short_alpha(Partial::new(b"latin123")), Ok((Partial::new(&b"123"[..]), &b"latin"[..]))); +/// assert_eq!(short_alpha(Partial::new(b"lengthy")), Ok((Partial::new(&b"y"[..]), &b"length"[..]))); +/// assert_eq!(short_alpha(Partial::new(b"latin")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(short_alpha(Partial::new(b"ed")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(short_alpha(Partial::new(b"12345")), Err(ErrMode::Backtrack(Error::new(Partial::new(&b"12345"[..]), ErrorKind::Slice)))); +/// ``` +#[inline(always)] +#[doc(alias = "is_a")] +#[doc(alias = "take_while0")] +#[doc(alias = "take_while1")] +pub fn take_while>( + range: impl Into, + list: T, +) -> impl Parser::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<::Token>, +{ + let Range { + start_inclusive, + end_inclusive, + } = range.into(); + trace("take_while", move |i: I| { + match (start_inclusive, end_inclusive) { + (0, None) => { + if ::is_partial_supported() { + take_while0_::<_, _, _, true>(i, &list) + } else { + take_while0_::<_, _, _, false>(i, &list) + } + } + (1, None) => { + if ::is_partial_supported() { + take_while1_::<_, _, _, true>(i, &list) + } else { + take_while1_::<_, _, _, false>(i, &list) + } + } + (start, end) => { + let end = end.unwrap_or(usize::MAX); + if ::is_partial_supported() { + take_while_m_n_::<_, _, _, true>(i, start, end, &list) + } else { + take_while_m_n_::<_, _, _, false>(i, start, end, &list) + } + } + } + }) +} + +/// Deprecated, see [`take_while`] +#[deprecated(since = "0.4.6", note = "Replaced with `take_while`")] +#[inline(always)] +pub fn take_while0>( + list: T, +) -> impl Parser::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<::Token>, +{ + take_while(0.., list) +} + +/// Deprecated, see [`take_while`] +#[deprecated(since = "0.4.6", note = "Replaced with `take_while`")] +#[inline(always)] +pub fn take_while1>( + list: T, +) -> impl Parser::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<::Token>, +{ + take_while(1.., list) +} + +fn take_while0_, const PARTIAL: bool>( + input: I, + list: &T, +) -> IResult::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<::Token>, +{ + if PARTIAL && input.is_partial() { + split_at_offset_partial(&input, |c| !list.contains_token(c)) + } else { + split_at_offset_complete(&input, |c| !list.contains_token(c)) + } +} + +fn take_while1_, const PARTIAL: bool>( + input: I, + list: &T, +) -> IResult::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<::Token>, +{ + let e: ErrorKind = ErrorKind::Slice; + if PARTIAL && input.is_partial() { + split_at_offset1_partial(&input, |c| !list.contains_token(c), e) + } else { + split_at_offset1_complete(&input, |c| !list.contains_token(c), e) + } +} + +fn take_while_m_n_, const PARTIAL: bool>( + input: I, + m: usize, + n: usize, + list: &T, +) -> IResult::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<::Token>, +{ + if n < m { + return Err(ErrMode::assert(input, "`m` should be <= `n`")); + } + + let mut final_count = 0; + for (processed, (offset, token)) in input.iter_offsets().enumerate() { + if !list.contains_token(token) { + if processed < m { + return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); + } else { + return Ok(input.next_slice(offset)); + } + } else { + if processed == n { + return Ok(input.next_slice(offset)); + } + final_count = processed + 1; + } + } + if PARTIAL && input.is_partial() { + if final_count == n { + Ok(input.next_slice(input.eof_offset())) + } else { + let needed = if m > input.eof_offset() { + m - input.eof_offset() + } else { + 1 + }; + Err(ErrMode::Incomplete(Needed::new(needed))) + } + } else { + if m <= final_count { + Ok(input.next_slice(input.eof_offset())) + } else { + Err(ErrMode::from_error_kind(input, ErrorKind::Slice)) + } + } +} + +/// Recognize the longest input slice (if any) till a [pattern][ContainsToken] is met. +/// +/// *Partial version* will return a `ErrMode::Incomplete(Needed::new(1))` if the match reaches the +/// end of input or if there was not match. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::take_till0; +/// +/// fn till_colon(s: &str) -> IResult<&str, &str> { +/// take_till0(|c| c == ':').parse_next(s) +/// } +/// +/// assert_eq!(till_colon("latin:123"), Ok((":123", "latin"))); +/// assert_eq!(till_colon(":empty matched"), Ok((":empty matched", ""))); //allowed +/// assert_eq!(till_colon("12345"), Ok(("", "12345"))); +/// assert_eq!(till_colon(""), Ok(("", ""))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::take_till0; +/// +/// fn till_colon(s: Partial<&str>) -> IResult, &str> { +/// take_till0(|c| c == ':').parse_next(s) +/// } +/// +/// assert_eq!(till_colon(Partial::new("latin:123")), Ok((Partial::new(":123"), "latin"))); +/// assert_eq!(till_colon(Partial::new(":empty matched")), Ok((Partial::new(":empty matched"), ""))); //allowed +/// assert_eq!(till_colon(Partial::new("12345")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(till_colon(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn take_till0>( + list: T, +) -> impl Parser::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<::Token>, +{ + trace("take_till0", move |i: I| { + if ::is_partial_supported() && i.is_partial() { + split_at_offset_partial(&i, |c| list.contains_token(c)) + } else { + split_at_offset_complete(&i, |c| list.contains_token(c)) + } + }) +} + +/// Recognize the longest (at least 1) input slice till a [pattern][ContainsToken] is met. +/// +/// It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Slice)))` if the input is empty or the +/// predicate matches the first input. +/// +/// *Partial version* will return a `ErrMode::Incomplete(Needed::new(1))` if the match reaches the +/// end of input or if there was not match. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::take_till1; +/// +/// fn till_colon(s: &str) -> IResult<&str, &str> { +/// take_till1(|c| c == ':').parse_next(s) +/// } +/// +/// assert_eq!(till_colon("latin:123"), Ok((":123", "latin"))); +/// assert_eq!(till_colon(":empty matched"), Err(ErrMode::Backtrack(Error::new(":empty matched", ErrorKind::Slice)))); +/// assert_eq!(till_colon("12345"), Ok(("", "12345"))); +/// assert_eq!(till_colon(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// +/// fn not_space(s: &str) -> IResult<&str, &str> { +/// take_till1(" \t\r\n").parse_next(s) +/// } +/// +/// assert_eq!(not_space("Hello, World!"), Ok((" World!", "Hello,"))); +/// assert_eq!(not_space("Sometimes\t"), Ok(("\t", "Sometimes"))); +/// assert_eq!(not_space("Nospace"), Ok(("", "Nospace"))); +/// assert_eq!(not_space(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::take_till1; +/// +/// fn till_colon(s: Partial<&str>) -> IResult, &str> { +/// take_till1(|c| c == ':').parse_next(s) +/// } +/// +/// assert_eq!(till_colon(Partial::new("latin:123")), Ok((Partial::new(":123"), "latin"))); +/// assert_eq!(till_colon(Partial::new(":empty matched")), Err(ErrMode::Backtrack(Error::new(Partial::new(":empty matched"), ErrorKind::Slice)))); +/// assert_eq!(till_colon(Partial::new("12345")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(till_colon(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// +/// fn not_space(s: Partial<&str>) -> IResult, &str> { +/// take_till1(" \t\r\n").parse_next(s) +/// } +/// +/// assert_eq!(not_space(Partial::new("Hello, World!")), Ok((Partial::new(" World!"), "Hello,"))); +/// assert_eq!(not_space(Partial::new("Sometimes\t")), Ok((Partial::new("\t"), "Sometimes"))); +/// assert_eq!(not_space(Partial::new("Nospace")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(not_space(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +#[doc(alias = "is_not")] +pub fn take_till1>( + list: T, +) -> impl Parser::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<::Token>, +{ + trace("take_till1", move |i: I| { + let e: ErrorKind = ErrorKind::Slice; + if ::is_partial_supported() && i.is_partial() { + split_at_offset1_partial(&i, |c| list.contains_token(c), e) + } else { + split_at_offset1_complete(&i, |c| list.contains_token(c), e) + } + }) +} + +/// Recognize an input slice containing the first N input elements (I[..N]). +/// +/// *Complete version*: It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Slice)))` if the input is shorter than the argument. +/// +/// *Partial version*: if the input has less than N elements, `take` will +/// return a `ErrMode::Incomplete(Needed::new(M))` where M is the number of +/// additional bytes the parser would need to succeed. +/// It is well defined for `&[u8]` as the number of elements is the byte size, +/// but for types like `&str`, we cannot know how many bytes correspond for +/// the next few chars, so the result will be `ErrMode::Incomplete(Needed::Unknown)` +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::take; +/// +/// fn take6(s: &str) -> IResult<&str, &str> { +/// take(6usize).parse_next(s) +/// } +/// +/// assert_eq!(take6("1234567"), Ok(("7", "123456"))); +/// assert_eq!(take6("things"), Ok(("", "things"))); +/// assert_eq!(take6("short"), Err(ErrMode::Backtrack(Error::new("short", ErrorKind::Slice)))); +/// assert_eq!(take6(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// ``` +/// +/// The units that are taken will depend on the input type. For example, for a +/// `&str` it will take a number of `char`'s, whereas for a `&[u8]` it will +/// take that many `u8`'s: +/// +/// ```rust +/// # use winnow::prelude::*; +/// use winnow::error::Error; +/// use winnow::token::take; +/// +/// assert_eq!(take::<_, _, Error<_>>(1usize).parse_next("💙"), Ok(("", "💙"))); +/// assert_eq!(take::<_, _, Error<_>>(1usize).parse_next("💙".as_bytes()), Ok((b"\x9F\x92\x99".as_ref(), b"\xF0".as_ref()))); +/// ``` +/// +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::Partial; +/// use winnow::token::take; +/// +/// fn take6(s: Partial<&str>) -> IResult, &str> { +/// take(6usize).parse_next(s) +/// } +/// +/// assert_eq!(take6(Partial::new("1234567")), Ok((Partial::new("7"), "123456"))); +/// assert_eq!(take6(Partial::new("things")), Ok((Partial::new(""), "things"))); +/// // `Unknown` as we don't know the number of bytes that `count` corresponds to +/// assert_eq!(take6(Partial::new("short")), Err(ErrMode::Incomplete(Needed::Unknown))); +/// ``` +#[inline(always)] +pub fn take>(count: C) -> impl Parser::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + C: ToUsize, +{ + let c = count.to_usize(); + trace("take", move |i: I| { + if ::is_partial_supported() { + take_::<_, _, true>(i, c) + } else { + take_::<_, _, false>(i, c) + } + }) +} + +fn take_, const PARTIAL: bool>( + i: I, + c: usize, +) -> IResult::Slice, Error> +where + I: StreamIsPartial, + I: Stream, +{ + match i.offset_at(c) { + Ok(offset) => Ok(i.next_slice(offset)), + Err(e) if PARTIAL && i.is_partial() => Err(ErrMode::Incomplete(e)), + Err(_needed) => Err(ErrMode::from_error_kind(i, ErrorKind::Slice)), + } +} + +/// Recognize the input slice up to the first occurrence of the literal. +/// +/// It doesn't consume the pattern. +/// +/// *Complete version*: It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Slice)))` +/// if the pattern wasn't met. +/// +/// *Partial version*: will return a `ErrMode::Incomplete(Needed::new(N))` if the input doesn't +/// contain the pattern or if the input is smaller than the pattern. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::take_until0; +/// +/// fn until_eof(s: &str) -> IResult<&str, &str> { +/// take_until0("eof").parse_next(s) +/// } +/// +/// assert_eq!(until_eof("hello, worldeof"), Ok(("eof", "hello, world"))); +/// assert_eq!(until_eof("hello, world"), Err(ErrMode::Backtrack(Error::new("hello, world", ErrorKind::Slice)))); +/// assert_eq!(until_eof(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// assert_eq!(until_eof("1eof2eof"), Ok(("eof2eof", "1"))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::take_until0; +/// +/// fn until_eof(s: Partial<&str>) -> IResult, &str> { +/// take_until0("eof").parse_next(s) +/// } +/// +/// assert_eq!(until_eof(Partial::new("hello, worldeof")), Ok((Partial::new("eof"), "hello, world"))); +/// assert_eq!(until_eof(Partial::new("hello, world")), Err(ErrMode::Incomplete(Needed::Unknown))); +/// assert_eq!(until_eof(Partial::new("hello, worldeo")), Err(ErrMode::Incomplete(Needed::Unknown))); +/// assert_eq!(until_eof(Partial::new("1eof2eof")), Ok((Partial::new("eof2eof"), "1"))); +/// ``` +#[inline(always)] +pub fn take_until0>( + tag: T, +) -> impl Parser::Slice, Error> +where + I: StreamIsPartial, + I: Stream + FindSlice, + T: SliceLen + Clone, +{ + trace("take_until0", move |i: I| { + if ::is_partial_supported() { + take_until0_::<_, _, _, true>(i, tag.clone()) + } else { + take_until0_::<_, _, _, false>(i, tag.clone()) + } + }) +} + +fn take_until0_, const PARTIAL: bool>( + i: I, + t: T, +) -> IResult::Slice, Error> +where + I: StreamIsPartial, + I: Stream + FindSlice, + T: SliceLen, +{ + match i.find_slice(t) { + Some(offset) => Ok(i.next_slice(offset)), + None if PARTIAL && i.is_partial() => Err(ErrMode::Incomplete(Needed::Unknown)), + None => Err(ErrMode::from_error_kind(i, ErrorKind::Slice)), + } +} + +/// Recognize the non empty input slice up to the first occurrence of the literal. +/// +/// It doesn't consume the pattern. +/// +/// *Complete version*: It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Slice)))` +/// if the pattern wasn't met. +/// +/// *Partial version*: will return a `ErrMode::Incomplete(Needed::new(N))` if the input doesn't +/// contain the pattern or if the input is smaller than the pattern. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::take_until1; +/// +/// fn until_eof(s: &str) -> IResult<&str, &str> { +/// take_until1("eof").parse_next(s) +/// } +/// +/// assert_eq!(until_eof("hello, worldeof"), Ok(("eof", "hello, world"))); +/// assert_eq!(until_eof("hello, world"), Err(ErrMode::Backtrack(Error::new("hello, world", ErrorKind::Slice)))); +/// assert_eq!(until_eof(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// assert_eq!(until_eof("1eof2eof"), Ok(("eof2eof", "1"))); +/// assert_eq!(until_eof("eof"), Err(ErrMode::Backtrack(Error::new("eof", ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::take_until1; +/// +/// fn until_eof(s: Partial<&str>) -> IResult, &str> { +/// take_until1("eof").parse_next(s) +/// } +/// +/// assert_eq!(until_eof(Partial::new("hello, worldeof")), Ok((Partial::new("eof"), "hello, world"))); +/// assert_eq!(until_eof(Partial::new("hello, world")), Err(ErrMode::Incomplete(Needed::Unknown))); +/// assert_eq!(until_eof(Partial::new("hello, worldeo")), Err(ErrMode::Incomplete(Needed::Unknown))); +/// assert_eq!(until_eof(Partial::new("1eof2eof")), Ok((Partial::new("eof2eof"), "1"))); +/// assert_eq!(until_eof(Partial::new("eof")), Err(ErrMode::Backtrack(Error::new(Partial::new("eof"), ErrorKind::Slice)))); +/// ``` +#[inline(always)] +pub fn take_until1>( + tag: T, +) -> impl Parser::Slice, Error> +where + I: StreamIsPartial, + I: Stream + FindSlice, + T: SliceLen + Clone, +{ + trace("take_until1", move |i: I| { + if ::is_partial_supported() { + take_until1_::<_, _, _, true>(i, tag.clone()) + } else { + take_until1_::<_, _, _, false>(i, tag.clone()) + } + }) +} + +fn take_until1_, const PARTIAL: bool>( + i: I, + t: T, +) -> IResult::Slice, Error> +where + I: StreamIsPartial, + I: Stream + FindSlice, + T: SliceLen, +{ + match i.find_slice(t) { + None if PARTIAL && i.is_partial() => Err(ErrMode::Incomplete(Needed::Unknown)), + None | Some(0) => Err(ErrMode::from_error_kind(i, ErrorKind::Slice)), + Some(offset) => Ok(i.next_slice(offset)), + } +} diff --git a/vendor/winnow/src/token/tests.rs b/vendor/winnow/src/token/tests.rs new file mode 100644 index 000000000..e1c7999c2 --- /dev/null +++ b/vendor/winnow/src/token/tests.rs @@ -0,0 +1,700 @@ +use super::*; + +#[cfg(feature = "std")] +use proptest::prelude::*; + +use crate::binary::length_data; +use crate::combinator::delimited; +use crate::error::ErrMode; +use crate::error::Error; +use crate::error::ErrorKind; +use crate::error::Needed; +use crate::stream::AsChar; +use crate::token::tag; +use crate::IResult; +use crate::Parser; +use crate::Partial; + +#[test] +fn complete_take_while_m_n_utf8_all_matching() { + let result: IResult<&str, &str> = + take_while(1..=4, |c: char| c.is_alphabetic()).parse_next("øn"); + assert_eq!(result, Ok(("", "øn"))); +} + +#[test] +fn complete_take_while_m_n_utf8_all_matching_substring() { + let result: IResult<&str, &str> = take_while(1, |c: char| c.is_alphabetic()).parse_next("øn"); + assert_eq!(result, Ok(("n", "ø"))); +} + +#[cfg(feature = "std")] +fn model_complete_take_while_m_n( + m: usize, + n: usize, + valid: usize, + input: &str, +) -> IResult<&str, &str> { + if n < m { + Err(crate::error::ErrMode::from_error_kind( + input, + crate::error::ErrorKind::Slice, + )) + } else if m <= valid { + let offset = n.min(valid); + Ok((&input[offset..], &input[0..offset])) + } else { + Err(crate::error::ErrMode::from_error_kind( + input, + crate::error::ErrorKind::Slice, + )) + } +} + +#[cfg(feature = "std")] +proptest! { + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn complete_take_while_m_n_bounds(m in 0..20usize, n in 0..20usize, valid in 0..20usize, invalid in 0..20usize) { + let input = format!("{:a>>(Partial::new("Ә")), + Ok((Partial::new(""), 'Ә')) + ); +} + +#[test] +fn partial_one_of_test() { + fn f(i: Partial<&[u8]>) -> IResult, u8> { + one_of("ab").parse_next(i) + } + + let a = &b"abcd"[..]; + assert_eq!(f(Partial::new(a)), Ok((Partial::new(&b"bcd"[..]), b'a'))); + + let b = &b"cde"[..]; + assert_eq!( + f(Partial::new(b)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(b), + ErrorKind::Verify + ))) + ); + + fn utf8(i: Partial<&str>) -> IResult, char> { + one_of("+\u{FF0B}").parse_next(i) + } + + assert!(utf8(Partial::new("+")).is_ok()); + assert!(utf8(Partial::new("\u{FF0B}")).is_ok()); +} + +#[test] +fn char_byteslice() { + fn f(i: Partial<&[u8]>) -> IResult, u8> { + 'c'.parse_next(i) + } + + let a = &b"abcd"[..]; + assert_eq!( + f(Partial::new(a)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(a), + ErrorKind::Verify + ))) + ); + + let b = &b"cde"[..]; + assert_eq!(f(Partial::new(b)), Ok((Partial::new(&b"de"[..]), b'c'))); +} + +#[test] +fn char_str() { + fn f(i: Partial<&str>) -> IResult, char> { + 'c'.parse_next(i) + } + + let a = "abcd"; + assert_eq!( + f(Partial::new(a)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(a), + ErrorKind::Verify + ))) + ); + + let b = "cde"; + assert_eq!(f(Partial::new(b)), Ok((Partial::new("de"), 'c'))); +} + +#[test] +fn partial_none_of_test() { + fn f(i: Partial<&[u8]>) -> IResult, u8> { + none_of("ab").parse_next(i) + } + + let a = &b"abcd"[..]; + assert_eq!( + f(Partial::new(a)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(a), + ErrorKind::Verify + ))) + ); + + let b = &b"cde"[..]; + assert_eq!(f(Partial::new(b)), Ok((Partial::new(&b"de"[..]), b'c'))); +} + +#[test] +fn partial_is_a() { + fn a_or_b(i: Partial<&[u8]>) -> IResult, &[u8]> { + take_while(1.., "ab").parse_next(i) + } + + let a = Partial::new(&b"abcd"[..]); + assert_eq!(a_or_b(a), Ok((Partial::new(&b"cd"[..]), &b"ab"[..]))); + + let b = Partial::new(&b"bcde"[..]); + assert_eq!(a_or_b(b), Ok((Partial::new(&b"cde"[..]), &b"b"[..]))); + + let c = Partial::new(&b"cdef"[..]); + assert_eq!( + a_or_b(c), + Err(ErrMode::Backtrack(error_position!(c, ErrorKind::Slice))) + ); + + let d = Partial::new(&b"bacdef"[..]); + assert_eq!(a_or_b(d), Ok((Partial::new(&b"cdef"[..]), &b"ba"[..]))); +} + +#[test] +fn partial_is_not() { + fn a_or_b(i: Partial<&[u8]>) -> IResult, &[u8]> { + take_till1("ab").parse_next(i) + } + + let a = Partial::new(&b"cdab"[..]); + assert_eq!(a_or_b(a), Ok((Partial::new(&b"ab"[..]), &b"cd"[..]))); + + let b = Partial::new(&b"cbde"[..]); + assert_eq!(a_or_b(b), Ok((Partial::new(&b"bde"[..]), &b"c"[..]))); + + let c = Partial::new(&b"abab"[..]); + assert_eq!( + a_or_b(c), + Err(ErrMode::Backtrack(error_position!(c, ErrorKind::Slice))) + ); + + let d = Partial::new(&b"cdefba"[..]); + assert_eq!(a_or_b(d), Ok((Partial::new(&b"ba"[..]), &b"cdef"[..]))); + + let e = Partial::new(&b"e"[..]); + assert_eq!(a_or_b(e), Err(ErrMode::Incomplete(Needed::new(1)))); +} + +#[test] +fn partial_take_until_incomplete() { + fn y(i: Partial<&[u8]>) -> IResult, &[u8]> { + take_until0("end").parse_next(i) + } + assert_eq!( + y(Partial::new(&b"nd"[..])), + Err(ErrMode::Incomplete(Needed::Unknown)) + ); + assert_eq!( + y(Partial::new(&b"123"[..])), + Err(ErrMode::Incomplete(Needed::Unknown)) + ); + assert_eq!( + y(Partial::new(&b"123en"[..])), + Err(ErrMode::Incomplete(Needed::Unknown)) + ); +} + +#[test] +fn partial_take_until_incomplete_s() { + fn ys(i: Partial<&str>) -> IResult, &str> { + take_until0("end").parse_next(i) + } + assert_eq!( + ys(Partial::new("123en")), + Err(ErrMode::Incomplete(Needed::Unknown)) + ); +} + +#[test] +fn partial_recognize() { + use crate::ascii::{ + alpha1 as alpha, alphanumeric1 as alphanumeric, digit1 as digit, hex_digit1 as hex_digit, + multispace1 as multispace, oct_digit1 as oct_digit, space1 as space, + }; + + fn x(i: Partial<&[u8]>) -> IResult, &[u8]> { + delimited("") + .recognize() + .parse_next(i) + } + let r = x(Partial::new(&b" aaa"[..])); + assert_eq!(r, Ok((Partial::new(&b" aaa"[..]), &b""[..]))); + + let semicolon = &b";"[..]; + + fn ya(i: Partial<&[u8]>) -> IResult, &[u8]> { + alpha.recognize().parse_next(i) + } + let ra = ya(Partial::new(&b"abc;"[..])); + assert_eq!(ra, Ok((Partial::new(semicolon), &b"abc"[..]))); + + fn yd(i: Partial<&[u8]>) -> IResult, &[u8]> { + digit.recognize().parse_next(i) + } + let rd = yd(Partial::new(&b"123;"[..])); + assert_eq!(rd, Ok((Partial::new(semicolon), &b"123"[..]))); + + fn yhd(i: Partial<&[u8]>) -> IResult, &[u8]> { + hex_digit.recognize().parse_next(i) + } + let rhd = yhd(Partial::new(&b"123abcDEF;"[..])); + assert_eq!(rhd, Ok((Partial::new(semicolon), &b"123abcDEF"[..]))); + + fn yod(i: Partial<&[u8]>) -> IResult, &[u8]> { + oct_digit.recognize().parse_next(i) + } + let rod = yod(Partial::new(&b"1234567;"[..])); + assert_eq!(rod, Ok((Partial::new(semicolon), &b"1234567"[..]))); + + fn yan(i: Partial<&[u8]>) -> IResult, &[u8]> { + alphanumeric.recognize().parse_next(i) + } + let ran = yan(Partial::new(&b"123abc;"[..])); + assert_eq!(ran, Ok((Partial::new(semicolon), &b"123abc"[..]))); + + fn ys(i: Partial<&[u8]>) -> IResult, &[u8]> { + space.recognize().parse_next(i) + } + let rs = ys(Partial::new(&b" \t;"[..])); + assert_eq!(rs, Ok((Partial::new(semicolon), &b" \t"[..]))); + + fn yms(i: Partial<&[u8]>) -> IResult, &[u8]> { + multispace.recognize().parse_next(i) + } + let rms = yms(Partial::new(&b" \t\r\n;"[..])); + assert_eq!(rms, Ok((Partial::new(semicolon), &b" \t\r\n"[..]))); +} + +#[test] +fn partial_take_while0() { + fn f(i: Partial<&[u8]>) -> IResult, &[u8]> { + take_while(0.., AsChar::is_alpha).parse_next(i) + } + let a = &b""[..]; + let b = &b"abcd"[..]; + let c = &b"abcd123"[..]; + let d = &b"123"[..]; + + assert_eq!(f(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_eq!(f(Partial::new(b)), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_eq!(f(Partial::new(c)), Ok((Partial::new(d), b))); + assert_eq!(f(Partial::new(d)), Ok((Partial::new(d), a))); +} + +#[test] +fn partial_take_while1() { + fn f(i: Partial<&[u8]>) -> IResult, &[u8]> { + take_while(1.., AsChar::is_alpha).parse_next(i) + } + let a = &b""[..]; + let b = &b"abcd"[..]; + let c = &b"abcd123"[..]; + let d = &b"123"[..]; + + assert_eq!(f(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_eq!(f(Partial::new(b)), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_eq!(f(Partial::new(c)), Ok((Partial::new(&b"123"[..]), b))); + assert_eq!( + f(Partial::new(d)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(d), + ErrorKind::Slice + ))) + ); +} + +#[test] +fn partial_take_while_m_n() { + fn x(i: Partial<&[u8]>) -> IResult, &[u8]> { + take_while(2..=4, AsChar::is_alpha).parse_next(i) + } + let a = &b""[..]; + let b = &b"a"[..]; + let c = &b"abc"[..]; + let d = &b"abc123"[..]; + let e = &b"abcde"[..]; + let f = &b"123"[..]; + + assert_eq!(x(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(2)))); + assert_eq!(x(Partial::new(b)), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_eq!(x(Partial::new(c)), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_eq!(x(Partial::new(d)), Ok((Partial::new(&b"123"[..]), c))); + assert_eq!( + x(Partial::new(e)), + Ok((Partial::new(&b"e"[..]), &b"abcd"[..])) + ); + assert_eq!( + x(Partial::new(f)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(f), + ErrorKind::Slice + ))) + ); +} + +#[test] +fn partial_take_till0() { + fn f(i: Partial<&[u8]>) -> IResult, &[u8]> { + take_till0(AsChar::is_alpha).parse_next(i) + } + let a = &b""[..]; + let b = &b"abcd"[..]; + let c = &b"123abcd"[..]; + let d = &b"123"[..]; + + assert_eq!(f(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_eq!( + f(Partial::new(b)), + Ok((Partial::new(&b"abcd"[..]), &b""[..])) + ); + assert_eq!( + f(Partial::new(c)), + Ok((Partial::new(&b"abcd"[..]), &b"123"[..])) + ); + assert_eq!(f(Partial::new(d)), Err(ErrMode::Incomplete(Needed::new(1)))); +} + +#[test] +fn partial_take_till1() { + fn f(i: Partial<&[u8]>) -> IResult, &[u8]> { + take_till1(AsChar::is_alpha).parse_next(i) + } + let a = &b""[..]; + let b = &b"abcd"[..]; + let c = &b"123abcd"[..]; + let d = &b"123"[..]; + + assert_eq!(f(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_eq!( + f(Partial::new(b)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(b), + ErrorKind::Slice + ))) + ); + assert_eq!( + f(Partial::new(c)), + Ok((Partial::new(&b"abcd"[..]), &b"123"[..])) + ); + assert_eq!(f(Partial::new(d)), Err(ErrMode::Incomplete(Needed::new(1)))); +} + +#[test] +fn partial_take_while_utf8() { + fn f(i: Partial<&str>) -> IResult, &str> { + take_while(0.., |c| c != '點').parse_next(i) + } + + assert_eq!( + f(Partial::new("")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + f(Partial::new("abcd")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!(f(Partial::new("abcd點")), Ok((Partial::new("點"), "abcd"))); + assert_eq!( + f(Partial::new("abcd點a")), + Ok((Partial::new("點a"), "abcd")) + ); + + fn g(i: Partial<&str>) -> IResult, &str> { + take_while(0.., |c| c == '點').parse_next(i) + } + + assert_eq!( + g(Partial::new("")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!(g(Partial::new("點abcd")), Ok((Partial::new("abcd"), "點"))); + assert_eq!( + g(Partial::new("點點點a")), + Ok((Partial::new("a"), "點點點")) + ); +} + +#[test] +fn partial_take_till0_utf8() { + fn f(i: Partial<&str>) -> IResult, &str> { + take_till0(|c| c == '點').parse_next(i) + } + + assert_eq!( + f(Partial::new("")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + f(Partial::new("abcd")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!(f(Partial::new("abcd點")), Ok((Partial::new("點"), "abcd"))); + assert_eq!( + f(Partial::new("abcd點a")), + Ok((Partial::new("點a"), "abcd")) + ); + + fn g(i: Partial<&str>) -> IResult, &str> { + take_till0(|c| c != '點').parse_next(i) + } + + assert_eq!( + g(Partial::new("")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!(g(Partial::new("點abcd")), Ok((Partial::new("abcd"), "點"))); + assert_eq!( + g(Partial::new("點點點a")), + Ok((Partial::new("a"), "點點點")) + ); +} + +#[test] +fn partial_take_utf8() { + fn f(i: Partial<&str>) -> IResult, &str> { + take(3_usize).parse_next(i) + } + + assert_eq!( + f(Partial::new("")), + Err(ErrMode::Incomplete(Needed::Unknown)) + ); + assert_eq!( + f(Partial::new("ab")), + Err(ErrMode::Incomplete(Needed::Unknown)) + ); + assert_eq!( + f(Partial::new("點")), + Err(ErrMode::Incomplete(Needed::Unknown)) + ); + assert_eq!(f(Partial::new("ab點cd")), Ok((Partial::new("cd"), "ab點"))); + assert_eq!(f(Partial::new("a點bcd")), Ok((Partial::new("cd"), "a點b"))); + assert_eq!(f(Partial::new("a點b")), Ok((Partial::new(""), "a點b"))); + + fn g(i: Partial<&str>) -> IResult, &str> { + take_while(0.., |c| c == '點').parse_next(i) + } + + assert_eq!( + g(Partial::new("")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!(g(Partial::new("點abcd")), Ok((Partial::new("abcd"), "點"))); + assert_eq!( + g(Partial::new("點點點a")), + Ok((Partial::new("a"), "點點點")) + ); +} + +#[test] +fn partial_take_while_m_n_utf8_fixed() { + fn parser(i: Partial<&str>) -> IResult, &str> { + take_while(1, |c| c == 'A' || c == '😃').parse_next(i) + } + assert_eq!(parser(Partial::new("A!")), Ok((Partial::new("!"), "A"))); + assert_eq!(parser(Partial::new("😃!")), Ok((Partial::new("!"), "😃"))); +} + +#[test] +fn partial_take_while_m_n_utf8_range() { + fn parser(i: Partial<&str>) -> IResult, &str> { + take_while(1..=2, |c| c == 'A' || c == '😃').parse_next(i) + } + assert_eq!(parser(Partial::new("A!")), Ok((Partial::new("!"), "A"))); + assert_eq!(parser(Partial::new("😃!")), Ok((Partial::new("!"), "😃"))); +} + +#[test] +fn partial_take_while_m_n_utf8_full_match_fixed() { + fn parser(i: Partial<&str>) -> IResult, &str> { + take_while(1, |c: char| c.is_alphabetic()).parse_next(i) + } + assert_eq!(parser(Partial::new("øn")), Ok((Partial::new("n"), "ø"))); +} + +#[test] +fn partial_take_while_m_n_utf8_full_match_range() { + fn parser(i: Partial<&str>) -> IResult, &str> { + take_while(1..=2, |c: char| c.is_alphabetic()).parse_next(i) + } + assert_eq!(parser(Partial::new("øn")), Ok((Partial::new(""), "øn"))); +} + +#[test] +#[cfg(feature = "std")] +fn partial_recognize_take_while0() { + fn x(i: Partial<&[u8]>) -> IResult, &[u8]> { + take_while(0.., AsChar::is_alphanum).parse_next(i) + } + fn y(i: Partial<&[u8]>) -> IResult, &[u8]> { + x.recognize().parse_next(i) + } + assert_eq!( + x(Partial::new(&b"ab."[..])), + Ok((Partial::new(&b"."[..]), &b"ab"[..])) + ); + assert_eq!( + y(Partial::new(&b"ab."[..])), + Ok((Partial::new(&b"."[..]), &b"ab"[..])) + ); +} + +#[test] +fn partial_length_bytes() { + use crate::binary::le_u8; + + fn x(i: Partial<&[u8]>) -> IResult, &[u8]> { + length_data(le_u8).parse_next(i) + } + assert_eq!( + x(Partial::new(b"\x02..>>")), + Ok((Partial::new(&b">>"[..]), &b".."[..])) + ); + assert_eq!( + x(Partial::new(b"\x02..")), + Ok((Partial::new(&[][..]), &b".."[..])) + ); + assert_eq!( + x(Partial::new(b"\x02.")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + x(Partial::new(b"\x02")), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + + fn y(i: Partial<&[u8]>) -> IResult, &[u8]> { + let (i, _) = "magic".parse_next(i)?; + length_data(le_u8).parse_next(i) + } + assert_eq!( + y(Partial::new(b"magic\x02..>>")), + Ok((Partial::new(&b">>"[..]), &b".."[..])) + ); + assert_eq!( + y(Partial::new(b"magic\x02..")), + Ok((Partial::new(&[][..]), &b".."[..])) + ); + assert_eq!( + y(Partial::new(b"magic\x02.")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + y(Partial::new(b"magic\x02")), + Err(ErrMode::Incomplete(Needed::new(2))) + ); +} + +#[cfg(feature = "alloc")] +#[test] +fn partial_case_insensitive() { + fn test(i: Partial<&[u8]>) -> IResult, &[u8]> { + tag_no_case("ABcd").parse_next(i) + } + assert_eq!( + test(Partial::new(&b"aBCdefgh"[..])), + Ok((Partial::new(&b"efgh"[..]), &b"aBCd"[..])) + ); + assert_eq!( + test(Partial::new(&b"abcdefgh"[..])), + Ok((Partial::new(&b"efgh"[..]), &b"abcd"[..])) + ); + assert_eq!( + test(Partial::new(&b"ABCDefgh"[..])), + Ok((Partial::new(&b"efgh"[..]), &b"ABCD"[..])) + ); + assert_eq!( + test(Partial::new(&b"ab"[..])), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_eq!( + test(Partial::new(&b"Hello"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"Hello"[..]), + ErrorKind::Tag + ))) + ); + assert_eq!( + test(Partial::new(&b"Hel"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"Hel"[..]), + ErrorKind::Tag + ))) + ); + + fn test2(i: Partial<&str>) -> IResult, &str> { + tag_no_case("ABcd").parse_next(i) + } + assert_eq!( + test2(Partial::new("aBCdefgh")), + Ok((Partial::new("efgh"), "aBCd")) + ); + assert_eq!( + test2(Partial::new("abcdefgh")), + Ok((Partial::new("efgh"), "abcd")) + ); + assert_eq!( + test2(Partial::new("ABCDefgh")), + Ok((Partial::new("efgh"), "ABCD")) + ); + assert_eq!( + test2(Partial::new("ab")), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_eq!( + test2(Partial::new("Hello")), + Err(ErrMode::Backtrack(error_position!( + Partial::new("Hello"), + ErrorKind::Tag + ))) + ); + assert_eq!( + test2(Partial::new("Hel")), + Err(ErrMode::Backtrack(error_position!( + Partial::new("Hel"), + ErrorKind::Tag + ))) + ); +} + +#[test] +fn partial_tag_fixed_size_array() { + fn test(i: Partial<&[u8]>) -> IResult, &[u8]> { + tag([0x42]).parse_next(i) + } + fn test2(i: Partial<&[u8]>) -> IResult, &[u8]> { + tag(&[0x42]).parse_next(i) + } + let input = Partial::new(&[0x42, 0x00][..]); + assert_eq!(test(input), Ok((Partial::new(&b"\x00"[..]), &b"\x42"[..]))); + assert_eq!(test2(input), Ok((Partial::new(&b"\x00"[..]), &b"\x42"[..]))); +} diff --git a/vendor/winnow/src/trace/internals.rs b/vendor/winnow/src/trace/internals.rs index 2e91f69a8..3a10204b7 100644 --- a/vendor/winnow/src/trace/internals.rs +++ b/vendor/winnow/src/trace/internals.rs @@ -74,30 +74,9 @@ pub fn start( count: usize, input: &I, ) { - let ansi_color = ansi_color(); - let reset = if ansi_color { - anstyle::Reset.render().to_string() - } else { - "".to_owned() - }; - let gutter_style = if ansi_color { - anstyle::Style::new().bold() - } else { - anstyle::Style::new() - } - .render(); - let input_style = if ansi_color { - anstyle::Style::new().underline() - } else { - anstyle::Style::new() - } - .render(); - let eof_style = if ansi_color { - anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Cyan.into())) - } else { - anstyle::Style::new() - } - .render(); + let gutter_style = anstyle::Style::new().bold(); + let input_style = anstyle::Style::new().underline(); + let eof_style = anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Cyan.into())); let (call_width, input_width) = column_widths(); @@ -132,9 +111,18 @@ pub fn start( (debug_slice, eof) }; - let writer = std::io::stderr(); + let writer = anstyle_stream::stderr(); let mut writer = writer.lock(); - let _ = writeln!(writer, "{call_column:call_width$} {gutter_style}|{reset} {input_style}{debug_slice}{eof_style}{eof}{reset}"); + let _ = writeln!( + writer, + "{call_column:call_width$} {gutter_style}|{gutter_reset} {input_style}{debug_slice}{input_reset}{eof_style}{eof}{eof_reset}", + gutter_style=gutter_style.render(), + gutter_reset=gutter_style.render_reset(), + input_style=input_style.render(), + input_reset=input_style.render_reset(), + eof_style=eof_style.render(), + eof_reset=eof_style.render_reset(), + ); } pub fn end( @@ -144,18 +132,7 @@ pub fn end( consumed: Option, severity: Severity, ) { - let ansi_color = ansi_color(); - let reset = if ansi_color { - anstyle::Reset.render().to_string() - } else { - "".to_owned() - }; - let gutter_style = if ansi_color { - anstyle::Style::new().bold() - } else { - anstyle::Style::new() - } - .render(); + let gutter_style = anstyle::Style::new().bold(); let (call_width, _) = column_widths(); @@ -166,105 +143,76 @@ pub fn end( }; let call_column = format!("{:depth$}< {name}{count}", ""); - let (mut status_style, status) = match severity { + let (status_style, status) = match severity { Severity::Success => { - let style = anstyle::Style::new() - .fg_color(Some(anstyle::AnsiColor::Green.into())) - .render(); + let style = anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Green.into())); let status = format!("+{}", consumed.unwrap_or_default()); (style, status) } Severity::Backtrack => ( - anstyle::Style::new() - .fg_color(Some(anstyle::AnsiColor::Yellow.into())) - .render(), + anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Yellow.into())), "backtrack".to_owned(), ), Severity::Cut => ( - anstyle::Style::new() - .fg_color(Some(anstyle::AnsiColor::Red.into())) - .render(), + anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Red.into())), "cut".to_owned(), ), Severity::Incomplete => ( - anstyle::Style::new() - .fg_color(Some(anstyle::AnsiColor::Red.into())) - .render(), + anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Red.into())), "incomplete".to_owned(), ), }; - if !ansi_color { - status_style = anstyle::Style::new().render(); - } - let writer = std::io::stderr(); + let writer = anstyle_stream::stderr(); let mut writer = writer.lock(); let _ = writeln!( writer, - "{status_style}{call_column:call_width$}{reset} {gutter_style}|{reset} {status_style}{status}{reset}" + "{status_style}{call_column:call_width$}{status_reset} {gutter_style}|{gutter_reset} {status_style}{status}{status_reset}", + gutter_style=gutter_style.render(), + gutter_reset=gutter_style.render_reset(), + status_style=status_style.render(), + status_reset=status_style.render_reset(), ); } pub fn result(depth: usize, name: &dyn crate::lib::std::fmt::Display, severity: Severity) { - let ansi_color = ansi_color(); - let reset = if ansi_color { - anstyle::Reset.render().to_string() - } else { - "".to_owned() - }; - let gutter_style = if ansi_color { - anstyle::Style::new().bold() - } else { - anstyle::Style::new() - } - .render(); + let gutter_style = anstyle::Style::new().bold(); let (call_width, _) = column_widths(); let call_column = format!("{:depth$}| {name}", ""); - let (mut status_style, status) = match severity { + let (status_style, status) = match severity { Severity::Success => ( - anstyle::Style::new() - .fg_color(Some(anstyle::AnsiColor::Green.into())) - .render(), + anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Green.into())), "", ), Severity::Backtrack => ( - anstyle::Style::new() - .fg_color(Some(anstyle::AnsiColor::Yellow.into())) - .render(), + anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Yellow.into())), "backtrack", ), Severity::Cut => ( - anstyle::Style::new() - .fg_color(Some(anstyle::AnsiColor::Red.into())) - .render(), + anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Red.into())), "cut", ), Severity::Incomplete => ( - anstyle::Style::new() - .fg_color(Some(anstyle::AnsiColor::Red.into())) - .render(), + anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Red.into())), "incomplete", ), }; - if !ansi_color { - status_style = anstyle::Style::new().render(); - } - let writer = std::io::stderr(); + let writer = anstyle_stream::stderr(); let mut writer = writer.lock(); let _ = writeln!( writer, - "{status_style}{call_column:call_width$}{reset} {gutter_style}|{reset} {status_style}{status}{reset}" + "{status_style}{call_column:call_width$}{status_reset} {gutter_style}|{gutter_reset} {status_style}{status}{status_reset}", + gutter_style=gutter_style.render(), + gutter_reset=gutter_style.render_reset(), + status_style=status_style.render(), + status_reset=status_style.render_reset(), ); } -fn ansi_color() -> bool { - concolor::get(concolor::Stream::Stderr).ansi_color() -} - fn column_widths() -> (usize, usize) { let term_width = term_width(); diff --git a/vendor/winnow/src/trace/mod.rs b/vendor/winnow/src/trace/mod.rs index 59dafba8e..e5eaf9451 100644 --- a/vendor/winnow/src/trace/mod.rs +++ b/vendor/winnow/src/trace/mod.rs @@ -27,14 +27,14 @@ compile_error!("`debug` requires `std`"); /// /// ```rust /// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed, IResult}; -/// # use winnow::bytes::take_while_m_n; +/// # use winnow::token::take_while; /// # use winnow::stream::AsChar; /// # use winnow::prelude::*; /// use winnow::trace::trace; /// /// fn short_alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { /// trace("short_alpha", -/// take_while_m_n(3, 6, AsChar::is_alpha) +/// take_while(3..=6, AsChar::is_alpha) /// ).parse_next(s) /// } /// @@ -46,6 +46,7 @@ compile_error!("`debug` requires `std`"); /// ``` #[cfg_attr(not(feature = "debug"), allow(unused_variables))] #[cfg_attr(not(feature = "debug"), allow(unused_mut))] +#[cfg_attr(not(feature = "debug"), inline(always))] pub fn trace( name: impl crate::lib::std::fmt::Display, mut parser: impl Parser, -- cgit v1.2.3