summaryrefslogtreecommitdiffstats
path: root/vendor/winnow/src
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/winnow/src')
-rw-r--r--vendor/winnow/src/_topic/arithmetic.rs6
-rw-r--r--vendor/winnow/src/_topic/mod.rs3
-rw-r--r--vendor/winnow/src/_topic/partial.rs6
-rw-r--r--vendor/winnow/src/_topic/performance.rs6
-rw-r--r--vendor/winnow/src/_topic/stream.rs32
-rw-r--r--vendor/winnow/src/_topic/why.rs10
-rw-r--r--vendor/winnow/src/_tutorial/chapter_0.rs2
-rw-r--r--vendor/winnow/src/_tutorial/chapter_1.rs12
-rw-r--r--vendor/winnow/src/_tutorial/chapter_2.rs10
-rw-r--r--vendor/winnow/src/_tutorial/chapter_3.rs6
-rw-r--r--vendor/winnow/src/_tutorial/chapter_4.rs3
-rw-r--r--vendor/winnow/src/_tutorial/chapter_5.rs16
-rw-r--r--vendor/winnow/src/_tutorial/chapter_6.rs4
-rw-r--r--vendor/winnow/src/_tutorial/mod.rs1
-rw-r--r--vendor/winnow/src/ascii/mod.rs41
-rw-r--r--vendor/winnow/src/binary/bits/mod.rs2
-rw-r--r--vendor/winnow/src/combinator/core.rs2
-rw-r--r--vendor/winnow/src/combinator/mod.rs95
-rw-r--r--vendor/winnow/src/combinator/multi.rs590
-rw-r--r--vendor/winnow/src/combinator/parser.rs2
-rw-r--r--vendor/winnow/src/combinator/tests.rs53
-rw-r--r--vendor/winnow/src/error.rs66
-rw-r--r--vendor/winnow/src/lib.rs2
-rw-r--r--vendor/winnow/src/parser.rs108
-rw-r--r--vendor/winnow/src/stream/impls.rs8
-rw-r--r--vendor/winnow/src/stream/mod.rs529
-rw-r--r--vendor/winnow/src/stream/tests.rs32
-rw-r--r--vendor/winnow/src/token/mod.rs148
-rw-r--r--vendor/winnow/src/token/tests.rs15
-rw-r--r--vendor/winnow/src/trace/mod.rs5
30 files changed, 1440 insertions, 375 deletions
diff --git a/vendor/winnow/src/_topic/arithmetic.rs b/vendor/winnow/src/_topic/arithmetic.rs
index 1a6eddcc4..d94b4fa4b 100644
--- a/vendor/winnow/src/_topic/arithmetic.rs
+++ b/vendor/winnow/src/_topic/arithmetic.rs
@@ -11,3 +11,9 @@
//! ```rust
#![doc = include_str!("../../examples/arithmetic/parser_ast.rs")]
//! ```
+//!
+//! ## Parse to Tokens then AST
+//!
+//! ```rust
+#![doc = include_str!("../../examples/arithmetic/parser_lexer.rs")]
+//! ```
diff --git a/vendor/winnow/src/_topic/mod.rs b/vendor/winnow/src/_topic/mod.rs
index 72c8145fe..79ba28a62 100644
--- a/vendor/winnow/src/_topic/mod.rs
+++ b/vendor/winnow/src/_topic/mod.rs
@@ -14,13 +14,14 @@
//! - [Implementing `FromStr`][fromstr]
//! - [Performance][performance]
//! - [Parsing Partial Input][partial]
-//! - [Custom stream][stream]
+//! - [Custom stream or token][stream]
//! - [Custom errors][error]
//!
//! See also parsers written with `winnow`:
//!
//! - [`toml_edit`](https://crates.io/crates/toml_edit)
//! - [`hcl-edit`](https://crates.io/crates/hcl-edit)
+#![allow(clippy::std_instead_of_core)]
pub mod arithmetic;
pub mod error;
diff --git a/vendor/winnow/src/_topic/partial.rs b/vendor/winnow/src/_topic/partial.rs
index 19895d35a..7a974217e 100644
--- a/vendor/winnow/src/_topic/partial.rs
+++ b/vendor/winnow/src/_topic/partial.rs
@@ -1,12 +1,12 @@
//! # Parsing Partial Input
//!
-//! Typically, the input being parsed is all in-memory, or is complete. Some data sources are too
+//! Typically, the input being parsed is all in-memory, or is complete. Some data sources are too
//! large to fit into memory, only allowing parsing an incomplete or [`Partial`] subset of the
//! data, requiring incrementally parsing.
//!
//! By wrapping a stream, like `&[u8]`, with [`Partial`], parsers will report when the data is
//! [`Incomplete`] and more input is [`Needed`], allowing the caller to stream-in additional data
-//! to be parsed. The data is then parsed a chunk at a time.
+//! to be parsed. The data is then parsed a chunk at a time.
//!
//! Chunks are typically defined by either:
//! - A header reporting the number of bytes, like with [`length_value`]
@@ -19,7 +19,7 @@
//! parser is for the next chunk.
//!
//! Caveats:
-//! - `winnow` takes the approach of re-parsing from scratch. Chunks should be relatively small to
+//! - `winnow` takes the approach of re-parsing from scratch. Chunks should be relatively small to
//! prevent the re-parsing overhead from dominating.
//! - 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`].
diff --git a/vendor/winnow/src/_topic/performance.rs b/vendor/winnow/src/_topic/performance.rs
index 8a6555a06..2b5303846 100644
--- a/vendor/winnow/src/_topic/performance.rs
+++ b/vendor/winnow/src/_topic/performance.rs
@@ -5,19 +5,19 @@
//! See also the general Rust [Performance Book](https://nnethercote.github.io/perf-book/)
//!
//! Tips
-//! - Try `cargo add winnow -F simd`. For some it offers significant performance improvements
+//! - Try `cargo add winnow -F simd`. For some it offers significant performance improvements
//! - When enough cases of an [`alt`] have unique prefixes, prefer [`dispatch`]
//! - When parsing text, try to parse 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
+//! - Watch for large return types. A surprising place these can show up is when chaining parsers
//! with a tuple.
//!
//! ## Build-time Performance
//!
-//! Returning complex types as `impl Trait` can negatively impact build times. This can hit in
+//! Returning complex types as `impl Trait` can negatively impact build times. This can hit in
//! surprising cases like:
//! ```rust
//! # use winnow::prelude::*;
diff --git a/vendor/winnow/src/_topic/stream.rs b/vendor/winnow/src/_topic/stream.rs
index 4f94a94b9..2254f8710 100644
--- a/vendor/winnow/src/_topic/stream.rs
+++ b/vendor/winnow/src/_topic/stream.rs
@@ -1,20 +1,21 @@
-//! # Custom [`Stream`][crate::stream::Stream]
+//! # Custom [`Stream`]
//!
//! `winnow` is batteries included with support for
//! - Basic inputs like `&str`, newtypes with
-//! - Improved debug output like [`Bytes`][crate::Bytes]
-//! - [`Stateful`][crate::Stateful] for passing state through your parser, like tracking recursion
+//! - Improved debug output like [`Bytes`]
+//! - [`Stateful`] for passing state through your parser, like tracking recursion
//! depth
-//! - [`Located`][crate::Located] for looking up the absolute position of a token
+//! - [`Located`] for looking up the absolute position of a token
//!
-//! But that won't always cut it for your parser. For example, you might lex `&str` into
+//! But that won't always cut it for your parser. For example, you might lex `&str` into
//! a series of tokens and then want to parse a `TokenStream`.
//!
//! ## Implementing a custom stream
//!
-//! Let's assume we have an input type we'll call `MyStream`. `MyStream` is a sequence of `MyItem` type.
-//! The goal is to define parsers with this signature: `&mut MyStream -> PResult<Output>`.
+//! Let's assume we have an input type we'll call `MyStream`.
+//! `MyStream` is a sequence of `MyItem` type.
//!
+//! The goal is to define parsers with this signature: `&mut MyStream -> PResult<Output>`.
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::token::tag;
@@ -25,7 +26,7 @@
//! }
//! ```
//!
-//! Here are the traits we have to implement for `MyStream`:
+//! Here are the traits you may have to implement for `MyStream`:
//!
//! | trait | usage |
//! |---|---|
@@ -38,17 +39,28 @@
//! | [`Location`] |Calculate location within initial input|
//! | [`Offset`] |Calculate the offset between slices|
//!
-//! Here are the traits we have to implement for `MyItem`:
+//! And for `MyItem`:
//!
//! | trait | usage |
//! |---|---|
//! | [`AsChar`] |Transforms common types to a char for basic token parsing|
//! | [`ContainsToken`] |Look for the token in the given set|
//!
-//! And traits for slices of `MyItem`:
+//! And traits for `&[MyItem]`:
//!
+//! | trait | usage |
+//! |---|---|
//! | [`SliceLen`] |Calculate the input length|
//! | [`ParseSlice`] |Used to integrate `&str`'s `parse()` method|
+//!
+//! ## Implementing a custom token
+//!
+//! If you are parsing `&[Myitem]`, leaving just the `MyItem` traits.
+//!
+//! For example:
+//! ```rust
+#![doc = include_str!("../../examples/arithmetic/parser_lexer.rs")]
+//! ```
#[allow(unused_imports)] // Here for intra-dock links
use crate::stream::*;
diff --git a/vendor/winnow/src/_topic/why.rs b/vendor/winnow/src/_topic/why.rs
index e0328f117..d49af7e01 100644
--- a/vendor/winnow/src/_topic/why.rs
+++ b/vendor/winnow/src/_topic/why.rs
@@ -2,7 +2,7 @@
//!
//! To answer this question, it will be useful to contrast this with other approaches to parsing.
//!
-//! **Note:** This will focus on principles and priorities. For a deeper and wider wider
+//! **Note:** This will focus on principles and priorities. For a deeper and wider wider
//! comparison with other Rust parser libraries, see
//! [parse-rosetta-rs](https://github.com/rosetta-rs/parse-rosetta-rs).
//!
@@ -58,7 +58,7 @@
//!
//! ## `nom`
//!
-//! `winnow` is a fork of the venerable [`nom`](https://crates.io/crates/nom). The difference
+//! `winnow` is a fork of the venerable [`nom`](https://crates.io/crates/nom). The difference
//! between them is largely in priorities. `nom` prioritizes:
//! - Lower churn for existing users while `winnow` is trying to find ways to make things better
//! for the parsers yet to be written.
@@ -78,10 +78,10 @@
//! > "If you need to implement either `Parser` or `Strategy` by hand, that's a problem that needs fixing".
//!
//! This is under "batteries included" but it also ties into the feeling that `chumksy` acts more like
-//! a framework. Instead of composing together helpers, you are expected to do everything through
+//! a framework. Instead of composing together helpers, you are expected to do everything through
//! their system to the point that it is non-trivial to implement their `Parser` trait and are
//! encouraged to use the
-//! [`custom`](https://docs.rs/chumsky/0.9.0/chumsky/primitive/fn.custom.html) helper. This
+//! [`custom`](https://docs.rs/chumsky/0.9.0/chumsky/primitive/fn.custom.html) helper. This
//! requires re-framing everything to fit within their model and makes the code harder to understand
//! and debug as you are working with abstract operations that will eventually be applied
//! rather than directly with the parsers.
@@ -90,7 +90,7 @@
//! Probably the biggest thing that `winnow` loses out on is optimizations from ["parse modes" via
//! GATs](https://github.com/zesterer/chumsky/pull/82) which allows downstream parsers to tell
//! upstream parsers when information will be discarded, allowing bypassing expensive operations,
-//! like allocations. This requires a lot more complex interaction with parsers that isn't as
+//! like allocations. This requires a lot more complex interaction with parsers that isn't as
//! trivial to do with bare functions which would lose out on any of that side-band information.
//! Instead, we work around this with things like the [`Accumulate`] trait.
diff --git a/vendor/winnow/src/_tutorial/chapter_0.rs b/vendor/winnow/src/_tutorial/chapter_0.rs
index 47c196e86..35a2d1476 100644
--- a/vendor/winnow/src/_tutorial/chapter_0.rs
+++ b/vendor/winnow/src/_tutorial/chapter_0.rs
@@ -10,7 +10,7 @@
//! ## About
//!
//! `winnow` is a parser-combinator library. In other words, it gives you tools to define:
-//! - "parsers", or functions that takes an input and gives back an output
+//! - "parsers", or functions that take an input and give back an output
//! - "combinators", or functions that take parsers and _combine_ them together!
//!
//! While "combinator" might be an unfamiliar word, you are likely using them in your rust code
diff --git a/vendor/winnow/src/_tutorial/chapter_1.rs b/vendor/winnow/src/_tutorial/chapter_1.rs
index b16a16657..2d94418a9 100644
--- a/vendor/winnow/src/_tutorial/chapter_1.rs
+++ b/vendor/winnow/src/_tutorial/chapter_1.rs
@@ -10,17 +10,17 @@
//! - `Err` indicates the parser could not find what it was looking for.
//!
//! Parsers do more than just return a binary "success"/"failure" code.
-//! On success, the parser will return the processed data. The input will be left pointing to
+//! On success, the parser will return the processed data. The input will be left pointing to
//! data that still needs processing
//!
//! If the parser failed, then there are multiple errors that could be returned.
//! For simplicity, however, in the next chapters we will leave these unexplored.
//!
//! ```text
-//! ┌─► Ok(what matched the parser)
-//! ┌─────────┐ │
-//! my input───►│my parser├──►either──┤
-//! └─────────┘ └─► Err(...)
+//! ┌─► Ok(what matched the parser)
+//! ┌─────────┐ │
+//! my input───►│my parser├──►either──┤
+//! └─────────┘ └─► Err(...)
//! ```
//!
//!
@@ -53,7 +53,7 @@
//!
//! This parser function should take in a `&str`:
//!
-//! - Since it is supposed to succeed, we know it will return the Ok Variant.
+//! - Since it is supposed to succeed, we know it will return the `Ok` variant.
//! - Since it does nothing to our input, the remaining input is the same as the input.
//! - Since it doesn't parse anything, it also should just return an empty string.
//!
diff --git a/vendor/winnow/src/_tutorial/chapter_2.rs b/vendor/winnow/src/_tutorial/chapter_2.rs
index 0fb80ac37..c27b7196e 100644
--- a/vendor/winnow/src/_tutorial/chapter_2.rs
+++ b/vendor/winnow/src/_tutorial/chapter_2.rs
@@ -4,7 +4,7 @@
//!
//! ## Tokens
//!
-//! [`Stream`] provides some core operations to help with parsing. For example, to process a
+//! [`Stream`] provides some core operations to help with parsing. For example, to process a
//! single token, you can do:
//! ```rust
//! # use winnow::Parser;
@@ -135,13 +135,13 @@
//! # }
//! ```
//!
-//! In `winnow`, we call this type of parser a [`tag`]. See [`token`] for additional individual
+//! In `winnow`, we call this type of parser a [`tag`]. See [`token`] for additional individual
//! and token-slice parsers.
//!
//! ## Character Classes
//!
-//! Selecting a single `char` or a [`tag`] is fairly limited. Sometimes, you will want to select one of several
-//! `chars` of a specific class, like digits. For this, we use the [`one_of`] parer:
+//! Selecting a single `char` or a [`tag`] is fairly limited. Sometimes, you will want to select one of several
+//! `chars` of a specific class, like digits. For this, we use the [`one_of`] parser:
//!
//! ```rust
//! # use winnow::Parser;
@@ -207,7 +207,7 @@
//! }
//! ```
//!
-//! We could simplify this further with by using one of the built-in character classes, [`hex_digit1`]:
+//! We could simplify this further by using one of the built-in character classes, [`hex_digit1`]:
//! ```rust
//! # use winnow::Parser;
//! # use winnow::PResult;
diff --git a/vendor/winnow/src/_tutorial/chapter_3.rs b/vendor/winnow/src/_tutorial/chapter_3.rs
index 4dfdc31e4..e3f86b501 100644
--- a/vendor/winnow/src/_tutorial/chapter_3.rs
+++ b/vendor/winnow/src/_tutorial/chapter_3.rs
@@ -179,7 +179,7 @@
//! ```
//!
//! > **Warning:** the above example is for illustrative purposes and relying on `Result::Ok` or
-//! > `Result::Err` can lead to incorrect behavior. This will be clarified in later when covering
+//! > `Result::Err` can lead to incorrect behavior. This will be clarified in later when covering
//! > [error handling][`chapter_6`#errmode]
//!
//! [`opt`] is a basic building block for correctly handling retrying parsing:
@@ -296,8 +296,8 @@
//! > **Note:** [`success`] and [`fail`] are parsers that might be useful in the `else` case.
//!
//! 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::combinator::dispatch] macro:
+//! branches of your parser that have unique prefixes. In this case, you can use the
+//! [`dispatch`] macro:
//!
//! ```rust
//! # use winnow::prelude::*;
diff --git a/vendor/winnow/src/_tutorial/chapter_4.rs b/vendor/winnow/src/_tutorial/chapter_4.rs
index 59aa7ee87..328a64843 100644
--- a/vendor/winnow/src/_tutorial/chapter_4.rs
+++ b/vendor/winnow/src/_tutorial/chapter_4.rs
@@ -10,9 +10,6 @@
//! All we need to do for our parser to return a different type is to change
//! the type parameter of [`PResult`] to the desired return type.
//! For example, to return a `usize`, return a `PResult<usize>`.
-//! Recall that the type parameter of the `PResult` is the input
-//! type, so even if you're returning something different, if your input
-//! is a `&str`, the type argument of `PResult` should be also.
//!
//! One winnow-native way of doing a type conversion is to use the
//! [`Parser::parse_to`] combinator
diff --git a/vendor/winnow/src/_tutorial/chapter_5.rs b/vendor/winnow/src/_tutorial/chapter_5.rs
index ffd8a29ce..8aa719b98 100644
--- a/vendor/winnow/src/_tutorial/chapter_5.rs
+++ b/vendor/winnow/src/_tutorial/chapter_5.rs
@@ -136,18 +136,18 @@
//! # }
//! ```
//!
-//! You'll notice that the above allows trailing `,` when we intended to not support that. We can
-//! easily fix this by using [`separated0`]:
+//! You'll notice that the above allows trailing `,` when we intended to not support that. We can
+//! easily fix this by using [`separated`]:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::token::take_while;
//! # use winnow::combinator::dispatch;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
-//! use winnow::combinator::separated0;
+//! use winnow::combinator::separated;
//!
//! fn parse_list(input: &mut &str) -> PResult<Vec<usize>> {
-//! separated0(parse_digits, ",").parse_next(input)
+//! separated(0.., parse_digits, ",").parse_next(input)
//! }
//!
//! // ...
@@ -200,7 +200,7 @@
//! ```
//!
//! 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
+//! [`Accumulate`] to gather the results. This lets 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::prelude::*;
@@ -208,14 +208,14 @@
//! # use winnow::combinator::dispatch;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
-//! # use winnow::combinator::separated0;
+//! # use winnow::combinator::separated;
//! #
//! fn recognize_list<'s>(input: &mut &'s str) -> PResult<&'s str> {
//! parse_list.recognize().parse_next(input)
//! }
//!
//! fn parse_list(input: &mut &str) -> PResult<()> {
-//! separated0(parse_digits, ",").parse_next(input)
+//! separated(0.., parse_digits, ",").parse_next(input)
//! }
//!
//! # fn parse_digits(input: &mut &str) -> PResult<usize> {
@@ -272,7 +272,7 @@ use super::chapter_2;
use super::chapter_3;
use crate::combinator;
use crate::combinator::repeat;
-use crate::combinator::separated0;
+use crate::combinator::separated;
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 9f4230942..0d54e1505 100644
--- a/vendor/winnow/src/_tutorial/chapter_6.rs
+++ b/vendor/winnow/src/_tutorial/chapter_6.rs
@@ -72,13 +72,13 @@
//! ```rust
//! # use winnow::error::ErrorKind;
//! # use winnow::error::ErrMode;
-//! pub type OResult<O, E = ErrorKind> = Result<O, ErrMode<E>>;
+//! pub type PResult<O, E = ErrorKind> = Result<O, ErrMode<E>>;
//! ```
//! [`PResult`] is just a fancy wrapper around `Result` that wraps our error in an [`ErrMode`]
//! type.
//!
//! [`ErrMode`] is an enum with [`Backtrack`] and [`Cut`] variants (ignore [`Incomplete`] as its only
-//! relevant for [streaming][_topic::stream]). By default, errors are [`Backtrack`], meaning that
+//! relevant for [streaming][_topic::stream]). By default, errors are [`Backtrack`], meaning that
//! other parsing branches will be attempted on failure, like the next case of an [`alt`]. [`Cut`]
//! shortcircuits all other branches, immediately reporting the error.
//!
diff --git a/vendor/winnow/src/_tutorial/mod.rs b/vendor/winnow/src/_tutorial/mod.rs
index 224fe6a80..2a4bd61f7 100644
--- a/vendor/winnow/src/_tutorial/mod.rs
+++ b/vendor/winnow/src/_tutorial/mod.rs
@@ -1,6 +1,7 @@
//! # Tutorial
//!
//! Table of Contents
+#![allow(clippy::std_instead_of_core)]
pub mod chapter_0;
pub mod chapter_1;
diff --git a/vendor/winnow/src/ascii/mod.rs b/vendor/winnow/src/ascii/mod.rs
index 8b3119fbf..6221efc2d 100644
--- a/vendor/winnow/src/ascii/mod.rs
+++ b/vendor/winnow/src/ascii/mod.rs
@@ -15,12 +15,41 @@ use crate::error::{ErrMode, ErrorKind, Needed};
use crate::stream::{AsBStr, AsChar, ParseSlice, Stream, StreamIsPartial};
use crate::stream::{Compare, CompareResult};
use crate::token::one_of;
-use crate::token::take_till0;
+use crate::token::take_till;
use crate::token::take_while;
use crate::trace::trace;
use crate::PResult;
use crate::Parser;
+/// Mark a value as case-insensitive for ASCII characters
+///
+/// # Example
+/// ```rust
+/// # use winnow::prelude::*;
+/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}};
+/// # use winnow::ascii::Caseless;
+///
+/// fn parser<'s>(s: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
+/// Caseless("hello").parse_next(s)
+/// }
+///
+/// assert_eq!(parser.parse_peek("Hello, World!"), Ok((", World!", "Hello")));
+/// assert_eq!(parser.parse_peek("hello, World!"), Ok((", World!", "hello")));
+/// assert_eq!(parser.parse_peek("HeLlo, World!"), Ok((", World!", "HeLlo")));
+/// assert_eq!(parser.parse_peek("Some"), Err(ErrMode::Backtrack(InputError::new("Some", ErrorKind::Tag))));
+/// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag))));
+/// ```
+#[derive(Copy, Clone, Debug)]
+pub struct Caseless<T>(pub T);
+
+impl Caseless<&str> {
+ /// Get the byte-representation of this case-insensitive value
+ #[inline(always)]
+ pub fn as_bytes(&self) -> Caseless<&[u8]> {
+ Caseless(self.0.as_bytes())
+ }
+}
+
/// Recognizes the string `"\r\n"`.
///
/// *Complete version*: Will return an error if there's not enough input data.
@@ -123,7 +152,7 @@ where
I: Compare<&'static str>,
<I as Stream>::Token: AsChar + Clone,
{
- let res = take_till0(('\r', '\n')).parse_next(input)?;
+ let res = take_till(0.., ('\r', '\n')).parse_next(input)?;
if input.compare("\r") == CompareResult::Ok {
let comp = input.compare("\r\n");
match comp {
@@ -423,7 +452,7 @@ where
///
/// ## Parsing an integer
///
-/// You can use `digit1` in combination with [`Parser::try_map`][crate::Parser::try_map] to parse an integer:
+/// You can use `digit1` in combination with [`Parser::try_map`] to parse an integer:
///
/// ```
/// # use winnow::prelude::*;
@@ -965,6 +994,7 @@ impl Uint for u128 {
}
}
+/// Deprecated since v0.15.17
impl Uint for i8 {
fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option<Self> {
self.checked_mul(by as Self)
@@ -974,6 +1004,7 @@ impl Uint for i8 {
}
}
+/// Deprecated since v0.15.17
impl Uint for i16 {
fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option<Self> {
self.checked_mul(by as Self)
@@ -983,6 +1014,7 @@ impl Uint for i16 {
}
}
+/// Deprecated since v0.15.17
impl Uint for i32 {
fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option<Self> {
self.checked_mul(by as Self)
@@ -992,6 +1024,7 @@ impl Uint for i32 {
}
}
+/// Deprecated since v0.15.17
impl Uint for i64 {
fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option<Self> {
self.checked_mul(by as Self)
@@ -1001,6 +1034,7 @@ impl Uint for i64 {
}
}
+/// Deprecated since v0.15.17
impl Uint for i128 {
fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option<Self> {
self.checked_mul(by as Self)
@@ -1318,6 +1352,7 @@ where
}
#[allow(clippy::trait_duplication_in_bounds)] // HACK: clippy 1.64.0 bug
+#[allow(deprecated)]
fn recognize_float_or_exceptions<I, E: ParserError<I>>(
input: &mut I,
) -> PResult<<I as Stream>::Slice, E>
diff --git a/vendor/winnow/src/binary/bits/mod.rs b/vendor/winnow/src/binary/bits/mod.rs
index b11ba43c7..16a0f6464 100644
--- a/vendor/winnow/src/binary/bits/mod.rs
+++ b/vendor/winnow/src/binary/bits/mod.rs
@@ -157,7 +157,7 @@ where
/// }
///
/// fn parser(input: (Stream<'_>, usize), count: usize)-> IResult<(Stream<'_>, usize), u8> {
-/// take(count).parse_peek(input)
+/// take(count).parse_peek(input)
/// }
///
/// // Consumes 0 bits, returns 0
diff --git a/vendor/winnow/src/combinator/core.rs b/vendor/winnow/src/combinator/core.rs
index d784b4e9e..2a92d64b7 100644
--- a/vendor/winnow/src/combinator/core.rs
+++ b/vendor/winnow/src/combinator/core.rs
@@ -331,7 +331,7 @@ where
/// 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`].
+/// On [`ErrMode::Backtrack`], iteration will stop. To instead chain an error up, see [`cut_err`].
///
/// # Example
///
diff --git a/vendor/winnow/src/combinator/mod.rs b/vendor/winnow/src/combinator/mod.rs
index ec68e48e2..542b156a2 100644
--- a/vendor/winnow/src/combinator/mod.rs
+++ b/vendor/winnow/src/combinator/mod.rs
@@ -6,72 +6,71 @@
//!
//! Those are used to recognize the lowest level elements of your grammar, like, "here is a dot", or "here is an big endian integer".
//!
-//! | combinator | usage | input | output | comment |
-//! |---|---|---|---|---|
-//! | [`one_of`][crate::token::one_of] | `one_of(['a', 'b', 'c'])` | `"abc"` | `Ok(("bc", 'a'))` |Matches one of the provided characters (works with non ASCII characters too)|
-//! | [`none_of`][crate::token::none_of] | `none_of(['a', 'b', 'c'])` | `"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|
+//! | combinator | usage | input | new input | output | comment |
+//! |---|---|---|---|---|---|
+//! | [`one_of`][crate::token::one_of] | `one_of(['a', 'b', 'c'])` | `"abc"` | `"bc"` | `Ok('a')` |Matches one of the provided characters (works with non ASCII characters too)|
+//! | [`none_of`][crate::token::none_of] | `none_of(['a', 'b', 'c'])` | `"xyab"` | `"yab"` | `Ok('x')` |Matches anything but the provided characters|
+//! | [`tag`][crate::token::tag] | `"hello"` | `"hello world"` | `" world"` | `Ok("hello")` |Recognizes a specific suite of characters or bytes (see also [`Caseless`][crate::ascii::Caseless])|
+//! | [`take`][crate::token::take] | `take(4)` | `"hello"` | `"o"` | `Ok("hell")` |Takes a specific number of bytes or characters|
+//! | [`take_while`][crate::token::take_while] | `take_while(0.., is_alphabetic)` | `"abc123"` | `"123"` | `Ok("abc")` |Returns the longest list of bytes for which the provided pattern matches.|
+//! | [`take_till0`][crate::token::take_till0] | `take_till0(is_alphabetic)` | `"123abc"` | `"abc"` | `Ok("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"` | `"world"` | `Ok("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::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|
+//! | combinator | usage | input | new input | output | comment |
+//! |---|---|---|---|---|---|
+//! | [`alt`] | `alt(("ab", "cd"))` | `"cdef"` | `"ef"` | `Ok("cd")` |Try a list of parsers and return the result of the first successful one|
+//! | [`dispatch`] | \- | \- | \- | \- | `match` for parsers |
+//! | [`permutation`] | `permutation(("ab", "cd", "12"))` | `"cd12abc"` | `"c"` | `Ok(("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`] | `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")))` ||
+//! | combinator | usage | input | new 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`] | `delimited(char('('), take(2), char(')'))` | `"(ab)cd"` | `"cd"` | `Ok("ab")` ||
+//! | [`preceded`] | `preceded("ab", "XY")` | `"abXYZ"` | `"Z"` | `Ok("XY")` ||
+//! | [`terminated`] | `terminated("ab", "XY")` | `"abXYZ"` | `"Z"` | `Ok("ab")` ||
+//! | [`separated_pair`] | `separated_pair("hello", char(','), "world")` | `"hello,world!"` | `"!"` | `Ok(("hello", "world"))` ||
//!
//! ## Applying a parser multiple times
//!
-//! | combinator | usage | input | output | comment |
-//! |---|---|---|---|---|
-//! | [`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|
+//! | combinator | usage | input | new input | output | comment |
+//! |---|---|---|---|---|---|
+//! | [`repeat`] | `repeat(1..=3, "ab")` | `"ababc"` | `"c"` | `Ok(vec!["ab", "ab"])` |Applies the parser between m and n times (n included) and returns the list of results in a Vec|
+//! | [`repeat_till0`] | `repeat_till0(tag( "ab" ), tag( "ef" ))` | `"ababefg"` | `"g"` | `Ok((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|
+//! | [`separated`] | `separated(1..=3, "ab", ",")` | `"ab,ab,ab."` | `"."` | `Ok(vec!["ab", "ab", "ab"])` |Applies the parser and separator between m and n times (n included) and returns the list of results in a Vec|
+//! | [`fold_repeat`] | `fold_repeat(1..=2, be_u8, \|\| 0, \|acc, item\| acc + item)` | `[1, 2, 3]` | `[3]` | `Ok(3)` |Applies the parser between m and n times (n included) and folds the list of return value|
//!
//! ## Partial related
//!
-//! - [`eof`][eof]: Returns its input if it is at the end of input data
+//! - [`eof`]: Returns its input if it is at the end of input data
//! - [`Parser::complete_err`]: Replaces an `Incomplete` returned by the child parser with an `Backtrack`
//!
//! ## Modifiers
//!
-//! - [`cond`][cond]: Conditional combinator. Wraps another parser and calls it if the condition is met
-//! - [`Parser::flat_map`][crate::Parser::flat_map]: method to map a new parser from the output of the first parser, then apply that parser over the rest of the input
-//! - [`Parser::value`][crate::Parser::value]: method to replace the result of a parser
-//! - [`Parser::map`][crate::Parser::map]: method to map a function on the result of a parser
-//! - [`Parser::and_then`][crate::Parser::and_then]: Applies a second parser over the output of the first one
-//! - [`Parser::verify_map`][Parser::verify_map]: Maps a function returning an `Option` on the output of a parser
-//! - [`Parser::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
-//! - [`peek`][peek]: Returns a result without consuming the input
-//! - [`Parser::recognize`][Parser::recognize]: If the child parser was successful, return the consumed input as the produced value
-//! - [`Parser::with_recognized`][Parser::with_recognized]: If the child parser was successful, return a tuple of the consumed input and the produced output.
-//! - [`Parser::span`][Parser::span]: If the child parser was successful, return the location of the consumed input as the produced value
-//! - [`Parser::with_span`][Parser::with_span]: If the child parser was successful, return a tuple of the location of the consumed input and the produced output.
+//! - [`cond`]: Conditional combinator. Wraps another parser and calls it if the condition is met
+//! - [`Parser::flat_map`]: method to map a new parser from the output of the first parser, then apply that parser over the rest of the input
+//! - [`Parser::value`]: method to replace the result of a parser
+//! - [`Parser::map`]: method to map a function on the result of a parser
+//! - [`Parser::and_then`]: Applies a second parser over the output of the first one
+//! - [`Parser::verify_map`]: Maps a function returning an `Option` on the output of a parser
+//! - [`Parser::try_map`]: Maps a function returning a `Result` on the output of a parser
+//! - [`Parser::parse_to`]: Apply [`std::str::FromStr`] to the output of the parser
+//! - [`not`]: Returns a result only if the embedded parser returns `Backtrack` or `Incomplete`. Does not consume the input
+//! - [`opt`]: Make the underlying parser optional
+//! - [`peek`]: Returns a result without consuming the input
+//! - [`Parser::recognize`]: If the child parser was successful, return the consumed input as the produced value
+//! - [`Parser::with_recognized`]: If the child parser was successful, return a tuple of the consumed input and the produced output.
+//! - [`Parser::span`]: If the child parser was successful, return the location of the consumed input as the produced value
+//! - [`Parser::with_span`]: If the child parser was successful, return a tuple of the location of the consumed input and the produced output.
//! - [`Parser::verify`]: Returns the result of the child parser if it satisfies a verification function
//!
//! ## Error management and debugging
//!
//! - [`cut_err`]: Commit the parse result, disallowing alternative parsers from being attempted
-//! - [`backtrack_err`]: Attemmpts a parse, allowing alternative parsers to be attempted despite
+//! - [`backtrack_err`]: Attempts a parse, allowing alternative parsers to be attempted despite
//! use of `cut_err`
//! - [`Parser::context`]: Add context to the error if the parser fails
//! - [`trace`][crate::trace::trace]: Print the parse state with the `debug` feature flag
@@ -79,8 +78,8 @@
//!
//! ## Remaining combinators
//!
-//! - [`success`][success]: Returns a value without consuming any input, always succeeds
-//! - [`fail`][fail]: Inversion of `success`. Always fails.
+//! - [`success`]: Returns a value without consuming any input, always succeeds
+//! - [`fail`]: Inversion of `success`. Always fails.
//! - [`Parser::by_ref`]: Allow moving `&mut impl Parser` into other parsers
//!
//! ## Text parsing
@@ -91,7 +90,7 @@
//! - [`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
+//! - [`rest`]: Return the remaining input
//!
//! - [`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
diff --git a/vendor/winnow/src/combinator/multi.rs b/vendor/winnow/src/combinator/multi.rs
index 1fdb7535b..d06362878 100644
--- a/vendor/winnow/src/combinator/multi.rs
+++ b/vendor/winnow/src/combinator/multi.rs
@@ -12,7 +12,7 @@ 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
+/// This stops before `n` when the parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
/// [`cut_err`][crate::combinator::cut_err].
///
/// # Arguments
@@ -28,7 +28,7 @@ use crate::Parser;
///
/// # Example
///
-/// Zero or more reptitions:
+/// Zero or more repetitions:
/// ```rust
/// # #[cfg(feature = "std")] {
/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed};
@@ -47,7 +47,7 @@ use crate::Parser;
/// # }
/// ```
///
-/// One or more reptitions:
+/// One or more repetitions:
/// ```rust
/// # #[cfg(feature = "std")] {
/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
@@ -66,7 +66,7 @@ use crate::Parser;
/// # }
/// ```
///
-/// Fixed number of repeitions:
+/// Fixed number of repetitions:
/// ```rust
/// # #[cfg(feature = "std")] {
/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
@@ -86,7 +86,7 @@ use crate::Parser;
/// # }
/// ```
///
-/// Arbitrary reptitions:
+/// Arbitrary repetitions:
/// ```rust
/// # #[cfg(feature = "std")] {
/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed};
@@ -201,6 +201,73 @@ where
}
}
+fn repeat_n_<I, O, C, E, F>(count: usize, f: &mut F, i: &mut I) -> PResult<C, E>
+where
+ I: Stream,
+ C: Accumulate<O>,
+ F: Parser<I, O, E>,
+ E: ParserError<I>,
+{
+ let mut res = C::initial(Some(count));
+
+ for _ in 0..count {
+ match f.parse_next(i) {
+ Ok(o) => {
+ res.accumulate(o);
+ }
+ Err(e) => {
+ return Err(e.append(i, ErrorKind::Many));
+ }
+ }
+ }
+
+ Ok(res)
+}
+
+fn repeat_m_n_<I, O, C, E, F>(min: usize, max: usize, parse: &mut F, input: &mut I) -> PResult<C, E>
+where
+ I: Stream,
+ C: Accumulate<O>,
+ F: Parser<I, O, E>,
+ E: ParserError<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 start = input.checkpoint();
+ let len = input.eof_offset();
+ match parse.parse_next(input) {
+ Ok(value) => {
+ // infinite loop check: the parser must always consume
+ if input.eof_offset() == len {
+ return Err(ErrMode::assert(
+ input,
+ "`repeat` parsers must always consume",
+ ));
+ }
+
+ res.accumulate(value);
+ }
+ Err(ErrMode::Backtrack(e)) => {
+ if count < min {
+ return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many)));
+ } else {
+ input.reset(start);
+ return Ok(res);
+ }
+ }
+ Err(e) => {
+ return Err(e);
+ }
+ }
+ }
+
+ Ok(res)
+}
+
/// [`Accumulate`] the output of parser `f` into a container, like `Vec`, until the parser `g`
/// produces a result.
///
@@ -269,9 +336,144 @@ where
})
}
-/// [`Accumulate`] the output of a parser, interleaed with `sep`
+/// [`Accumulate`] the output of a parser, interleaved with `sep`
///
-/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
+/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
+/// [`cut_err`][crate::combinator::cut_err].
+///
+/// # Arguments
+/// * `range` The minimum and maximum number of iterations.
+/// * `parser` The parser that parses the elements of the list.
+/// * `sep` The parser that parses the separator between list elements.
+///
+/// **Warning:** If the separator parser accepts empty inputs
+/// (like `alpha0` or `digit0`), `separated` will return an error,
+/// to prevent going into an infinite loop.
+///
+/// # Example
+///
+/// Zero or more repetitions:
+/// ```rust
+/// # #[cfg(feature = "std")] {
+/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed};
+/// # use winnow::prelude::*;
+/// use winnow::combinator::separated;
+/// use winnow::token::tag;
+///
+/// fn parser(s: &str) -> IResult<&str, Vec<&str>> {
+/// separated(0.., "abc", "|").parse_peek(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![])));
+/// # }
+/// ```
+///
+/// One or more repetitions:
+/// ```rust
+/// # #[cfg(feature = "std")] {
+/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
+/// # use winnow::prelude::*;
+/// use winnow::combinator::separated;
+/// use winnow::token::tag;
+///
+/// fn parser(s: &str) -> IResult<&str, Vec<&str>> {
+/// separated(1.., "abc", "|").parse_peek(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(InputError::new("", ErrorKind::Tag))));
+/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(InputError::new("def|abc", ErrorKind::Tag))));
+/// # }
+/// ```
+///
+/// Fixed number of repetitions:
+/// ```rust
+/// # #[cfg(feature = "std")] {
+/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
+/// # use winnow::prelude::*;
+/// use winnow::combinator::separated;
+/// use winnow::token::tag;
+///
+/// fn parser(s: &str) -> IResult<&str, Vec<&str>> {
+/// separated(2, "abc", "|").parse_peek(s)
+/// }
+///
+/// assert_eq!(parser("abc|abc|abc"), Ok(("|abc", vec!["abc", "abc"])));
+/// assert_eq!(parser("abc123abc"), Err(ErrMode::Backtrack(InputError::new("123abc", ErrorKind::Tag))));
+/// assert_eq!(parser("abc|def"), Err(ErrMode::Backtrack(InputError::new("def", ErrorKind::Tag))));
+/// assert_eq!(parser(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag))));
+/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(InputError::new("def|abc", ErrorKind::Tag))));
+/// # }
+/// ```
+///
+/// Arbitrary repetitions:
+/// ```rust
+/// # #[cfg(feature = "std")] {
+/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
+/// # use winnow::prelude::*;
+/// use winnow::combinator::separated;
+/// use winnow::token::tag;
+///
+/// fn parser(s: &str) -> IResult<&str, Vec<&str>> {
+/// separated(0..=2, "abc", "|").parse_peek(s)
+/// }
+///
+/// assert_eq!(parser("abc|abc|abc"), Ok(("|abc", vec!["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 = "sep_by1")]
+#[doc(alias = "separated_list0")]
+#[doc(alias = "separated_list1")]
+#[doc(alias = "separated_m_n")]
+#[inline(always)]
+pub fn separated<I, O, C, O2, E, P, S>(
+ range: impl Into<Range>,
+ mut parser: P,
+ mut separator: S,
+) -> impl Parser<I, C, E>
+where
+ I: Stream,
+ C: Accumulate<O>,
+ P: Parser<I, O, E>,
+ S: Parser<I, O2, E>,
+ E: ParserError<I>,
+{
+ let Range {
+ start_inclusive,
+ end_inclusive,
+ } = range.into();
+ trace("separated", move |input: &mut I| {
+ match (start_inclusive, end_inclusive) {
+ (0, None) => separated0_(&mut parser, &mut separator, input),
+ (1, None) => separated1_(&mut parser, &mut separator, input),
+ (start, end) if Some(start) == end => {
+ separated_n_(start, &mut parser, &mut separator, input)
+ }
+ (start, end) => separated_m_n_(
+ start,
+ end.unwrap_or(usize::MAX),
+ &mut parser,
+ &mut separator,
+ input,
+ ),
+ }
+ })
+}
+
+/// [`Accumulate`] the output of a parser, interleaved with `sep`
+///
+/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
/// [`cut_err`][crate::combinator::cut_err].
///
/// # Arguments
@@ -300,6 +502,7 @@ where
/// ```
#[doc(alias = "sep_by")]
#[doc(alias = "separated_list0")]
+#[deprecated(since = "0.5.19", note = "Replaced with `combinator::separated`")]
pub fn separated0<I, O, C, O2, E, P, S>(mut parser: P, mut sep: S) -> impl Parser<I, C, E>
where
I: Stream,
@@ -309,56 +512,74 @@ where
E: ParserError<I>,
{
trace("separated0", move |i: &mut I| {
- let mut res = C::initial(None);
+ separated0_(&mut parser, &mut sep, i)
+ })
+}
- let start = i.checkpoint();
- match parser.parse_next(i) {
+fn separated0_<I, O, C, O2, E, P, S>(
+ parser: &mut P,
+ separator: &mut S,
+ input: &mut I,
+) -> PResult<C, E>
+where
+ I: Stream,
+ C: Accumulate<O>,
+ P: Parser<I, O, E>,
+ S: Parser<I, O2, E>,
+ E: ParserError<I>,
+{
+ let mut acc = C::initial(None);
+
+ let start = input.checkpoint();
+ match parser.parse_next(input) {
+ Err(ErrMode::Backtrack(_)) => {
+ input.reset(start);
+ return Ok(acc);
+ }
+ Err(e) => return Err(e),
+ Ok(o) => {
+ acc.accumulate(o);
+ }
+ }
+
+ loop {
+ let start = input.checkpoint();
+ let len = input.eof_offset();
+ match separator.parse_next(input) {
Err(ErrMode::Backtrack(_)) => {
- i.reset(start);
- return Ok(res);
+ input.reset(start);
+ return Ok(acc);
}
Err(e) => return Err(e),
- Ok(o) => {
- res.accumulate(o);
- }
- }
-
- loop {
- let start = i.checkpoint();
- let len = i.eof_offset();
- match sep.parse_next(i) {
- Err(ErrMode::Backtrack(_)) => {
- i.reset(start);
- return Ok(res);
+ Ok(_) => {
+ // infinite loop check
+ if input.eof_offset() == len {
+ return Err(ErrMode::assert(
+ input,
+ "`separated` separator parser must always consume",
+ ));
}
- Err(e) => return Err(e),
- Ok(_) => {
- // infinite loop check: the parser must always consume
- if i.eof_offset() == len {
- return Err(ErrMode::assert(i, "sep parsers must always consume"));
- }
- match parser.parse_next(i) {
- Err(ErrMode::Backtrack(_)) => {
- i.reset(start);
- return Ok(res);
- }
- Err(e) => return Err(e),
- Ok(o) => {
- res.accumulate(o);
- }
+ match parser.parse_next(input) {
+ Err(ErrMode::Backtrack(_)) => {
+ input.reset(start);
+ return Ok(acc);
+ }
+ Err(e) => return Err(e),
+ Ok(o) => {
+ acc.accumulate(o);
}
}
}
}
- })
+ }
}
-/// [`Accumulate`] the output of a parser, interleaed with `sep`
+/// [`Accumulate`] the output of a parser, interleaved 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
+/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
/// [`cut_err`][crate::combinator::cut_err].
///
/// # Arguments
@@ -387,6 +608,7 @@ where
/// ```
#[doc(alias = "sep_by1")]
#[doc(alias = "separated_list1")]
+#[deprecated(since = "0.5.19", note = "Replaced with `combinator::separated`")]
pub fn separated1<I, O, C, O2, E, P, S>(mut parser: P, mut sep: S) -> impl Parser<I, C, E>
where
I: Stream,
@@ -396,50 +618,209 @@ where
E: ParserError<I>,
{
trace("separated1", move |i: &mut I| {
- let mut res = C::initial(None);
+ separated1_(&mut parser, &mut sep, i)
+ })
+}
+
+fn separated1_<I, O, C, O2, E, P, S>(
+ parser: &mut P,
+ separator: &mut S,
+ input: &mut I,
+) -> PResult<C, E>
+where
+ I: Stream,
+ C: Accumulate<O>,
+ P: Parser<I, O, E>,
+ S: Parser<I, O2, E>,
+ E: ParserError<I>,
+{
+ let mut acc = C::initial(None);
+
+ // Parse the first element
+ match parser.parse_next(input) {
+ Err(e) => return Err(e),
+ Ok(o) => {
+ acc.accumulate(o);
+ }
+ }
- // Parse the first element
- match parser.parse_next(i) {
+ loop {
+ let start = input.checkpoint();
+ let len = input.eof_offset();
+ match separator.parse_next(input) {
+ Err(ErrMode::Backtrack(_)) => {
+ input.reset(start);
+ return Ok(acc);
+ }
Err(e) => return Err(e),
- Ok(o) => {
- res.accumulate(o);
+ Ok(_) => {
+ // infinite loop check
+ if input.eof_offset() == len {
+ return Err(ErrMode::assert(
+ input,
+ "`separated` separator parser must always consume",
+ ));
+ }
+
+ match parser.parse_next(input) {
+ Err(ErrMode::Backtrack(_)) => {
+ input.reset(start);
+ return Ok(acc);
+ }
+ Err(e) => return Err(e),
+ Ok(o) => {
+ acc.accumulate(o);
+ }
+ }
}
}
+ }
+}
- loop {
- let start = i.checkpoint();
- let len = i.eof_offset();
- match sep.parse_next(i) {
- Err(ErrMode::Backtrack(_)) => {
- i.reset(start);
- return Ok(res);
+fn separated_n_<I, O, C, O2, E, P, S>(
+ count: usize,
+ parser: &mut P,
+ separator: &mut S,
+ input: &mut I,
+) -> PResult<C, E>
+where
+ I: Stream,
+ C: Accumulate<O>,
+ P: Parser<I, O, E>,
+ S: Parser<I, O2, E>,
+ E: ParserError<I>,
+{
+ let mut acc = C::initial(Some(count));
+
+ if count == 0 {
+ return Ok(acc);
+ }
+
+ match parser.parse_next(input) {
+ Err(e) => {
+ return Err(e.append(input, ErrorKind::Many));
+ }
+ Ok(o) => {
+ acc.accumulate(o);
+ }
+ }
+
+ for _ in 1..count {
+ let len = input.eof_offset();
+ match separator.parse_next(input) {
+ Err(e) => {
+ return Err(e.append(input, ErrorKind::Many));
+ }
+ Ok(_) => {
+ // infinite loop check
+ if input.eof_offset() == len {
+ return Err(ErrMode::assert(
+ input,
+ "`separated` separator parser must always consume",
+ ));
}
- Err(e) => return Err(e),
- Ok(_) => {
- // infinite loop check: the parser must always consume
- if i.eof_offset() == len {
- return Err(ErrMode::assert(i, "sep parsers must always consume"));
+
+ match parser.parse_next(input) {
+ Err(e) => {
+ return Err(e.append(input, ErrorKind::Many));
+ }
+ Ok(o) => {
+ acc.accumulate(o);
}
+ }
+ }
+ }
+ }
- match parser.parse_next(i) {
- Err(ErrMode::Backtrack(_)) => {
- i.reset(start);
- return Ok(res);
- }
- Err(e) => return Err(e),
- Ok(o) => {
- res.accumulate(o);
+ Ok(acc)
+}
+
+fn separated_m_n_<I, O, C, O2, E, P, S>(
+ min: usize,
+ max: usize,
+ parser: &mut P,
+ separator: &mut S,
+ input: &mut I,
+) -> PResult<C, E>
+where
+ I: Stream,
+ C: Accumulate<O>,
+ P: Parser<I, O, E>,
+ S: Parser<I, O2, E>,
+ E: ParserError<I>,
+{
+ if min > max {
+ return Err(ErrMode::Cut(E::from_error_kind(input, ErrorKind::Many)));
+ }
+
+ let mut acc = C::initial(Some(min));
+
+ let start = input.checkpoint();
+ match parser.parse_next(input) {
+ Err(ErrMode::Backtrack(e)) => {
+ if min == 0 {
+ input.reset(start);
+ return Ok(acc);
+ } else {
+ return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many)));
+ }
+ }
+ Err(e) => return Err(e),
+ Ok(o) => {
+ acc.accumulate(o);
+ }
+ }
+
+ for index in 1..max {
+ let start = input.checkpoint();
+ let len = input.eof_offset();
+ match separator.parse_next(input) {
+ Err(ErrMode::Backtrack(e)) => {
+ if index < min {
+ return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many)));
+ } else {
+ input.reset(start);
+ return Ok(acc);
+ }
+ }
+ Err(e) => {
+ return Err(e);
+ }
+ Ok(_) => {
+ // infinite loop check
+ if input.eof_offset() == len {
+ return Err(ErrMode::assert(
+ input,
+ "`separated` separator parser must always consume",
+ ));
+ }
+
+ match parser.parse_next(input) {
+ Err(ErrMode::Backtrack(e)) => {
+ if index < min {
+ return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many)));
+ } else {
+ input.reset(start);
+ return Ok(acc);
}
}
+ Err(e) => {
+ return Err(e);
+ }
+ Ok(o) => {
+ acc.accumulate(o);
+ }
}
}
}
- })
+ }
+
+ Ok(acc)
}
/// Alternates between two parsers, merging the results (left associative)
///
-/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
+/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
/// [`cut_err`][crate::combinator::cut_err].
///
/// # Example
@@ -506,7 +887,7 @@ where
/// Alternates between two parsers, merging the results (right associative)
///
-/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
+/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
/// [`cut_err`][crate::combinator::cut_err].
///
/// # Example
@@ -556,73 +937,6 @@ where
})
}
-fn repeat_m_n_<I, O, C, E, F>(min: usize, max: usize, parse: &mut F, input: &mut I) -> PResult<C, E>
-where
- I: Stream,
- C: Accumulate<O>,
- F: Parser<I, O, E>,
- E: ParserError<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 start = input.checkpoint();
- let len = input.eof_offset();
- match parse.parse_next(input) {
- Ok(value) => {
- // infinite loop check: the parser must always consume
- if input.eof_offset() == len {
- return Err(ErrMode::assert(
- input,
- "`repeat` parsers must always consume",
- ));
- }
-
- res.accumulate(value);
- }
- Err(ErrMode::Backtrack(e)) => {
- if count < min {
- return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many)));
- } else {
- input.reset(start);
- return Ok(res);
- }
- }
- Err(e) => {
- return Err(e);
- }
- }
- }
-
- Ok(res)
-}
-
-fn repeat_n_<I, O, C, E, F>(count: usize, f: &mut F, i: &mut I) -> PResult<C, E>
-where
- I: Stream,
- C: Accumulate<O>,
- F: Parser<I, O, E>,
- E: ParserError<I>,
-{
- let mut res = C::initial(Some(count));
-
- for _ in 0..count {
- match f.parse_next(i) {
- Ok(o) => {
- res.accumulate(o);
- }
- Err(e) => {
- return Err(e.append(i, ErrorKind::Many));
- }
- }
- }
-
- Ok(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.
@@ -675,7 +989,7 @@ where
/// 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
+/// This stops before `n` when the parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
/// [`cut_err`][crate::combinator::cut_err].
///
/// # Arguments
diff --git a/vendor/winnow/src/combinator/parser.rs b/vendor/winnow/src/combinator/parser.rs
index fb11adc15..c95f1f6f3 100644
--- a/vendor/winnow/src/combinator/parser.rs
+++ b/vendor/winnow/src/combinator/parser.rs
@@ -7,7 +7,7 @@ use crate::trace::trace;
use crate::trace::trace_result;
use crate::*;
-/// Implementation of [`Parser::by_ref`][Parser::by_ref]
+/// Implementation of [`Parser::by_ref`]
#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
pub struct ByRef<'p, P> {
p: &'p mut P,
diff --git a/vendor/winnow/src/combinator/tests.rs b/vendor/winnow/src/combinator/tests.rs
index 9d2b49d80..27fa53456 100644
--- a/vendor/winnow/src/combinator/tests.rs
+++ b/vendor/winnow/src/combinator/tests.rs
@@ -717,13 +717,13 @@ fn permutation_test() {
#[cfg(feature = "alloc")]
fn separated0_test() {
fn multi(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> {
- separated0("abcd", ",").parse_peek(i)
+ separated(0.., "abcd", ",").parse_peek(i)
}
fn multi_empty(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> {
- separated0("", ",").parse_peek(i)
+ separated(0.., "", ",").parse_peek(i)
}
fn multi_longsep(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> {
- separated0("abcd", "..").parse_peek(i)
+ separated(0.., "abcd", "..").parse_peek(i)
}
let a = &b"abcdef"[..];
@@ -773,7 +773,7 @@ fn separated0_test() {
#[cfg_attr(debug_assertions, should_panic)]
fn separated0_empty_sep_test() {
fn empty_sep(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> {
- separated0("abc", "").parse_peek(i)
+ separated(0.., "abc", "").parse_peek(i)
}
let i = &b"abcabc"[..];
@@ -792,10 +792,10 @@ fn separated0_empty_sep_test() {
#[cfg(feature = "alloc")]
fn separated1_test() {
fn multi(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> {
- separated1("abcd", ",").parse_peek(i)
+ separated(1.., "abcd", ",").parse_peek(i)
}
fn multi_longsep(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> {
- separated1("abcd", "..").parse_peek(i)
+ separated(1.., "abcd", "..").parse_peek(i)
}
let a = &b"abcdef"[..];
@@ -840,6 +840,47 @@ fn separated1_test() {
#[test]
#[cfg(feature = "alloc")]
+fn separated_test() {
+ fn multi(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> {
+ separated(2..=4, "abcd", ",").parse_peek(i)
+ }
+
+ let a = &b"abcd,ef"[..];
+ let b = &b"abcd,abcd,efgh"[..];
+ let c = &b"abcd,abcd,abcd,abcd,efgh"[..];
+ let d = &b"abcd,abcd,abcd,abcd,abcd,efgh"[..];
+ let e = &b"abcd,ab"[..];
+
+ 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",abcd,efgh"[..]), res3))
+ );
+ assert_eq!(
+ multi(Partial::new(e)),
+ Err(ErrMode::Incomplete(Needed::new(2)))
+ );
+}
+
+#[test]
+#[cfg(feature = "alloc")]
fn repeat0_test() {
fn multi(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> {
repeat(0.., "abcd").parse_peek(i)
diff --git a/vendor/winnow/src/error.rs b/vendor/winnow/src/error.rs
index 449bebc55..fd7d94695 100644
--- a/vendor/winnow/src/error.rs
+++ b/vendor/winnow/src/error.rs
@@ -4,12 +4,12 @@
//! - Accumulate more [context][Parser::context] as the error goes up the parser chain
//! - Distinguish between [recoverable errors,
//! unrecoverable errors, and more data is needed][ErrMode]
-//! - Have a very low overhead, as errors are often discarded by the calling parser (examples: `many0`, `alt`)
+//! - Have a very low overhead, as errors are often discarded by the calling parser (examples: `repeat`, `alt`)
//! - Can be modified according to the user's needs, because some languages need a lot more information
//! - Help thread-through the [stream][crate::stream]
//!
//! To abstract these needs away from the user, generally `winnow` parsers use the [`PResult`]
-//! alias, rather than [`Result`][std::result::Result]. [`Parser::parse`] is a top-level operation
+//! alias, rather than [`Result`]. [`Parser::parse`] is a top-level operation
//! that can help convert to a `Result` for integrating with your application's error reporting.
//!
//! Error types include:
@@ -30,26 +30,29 @@ use crate::stream::Stream;
#[allow(unused_imports)] // Here for intra-doc links
use crate::Parser;
-/// Holds the result of [`Parser`]
+/// For use with [`Parser::parse_peek`] which allows the input stream to be threaded through a
+/// parser.
///
/// - `Ok((I, O))` is the remaining [input][crate::stream] and the parsed value
/// - [`Err(ErrMode<E>)`][ErrMode] is the error along with how to respond to it
///
/// By default, the error type (`E`) is [`InputError`]
///
-/// [`Parser::parse`] is a top-level operation that can help convert to a `Result` for integrating
-/// with your application's error reporting.
+/// When integrating into the result of the application, see
+/// - [`Parser::parse`]
+/// - [`ErrMode::into_inner`]
pub type IResult<I, O, E = InputError<I>> = PResult<(I, O), E>;
-/// Holds the result of [`Parser`]
+/// For use with [`Parser::parse_next`]
///
/// - `Ok(O)` is the parsed value
/// - [`Err(ErrMode<E>)`][ErrMode] is the error along with how to respond to it
///
-/// By default, the error type (`E`) is [`ErrorKind`].
+/// By default, the error type (`E`) is [`ContextError`].
///
-/// [`Parser::parse`] is a top-level operation that can help convert to a `Result` for integrating
-/// with your application's error reporting.
+/// When integrating into the result of the application, see
+/// - [`Parser::parse`]
+/// - [`ErrMode::into_inner`]
pub type PResult<O, E = ContextError> = Result<O, ErrMode<E>>;
/// Contains information on needed data if a parser returned `Incomplete`
@@ -97,7 +100,7 @@ pub enum ErrMode<E> {
///
/// More data needs to be buffered before retrying the parse.
///
- /// This must only be set when the [`Stream`][crate::stream::Stream] is [partial][`crate::stream::StreamIsPartial`], like with
+ /// This must only be set when the [`Stream`] is [partial][`crate::stream::StreamIsPartial`], like with
/// [`Partial`][crate::Partial]
///
/// Convert this into an `Backtrack` with [`Parser::complete_err`]
@@ -106,7 +109,7 @@ pub enum ErrMode<E> {
///
/// For example, a parser for json values might include a
/// [`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.
+ /// combinator. If it fails, the next case should be tried.
Backtrack(E),
/// The parser had an unrecoverable error.
///
@@ -877,7 +880,7 @@ where
#[cfg(feature = "std")]
impl<I, C> TreeError<I, C>
where
- I: Clone + std::fmt::Display,
+ I: Clone + crate::lib::std::fmt::Display,
C: fmt::Display,
{
fn write(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result {
@@ -1179,6 +1182,9 @@ impl<I, E> ParseError<I, E> {
}
/// The location in [`ParseError::input`] where parsing failed
+ ///
+ /// **Note:** This is an offset, not an index, and may point to the end of input
+ /// (`input.len()`) on eof errors.
#[inline]
pub fn offset(&self) -> usize {
self.offset
@@ -1219,21 +1225,21 @@ where
writeln!(f, "parse error at line {}, column {}", line_num, col_num)?;
// |
- for _ in 0..=gutter {
+ for _ in 0..gutter {
write!(f, " ")?;
}
- writeln!(f, "|")?;
+ writeln!(f, " |")?;
// 1 | 00:32:00.a999999
write!(f, "{} | ", line_num)?;
writeln!(f, "{}", String::from_utf8_lossy(content))?;
// | ^
- for _ in 0..=gutter {
+ for _ in 0..gutter {
write!(f, " ")?;
}
- write!(f, "|")?;
- for _ in 0..=col_idx {
+ write!(f, " | ")?;
+ for _ in 0..col_idx {
write!(f, " ")?;
}
// The span will be empty at eof, so we need to make sure we always print at least
@@ -1246,7 +1252,7 @@ where
} else {
let content = input;
writeln!(f, "{}", String::from_utf8_lossy(content))?;
- for _ in 0..=span_start {
+ for _ in 0..span_start {
write!(f, " ")?;
}
// The span will be empty at eof, so we need to make sure we always print at least
@@ -1284,10 +1290,9 @@ fn translate_position(input: &[u8], index: usize) -> (usize, usize) {
None => 0,
};
let line = input[0..line_start].iter().filter(|b| **b == b'\n').count();
- let line = line;
// HACK: This treats byte offset and column offsets the same
- let column = std::str::from_utf8(&input[line_start..=index])
+ let column = crate::lib::std::str::from_utf8(&input[line_start..=index])
.map(|s| s.chars().count() - 1)
.unwrap_or_else(|_| index - line_start);
let column = column + column_offset;
@@ -1297,6 +1302,27 @@ fn translate_position(input: &[u8], index: usize) -> (usize, usize) {
#[cfg(test)]
#[cfg(feature = "std")]
+mod test_parse_error {
+ use super::*;
+
+ #[test]
+ fn single_line() {
+ let mut input = "0xZ123";
+ let start = input.checkpoint();
+ let _ = input.next_token().unwrap();
+ let _ = input.next_token().unwrap();
+ let inner = InputError::new(input, ErrorKind::Slice);
+ let error = ParseError::new(input, start, inner);
+ let expected = "\
+0xZ123
+ ^
+slice error starting at: Z123";
+ assert_eq!(error.to_string(), expected);
+ }
+}
+
+#[cfg(test)]
+#[cfg(feature = "std")]
mod test_translate_position {
use super::*;
diff --git a/vendor/winnow/src/lib.rs b/vendor/winnow/src/lib.rs
index 5614b7f11..4a21b9e11 100644
--- a/vendor/winnow/src/lib.rs
+++ b/vendor/winnow/src/lib.rs
@@ -49,6 +49,7 @@
#![cfg_attr(docsrs, feature(extended_key_value_attributes))]
#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs)]
+#![warn(clippy::std_instead_of_core)]
// 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: <https://github.com/EmbarkStudios/rust-ecosystem/issues/59>
@@ -175,6 +176,7 @@ pub(crate) mod lib {
#[cfg(feature = "std")]
/// internal std exports for `no_std` compatibility
pub mod std {
+ #![allow(clippy::std_instead_of_core)]
#[doc(hidden)]
pub use std::{
alloc, borrow, boxed, cmp, collections, convert, fmt, hash, iter, mem, ops, option,
diff --git a/vendor/winnow/src/parser.rs b/vendor/winnow/src/parser.rs
index b59e4cd83..8a1040dc9 100644
--- a/vendor/winnow/src/parser.rs
+++ b/vendor/winnow/src/parser.rs
@@ -1,5 +1,6 @@
//! Basic types to build the parsers
+use crate::ascii::Caseless as AsciiCaseless;
use crate::combinator::*;
use crate::error::{AddContext, FromExternalError, IResult, PResult, ParseError, ParserError};
use crate::stream::{AsChar, Compare, Location, ParseSlice, Stream, StreamIsPartial};
@@ -91,7 +92,7 @@ pub trait Parser<I, O, E> {
///
/// # Example
///
- /// Because parsers are `FnMut`, they can be called multiple times. This prevents moving `f`
+ /// Because parsers are `FnMut`, they can be called multiple times. This prevents moving `f`
/// into [`length_data`][crate::binary::length_data] and `g` into
/// [`Parser::complete_err`]:
/// ```rust,compile_fail
@@ -194,11 +195,11 @@ pub trait Parser<I, O, E> {
/// use winnow::ascii::alpha1;
/// # fn main() {
///
- /// fn parser1<'s>(i: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
- /// alpha1(i)
- /// }
+ /// fn parser1<'s>(i: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
+ /// alpha1(i)
+ /// }
///
- /// let mut parser2 = parser1.output_into();
+ /// let mut parser2 = parser1.output_into();
///
/// // the parser converts the &str output of the child parser into a Vec<u8>
/// let bytes: IResult<&str, Vec<u8>> = parser2.parse_peek("abcd");
@@ -742,6 +743,38 @@ where
/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
/// # use winnow::combinator::alt;
/// # use winnow::token::take;
+/// use winnow::ascii::Caseless;
+///
+/// fn parser<'s>(s: &mut &'s [u8]) -> PResult<&'s [u8], InputError<&'s [u8]>> {
+/// alt((Caseless(&"hello"[..]), take(5usize))).parse_next(s)
+/// }
+///
+/// assert_eq!(parser.parse_peek(&b"Hello, World!"[..]), Ok((&b", World!"[..], &b"Hello"[..])));
+/// assert_eq!(parser.parse_peek(&b"hello, World!"[..]), Ok((&b", World!"[..], &b"hello"[..])));
+/// assert_eq!(parser.parse_peek(&b"HeLlo, World!"[..]), Ok((&b", World!"[..], &b"HeLlo"[..])));
+/// assert_eq!(parser.parse_peek(&b"Something"[..]), Ok((&b"hing"[..], &b"Somet"[..])));
+/// assert_eq!(parser.parse_peek(&b"Some"[..]), Err(ErrMode::Backtrack(InputError::new(&b"Some"[..], ErrorKind::Slice))));
+/// assert_eq!(parser.parse_peek(&b""[..]), Err(ErrMode::Backtrack(InputError::new(&b""[..], ErrorKind::Slice))));
+/// ```
+impl<'s, I, E: ParserError<I>> Parser<I, <I as Stream>::Slice, E> for AsciiCaseless<&'s [u8]>
+where
+ I: Compare<AsciiCaseless<&'s [u8]>> + StreamIsPartial,
+ I: Stream,
+{
+ #[inline(always)]
+ fn parse_next(&mut self, i: &mut I) -> PResult<<I as Stream>::Slice, E> {
+ crate::token::tag(*self).parse_next(i)
+ }
+}
+
+/// This is a shortcut for [`tag`][crate::token::tag].
+///
+/// # Example
+/// ```rust
+/// # use winnow::prelude::*;
+/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
+/// # use winnow::combinator::alt;
+/// # use winnow::token::take;
///
/// fn parser<'s>(s: &mut &'s [u8]) -> PResult<&'s [u8], InputError<&'s [u8]>> {
/// alt((b"Hello", take(5usize))).parse_next(s)
@@ -768,6 +801,39 @@ where
/// # Example
/// ```rust
/// # use winnow::prelude::*;
+/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
+/// # use winnow::combinator::alt;
+/// # use winnow::token::take;
+/// use winnow::ascii::Caseless;
+///
+/// fn parser<'s>(s: &mut &'s [u8]) -> PResult<&'s [u8], InputError<&'s [u8]>> {
+/// alt((Caseless(b"hello"), take(5usize))).parse_next(s)
+/// }
+///
+/// assert_eq!(parser.parse_peek(&b"Hello, World!"[..]), Ok((&b", World!"[..], &b"Hello"[..])));
+/// assert_eq!(parser.parse_peek(&b"hello, World!"[..]), Ok((&b", World!"[..], &b"hello"[..])));
+/// assert_eq!(parser.parse_peek(&b"HeLlo, World!"[..]), Ok((&b", World!"[..], &b"HeLlo"[..])));
+/// assert_eq!(parser.parse_peek(&b"Something"[..]), Ok((&b"hing"[..], &b"Somet"[..])));
+/// assert_eq!(parser.parse_peek(&b"Some"[..]), Err(ErrMode::Backtrack(InputError::new(&b"Some"[..], ErrorKind::Slice))));
+/// assert_eq!(parser.parse_peek(&b""[..]), Err(ErrMode::Backtrack(InputError::new(&b""[..], ErrorKind::Slice))));
+/// ```
+impl<'s, I, E: ParserError<I>, const N: usize> Parser<I, <I as Stream>::Slice, E>
+ for AsciiCaseless<&'s [u8; N]>
+where
+ I: Compare<AsciiCaseless<&'s [u8; N]>> + StreamIsPartial,
+ I: Stream,
+{
+ #[inline(always)]
+ fn parse_next(&mut self, i: &mut I) -> PResult<<I as Stream>::Slice, E> {
+ crate::token::tag(*self).parse_next(i)
+ }
+}
+
+/// This is a shortcut for [`tag`][crate::token::tag].
+///
+/// # Example
+/// ```rust
+/// # use winnow::prelude::*;
/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}};
/// # use winnow::combinator::alt;
/// # use winnow::token::take;
@@ -792,6 +858,38 @@ where
}
}
+/// This is a shortcut for [`tag`][crate::token::tag].
+///
+/// # Example
+/// ```rust
+/// # use winnow::prelude::*;
+/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}};
+/// # use winnow::combinator::alt;
+/// # use winnow::token::take;
+/// # use winnow::ascii::Caseless;
+///
+/// fn parser<'s>(s: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> {
+/// alt((Caseless("hello"), take(5usize))).parse_next(s)
+/// }
+///
+/// assert_eq!(parser.parse_peek("Hello, World!"), Ok((", World!", "Hello")));
+/// assert_eq!(parser.parse_peek("hello, World!"), Ok((", World!", "hello")));
+/// assert_eq!(parser.parse_peek("HeLlo, World!"), Ok((", World!", "HeLlo")));
+/// assert_eq!(parser.parse_peek("Something"), Ok(("hing", "Somet")));
+/// assert_eq!(parser.parse_peek("Some"), Err(ErrMode::Backtrack(InputError::new("Some", ErrorKind::Slice))));
+/// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Slice))));
+/// ```
+impl<'s, I, E: ParserError<I>> Parser<I, <I as Stream>::Slice, E> for AsciiCaseless<&'s str>
+where
+ I: Compare<AsciiCaseless<&'s str>> + StreamIsPartial,
+ I: Stream,
+{
+ #[inline(always)]
+ fn parse_next(&mut self, i: &mut I) -> PResult<<I as Stream>::Slice, E> {
+ crate::token::tag(*self).parse_next(i)
+ }
+}
+
impl<I, E: ParserError<I>> Parser<I, (), E> for () {
#[inline(always)]
fn parse_next(&mut self, _i: &mut I) -> PResult<(), E> {
diff --git a/vendor/winnow/src/stream/impls.rs b/vendor/winnow/src/stream/impls.rs
index b277dd9a9..d76e1bf35 100644
--- a/vendor/winnow/src/stream/impls.rs
+++ b/vendor/winnow/src/stream/impls.rs
@@ -238,14 +238,14 @@ mod bytes {
impl PartialOrd for Bytes {
#[inline]
fn partial_cmp(&self, other: &Bytes) -> Option<Ordering> {
- PartialOrd::partial_cmp(self.as_bytes(), other.as_bytes())
+ Some(self.cmp(other))
}
}
impl Ord for Bytes {
#[inline]
fn cmp(&self, other: &Bytes) -> Ordering {
- self.partial_cmp(other).unwrap()
+ Ord::cmp(self.as_bytes(), other.as_bytes())
}
}
@@ -485,14 +485,14 @@ mod bstr {
impl PartialOrd for BStr {
#[inline]
fn partial_cmp(&self, other: &BStr) -> Option<Ordering> {
- PartialOrd::partial_cmp(self.as_bytes(), other.as_bytes())
+ Some(self.cmp(other))
}
}
impl Ord for BStr {
#[inline]
fn cmp(&self, other: &BStr) -> Ordering {
- self.partial_cmp(other).unwrap()
+ Ord::cmp(self.as_bytes(), other.as_bytes())
}
}
diff --git a/vendor/winnow/src/stream/mod.rs b/vendor/winnow/src/stream/mod.rs
index 5f2152e27..d0af80f3e 100644
--- a/vendor/winnow/src/stream/mod.rs
+++ b/vendor/winnow/src/stream/mod.rs
@@ -9,8 +9,10 @@
//! - [`Partial`] can mark an input as partial buffer that is being streamed into
//! - [Custom stream types][crate::_topic::stream]
+use core::hash::BuildHasher;
use core::num::NonZeroUsize;
+use crate::ascii::Caseless as AsciiCaseless;
use crate::error::Needed;
use crate::lib::std::iter::{Cloned, Enumerate};
use crate::lib::std::slice::Iter;
@@ -24,8 +26,12 @@ use crate::error::ErrMode;
#[cfg(feature = "alloc")]
use crate::lib::std::collections::BTreeMap;
+#[cfg(feature = "alloc")]
+use crate::lib::std::collections::BTreeSet;
#[cfg(feature = "std")]
use crate::lib::std::collections::HashMap;
+#[cfg(feature = "std")]
+use crate::lib::std::collections::HashSet;
#[cfg(feature = "alloc")]
use crate::lib::std::string::String;
#[cfg(feature = "alloc")]
@@ -88,6 +94,15 @@ impl BStr {
/// Allow collecting the span of a parsed token
///
+/// Spans are tracked as a [`Range<usize>`] of byte offsets.
+///
+/// Converting byte offsets to line or column numbers is left up to the user, as computing column
+/// numbers requires domain knowledge (are columns byte-based, codepoint-based, or grapheme-based?)
+/// and O(n) iteration over the input to determine codepoint and line boundaries.
+///
+/// [The `line-span` crate](https://docs.rs/line-span/latest/line_span/) can help with converting
+/// byte offsets to line numbers.
+///
/// See [`Parser::span`][crate::Parser::span] and [`Parser::with_span`][crate::Parser::with_span] for more details
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Located<I> {
@@ -202,7 +217,7 @@ impl<I: crate::lib::std::fmt::Display, S> crate::lib::std::fmt::Display for Stat
/// Mark the input as a partial buffer for streaming input.
///
-/// Complete input means that we already have all of the data. This will be the common case with
+/// Complete input means that we already have all of the data. This will be the common case with
/// small files that can be read entirely to memory.
///
/// In contrast, streaming input assumes that we might not have all of the data.
@@ -322,6 +337,13 @@ pub trait SliceLen {
fn slice_len(&self) -> usize;
}
+impl<S: SliceLen> SliceLen for AsciiCaseless<S> {
+ #[inline(always)]
+ fn slice_len(&self) -> usize {
+ self.0.slice_len()
+ }
+}
+
impl<'a, T> SliceLen for &'a [T] {
#[inline]
fn slice_len(&self) -> usize {
@@ -423,7 +445,8 @@ pub trait Stream: Offset<<Self as Stream>::Checkpoint> + crate::lib::std::fmt::D
/// Iterate with the offset from the current location
fn iter_offsets(&self) -> Self::IterOffsets;
- /// Returns the offaet to the end of the input
+
+ /// Returns the offset to the end of the input
fn eof_offset(&self) -> usize;
/// Split off the next token from the input
@@ -450,7 +473,7 @@ pub trait Stream: Offset<<Self as Stream>::Checkpoint> + crate::lib::std::fmt::D
/// Split off a slice of tokens from the input
///
/// **NOTE:** For inputs with variable width tokens, like `&str`'s `char`, `offset` might not correspond
- /// with the number of tokens. To get a valid offset, use:
+ /// with the number of tokens. To get a valid offset, use:
/// - [`Stream::eof_offset`]
/// - [`Stream::iter_offsets`]
/// - [`Stream::offset_for`]
@@ -1276,7 +1299,10 @@ where
/// Useful functions to calculate the offset between slices and show a hexdump of a slice
pub trait Offset<Start = Self> {
- /// Offset between the first byte of `start` and the first byte of `self`
+ /// Offset between the first byte of `start` and the first byte of `self`a
+ ///
+ /// **Note:** This is an offset, not an index, and may point to the end of input
+ /// (`start.len()`) when `self` is exhausted.
fn offset_from(&self, start: &Start) -> usize;
}
@@ -1288,9 +1314,9 @@ impl<'a, T> Offset for &'a [T] {
debug_assert!(
fst <= snd,
- "`Offset::offset_to` only accepts slices of `self`"
+ "`Offset::offset_from({snd:?}, {fst:?})` only accepts slices of `self`"
);
- snd as usize - fst as usize
+ (snd as usize - fst as usize) / crate::lib::std::mem::size_of::<T>()
}
}
@@ -1567,47 +1593,50 @@ pub trait Compare<T> {
/// by lowercasing both strings and comparing
/// the result. This is a temporary solution until
/// a better one appears
+ #[deprecated(since = "0.5.20", note = "Replaced with `compare(ascii::Caseless(_))`")]
fn compare_no_case(&self, t: T) -> CompareResult;
}
-fn lowercase_byte(c: u8) -> u8 {
- match c {
- b'A'..=b'Z' => c - b'A' + b'a',
- _ => c,
- }
-}
-
impl<'a, 'b> Compare<&'b [u8]> for &'a [u8] {
#[inline]
fn compare(&self, t: &'b [u8]) -> CompareResult {
- let pos = self.iter().zip(t.iter()).position(|(a, b)| a != b);
-
- match pos {
- Some(_) => CompareResult::Error,
- None => {
- if self.len() >= t.len() {
- CompareResult::Ok
- } else {
- CompareResult::Incomplete
- }
- }
+ if t.iter().zip(*self).any(|(a, b)| a != b) {
+ CompareResult::Error
+ } else if self.len() < t.slice_len() {
+ CompareResult::Incomplete
+ } else {
+ CompareResult::Ok
}
}
- #[inline]
+ #[inline(always)]
+ #[allow(deprecated)]
fn compare_no_case(&self, t: &'b [u8]) -> CompareResult {
- if self
+ self.compare(AsciiCaseless(t))
+ }
+}
+
+impl<'a, 'b> Compare<AsciiCaseless<&'b [u8]>> for &'a [u8] {
+ #[inline]
+ fn compare(&self, t: AsciiCaseless<&'b [u8]>) -> CompareResult {
+ if t.0
.iter()
- .zip(t)
- .any(|(a, b)| lowercase_byte(*a) != lowercase_byte(*b))
+ .zip(*self)
+ .any(|(a, b)| !a.eq_ignore_ascii_case(b))
{
CompareResult::Error
- } else if self.len() < t.len() {
+ } else if self.len() < t.slice_len() {
CompareResult::Incomplete
} else {
CompareResult::Ok
}
}
+
+ #[inline(always)]
+ #[allow(deprecated)]
+ fn compare_no_case(&self, t: AsciiCaseless<&'b [u8]>) -> CompareResult {
+ self.compare(t)
+ }
}
impl<'a, const LEN: usize> Compare<[u8; LEN]> for &'a [u8] {
@@ -1617,11 +1646,25 @@ impl<'a, const LEN: usize> Compare<[u8; LEN]> for &'a [u8] {
}
#[inline(always)]
+ #[allow(deprecated)]
fn compare_no_case(&self, t: [u8; LEN]) -> CompareResult {
self.compare_no_case(&t[..])
}
}
+impl<'a, const LEN: usize> Compare<AsciiCaseless<[u8; LEN]>> for &'a [u8] {
+ #[inline(always)]
+ fn compare(&self, t: AsciiCaseless<[u8; LEN]>) -> CompareResult {
+ self.compare(AsciiCaseless(&t.0[..]))
+ }
+
+ #[inline(always)]
+ #[allow(deprecated)]
+ fn compare_no_case(&self, t: AsciiCaseless<[u8; LEN]>) -> CompareResult {
+ self.compare_no_case(AsciiCaseless(&t.0[..]))
+ }
+}
+
impl<'a, 'b, const LEN: usize> Compare<&'b [u8; LEN]> for &'a [u8] {
#[inline(always)]
fn compare(&self, t: &'b [u8; LEN]) -> CompareResult {
@@ -1629,46 +1672,72 @@ impl<'a, 'b, const LEN: usize> Compare<&'b [u8; LEN]> for &'a [u8] {
}
#[inline(always)]
+ #[allow(deprecated)]
fn compare_no_case(&self, t: &'b [u8; LEN]) -> CompareResult {
self.compare_no_case(&t[..])
}
}
+impl<'a, 'b, const LEN: usize> Compare<AsciiCaseless<&'b [u8; LEN]>> for &'a [u8] {
+ #[inline(always)]
+ fn compare(&self, t: AsciiCaseless<&'b [u8; LEN]>) -> CompareResult {
+ self.compare(AsciiCaseless(&t.0[..]))
+ }
+
+ #[inline(always)]
+ #[allow(deprecated)]
+ fn compare_no_case(&self, t: AsciiCaseless<&'b [u8; LEN]>) -> CompareResult {
+ self.compare_no_case(AsciiCaseless(&t.0[..]))
+ }
+}
+
impl<'a, 'b> Compare<&'b str> for &'a [u8] {
#[inline(always)]
fn compare(&self, t: &'b str) -> CompareResult {
self.compare(t.as_bytes())
}
#[inline(always)]
+ #[allow(deprecated)]
fn compare_no_case(&self, t: &'b str) -> CompareResult {
self.compare_no_case(t.as_bytes())
}
}
+impl<'a, 'b> Compare<AsciiCaseless<&'b str>> for &'a [u8] {
+ #[inline(always)]
+ fn compare(&self, t: AsciiCaseless<&'b str>) -> CompareResult {
+ self.compare(AsciiCaseless(t.0.as_bytes()))
+ }
+ #[inline(always)]
+ #[allow(deprecated)]
+ fn compare_no_case(&self, t: AsciiCaseless<&'b str>) -> CompareResult {
+ self.compare_no_case(AsciiCaseless(t.0.as_bytes()))
+ }
+}
+
impl<'a, 'b> Compare<&'b str> for &'a str {
#[inline(always)]
fn compare(&self, t: &'b str) -> CompareResult {
self.as_bytes().compare(t.as_bytes())
}
- //FIXME: this version is too simple and does not use the current locale
#[inline]
+ #[allow(deprecated)]
fn compare_no_case(&self, t: &'b str) -> CompareResult {
- let pos = self
- .chars()
- .zip(t.chars())
- .position(|(a, b)| a.to_lowercase().ne(b.to_lowercase()));
+ self.compare(AsciiCaseless(t))
+ }
+}
- match pos {
- Some(_) => CompareResult::Error,
- None => {
- if self.len() >= t.len() {
- CompareResult::Ok
- } else {
- CompareResult::Incomplete
- }
- }
- }
+impl<'a, 'b> Compare<AsciiCaseless<&'b str>> for &'a str {
+ #[inline(always)]
+ fn compare(&self, t: AsciiCaseless<&'b str>) -> CompareResult {
+ self.as_bytes().compare(t.as_bytes())
+ }
+
+ #[inline(always)]
+ #[allow(deprecated)]
+ fn compare_no_case(&self, t: AsciiCaseless<&'b str>) -> CompareResult {
+ self.compare(t)
}
}
@@ -1678,11 +1747,24 @@ impl<'a, 'b> Compare<&'b [u8]> for &'a str {
AsBStr::as_bstr(self).compare(t)
}
#[inline(always)]
+ #[allow(deprecated)]
fn compare_no_case(&self, t: &'b [u8]) -> CompareResult {
AsBStr::as_bstr(self).compare_no_case(t)
}
}
+impl<'a, 'b> Compare<AsciiCaseless<&'b [u8]>> for &'a str {
+ #[inline(always)]
+ fn compare(&self, t: AsciiCaseless<&'b [u8]>) -> CompareResult {
+ AsBStr::as_bstr(self).compare(t)
+ }
+ #[inline(always)]
+ #[allow(deprecated)]
+ fn compare_no_case(&self, t: AsciiCaseless<&'b [u8]>) -> CompareResult {
+ AsBStr::as_bstr(self).compare_no_case(t)
+ }
+}
+
impl<'a, T> Compare<T> for &'a Bytes
where
&'a [u8]: Compare<T>,
@@ -1694,6 +1776,7 @@ where
}
#[inline(always)]
+ #[allow(deprecated)]
fn compare_no_case(&self, t: T) -> CompareResult {
let bytes = (*self).as_bytes();
bytes.compare_no_case(t)
@@ -1711,6 +1794,7 @@ where
}
#[inline(always)]
+ #[allow(deprecated)]
fn compare_no_case(&self, t: T) -> CompareResult {
let bytes = (*self).as_bytes();
bytes.compare_no_case(t)
@@ -1727,6 +1811,7 @@ where
}
#[inline(always)]
+ #[allow(deprecated)]
fn compare_no_case(&self, other: U) -> CompareResult {
self.input.compare_no_case(other)
}
@@ -1742,6 +1827,7 @@ where
}
#[inline(always)]
+ #[allow(deprecated)]
fn compare_no_case(&self, other: U) -> CompareResult {
self.input.compare_no_case(other)
}
@@ -1757,6 +1843,7 @@ where
}
#[inline(always)]
+ #[allow(deprecated)]
fn compare_no_case(&self, t: T) -> CompareResult {
self.input.compare_no_case(t)
}
@@ -1775,6 +1862,27 @@ impl<'i, 's> FindSlice<&'s [u8]> for &'i [u8] {
}
}
+impl<'i, 's> FindSlice<(&'s [u8],)> for &'i [u8] {
+ #[inline(always)]
+ fn find_slice(&self, substr: (&'s [u8],)) -> Option<usize> {
+ memmem(self, substr.0)
+ }
+}
+
+impl<'i, 's> FindSlice<(&'s [u8], &'s [u8])> for &'i [u8] {
+ #[inline(always)]
+ fn find_slice(&self, substr: (&'s [u8], &'s [u8])) -> Option<usize> {
+ memmem2(self, substr)
+ }
+}
+
+impl<'i, 's> FindSlice<(&'s [u8], &'s [u8], &'s [u8])> for &'i [u8] {
+ #[inline(always)]
+ fn find_slice(&self, substr: (&'s [u8], &'s [u8], &'s [u8])) -> Option<usize> {
+ memmem3(self, substr)
+ }
+}
+
impl<'i> FindSlice<u8> for &'i [u8] {
#[inline(always)]
fn find_slice(&self, substr: u8) -> Option<usize> {
@@ -1782,6 +1890,27 @@ impl<'i> FindSlice<u8> for &'i [u8] {
}
}
+impl<'i> FindSlice<(u8,)> for &'i [u8] {
+ #[inline(always)]
+ fn find_slice(&self, substr: (u8,)) -> Option<usize> {
+ memchr(substr.0, self)
+ }
+}
+
+impl<'i> FindSlice<(u8, u8)> for &'i [u8] {
+ #[inline(always)]
+ fn find_slice(&self, substr: (u8, u8)) -> Option<usize> {
+ memchr2(substr, self)
+ }
+}
+
+impl<'i> FindSlice<(u8, u8, u8)> for &'i [u8] {
+ #[inline(always)]
+ fn find_slice(&self, substr: (u8, u8, u8)) -> Option<usize> {
+ memchr3(substr, self)
+ }
+}
+
impl<'i, 's> FindSlice<&'s str> for &'i [u8] {
#[inline(always)]
fn find_slice(&self, substr: &'s str) -> Option<usize> {
@@ -1789,17 +1918,129 @@ impl<'i, 's> FindSlice<&'s str> for &'i [u8] {
}
}
+impl<'i, 's> FindSlice<(&'s str,)> for &'i [u8] {
+ #[inline(always)]
+ fn find_slice(&self, substr: (&'s str,)) -> Option<usize> {
+ memmem(self, substr.0.as_bytes())
+ }
+}
+
+impl<'i, 's> FindSlice<(&'s str, &'s str)> for &'i [u8] {
+ #[inline(always)]
+ fn find_slice(&self, substr: (&'s str, &'s str)) -> Option<usize> {
+ memmem2(self, (substr.0.as_bytes(), substr.1.as_bytes()))
+ }
+}
+
+impl<'i, 's> FindSlice<(&'s str, &'s str, &'s str)> for &'i [u8] {
+ #[inline(always)]
+ fn find_slice(&self, substr: (&'s str, &'s str, &'s str)) -> Option<usize> {
+ memmem3(
+ self,
+ (
+ substr.0.as_bytes(),
+ substr.1.as_bytes(),
+ substr.2.as_bytes(),
+ ),
+ )
+ }
+}
+
impl<'i, 's> FindSlice<&'s str> for &'i str {
#[inline(always)]
fn find_slice(&self, substr: &'s str) -> Option<usize> {
- self.find(substr)
+ self.as_bytes().find_slice(substr.as_bytes())
+ }
+}
+
+impl<'i, 's> FindSlice<(&'s str,)> for &'i str {
+ #[inline(always)]
+ fn find_slice(&self, substr: (&'s str,)) -> Option<usize> {
+ self.as_bytes().find_slice(substr)
+ }
+}
+
+impl<'i, 's> FindSlice<(&'s str, &'s str)> for &'i str {
+ #[inline(always)]
+ fn find_slice(&self, substr: (&'s str, &'s str)) -> Option<usize> {
+ self.as_bytes().find_slice(substr)
+ }
+}
+
+impl<'i, 's> FindSlice<(&'s str, &'s str, &'s str)> for &'i str {
+ #[inline(always)]
+ fn find_slice(&self, substr: (&'s str, &'s str, &'s str)) -> Option<usize> {
+ self.as_bytes().find_slice(substr)
}
}
impl<'i> FindSlice<char> for &'i str {
#[inline(always)]
fn find_slice(&self, substr: char) -> Option<usize> {
- self.find(substr)
+ let mut b = [0; 4];
+ let substr = substr.encode_utf8(&mut b);
+ self.find_slice(&*substr)
+ }
+}
+
+impl<'i> FindSlice<(char,)> for &'i str {
+ #[inline(always)]
+ fn find_slice(&self, substr: (char,)) -> Option<usize> {
+ let mut b = [0; 4];
+ let substr0 = substr.0.encode_utf8(&mut b);
+ self.find_slice((&*substr0,))
+ }
+}
+
+impl<'i> FindSlice<(char, char)> for &'i str {
+ #[inline(always)]
+ fn find_slice(&self, substr: (char, char)) -> Option<usize> {
+ let mut b = [0; 4];
+ let substr0 = substr.0.encode_utf8(&mut b);
+ let mut b = [0; 4];
+ let substr1 = substr.1.encode_utf8(&mut b);
+ self.find_slice((&*substr0, &*substr1))
+ }
+}
+
+impl<'i> FindSlice<(char, char, char)> for &'i str {
+ #[inline(always)]
+ fn find_slice(&self, substr: (char, char, char)) -> Option<usize> {
+ let mut b = [0; 4];
+ let substr0 = substr.0.encode_utf8(&mut b);
+ let mut b = [0; 4];
+ let substr1 = substr.1.encode_utf8(&mut b);
+ let mut b = [0; 4];
+ let substr2 = substr.2.encode_utf8(&mut b);
+ self.find_slice((&*substr0, &*substr1, &*substr2))
+ }
+}
+
+impl<'i> FindSlice<u8> for &'i str {
+ #[inline(always)]
+ fn find_slice(&self, substr: u8) -> Option<usize> {
+ self.find_slice(substr.as_char())
+ }
+}
+
+impl<'i> FindSlice<(u8,)> for &'i str {
+ #[inline(always)]
+ fn find_slice(&self, substr: (u8,)) -> Option<usize> {
+ self.find_slice((substr.0.as_char(),))
+ }
+}
+
+impl<'i> FindSlice<(u8, u8)> for &'i str {
+ #[inline(always)]
+ fn find_slice(&self, substr: (u8, u8)) -> Option<usize> {
+ self.find_slice((substr.0.as_char(), substr.1.as_char()))
+ }
+}
+
+impl<'i> FindSlice<(u8, u8, u8)> for &'i str {
+ #[inline(always)]
+ fn find_slice(&self, substr: (u8, u8, u8)) -> Option<usize> {
+ self.find_slice((substr.0.as_char(), substr.1.as_char(), substr.2.as_char()))
}
}
@@ -1953,7 +2194,7 @@ where
}
}
-/// Ensure checkpoint details are kept privazte
+/// Ensure checkpoint details are kept private
#[derive(Copy, Clone, Debug)]
pub struct Checkpoint<T>(T);
@@ -2177,15 +2418,19 @@ where
}
#[cfg(feature = "std")]
-impl<K, V> Accumulate<(K, V)> for HashMap<K, V>
+impl<K, V, S> Accumulate<(K, V)> for HashMap<K, V, S>
where
K: crate::lib::std::cmp::Eq + crate::lib::std::hash::Hash,
+ S: BuildHasher + Default,
{
#[inline(always)]
fn initial(capacity: Option<usize>) -> Self {
+ let h = S::default();
match capacity {
- Some(capacity) => HashMap::with_capacity(clamp_capacity::<(K, V)>(capacity)),
- None => HashMap::new(),
+ Some(capacity) => {
+ HashMap::with_capacity_and_hasher(clamp_capacity::<(K, V)>(capacity), h)
+ }
+ None => HashMap::with_hasher(h),
}
}
#[inline(always)]
@@ -2195,6 +2440,41 @@ where
}
#[cfg(feature = "alloc")]
+impl<K> Accumulate<K> for BTreeSet<K>
+where
+ K: crate::lib::std::cmp::Ord,
+{
+ #[inline(always)]
+ fn initial(_capacity: Option<usize>) -> Self {
+ BTreeSet::new()
+ }
+ #[inline(always)]
+ fn accumulate(&mut self, key: K) {
+ self.insert(key);
+ }
+}
+
+#[cfg(feature = "std")]
+impl<K, S> Accumulate<K> for HashSet<K, S>
+where
+ K: crate::lib::std::cmp::Eq + crate::lib::std::hash::Hash,
+ S: BuildHasher + Default,
+{
+ #[inline(always)]
+ fn initial(capacity: Option<usize>) -> Self {
+ let h = S::default();
+ match capacity {
+ Some(capacity) => HashSet::with_capacity_and_hasher(clamp_capacity::<K>(capacity), h),
+ None => HashSet::with_hasher(h),
+ }
+ }
+ #[inline(always)]
+ fn accumulate(&mut self, key: K) {
+ self.insert(key);
+ }
+}
+
+#[cfg(feature = "alloc")]
#[inline]
pub(crate) fn clamp_capacity<T>(capacity: usize) -> usize {
/// Don't pre-allocate more than 64KiB when calling `Vec::with_capacity`.
@@ -2520,7 +2800,7 @@ impl<C: AsChar> ContainsToken<C> for char {
}
}
-impl<C: AsChar, F: Fn(C) -> bool> ContainsToken<C> for F {
+impl<C, F: Fn(C) -> bool> ContainsToken<C> for F {
#[inline(always)]
fn contains_token(&self, token: C) -> bool {
self(token)
@@ -2675,51 +2955,158 @@ fn memchr(token: u8, slice: &[u8]) -> Option<usize> {
memchr::memchr(token, slice)
}
+#[cfg(feature = "simd")]
+#[inline(always)]
+fn memchr2(token: (u8, u8), slice: &[u8]) -> Option<usize> {
+ memchr::memchr2(token.0, token.1, slice)
+}
+
+#[cfg(feature = "simd")]
+#[inline(always)]
+fn memchr3(token: (u8, u8, u8), slice: &[u8]) -> Option<usize> {
+ memchr::memchr3(token.0, token.1, token.2, slice)
+}
+
#[cfg(not(feature = "simd"))]
#[inline(always)]
fn memchr(token: u8, slice: &[u8]) -> Option<usize> {
slice.iter().position(|t| *t == token)
}
-#[cfg(feature = "simd")]
+#[cfg(not(feature = "simd"))]
+#[inline(always)]
+fn memchr2(token: (u8, u8), slice: &[u8]) -> Option<usize> {
+ slice.iter().position(|t| *t == token.0 || *t == token.1)
+}
+
+#[cfg(not(feature = "simd"))]
+#[inline(always)]
+fn memchr3(token: (u8, u8, u8), slice: &[u8]) -> Option<usize> {
+ slice
+ .iter()
+ .position(|t| *t == token.0 || *t == token.1 || *t == token.2)
+}
+
#[inline(always)]
fn memmem(slice: &[u8], tag: &[u8]) -> Option<usize> {
- if tag.len() > slice.len() {
- return None;
+ if tag.len() == 1 {
+ memchr(tag[0], slice)
+ } else {
+ memmem_(slice, tag)
+ }
+}
+
+#[inline(always)]
+fn memmem2(slice: &[u8], tag: (&[u8], &[u8])) -> Option<usize> {
+ if tag.0.len() == 1 && tag.1.len() == 1 {
+ memchr2((tag.0[0], tag.1[0]), slice)
+ } else {
+ memmem2_(slice, tag)
+ }
+}
+
+#[inline(always)]
+fn memmem3(slice: &[u8], tag: (&[u8], &[u8], &[u8])) -> Option<usize> {
+ if tag.0.len() == 1 && tag.1.len() == 1 && tag.2.len() == 1 {
+ memchr3((tag.0[0], tag.1[0], tag.2[0]), slice)
+ } else {
+ memmem3_(slice, tag)
}
+}
- let (&substr_first, substr_rest) = match tag.split_first() {
- Some(split) => split,
- // an empty substring is found at position 0
- // This matches the behavior of str.find("").
+#[cfg(feature = "simd")]
+#[inline(always)]
+fn memmem_(slice: &[u8], tag: &[u8]) -> Option<usize> {
+ let &prefix = match tag.first() {
+ Some(x) => x,
None => return Some(0),
};
-
- if substr_rest.is_empty() {
- return memchr::memchr(substr_first, slice);
+ #[allow(clippy::manual_find)] // faster this way
+ for i in memchr::memchr_iter(prefix, slice) {
+ if slice[i..].starts_with(tag) {
+ return Some(i);
+ }
}
+ None
+}
- let mut offset = 0;
- let haystack = &slice[..slice.len() - substr_rest.len()];
+#[cfg(feature = "simd")]
+fn memmem2_(slice: &[u8], tag: (&[u8], &[u8])) -> Option<usize> {
+ let prefix = match (tag.0.first(), tag.1.first()) {
+ (Some(&a), Some(&b)) => (a, b),
+ _ => return Some(0),
+ };
+ #[allow(clippy::manual_find)] // faster this way
+ for i in memchr::memchr2_iter(prefix.0, prefix.1, slice) {
+ let subslice = &slice[i..];
+ if subslice.starts_with(tag.0) {
+ return Some(i);
+ }
+ if subslice.starts_with(tag.1) {
+ return Some(i);
+ }
+ }
+ None
+}
- while let Some(position) = memchr::memchr(substr_first, &haystack[offset..]) {
- offset += position;
- let next_offset = offset + 1;
- if &slice[next_offset..][..substr_rest.len()] == substr_rest {
- return Some(offset);
+#[cfg(feature = "simd")]
+fn memmem3_(slice: &[u8], tag: (&[u8], &[u8], &[u8])) -> Option<usize> {
+ let prefix = match (tag.0.first(), tag.1.first(), tag.2.first()) {
+ (Some(&a), Some(&b), Some(&c)) => (a, b, c),
+ _ => return Some(0),
+ };
+ #[allow(clippy::manual_find)] // faster this way
+ for i in memchr::memchr3_iter(prefix.0, prefix.1, prefix.2, slice) {
+ let subslice = &slice[i..];
+ if subslice.starts_with(tag.0) {
+ return Some(i);
+ }
+ if subslice.starts_with(tag.1) {
+ return Some(i);
}
+ if subslice.starts_with(tag.2) {
+ return Some(i);
+ }
+ }
+ None
+}
- offset = next_offset;
+#[cfg(not(feature = "simd"))]
+fn memmem_(slice: &[u8], tag: &[u8]) -> Option<usize> {
+ for i in 0..slice.len() {
+ let subslice = &slice[i..];
+ if subslice.starts_with(tag) {
+ return Some(i);
+ }
}
+ None
+}
+#[cfg(not(feature = "simd"))]
+fn memmem2_(slice: &[u8], tag: (&[u8], &[u8])) -> Option<usize> {
+ for i in 0..slice.len() {
+ let subslice = &slice[i..];
+ if subslice.starts_with(tag.0) {
+ return Some(i);
+ }
+ if subslice.starts_with(tag.1) {
+ return Some(i);
+ }
+ }
None
}
#[cfg(not(feature = "simd"))]
-fn memmem(slice: &[u8], tag: &[u8]) -> Option<usize> {
+fn memmem3_(slice: &[u8], tag: (&[u8], &[u8], &[u8])) -> Option<usize> {
for i in 0..slice.len() {
let subslice = &slice[i..];
- if subslice.starts_with(tag) {
+ if subslice.starts_with(tag.0) {
+ return Some(i);
+ }
+ if subslice.starts_with(tag.1) {
+ return Some(i);
+ }
+ if subslice.starts_with(tag.2) {
return Some(i);
}
}
diff --git a/vendor/winnow/src/stream/tests.rs b/vendor/winnow/src/stream/tests.rs
index e653ad9e0..0129f6e3f 100644
--- a/vendor/winnow/src/stream/tests.rs
+++ b/vendor/winnow/src/stream/tests.rs
@@ -1,8 +1,25 @@
#[cfg(feature = "std")]
use proptest::prelude::*;
+use crate::{
+ combinator::{separated, separated_pair},
+ PResult, Parser,
+};
+
use super::*;
+#[cfg(feature = "std")]
+#[test]
+fn test_fxhashmap_compiles() {
+ let input = "a=b";
+ fn pair(i: &mut &str) -> PResult<(char, char)> {
+ let out = separated_pair('a', '=', 'b').parse_next(i)?;
+ Ok(out)
+ }
+
+ let _: rustc_hash::FxHashMap<char, char> = separated(0.., pair, ',').parse(input).unwrap();
+}
+
#[test]
fn test_offset_u8() {
let s = b"abcd123";
@@ -114,3 +131,18 @@ fn test_partial_complete() {
i.restore_partial(incomplete_state);
assert!(i.is_partial(), "incomplete stream state should be restored");
}
+
+#[test]
+fn test_custom_slice() {
+ type Token = usize;
+ type TokenSlice<'i> = &'i [Token];
+
+ let mut tokens: TokenSlice<'_> = &[1, 2, 3, 4];
+
+ let input = &mut tokens;
+ let start = input.checkpoint();
+ let _ = input.next_token();
+ let _ = input.next_token();
+ let offset = input.offset_from(&start);
+ assert_eq!(offset, 2);
+}
diff --git a/vendor/winnow/src/token/mod.rs b/vendor/winnow/src/token/mod.rs
index fba019c97..839821f79 100644
--- a/vendor/winnow/src/token/mod.rs
+++ b/vendor/winnow/src/token/mod.rs
@@ -81,7 +81,7 @@ where
///
/// It will return `Err(ErrMode::Backtrack(InputError::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
+/// **Note:** [`Parser`] is implemented for strings and byte strings as a convenience (complete
/// only)
///
/// # Example
@@ -114,6 +114,23 @@ where
/// assert_eq!(parser(Partial::new("S")), Err(ErrMode::Backtrack(InputError::new(Partial::new("S"), ErrorKind::Tag))));
/// assert_eq!(parser(Partial::new("H")), Err(ErrMode::Incomplete(Needed::new(4))));
/// ```
+///
+/// ```rust
+/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
+/// # use winnow::prelude::*;
+/// use winnow::token::tag;
+/// use winnow::ascii::Caseless;
+///
+/// fn parser(s: &str) -> IResult<&str, &str> {
+/// tag(Caseless("hello")).parse_peek(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(InputError::new("Something", ErrorKind::Tag))));
+/// assert_eq!(parser(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag))));
+/// ```
#[inline(always)]
#[doc(alias = "literal")]
#[doc(alias = "bytes")]
@@ -201,6 +218,7 @@ where
#[doc(alias = "literal")]
#[doc(alias = "bytes")]
#[doc(alias = "just")]
+#[deprecated(since = "0.5.20", note = "Replaced with `tag(ascii::Caseless(_))`")]
pub fn tag_no_case<T, I, Error: ParserError<I>>(
tag: T,
) -> impl Parser<I, <I as Stream>::Slice, Error>
@@ -219,6 +237,7 @@ where
})
}
+#[allow(deprecated)]
fn tag_no_case_<T, I, Error: ParserError<I>, const PARTIAL: bool>(
i: &mut I,
t: T,
@@ -244,7 +263,7 @@ where
/// Recognize a token that matches the [pattern][ContainsToken]
///
-/// **Note:** [`Parser`][crate::Parser] is implemented as a convenience (complete
+/// **Note:** [`Parser`] is implemented as a convenience (complete
/// only) for
/// - `u8`
/// - `char`
@@ -349,9 +368,9 @@ where
/// It will return an `ErrMode::Backtrack(InputError::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.
+/// *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].
+/// To recognize a series of tokens, use [`repeat`][crate::combinator::repeat] to [`Accumulate`][crate::stream::Accumulate] into a `()` and then [`Parser::recognize`].
///
/// # Example
///
@@ -546,14 +565,27 @@ where
I: Stream,
T: ContainsToken<<I as Stream>::Token>,
{
- let e: ErrorKind = ErrorKind::Slice;
if PARTIAL && input.is_partial() {
- take_till1_partial(input, |c| !list.contains_token(c), e)
+ take_till1_partial(input, |c| !list.contains_token(c))
} else {
- take_till1_complete(input, |c| !list.contains_token(c), e)
+ take_till1_complete(input, |c| !list.contains_token(c))
}
}
+fn take_while_m_n_<T, I, Error: ParserError<I>, const PARTIAL: bool>(
+ input: &mut I,
+ m: usize,
+ n: usize,
+ list: &T,
+) -> PResult<<I as Stream>::Slice, Error>
+where
+ I: StreamIsPartial,
+ I: Stream,
+ T: ContainsToken<<I as Stream>::Token>,
+{
+ take_till_m_n::<_, _, _, PARTIAL>(input, m, n, |c| !list.contains_token(c))
+}
+
/// Looks for the first element of the input type for which the condition returns true,
/// and returns the input up to this position.
///
@@ -580,11 +612,11 @@ where
fn take_till1_partial<P, I: Stream, E: ParserError<I>>(
input: &mut I,
predicate: P,
- e: ErrorKind,
) -> PResult<<I as Stream>::Slice, E>
where
P: Fn(I::Token) -> bool,
{
+ let e: ErrorKind = ErrorKind::Slice;
let offset = input
.offset_for(predicate)
.ok_or_else(|| ErrMode::Incomplete(Needed::new(1)))?;
@@ -621,11 +653,11 @@ where
fn take_till1_complete<P, I: Stream, E: ParserError<I>>(
input: &mut I,
predicate: P,
- e: ErrorKind,
) -> PResult<<I as Stream>::Slice, E>
where
P: Fn(I::Token) -> bool,
{
+ let e: ErrorKind = ErrorKind::Slice;
let offset = input
.offset_for(predicate)
.unwrap_or_else(|| input.eof_offset());
@@ -636,16 +668,16 @@ where
}
}
-fn take_while_m_n_<T, I, Error: ParserError<I>, const PARTIAL: bool>(
+fn take_till_m_n<P, I, Error: ParserError<I>, const PARTIAL: bool>(
input: &mut I,
m: usize,
n: usize,
- list: &T,
+ predicate: P,
) -> PResult<<I as Stream>::Slice, Error>
where
I: StreamIsPartial,
I: Stream,
- T: ContainsToken<<I as Stream>::Token>,
+ P: Fn(I::Token) -> bool,
{
if n < m {
return Err(ErrMode::assert(input, "`m` should be <= `n`"));
@@ -653,7 +685,7 @@ where
let mut final_count = 0;
for (processed, (offset, token)) in input.iter_offsets().enumerate() {
- if !list.contains_token(token) {
+ if predicate(token) {
if processed < m {
return Err(ErrMode::from_error_kind(input, ErrorKind::Slice));
} else {
@@ -696,6 +728,86 @@ where
/// ```rust
/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
/// # use winnow::prelude::*;
+/// use winnow::token::take_till;
+///
+/// fn till_colon(s: &str) -> IResult<&str, &str> {
+/// take_till(0.., |c| c == ':').parse_peek(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::InputError, error::Needed};
+/// # use winnow::prelude::*;
+/// # use winnow::Partial;
+/// use winnow::token::take_till;
+///
+/// fn till_colon(s: Partial<&str>) -> IResult<Partial<&str>, &str> {
+/// take_till(0.., |c| c == ':').parse_peek(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)]
+#[doc(alias = "is_not")]
+pub fn take_till<T, I, Error: ParserError<I>>(
+ range: impl Into<Range>,
+ list: T,
+) -> impl Parser<I, <I as Stream>::Slice, Error>
+where
+ I: StreamIsPartial,
+ I: Stream,
+ T: ContainsToken<<I as Stream>::Token>,
+{
+ let Range {
+ start_inclusive,
+ end_inclusive,
+ } = range.into();
+ trace("take_till", move |i: &mut I| {
+ match (start_inclusive, end_inclusive) {
+ (0, None) => {
+ if <I as StreamIsPartial>::is_partial_supported() {
+ take_till0_partial(i, |c| list.contains_token(c))
+ } else {
+ take_till0_complete(i, |c| list.contains_token(c))
+ }
+ }
+ (1, None) => {
+ if <I as StreamIsPartial>::is_partial_supported() {
+ take_till1_partial(i, |c| list.contains_token(c))
+ } else {
+ take_till1_complete(i, |c| list.contains_token(c))
+ }
+ }
+ (start, end) => {
+ let end = end.unwrap_or(usize::MAX);
+ if <I as StreamIsPartial>::is_partial_supported() {
+ take_till_m_n::<_, _, _, true>(i, start, end, |c| list.contains_token(c))
+ } else {
+ take_till_m_n::<_, _, _, false>(i, start, end, |c| list.contains_token(c))
+ }
+ }
+ }
+ })
+}
+
+/// 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::InputError, error::Needed};
+/// # use winnow::prelude::*;
/// use winnow::token::take_till0;
///
/// fn till_colon(s: &str) -> IResult<&str, &str> {
@@ -723,6 +835,7 @@ where
/// 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))));
/// ```
+#[deprecated(since = "0.5.21", note = "Replaced with `take_till(0.., ...)`")]
#[inline(always)]
pub fn take_till0<T, I, Error: ParserError<I>>(
list: T,
@@ -800,7 +913,7 @@ where
/// assert_eq!(not_space(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1))));
/// ```
#[inline(always)]
-#[doc(alias = "is_not")]
+#[deprecated(since = "0.5.21", note = "Replaced with `take_till(1.., ...)`")]
pub fn take_till1<T, I, Error: ParserError<I>>(
list: T,
) -> impl Parser<I, <I as Stream>::Slice, Error>
@@ -810,11 +923,10 @@ where
T: ContainsToken<<I as Stream>::Token>,
{
trace("take_till1", move |i: &mut I| {
- let e: ErrorKind = ErrorKind::Slice;
if <I as StreamIsPartial>::is_partial_supported() && i.is_partial() {
- take_till1_partial(i, |c| list.contains_token(c), e)
+ take_till1_partial(i, |c| list.contains_token(c))
} else {
- take_till1_complete(i, |c| list.contains_token(c), e)
+ take_till1_complete(i, |c| list.contains_token(c))
}
})
}
@@ -1025,7 +1137,7 @@ where
/// 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(InputError::new(Partial::new("eof"), ErrorKind::Slice))));
+/// assert_eq!(until_eof(Partial::new("eof")), Err(ErrMode::Backtrack(InputError::new(Partial::new("eof"), ErrorKind::Slice))));
/// ```
#[inline(always)]
pub fn take_until1<T, I, Error: ParserError<I>>(
diff --git a/vendor/winnow/src/token/tests.rs b/vendor/winnow/src/token/tests.rs
index d9f364607..696187d64 100644
--- a/vendor/winnow/src/token/tests.rs
+++ b/vendor/winnow/src/token/tests.rs
@@ -3,6 +3,7 @@ use super::*;
#[cfg(feature = "std")]
use proptest::prelude::*;
+use crate::ascii::Caseless;
use crate::binary::length_data;
use crate::combinator::delimited;
use crate::error::ErrMode;
@@ -183,7 +184,7 @@ fn partial_is_a() {
#[test]
fn partial_is_not() {
fn a_or_b(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
- take_till1(['a', 'b']).parse_peek(i)
+ take_till(1.., ['a', 'b']).parse_peek(i)
}
let a = Partial::new(&b"cdab"[..]);
@@ -365,7 +366,7 @@ fn partial_take_while_m_n() {
#[test]
fn partial_take_till0() {
fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
- take_till0(AsChar::is_alpha).parse_peek(i)
+ take_till(0.., AsChar::is_alpha).parse_peek(i)
}
let a = &b""[..];
let b = &b"abcd"[..];
@@ -387,7 +388,7 @@ fn partial_take_till0() {
#[test]
fn partial_take_till1() {
fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
- take_till1(AsChar::is_alpha).parse_peek(i)
+ take_till(1.., AsChar::is_alpha).parse_peek(i)
}
let a = &b""[..];
let b = &b"abcd"[..];
@@ -447,7 +448,7 @@ fn partial_take_while_utf8() {
#[test]
fn partial_take_till0_utf8() {
fn f(i: Partial<&str>) -> IResult<Partial<&str>, &str> {
- take_till0(|c| c == '點').parse_peek(i)
+ take_till(0.., |c| c == '點').parse_peek(i)
}
assert_eq!(
@@ -465,7 +466,7 @@ fn partial_take_till0_utf8() {
);
fn g(i: Partial<&str>) -> IResult<Partial<&str>, &str> {
- take_till0(|c| c != '點').parse_peek(i)
+ take_till(0.., |c| c != '點').parse_peek(i)
}
assert_eq!(
@@ -619,7 +620,7 @@ fn partial_length_bytes() {
#[test]
fn partial_case_insensitive() {
fn test(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
- tag_no_case("ABcd").parse_peek(i)
+ tag(Caseless("ABcd")).parse_peek(i)
}
assert_eq!(
test(Partial::new(&b"aBCdefgh"[..])),
@@ -653,7 +654,7 @@ fn partial_case_insensitive() {
);
fn test2(i: Partial<&str>) -> IResult<Partial<&str>, &str> {
- tag_no_case("ABcd").parse_peek(i)
+ tag(Caseless("ABcd")).parse_peek(i)
}
assert_eq!(
test2(Partial::new("aBCdefgh")),
diff --git a/vendor/winnow/src/trace/mod.rs b/vendor/winnow/src/trace/mod.rs
index cd96e0258..6fe89aca2 100644
--- a/vendor/winnow/src/trace/mod.rs
+++ b/vendor/winnow/src/trace/mod.rs
@@ -1,11 +1,12 @@
//! Parser execution tracing
//!
-//! By default, nothing happens and tracing gets compiled away as a no-op. To enable tracing, use
+//! By default, nothing happens and tracing gets compiled away as a no-op. To enable tracing, use
//! `--features debug`.
//!
//! # Example
//!
//!![Trace output from string example](https://raw.githubusercontent.com/winnow-rs/winnow/main/assets/trace.svg "Example output")
+#![cfg_attr(feature = "debug", allow(clippy::std_instead_of_core))]
#[cfg(feature = "debug")]
mod internals;
@@ -19,7 +20,7 @@ compile_error!("`debug` requires `std`");
/// Trace the execution of the parser
///
-/// Note that [`Parser::context` also provides high level trace information.
+/// Note that [`Parser::context`] also provides high level trace information.
///
/// See [`trace` module][self] for more details.
///