diff options
Diffstat (limited to 'vendor/winnow/src')
22 files changed, 674 insertions, 53 deletions
diff --git a/vendor/winnow/src/_topic/performance.rs b/vendor/winnow/src/_topic/performance.rs index 5bda958ee..8a6555a06 100644 --- a/vendor/winnow/src/_topic/performance.rs +++ b/vendor/winnow/src/_topic/performance.rs @@ -5,6 +5,7 @@ //! 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 //! - 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) diff --git a/vendor/winnow/src/_topic/why.rs b/vendor/winnow/src/_topic/why.rs index e28181b1a..e0328f117 100644 --- a/vendor/winnow/src/_topic/why.rs +++ b/vendor/winnow/src/_topic/why.rs @@ -16,7 +16,7 @@ //! - Fewer dependencies to audit //! //! However, this comes at the cost of doing it all yourself, including -//! - Optimizing for each of the above characteristics you are about +//! - Optimizing for each of the above characteristics you care about //! - Ensuring the safety of any `unsafe` code (buffer overflows being a common bug with parsers) //! - Being aware of, familiar with, and correctly implement the relevant algorithms. //! matklad, who has written two rust compile frontends, commented @@ -52,7 +52,7 @@ //! //! This works well for: //! - Prototyping for what will be a hand-written parser -//! - When you to minimize the work to evolve your format +//! - When you want to minimize the work to evolve your format //! - When you don't have contributors focused solely on parsing and your grammar is large enough //! to be unwieldy to hand write. //! diff --git a/vendor/winnow/src/_tutorial/chapter_0.rs b/vendor/winnow/src/_tutorial/chapter_0.rs index 4c768d8f8..47c196e86 100644 --- a/vendor/winnow/src/_tutorial/chapter_0.rs +++ b/vendor/winnow/src/_tutorial/chapter_0.rs @@ -36,3 +36,4 @@ use crate::_topic; use std::iter::Iterator; pub use super::chapter_1 as next; +pub use crate::_tutorial as table_of_contents; diff --git a/vendor/winnow/src/_tutorial/chapter_1.rs b/vendor/winnow/src/_tutorial/chapter_1.rs index 1bf146bec..b16a16657 100644 --- a/vendor/winnow/src/_tutorial/chapter_1.rs +++ b/vendor/winnow/src/_tutorial/chapter_1.rs @@ -83,3 +83,4 @@ use crate::Parser; pub use super::chapter_0 as previous; pub use super::chapter_2 as next; +pub use crate::_tutorial as table_of_contents; diff --git a/vendor/winnow/src/_tutorial/chapter_2.rs b/vendor/winnow/src/_tutorial/chapter_2.rs index b0daedc74..0fb80ac37 100644 --- a/vendor/winnow/src/_tutorial/chapter_2.rs +++ b/vendor/winnow/src/_tutorial/chapter_2.rs @@ -245,3 +245,4 @@ use std::ops::RangeInclusive; pub use super::chapter_1 as previous; pub use super::chapter_3 as next; +pub use crate::_tutorial as table_of_contents; diff --git a/vendor/winnow/src/_tutorial/chapter_3.rs b/vendor/winnow/src/_tutorial/chapter_3.rs index 83714f4d7..4dfdc31e4 100644 --- a/vendor/winnow/src/_tutorial/chapter_3.rs +++ b/vendor/winnow/src/_tutorial/chapter_3.rs @@ -373,3 +373,4 @@ use crate::stream::Stream; pub use super::chapter_2 as previous; pub use super::chapter_4 as next; +pub use crate::_tutorial as table_of_contents; diff --git a/vendor/winnow/src/_tutorial/chapter_4.rs b/vendor/winnow/src/_tutorial/chapter_4.rs index fb14613f3..59aa7ee87 100644 --- a/vendor/winnow/src/_tutorial/chapter_4.rs +++ b/vendor/winnow/src/_tutorial/chapter_4.rs @@ -107,3 +107,4 @@ use std::str::FromStr; pub use super::chapter_3 as previous; pub use super::chapter_5 as next; +pub use crate::_tutorial as table_of_contents; diff --git a/vendor/winnow/src/_tutorial/chapter_5.rs b/vendor/winnow/src/_tutorial/chapter_5.rs index 95a89dc8c..ffd8a29ce 100644 --- a/vendor/winnow/src/_tutorial/chapter_5.rs +++ b/vendor/winnow/src/_tutorial/chapter_5.rs @@ -279,3 +279,4 @@ use std::vec::Vec; pub use super::chapter_4 as previous; pub use super::chapter_6 as next; +pub use crate::_tutorial as table_of_contents; diff --git a/vendor/winnow/src/_tutorial/chapter_6.rs b/vendor/winnow/src/_tutorial/chapter_6.rs index d7d2c9fc8..9f4230942 100644 --- a/vendor/winnow/src/_tutorial/chapter_6.rs +++ b/vendor/winnow/src/_tutorial/chapter_6.rs @@ -153,3 +153,4 @@ use crate::_topic; pub use super::chapter_5 as previous; pub use super::chapter_7 as next; +pub use crate::_tutorial as table_of_contents; diff --git a/vendor/winnow/src/_tutorial/chapter_7.rs b/vendor/winnow/src/_tutorial/chapter_7.rs index 45f2d2d2a..7f13f9829 100644 --- a/vendor/winnow/src/_tutorial/chapter_7.rs +++ b/vendor/winnow/src/_tutorial/chapter_7.rs @@ -115,3 +115,4 @@ use crate::PResult; use crate::Parser; pub use super::chapter_6 as previous; +pub use crate::_tutorial as table_of_contents; diff --git a/vendor/winnow/src/_tutorial/mod.rs b/vendor/winnow/src/_tutorial/mod.rs index e4b8392f9..224fe6a80 100644 --- a/vendor/winnow/src/_tutorial/mod.rs +++ b/vendor/winnow/src/_tutorial/mod.rs @@ -1,6 +1,6 @@ //! # Tutorial //! -//! Table of Content +//! Table of Contents pub mod chapter_0; pub mod chapter_1; diff --git a/vendor/winnow/src/binary/bits/mod.rs b/vendor/winnow/src/binary/bits/mod.rs index 334c6bf00..b11ba43c7 100644 --- a/vendor/winnow/src/binary/bits/mod.rs +++ b/vendor/winnow/src/binary/bits/mod.rs @@ -10,6 +10,9 @@ use crate::stream::{AsBytes, Stream, StreamIsPartial, ToUsize}; use crate::trace::trace; use crate::{unpeek, IResult, PResult, Parser}; +/// Number of bits in a byte +const BYTE: usize = u8::BITS as usize; + /// Converts a byte-level input to a bit-level input /// /// See [`bytes`] to convert it back. @@ -57,12 +60,15 @@ where Ok(((rest, offset), result)) => { // If the next byte has been partially read, it will be sliced away as well. // The parser functions might already slice away all fully read bytes. - // That's why `offset / 8` isn't necessarily needed at all times. - let remaining_bytes_index = offset / 8 + if offset % 8 == 0 { 0 } else { 1 }; + // That's why `offset / BYTE` isn't necessarily needed at all times. + let remaining_bytes_index = + offset / BYTE + if offset % BYTE == 0 { 0 } else { 1 }; let (input, _) = rest.peek_slice(remaining_bytes_index); Ok((input, result)) } - Err(ErrMode::Incomplete(n)) => Err(ErrMode::Incomplete(n.map(|u| u.get() / 8 + 1))), + Err(ErrMode::Incomplete(n)) => { + Err(ErrMode::Incomplete(n.map(|u| u.get() / BYTE + 1))) + } Err(e) => Err(e.convert()), } }), @@ -109,10 +115,10 @@ where trace( "bytes", unpeek(move |(input, offset): (I, usize)| { - let (inner, _) = if offset % 8 != 0 { - input.peek_slice(1 + offset / 8) + let (inner, _) = if offset % BYTE != 0 { + input.peek_slice(1 + offset / BYTE) } else { - input.peek_slice(offset / 8) + input.peek_slice(offset / BYTE) }; let i = (input, offset); match parser.parse_peek(inner) { @@ -120,13 +126,15 @@ where Err(ErrMode::Incomplete(Needed::Unknown)) => { Err(ErrMode::Incomplete(Needed::Unknown)) } - Err(ErrMode::Incomplete(Needed::Size(sz))) => Err(match sz.get().checked_mul(8) { - Some(v) => ErrMode::Incomplete(Needed::new(v)), - None => ErrMode::Cut(E2::assert( - &i, - "overflow in turning needed bytes into needed bits", - )), - }), + Err(ErrMode::Incomplete(Needed::Size(sz))) => { + Err(match sz.get().checked_mul(BYTE) { + Some(v) => ErrMode::Incomplete(Needed::new(v)), + None => ErrMode::Cut(E2::assert( + &i, + "overflow in turning needed bytes into needed bits", + )), + }) + } Err(e) => Err(e.convert()), } }), @@ -196,8 +204,7 @@ where if count == 0 { Ok(((input, bit_offset), 0u8.into())) } else { - let cnt = (count + bit_offset).div(8); - if input.eof_offset() * 8 < count + bit_offset { + if input.eof_offset() * BYTE < count + bit_offset { if PARTIAL && input.is_partial() { Err(ErrMode::Incomplete(Needed::new(count))) } else { @@ -207,6 +214,7 @@ where )) } } else { + let cnt = (count + bit_offset).div(BYTE); let mut acc: O = 0_u8.into(); let mut offset: usize = bit_offset; let mut remaining: usize = count; @@ -222,13 +230,13 @@ where (byte << offset >> offset).into() }; - if remaining < 8 - offset { - acc += val >> (8 - offset - remaining); + if remaining < BYTE - offset { + acc += val >> (BYTE - offset - remaining); end_offset = remaining + offset; break; } else { - acc += val << (remaining - (8 - offset)); - remaining -= 8 - offset; + acc += val << (remaining - (BYTE - offset)); + remaining -= BYTE - offset; offset = 0; } } diff --git a/vendor/winnow/src/combinator/branch.rs b/vendor/winnow/src/combinator/branch.rs index 2a712ec1d..b909ff1c7 100644 --- a/vendor/winnow/src/combinator/branch.rs +++ b/vendor/winnow/src/combinator/branch.rs @@ -112,6 +112,31 @@ pub fn permutation<I: Stream, O, E: ParserError<I>, List: Permutation<I, O, E>>( trace("permutation", move |i: &mut I| l.permutation(i)) } +impl<const N: usize, I: Stream, O, E: ParserError<I>, P: Parser<I, O, E>> Alt<I, O, E> for [P; N] { + fn choice(&mut self, input: &mut I) -> PResult<O, E> { + let mut error: Option<E> = None; + + let start = input.checkpoint(); + for branch in self { + input.reset(start.clone()); + match branch.parse_next(input) { + Err(ErrMode::Backtrack(e)) => { + error = match error { + Some(error) => Some(error.or(e)), + None => Some(e), + }; + } + res => return res, + } + } + + match error { + Some(e) => Err(ErrMode::Backtrack(e.append(input, ErrorKind::Alt))), + None => Err(ErrMode::assert(input, "`alt` needs at least one parser")), + } + } +} + macro_rules! alt_trait( ($first:ident $second:ident $($id: ident)+) => ( alt_trait!(__impl $first $second; $($id)+); diff --git a/vendor/winnow/src/combinator/mod.rs b/vendor/winnow/src/combinator/mod.rs index d76ef8e5f..ec68e48e2 100644 --- a/vendor/winnow/src/combinator/mod.rs +++ b/vendor/winnow/src/combinator/mod.rs @@ -8,8 +8,8 @@ //! //! | combinator | usage | input | output | comment | //! |---|---|---|---|---| -//! | [`one_of`][crate::token::one_of] | `one_of("abc")` | `"abc"` | `Ok(("bc", 'a'))` |Matches one of the provided characters (works with non ASCII characters too)| -//! | [`none_of`][crate::token::none_of] | `none_of("abc")` | `"xyab"` | `Ok(("yab", 'x'))` |Matches anything but the provided characters| +//! | [`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| diff --git a/vendor/winnow/src/combinator/parser.rs b/vendor/winnow/src/combinator/parser.rs index 969c2d525..fb11adc15 100644 --- a/vendor/winnow/src/combinator/parser.rs +++ b/vendor/winnow/src/combinator/parser.rs @@ -14,12 +14,16 @@ pub struct ByRef<'p, P> { } impl<'p, P> ByRef<'p, P> { + #[inline(always)] pub(crate) fn new(p: &'p mut P) -> Self { Self { p } } } -impl<'p, I, O, E, P: Parser<I, O, E>> Parser<I, O, E> for ByRef<'p, P> { +impl<'p, I, O, E, P> Parser<I, O, E> for ByRef<'p, P> +where + P: Parser<I, O, E>, +{ #[inline(always)] fn parse_next(&mut self, i: &mut I) -> PResult<O, E> { self.p.parse_next(i) @@ -46,6 +50,7 @@ where F: Parser<I, O, E>, G: Fn(O) -> O2, { + #[inline(always)] pub(crate) fn new(parser: F, map: G) -> Self { Self { parser, @@ -97,6 +102,7 @@ where I: Stream, E: FromExternalError<I, E2>, { + #[inline(always)] pub(crate) fn new(parser: F, map: G) -> Self { Self { parser, @@ -154,6 +160,7 @@ where I: Stream, E: ParserError<I>, { + #[inline(always)] pub(crate) fn new(parser: F, map: G) -> Self { Self { parser, @@ -210,6 +217,7 @@ where O: StreamIsPartial, I: Stream, { + #[inline(always)] pub(crate) fn new(outer: F, inner: G) -> Self { Self { outer, @@ -265,6 +273,7 @@ where O: crate::stream::ParseSlice<O2>, E: ParserError<I>, { + #[inline(always)] pub(crate) fn new(p: P) -> Self { Self { p, @@ -319,6 +328,7 @@ where G: FnMut(O) -> H, H: Parser<I, O2, E>, { + #[inline(always)] pub(crate) fn new(f: F, g: G) -> Self { Self { f, @@ -352,6 +362,7 @@ pub struct CompleteErr<F> { } impl<F> CompleteErr<F> { + #[inline(always)] pub(crate) fn new(f: F) -> Self { Self { f } } @@ -405,6 +416,7 @@ where O2: ?Sized, E: ParserError<I>, { + #[inline(always)] pub(crate) fn new(parser: F, filter: G) -> Self { Self { parser, @@ -458,6 +470,7 @@ where F: Parser<I, O, E>, O2: Clone, { + #[inline(always)] pub(crate) fn new(parser: F, val: O2) -> Self { Self { parser, @@ -496,6 +509,7 @@ impl<F, I, O, E> Void<F, I, O, E> where F: Parser<I, O, E>, { + #[inline(always)] pub(crate) fn new(parser: F) -> Self { Self { parser, @@ -534,6 +548,7 @@ where F: Parser<I, O, E>, I: Stream, { + #[inline(always)] pub(crate) fn new(parser: F) -> Self { Self { parser, @@ -582,6 +597,7 @@ where F: Parser<I, O, E>, I: Stream, { + #[inline(always)] pub(crate) fn new(parser: F) -> Self { Self { parser, @@ -630,6 +646,7 @@ where F: Parser<I, O, E>, I: Stream + Location, { + #[inline(always)] pub(crate) fn new(parser: F) -> Self { Self { parser, @@ -673,6 +690,7 @@ where F: Parser<I, O, E>, I: Stream + Location, { + #[inline(always)] pub(crate) fn new(parser: F) -> Self { Self { parser, @@ -717,6 +735,7 @@ where F: Parser<I, O, E>, O: Into<O2>, { + #[inline(always)] pub(crate) fn new(parser: F) -> Self { Self { parser, @@ -758,6 +777,7 @@ where F: Parser<I, O, E>, E: Into<E2>, { + #[inline(always)] pub(crate) fn new(parser: F) -> Self { Self { parser, @@ -808,6 +828,7 @@ where E: AddContext<I, C>, C: Clone + crate::lib::std::fmt::Debug, { + #[inline(always)] pub(crate) fn new(parser: F, context: C) -> Self { Self { parser, @@ -835,7 +856,7 @@ where trace(name, move |i: &mut I| { (self.parser) .parse_next(i) - .map_err(|err| err.map(|err| err.add_context(i, self.context.clone()))) + .map_err(|err| err.add_context(i, self.context.clone())) }) .parse_next(i) } diff --git a/vendor/winnow/src/combinator/tests.rs b/vendor/winnow/src/combinator/tests.rs index 62dc420e5..9d2b49d80 100644 --- a/vendor/winnow/src/combinator/tests.rs +++ b/vendor/winnow/src/combinator/tests.rs @@ -13,6 +13,7 @@ use crate::stream::Stream; use crate::token::take; use crate::unpeek; use crate::IResult; +use crate::PResult; use crate::Parser; use crate::Partial; @@ -649,6 +650,28 @@ fn alt_incomplete() { } #[test] +fn alt_array() { + fn alt1<'i>(i: &mut &'i [u8]) -> PResult<&'i [u8]> { + alt(["a", "bc", "def"]).parse_next(i) + } + + let i = &b"a"[..]; + assert_eq!(alt1.parse_peek(i), Ok((&b""[..], (&b"a"[..])))); + + let i = &b"bc"[..]; + assert_eq!(alt1.parse_peek(i), Ok((&b""[..], (&b"bc"[..])))); + + let i = &b"defg"[..]; + assert_eq!(alt1.parse_peek(i), Ok((&b"g"[..], (&b"def"[..])))); + + let i = &b"z"[..]; + assert_eq!( + alt1.parse_peek(i), + Err(ErrMode::Backtrack(error_position!(&i, ErrorKind::Tag))) + ); +} + +#[test] fn permutation_test() { #[allow(clippy::type_complexity)] fn perm(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, (&[u8], &[u8], &[u8])> { diff --git a/vendor/winnow/src/error.rs b/vendor/winnow/src/error.rs index d40e8244b..449bebc55 100644 --- a/vendor/winnow/src/error.rs +++ b/vendor/winnow/src/error.rs @@ -17,6 +17,7 @@ //! - [`ErrorKind`] //! - [`InputError`] (mostly for testing) //! - [`ContextError`] +//! - [`TreeError`] (mostly for testing) //! - [Custom errors][crate::_topic::error] #[cfg(feature = "alloc")] @@ -88,7 +89,7 @@ impl Needed { } } -/// The `Err` enum indicates the parser was not successful +/// Add parse error state to [`ParserError`]s #[derive(Debug, Clone, PartialEq)] #[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] pub enum ErrMode<E> { @@ -120,6 +121,7 @@ pub enum ErrMode<E> { impl<E> ErrMode<E> { /// Tests if the result is Incomplete + #[inline] pub fn is_incomplete(&self) -> bool { matches!(self, ErrMode::Incomplete(_)) } @@ -164,6 +166,7 @@ impl<E> ErrMode<E> { /// /// Returns `None` for [`ErrMode::Incomplete`] #[cfg_attr(debug_assertions, track_caller)] + #[inline(always)] pub fn into_inner(self) -> Option<E> { match self { ErrMode::Backtrack(e) | ErrMode::Cut(e) => Some(e), @@ -173,11 +176,13 @@ impl<E> ErrMode<E> { } impl<I, E: ParserError<I>> ParserError<I> for ErrMode<E> { + #[inline(always)] fn from_error_kind(input: &I, kind: ErrorKind) -> Self { ErrMode::Backtrack(E::from_error_kind(input, kind)) } #[cfg_attr(debug_assertions, track_caller)] + #[inline(always)] fn assert(input: &I, message: &'static str) -> Self where I: crate::lib::std::fmt::Debug, @@ -185,6 +190,7 @@ impl<I, E: ParserError<I>> ParserError<I> for ErrMode<E> { ErrMode::Backtrack(E::assert(input, message)) } + #[inline] fn append(self, input: &I, kind: ErrorKind) -> Self { match self { ErrMode::Backtrack(e) => ErrMode::Backtrack(e.append(input, kind)), @@ -205,11 +211,19 @@ impl<I, EXT, E> FromExternalError<I, EXT> for ErrMode<E> where E: FromExternalError<I, EXT>, { + #[inline(always)] fn from_external_error(input: &I, kind: ErrorKind, e: EXT) -> Self { ErrMode::Backtrack(E::from_external_error(input, kind, e)) } } +impl<I, C, E: AddContext<I, C>> AddContext<I, C> for ErrMode<E> { + #[inline(always)] + fn add_context(self, input: &I, ctx: C) -> Self { + self.map(|err| err.add_context(input, ctx)) + } +} + impl<T: Clone> ErrMode<InputError<T>> { /// Maps `ErrMode<InputError<T>>` to `ErrMode<InputError<U>>` with the given `F: T -> U` pub fn map_input<U: Clone, F>(self, f: F) -> ErrMode<InputError<U>> @@ -276,6 +290,7 @@ pub trait ParserError<I>: Sized { /// /// For example, this would be used by [`alt`][crate::combinator::alt] to report the error from /// each case. + #[inline] fn or(self, other: Self) -> Self { other } @@ -330,19 +345,25 @@ impl<I: Clone> InputError<I> { pub fn new(input: I, kind: ErrorKind) -> Self { Self { input, kind } } + + /// Translate the input type + #[inline] + pub fn map_input<I2: Clone, O: Fn(I) -> I2>(self, op: O) -> InputError<I2> { + InputError { + input: op(self.input), + kind: self.kind, + } + } } #[cfg(feature = "alloc")] -impl<'i, I: Clone + ToOwned + ?Sized> InputError<&'i I> +impl<'i, I: ToOwned> InputError<&'i I> where <I as ToOwned>::Owned: Clone, { /// Obtaining ownership pub fn into_owned(self) -> InputError<<I as ToOwned>::Owned> { - InputError { - input: self.input.to_owned(), - kind: self.kind, - } + self.map_input(ToOwned::to_owned) } } @@ -397,7 +418,12 @@ impl<I: Clone> ErrorConvert<InputError<I>> for InputError<(I, usize)> { /// The Display implementation allows the `std::error::Error` implementation impl<I: Clone + fmt::Display> fmt::Display for InputError<I> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{} error starting at: {}", self.kind, self.input) + write!( + f, + "{} error starting at: {}", + self.kind.description(), + self.input + ) } } @@ -464,6 +490,16 @@ impl<C> ContextError<C> { } } +impl<C: Clone> Clone for ContextError<C> { + fn clone(&self) -> Self { + Self { + context: self.context.clone(), + #[cfg(feature = "std")] + cause: self.cause.as_ref().map(|e| e.to_string().into()), + } + } +} + impl<C> Default for ContextError<C> { #[inline] fn default() -> Self { @@ -606,6 +642,15 @@ pub enum StrContext { Expected(StrContextValue), } +impl crate::lib::std::fmt::Display for StrContext { + fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result { + match self { + Self::Label(name) => write!(f, "invalid {name}"), + Self::Expected(value) => write!(f, "expected {value}"), + } + } +} + /// See [`StrContext`] #[derive(Clone, Debug, PartialEq, Eq)] #[non_exhaustive] @@ -619,12 +664,14 @@ pub enum StrContextValue { } impl From<char> for StrContextValue { + #[inline] fn from(inner: char) -> Self { Self::CharLiteral(inner) } } impl From<&'static str> for StrContextValue { + #[inline] fn from(inner: &'static str) -> Self { Self::StringLiteral(inner) } @@ -645,6 +692,395 @@ impl crate::lib::std::fmt::Display for StrContextValue { } } +/// Trace all error paths, particularly for tests +#[derive(Debug)] +#[cfg(feature = "std")] +pub enum TreeError<I, C = StrContext> { + /// Initial error that kicked things off + Base(TreeErrorBase<I>), + /// Traces added to the error while walking back up the stack + Stack { + /// Initial error that kicked things off + base: Box<Self>, + /// Traces added to the error while walking back up the stack + stack: Vec<TreeErrorFrame<I, C>>, + }, + /// All failed branches of an `alt` + Alt(Vec<Self>), +} + +/// See [`TreeError::Stack`] +#[derive(Debug)] +#[cfg(feature = "std")] +pub enum TreeErrorFrame<I, C = StrContext> { + /// See [`ParserError::append`] + Kind(TreeErrorBase<I>), + /// See [`AddContext::add_context`] + Context(TreeErrorContext<I, C>), +} + +/// See [`TreeErrorFrame::Kind`], [`ParserError::append`] +#[derive(Debug)] +#[cfg(feature = "std")] +pub struct TreeErrorBase<I> { + /// Parsed input, at the location where the error occurred + pub input: I, + /// Debug context + pub kind: ErrorKind, + /// See [`FromExternalError::from_external_error`] + pub cause: Option<Box<dyn std::error::Error + Send + Sync + 'static>>, +} + +/// See [`TreeErrorFrame::Context`], [`AddContext::add_context`] +#[derive(Debug)] +#[cfg(feature = "std")] +pub struct TreeErrorContext<I, C = StrContext> { + /// Parsed input, at the location where the error occurred + pub input: I, + /// See [`AddContext::add_context`] + pub context: C, +} + +#[cfg(feature = "std")] +impl<'i, I: ToOwned, C> TreeError<&'i I, C> +where + <I as ToOwned>::Owned: Clone, +{ + /// Obtaining ownership + pub fn into_owned(self) -> TreeError<<I as ToOwned>::Owned, C> { + self.map_input(ToOwned::to_owned) + } +} + +#[cfg(feature = "std")] +impl<I, C> TreeError<I, C> +where + I: Clone, +{ + /// Translate the input type + pub fn map_input<I2: Clone, O: Clone + Fn(I) -> I2>(self, op: O) -> TreeError<I2, C> { + match self { + TreeError::Base(base) => TreeError::Base(TreeErrorBase { + input: op(base.input), + kind: base.kind, + cause: base.cause, + }), + TreeError::Stack { base, stack } => { + let base = Box::new(base.map_input(op.clone())); + let stack = stack + .into_iter() + .map(|frame| match frame { + TreeErrorFrame::Kind(kind) => TreeErrorFrame::Kind(TreeErrorBase { + input: op(kind.input), + kind: kind.kind, + cause: kind.cause, + }), + TreeErrorFrame::Context(context) => { + TreeErrorFrame::Context(TreeErrorContext { + input: op(context.input), + context: context.context, + }) + } + }) + .collect(); + TreeError::Stack { base, stack } + } + TreeError::Alt(alt) => { + TreeError::Alt(alt.into_iter().map(|e| e.map_input(op.clone())).collect()) + } + } + } + + fn append_frame(self, frame: TreeErrorFrame<I, C>) -> Self { + match self { + TreeError::Stack { base, mut stack } => { + stack.push(frame); + TreeError::Stack { base, stack } + } + base => TreeError::Stack { + base: Box::new(base), + stack: vec![frame], + }, + } + } +} + +#[cfg(feature = "std")] +impl<I, C> ParserError<I> for TreeError<I, C> +where + I: Clone, +{ + fn from_error_kind(input: &I, kind: ErrorKind) -> Self { + TreeError::Base(TreeErrorBase { + input: input.clone(), + kind, + cause: None, + }) + } + + fn append(self, input: &I, kind: ErrorKind) -> Self { + let frame = TreeErrorFrame::Kind(TreeErrorBase { + input: input.clone(), + kind, + cause: None, + }); + self.append_frame(frame) + } + + fn or(self, other: Self) -> Self { + match (self, other) { + (TreeError::Alt(mut first), TreeError::Alt(second)) => { + // Just in case an implementation does a divide-and-conquer algorithm + // + // To prevent mixing `alt`s at different levels, parsers should + // `alt_err.append(input, ErrorKind::Alt)`. + first.extend(second); + TreeError::Alt(first) + } + (TreeError::Alt(mut alt), new) | (new, TreeError::Alt(mut alt)) => { + alt.push(new); + TreeError::Alt(alt) + } + (first, second) => TreeError::Alt(vec![first, second]), + } + } +} + +#[cfg(feature = "std")] +impl<I, C> AddContext<I, C> for TreeError<I, C> +where + I: Clone, +{ + fn add_context(self, input: &I, context: C) -> Self { + let frame = TreeErrorFrame::Context(TreeErrorContext { + input: input.clone(), + context, + }); + self.append_frame(frame) + } +} + +#[cfg(feature = "std")] +impl<I, C, E: std::error::Error + Send + Sync + 'static> FromExternalError<I, E> for TreeError<I, C> +where + I: Clone, +{ + fn from_external_error(input: &I, kind: ErrorKind, e: E) -> Self { + TreeError::Base(TreeErrorBase { + input: input.clone(), + kind, + cause: Some(Box::new(e)), + }) + } +} + +#[cfg(feature = "std")] +impl<I, C> TreeError<I, C> +where + I: Clone + std::fmt::Display, + C: fmt::Display, +{ + fn write(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result { + let child_indent = indent + 2; + match self { + TreeError::Base(base) => { + writeln!(f, "{:indent$}{base}", "")?; + } + TreeError::Stack { base, stack } => { + base.write(f, indent)?; + for (level, frame) in stack.iter().enumerate() { + match frame { + TreeErrorFrame::Kind(frame) => { + writeln!(f, "{:child_indent$}{level}: {frame}", "")?; + } + TreeErrorFrame::Context(frame) => { + writeln!(f, "{:child_indent$}{level}: {frame}", "")?; + } + } + } + } + TreeError::Alt(alt) => { + writeln!(f, "{:indent$}during one of:", "")?; + for child in alt { + child.write(f, child_indent)?; + } + } + } + + Ok(()) + } +} + +#[cfg(feature = "std")] +impl<I: Clone + fmt::Display> fmt::Display for TreeErrorBase<I> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(cause) = self.cause.as_ref() { + write!(f, "caused by {cause}")?; + } else { + let kind = self.kind.description(); + write!(f, "in {kind}")?; + } + let input = abbreviate(self.input.to_string()); + write!(f, " at '{input}'")?; + Ok(()) + } +} + +#[cfg(feature = "std")] +impl<I: Clone + fmt::Display, C: fmt::Display> fmt::Display for TreeErrorContext<I, C> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let context = &self.context; + let input = abbreviate(self.input.to_string()); + write!(f, "{context} at '{input}'")?; + Ok(()) + } +} + +#[cfg(feature = "std")] +impl< + I: Clone + fmt::Debug + fmt::Display + Sync + Send + 'static, + C: fmt::Display + fmt::Debug, + > std::error::Error for TreeError<I, C> +{ +} + +#[cfg(feature = "std")] +fn abbreviate(input: String) -> String { + let mut abbrev = None; + + if let Some((line, _)) = input.split_once('\n') { + abbrev = Some(line); + } + + let max_len = 20; + let current = abbrev.unwrap_or(&input); + if max_len < current.len() { + if let Some((index, _)) = current.char_indices().nth(max_len) { + abbrev = Some(¤t[..index]); + } + } + + if let Some(abbrev) = abbrev { + format!("{abbrev}...") + } else { + input + } +} + +#[cfg(feature = "std")] +impl<I: Clone + fmt::Display, C: fmt::Display> fmt::Display for TreeError<I, C> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.write(f, 0) + } +} + +/// Deprecated, replaced with [`ContextError`] +#[cfg(feature = "std")] +#[allow(deprecated)] +#[deprecated(since = "0.5.8", note = "Replaced with `ContextError`")] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct VerboseError<I: Clone, C = &'static str> { + /// Accumulated error information + pub errors: crate::lib::std::vec::Vec<(I, VerboseErrorKind<C>)>, +} + +#[cfg(feature = "std")] +#[allow(deprecated)] +impl<'i, I: ToOwned, C> VerboseError<&'i I, C> +where + <I as ToOwned>::Owned: Clone, +{ + /// Obtaining ownership + pub fn into_owned(self) -> VerboseError<<I as ToOwned>::Owned, C> { + self.map_input(ToOwned::to_owned) + } +} + +#[cfg(feature = "std")] +#[allow(deprecated)] +impl<I: Clone, C> VerboseError<I, C> { + /// Translate the input type + pub fn map_input<I2: Clone, O>(self, op: O) -> VerboseError<I2, C> + where + O: Fn(I) -> I2, + { + VerboseError { + errors: self.errors.into_iter().map(|(i, k)| (op(i), k)).collect(), + } + } +} + +/// Deprecated, replaced with [`ContextError`] +#[cfg(feature = "std")] +#[deprecated(since = "0.5.8", note = "Replaced with `ContextError`")] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum VerboseErrorKind<C = &'static str> { + /// Static string added by the `context` function + Context(C), + /// Error kind given by various parsers + Winnow(ErrorKind), +} + +#[cfg(feature = "std")] +#[allow(deprecated)] +impl<I: Clone, C> ParserError<I> for VerboseError<I, C> { + fn from_error_kind(input: &I, kind: ErrorKind) -> Self { + VerboseError { + errors: vec![(input.clone(), VerboseErrorKind::Winnow(kind))], + } + } + + fn append(mut self, input: &I, kind: ErrorKind) -> Self { + self.errors + .push((input.clone(), VerboseErrorKind::Winnow(kind))); + self + } +} + +#[cfg(feature = "std")] +#[allow(deprecated)] +impl<I: Clone, C> AddContext<I, C> for VerboseError<I, C> { + fn add_context(mut self, input: &I, ctx: C) -> Self { + self.errors + .push((input.clone(), VerboseErrorKind::Context(ctx))); + self + } +} + +#[cfg(feature = "std")] +#[allow(deprecated)] +impl<I: Clone, C, E> FromExternalError<I, E> for VerboseError<I, C> { + /// Create a new error from an input position and an external error + fn from_external_error(input: &I, kind: ErrorKind, _e: E) -> Self { + Self::from_error_kind(input, kind) + } +} + +#[cfg(feature = "std")] +#[allow(deprecated)] +impl<I: Clone + fmt::Display, C: fmt::Display> fmt::Display for VerboseError<I, C> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "Parse error:")?; + for (input, error) in &self.errors { + match error { + VerboseErrorKind::Winnow(e) => writeln!(f, "{} at: {}", e.description(), input)?, + VerboseErrorKind::Context(s) => writeln!(f, "in section '{}', at: {}", s, input)?, + } + } + + Ok(()) + } +} + +#[cfg(feature = "std")] +#[allow(deprecated)] +impl< + I: Clone + fmt::Debug + fmt::Display + Sync + Send + 'static, + C: fmt::Display + fmt::Debug, + > std::error::Error for VerboseError<I, C> +{ +} + /// Provide some minor debug context for errors #[rustfmt::skip] #[derive(Debug,PartialEq,Eq,Hash,Clone,Copy)] @@ -684,10 +1120,12 @@ impl ErrorKind { } impl<I> ParserError<I> for ErrorKind { + #[inline] fn from_error_kind(_input: &I, kind: ErrorKind) -> Self { kind } + #[inline] fn append(self, _: &I, _: ErrorKind) -> Self { self } @@ -697,6 +1135,7 @@ impl<I, C> AddContext<I, C> for ErrorKind {} impl<I, E> FromExternalError<I, E> for ErrorKind { /// Create a new error from an input position and an external error + #[inline] fn from_external_error(_input: &I, kind: ErrorKind, _e: E) -> Self { kind } @@ -750,6 +1189,12 @@ impl<I, E> ParseError<I, E> { pub fn inner(&self) -> &E { &self.inner } + + /// The original [`ParserError`] + #[inline] + pub fn into_inner(self) -> E { + self.inner + } } impl<I, E> core::fmt::Display for ParseError<I, E> diff --git a/vendor/winnow/src/macros.rs b/vendor/winnow/src/macros.rs index b3078c605..35279bae8 100644 --- a/vendor/winnow/src/macros.rs +++ b/vendor/winnow/src/macros.rs @@ -38,6 +38,7 @@ /// assert_eq!(escaped.parse_peek("\\nHello"), Ok(("Hello", '\n'))); /// ``` #[macro_export] +#[doc(hidden)] // forced to be visible in intended location macro_rules! dispatch { ($match_parser: expr; $( $pat:pat $(if $pred:expr)? => $expr: expr ),+ $(,)? ) => { $crate::trace::trace("dispatch", move |i: &mut _| diff --git a/vendor/winnow/src/parser.rs b/vendor/winnow/src/parser.rs index d160a8ef8..b59e4cd83 100644 --- a/vendor/winnow/src/parser.rs +++ b/vendor/winnow/src/parser.rs @@ -128,6 +128,7 @@ pub trait Parser<I, O, E> { /// } /// } /// ``` + #[inline(always)] fn by_ref(&mut self) -> ByRef<'_, Self> where Self: core::marker::Sized, @@ -151,6 +152,7 @@ pub trait Parser<I, O, E> { /// # } /// ``` #[doc(alias = "to")] + #[inline(always)] fn value<O2>(self, val: O2) -> Value<Self, I, O, O2, E> where Self: core::marker::Sized, @@ -174,6 +176,7 @@ pub trait Parser<I, O, E> { /// assert_eq!(parser.parse_peek("123abcd;"), Err(ErrMode::Backtrack(InputError::new("123abcd;", ErrorKind::Slice)))); /// # } /// ``` + #[inline(always)] fn void(self) -> Void<Self, I, O, E> where Self: core::marker::Sized, @@ -202,6 +205,7 @@ pub trait Parser<I, O, E> { /// assert_eq!(bytes, Ok(("", vec![97, 98, 99, 100]))); /// # } /// ``` + #[inline(always)] fn output_into<O2>(self) -> OutputInto<Self, I, O, O2, E> where Self: core::marker::Sized, @@ -227,6 +231,7 @@ pub trait Parser<I, O, E> { /// # } /// ``` #[doc(alias = "concat")] + #[inline(always)] fn recognize(self) -> Recognize<Self, I, O, E> where Self: core::marker::Sized, @@ -272,6 +277,7 @@ pub trait Parser<I, O, E> { /// assert_eq!(recognize_parser.parse_peek("abcd"), consumed_parser.parse_peek("abcd")); /// ``` #[doc(alias = "consumed")] + #[inline(always)] fn with_recognized(self) -> WithRecognized<Self, I, O, E> where Self: core::marker::Sized, @@ -296,6 +302,7 @@ pub trait Parser<I, O, E> { /// assert_eq!(parser.parse(Located::new("abcd,efgh")), Ok((0..4, 5..9))); /// assert_eq!(parser.parse_peek(Located::new("abcd;")),Err(ErrMode::Backtrack(InputError::new(Located::new("abcd;").peek_slice(4).0, ErrorKind::Verify)))); /// ``` + #[inline(always)] fn span(self) -> Span<Self, I, O, E> where Self: core::marker::Sized, @@ -344,6 +351,7 @@ pub trait Parser<I, O, E> { /// assert_eq!(recognize_parser.parse_peek(Located::new("abcd")), consumed_parser.parse_peek(Located::new("abcd"))); /// # } /// ``` + #[inline(always)] fn with_span(self) -> WithSpan<Self, I, O, E> where Self: core::marker::Sized, @@ -370,6 +378,7 @@ pub trait Parser<I, O, E> { /// assert_eq!(parser.parse_peek("abc"), Err(ErrMode::Backtrack(InputError::new("abc", ErrorKind::Slice)))); /// # } /// ``` + #[inline(always)] fn map<G, O2>(self, map: G) -> Map<Self, G, I, O, O2, E> where G: Fn(O) -> O2, @@ -399,6 +408,7 @@ pub trait Parser<I, O, E> { /// assert_eq!(parse.parse_peek("123456"), Err(ErrMode::Backtrack(InputError::new("123456", ErrorKind::Verify)))); /// # } /// ``` + #[inline(always)] fn try_map<G, O2, E2>(self, map: G) -> TryMap<Self, G, I, O, O2, E, E2> where Self: core::marker::Sized, @@ -433,6 +443,7 @@ pub trait Parser<I, O, E> { #[doc(alias = "satisfy_map")] #[doc(alias = "filter_map")] #[doc(alias = "map_opt")] + #[inline(always)] fn verify_map<G, O2>(self, map: G) -> VerifyMap<Self, G, I, O, O2, E> where Self: core::marker::Sized, @@ -475,6 +486,7 @@ pub trait Parser<I, O, E> { /// assert_eq!(length_data.parse_peek(&[2, 0, 1, 2][..]), Ok((&[2][..], &[0, 1][..]))); /// assert_eq!(length_data.parse_peek(&[4, 0, 1, 2][..]), Err(ErrMode::Backtrack(InputError::new(&[0, 1, 2][..], ErrorKind::Slice)))); /// ``` + #[inline(always)] fn flat_map<G, H, O2>(self, map: G) -> FlatMap<Self, G, H, I, O, O2, E> where Self: core::marker::Sized, @@ -501,6 +513,7 @@ pub trait Parser<I, O, E> { /// assert_eq!(digits.parse_peek("123"), Err(ErrMode::Backtrack(InputError::new("123", ErrorKind::Slice)))); /// # } /// ``` + #[inline(always)] fn and_then<G, O2>(self, inner: G) -> AndThen<Self, G, I, O, O2, E> where Self: core::marker::Sized, @@ -531,6 +544,7 @@ pub trait Parser<I, O, E> { /// assert_eq!(parser.parse_peek("abc"), Err(ErrMode::Backtrack(InputError::new("abc", ErrorKind::Slice)))); /// ``` #[doc(alias = "from_str")] + #[inline(always)] fn parse_to<O2>(self) -> ParseTo<Self, I, O, O2, E> where Self: core::marker::Sized, @@ -562,6 +576,7 @@ pub trait Parser<I, O, E> { /// ``` #[doc(alias = "satisfy")] #[doc(alias = "filter")] + #[inline(always)] fn verify<G, O2>(self, filter: G) -> Verify<Self, G, I, O, O2, E> where Self: core::marker::Sized, @@ -579,6 +594,7 @@ pub trait Parser<I, O, E> { /// This is used mainly to add user friendly information /// to errors when backtracking through a parse tree. #[doc(alias = "labelled")] + #[inline(always)] fn context<C>(self, context: C) -> Context<Self, I, O, E, C> where Self: core::marker::Sized, @@ -604,6 +620,7 @@ pub trait Parser<I, O, E> { /// assert_eq!(parser.parse_peek(Partial::new("abcd")), Err(ErrMode::Backtrack(InputError::new(Partial::new("abcd"), ErrorKind::Complete)))); /// # } /// ``` + #[inline(always)] fn complete_err(self) -> CompleteErr<Self> where Self: core::marker::Sized, @@ -612,6 +629,7 @@ pub trait Parser<I, O, E> { } /// Convert the parser's error to another type using [`std::convert::From`] + #[inline(always)] fn err_into<E2>(self) -> ErrInto<Self, I, O, E, E2> where Self: core::marker::Sized, diff --git a/vendor/winnow/src/stream/mod.rs b/vendor/winnow/src/stream/mod.rs index fcacbd78f..5f2152e27 100644 --- a/vendor/winnow/src/stream/mod.rs +++ b/vendor/winnow/src/stream/mod.rs @@ -2684,7 +2684,35 @@ fn memchr(token: u8, slice: &[u8]) -> Option<usize> { #[cfg(feature = "simd")] #[inline(always)] fn memmem(slice: &[u8], tag: &[u8]) -> Option<usize> { - memchr::memmem::find(slice, tag) + if tag.len() > slice.len() { + return None; + } + + 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(""). + None => return Some(0), + }; + + if substr_rest.is_empty() { + return memchr::memchr(substr_first, slice); + } + + let mut offset = 0; + let haystack = &slice[..slice.len() - substr_rest.len()]; + + 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); + } + + offset = next_offset; + } + + None } #[cfg(not(feature = "simd"))] diff --git a/vendor/winnow/src/trace/internals.rs b/vendor/winnow/src/trace/internals.rs index b990ae7c7..c38b11eea 100644 --- a/vendor/winnow/src/trace/internals.rs +++ b/vendor/winnow/src/trace/internals.rs @@ -4,6 +4,63 @@ use std::io::Write; use crate::error::ErrMode; use crate::stream::Stream; +use crate::*; + +pub struct Trace<P, D, I, O, E> +where + P: Parser<I, O, E>, + I: Stream, + D: std::fmt::Display, +{ + parser: P, + name: D, + call_count: usize, + i: core::marker::PhantomData<I>, + o: core::marker::PhantomData<O>, + e: core::marker::PhantomData<E>, +} + +impl<P, D, I, O, E> Trace<P, D, I, O, E> +where + P: Parser<I, O, E>, + I: Stream, + D: std::fmt::Display, +{ + #[inline(always)] + pub fn new(parser: P, name: D) -> Self { + Self { + parser, + name, + call_count: 0, + i: Default::default(), + o: Default::default(), + e: Default::default(), + } + } +} + +impl<P, D, I, O, E> Parser<I, O, E> for Trace<P, D, I, O, E> +where + P: Parser<I, O, E>, + I: Stream, + D: std::fmt::Display, +{ + #[inline] + fn parse_next(&mut self, i: &mut I) -> PResult<O, E> { + let depth = Depth::new(); + let original = i.checkpoint(); + start(*depth, &self.name, self.call_count, i); + + let res = self.parser.parse_next(i); + + let consumed = i.offset_from(&original); + let severity = Severity::with_result(&res); + end(*depth, &self.name, self.call_count, consumed, severity); + self.call_count += 1; + + res + } +} pub struct Depth { depth: usize, @@ -107,7 +164,7 @@ pub fn start<I: Stream>( (debug_slice, eof) }; - let writer = anstyle_stream::stderr(); + let writer = anstream::stderr(); let mut writer = writer.lock(); let _ = writeln!( writer, @@ -159,7 +216,7 @@ pub fn end( ), }; - let writer = anstyle_stream::stderr(); + let writer = anstream::stderr(); let mut writer = writer.lock(); let _ = writeln!( writer, @@ -197,7 +254,7 @@ pub fn result(depth: usize, name: &dyn crate::lib::std::fmt::Display, severity: ), }; - let writer = anstyle_stream::stderr(); + let writer = anstream::stderr(); let mut writer = writer.lock(); let _ = writeln!( writer, diff --git a/vendor/winnow/src/trace/mod.rs b/vendor/winnow/src/trace/mod.rs index 316733e9a..cd96e0258 100644 --- a/vendor/winnow/src/trace/mod.rs +++ b/vendor/winnow/src/trace/mod.rs @@ -49,25 +49,11 @@ compile_error!("`debug` requires `std`"); #[cfg_attr(not(feature = "debug"), inline(always))] pub fn trace<I: Stream, O, E>( name: impl crate::lib::std::fmt::Display, - mut parser: impl Parser<I, O, E>, + parser: impl Parser<I, O, E>, ) -> impl Parser<I, O, E> { #[cfg(feature = "debug")] { - let mut call_count = 0; - move |i: &mut I| { - let depth = internals::Depth::new(); - let original = i.checkpoint(); - internals::start(*depth, &name, call_count, i); - - let res = parser.parse_next(i); - - let consumed = i.offset_from(&original); - let severity = internals::Severity::with_result(&res); - internals::end(*depth, &name, call_count, consumed, severity); - call_count += 1; - - res - } + internals::Trace::new(parser, name) } #[cfg(not(feature = "debug"))] { |