diff options
Diffstat (limited to 'vendor/winnow/src')
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. /// |