diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-07 05:48:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-07 05:48:48 +0000 |
commit | ef24de24a82fe681581cc130f342363c47c0969a (patch) | |
tree | 0d494f7e1a38b95c92426f58fe6eaa877303a86c /vendor/winnow-0.4.7/src/token | |
parent | Releasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip |
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/winnow-0.4.7/src/token')
-rw-r--r-- | vendor/winnow-0.4.7/src/token/mod.rs | 1009 | ||||
-rw-r--r-- | vendor/winnow-0.4.7/src/token/tests.rs | 700 |
2 files changed, 1709 insertions, 0 deletions
diff --git a/vendor/winnow-0.4.7/src/token/mod.rs b/vendor/winnow-0.4.7/src/token/mod.rs new file mode 100644 index 000000000..6f99dfa8d --- /dev/null +++ b/vendor/winnow-0.4.7/src/token/mod.rs @@ -0,0 +1,1009 @@ +//! Parsers extracting tokens from the stream + +#[cfg(test)] +mod tests; + +use crate::error::ErrMode; +use crate::error::ErrorKind; +use crate::error::Needed; +use crate::error::ParseError; +use crate::lib::std::result::Result::Ok; +use crate::stream::Range; +use crate::stream::{ + split_at_offset1_complete, split_at_offset1_partial, split_at_offset_complete, + split_at_offset_partial, Compare, CompareResult, ContainsToken, FindSlice, SliceLen, Stream, +}; +use crate::stream::{StreamIsPartial, ToUsize}; +use crate::trace::trace; +use crate::IResult; +use crate::Parser; + +/// Matches one token +/// +/// *Complete version*: Will return an error if there's not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{token::any, error::ErrMode, error::{Error, ErrorKind}}; +/// # use winnow::prelude::*; +/// fn parser(input: &str) -> IResult<&str, char> { +/// any.parse_next(input) +/// } +/// +/// assert_eq!(parser("abc"), Ok(("bc",'a'))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Token)))); +/// ``` +/// +/// ```rust +/// # use winnow::{token::any, error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// assert_eq!(any::<_, Error<_>>.parse_next(Partial::new("abc")), Ok((Partial::new("bc"),'a'))); +/// assert_eq!(any::<_, Error<_>>.parse_next(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +#[doc(alias = "token")] +pub fn any<I, E: ParseError<I>>(input: I) -> IResult<I, <I as Stream>::Token, E> +where + I: StreamIsPartial, + I: Stream, +{ + trace("any", move |input: I| { + if <I as StreamIsPartial>::is_partial_supported() { + any_::<_, _, true>(input) + } else { + any_::<_, _, true>(input) + } + }) + .parse_next(input) +} + +fn any_<I, E: ParseError<I>, const PARTIAL: bool>(input: I) -> IResult<I, <I as Stream>::Token, E> +where + I: StreamIsPartial, + I: Stream, +{ + input.next_token().ok_or_else(|| { + if PARTIAL && input.is_partial() { + ErrMode::Incomplete(Needed::new(1)) + } else { + ErrMode::from_error_kind(input, ErrorKind::Token) + } + }) +} + +/// Recognizes a literal +/// +/// The input data will be compared to the tag combinator's argument and will return the part of +/// the input that matches the argument +/// +/// It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Tag)))` if the input doesn't match the pattern +/// +/// **Note:** [`Parser`][crate::Parser] is implemented for strings and byte strings as a convenience (complete +/// only) +/// +/// # Example +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, &str> { +/// "Hello".parse_next(s) +/// } +/// +/// assert_eq!(parser("Hello, World!"), Ok((", World!", "Hello"))); +/// assert_eq!(parser("Something"), Err(ErrMode::Backtrack(Error::new("Something", ErrorKind::Tag)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); +/// ``` +/// +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::Partial; +/// use winnow::token::tag; +/// +/// fn parser(s: Partial<&str>) -> IResult<Partial<&str>, &str> { +/// "Hello".parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new("Hello, World!")), Ok((Partial::new(", World!"), "Hello"))); +/// assert_eq!(parser(Partial::new("Something")), Err(ErrMode::Backtrack(Error::new(Partial::new("Something"), ErrorKind::Tag)))); +/// assert_eq!(parser(Partial::new("S")), Err(ErrMode::Backtrack(Error::new(Partial::new("S"), ErrorKind::Tag)))); +/// assert_eq!(parser(Partial::new("H")), Err(ErrMode::Incomplete(Needed::new(4)))); +/// ``` +#[inline(always)] +#[doc(alias = "literal")] +#[doc(alias = "bytes")] +#[doc(alias = "just")] +pub fn tag<T, I, Error: ParseError<I>>(tag: T) -> impl Parser<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream + Compare<T>, + T: SliceLen + Clone, +{ + trace("tag", move |i: I| { + let t = tag.clone(); + if <I as StreamIsPartial>::is_partial_supported() { + tag_::<_, _, _, true>(i, t) + } else { + tag_::<_, _, _, false>(i, t) + } + }) +} + +fn tag_<T, I, Error: ParseError<I>, const PARTIAL: bool>( + i: I, + t: T, +) -> IResult<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream + Compare<T>, + T: SliceLen, +{ + let tag_len = t.slice_len(); + match i.compare(t) { + CompareResult::Ok => Ok(i.next_slice(tag_len)), + CompareResult::Incomplete if PARTIAL && i.is_partial() => { + Err(ErrMode::Incomplete(Needed::new(tag_len - i.eof_offset()))) + } + CompareResult::Incomplete | CompareResult::Error => { + let e: ErrorKind = ErrorKind::Tag; + Err(ErrMode::from_error_kind(i, e)) + } + } +} + +/// Recognizes a case insensitive literal. +/// +/// The input data will be compared to the tag combinator's argument and will return the part of +/// the input that matches the argument with no regard to case. +/// +/// It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Tag)))` if the input doesn't match the pattern. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::tag_no_case; +/// +/// fn parser(s: &str) -> IResult<&str, &str> { +/// tag_no_case("hello").parse_next(s) +/// } +/// +/// assert_eq!(parser("Hello, World!"), Ok((", World!", "Hello"))); +/// assert_eq!(parser("hello, World!"), Ok((", World!", "hello"))); +/// assert_eq!(parser("HeLlO, World!"), Ok((", World!", "HeLlO"))); +/// assert_eq!(parser("Something"), Err(ErrMode::Backtrack(Error::new("Something", ErrorKind::Tag)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::tag_no_case; +/// +/// fn parser(s: Partial<&str>) -> IResult<Partial<&str>, &str> { +/// tag_no_case("hello").parse_next(s) +/// } +/// +/// assert_eq!(parser(Partial::new("Hello, World!")), Ok((Partial::new(", World!"), "Hello"))); +/// assert_eq!(parser(Partial::new("hello, World!")), Ok((Partial::new(", World!"), "hello"))); +/// assert_eq!(parser(Partial::new("HeLlO, World!")), Ok((Partial::new(", World!"), "HeLlO"))); +/// assert_eq!(parser(Partial::new("Something")), Err(ErrMode::Backtrack(Error::new(Partial::new("Something"), ErrorKind::Tag)))); +/// assert_eq!(parser(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(5)))); +/// ``` +#[inline(always)] +#[doc(alias = "literal")] +#[doc(alias = "bytes")] +#[doc(alias = "just")] +pub fn tag_no_case<T, I, Error: ParseError<I>>( + tag: T, +) -> impl Parser<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream + Compare<T>, + T: SliceLen + Clone, +{ + trace("tag_no_case", move |i: I| { + let t = tag.clone(); + if <I as StreamIsPartial>::is_partial_supported() { + tag_no_case_::<_, _, _, true>(i, t) + } else { + tag_no_case_::<_, _, _, false>(i, t) + } + }) +} + +fn tag_no_case_<T, I, Error: ParseError<I>, const PARTIAL: bool>( + i: I, + t: T, +) -> IResult<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream + Compare<T>, + T: SliceLen, +{ + let tag_len = t.slice_len(); + + match (i).compare_no_case(t) { + CompareResult::Ok => Ok(i.next_slice(tag_len)), + CompareResult::Incomplete if PARTIAL && i.is_partial() => { + Err(ErrMode::Incomplete(Needed::new(tag_len - i.eof_offset()))) + } + CompareResult::Incomplete | CompareResult::Error => { + let e: ErrorKind = ErrorKind::Tag; + Err(ErrMode::from_error_kind(i, e)) + } + } +} + +/// Recognize a token that matches the [pattern][ContainsToken] +/// +/// **Note:** [`Parser`][crate::Parser] is implemented as a convenience (complete +/// only) for +/// - `u8` +/// - `char` +/// +/// *Complete version*: Will return an error if there's not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error}; +/// # use winnow::token::one_of; +/// assert_eq!(one_of::<_, _, Error<_>>("abc").parse_next("b"), Ok(("", 'b'))); +/// assert_eq!(one_of::<_, _, Error<_>>("a").parse_next("bc"), Err(ErrMode::Backtrack(Error::new("bc", ErrorKind::Verify)))); +/// assert_eq!(one_of::<_, _, Error<_>>("a").parse_next(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Token)))); +/// +/// fn parser_fn(i: &str) -> IResult<&str, char> { +/// one_of(|c| c == 'a' || c == 'b').parse_next(i) +/// } +/// assert_eq!(parser_fn("abc"), Ok(("bc", 'a'))); +/// assert_eq!(parser_fn("cd"), Err(ErrMode::Backtrack(Error::new("cd", ErrorKind::Verify)))); +/// assert_eq!(parser_fn(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Token)))); +/// ``` +/// +/// ``` +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::Partial; +/// # use winnow::token::one_of; +/// assert_eq!(one_of::<_, _, Error<_>>("abc").parse_next(Partial::new("b")), Ok((Partial::new(""), 'b'))); +/// assert_eq!(one_of::<_, _, Error<_>>("a").parse_next(Partial::new("bc")), Err(ErrMode::Backtrack(Error::new(Partial::new("bc"), ErrorKind::Verify)))); +/// assert_eq!(one_of::<_, _, Error<_>>("a").parse_next(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// +/// fn parser_fn(i: Partial<&str>) -> IResult<Partial<&str>, char> { +/// one_of(|c| c == 'a' || c == 'b').parse_next(i) +/// } +/// assert_eq!(parser_fn(Partial::new("abc")), Ok((Partial::new("bc"), 'a'))); +/// assert_eq!(parser_fn(Partial::new("cd")), Err(ErrMode::Backtrack(Error::new(Partial::new("cd"), ErrorKind::Verify)))); +/// assert_eq!(parser_fn(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +#[doc(alias = "char")] +#[doc(alias = "token")] +#[doc(alias = "satisfy")] +pub fn one_of<I, T, Error: ParseError<I>>(list: T) -> impl Parser<I, <I as Stream>::Token, Error> +where + I: StreamIsPartial, + I: Stream, + <I as Stream>::Token: Copy, + T: ContainsToken<<I as Stream>::Token>, +{ + trace( + "one_of", + any.verify(move |t: &<I as Stream>::Token| list.contains_token(*t)), + ) +} + +/// Recognize a token that does not match the [pattern][ContainsToken] +/// +/// *Complete version*: Will return an error if there's not enough input data. +/// +/// *Partial version*: Will return `Err(winnow::error::ErrMode::Incomplete(_))` if there's not enough input data. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error}; +/// # use winnow::prelude::*; +/// # use winnow::token::none_of; +/// assert_eq!(none_of::<_, _, Error<_>>("abc").parse_next("z"), Ok(("", 'z'))); +/// assert_eq!(none_of::<_, _, Error<_>>("ab").parse_next("a"), Err(ErrMode::Backtrack(Error::new("a", ErrorKind::Verify)))); +/// assert_eq!(none_of::<_, _, Error<_>>("a").parse_next(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Token)))); +/// ``` +/// +/// ``` +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// # use winnow::token::none_of; +/// assert_eq!(none_of::<_, _, Error<_>>("abc").parse_next(Partial::new("z")), Ok((Partial::new(""), 'z'))); +/// assert_eq!(none_of::<_, _, Error<_>>("ab").parse_next(Partial::new("a")), Err(ErrMode::Backtrack(Error::new(Partial::new("a"), ErrorKind::Verify)))); +/// assert_eq!(none_of::<_, _, Error<_>>("a").parse_next(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn none_of<I, T, Error: ParseError<I>>(list: T) -> impl Parser<I, <I as Stream>::Token, Error> +where + I: StreamIsPartial, + I: Stream, + <I as Stream>::Token: Copy, + T: ContainsToken<<I as Stream>::Token>, +{ + trace( + "none_of", + any.verify(move |t: &<I as Stream>::Token| !list.contains_token(*t)), + ) +} + +/// Recognize the longest (m <= len <= n) input slice that matches the [pattern][ContainsToken] +/// +/// It will return an `ErrMode::Backtrack(Error::new(_, ErrorKind::Slice))` if the pattern wasn't met or is out +/// of range (m <= len <= n). +/// +/// *Partial version* will return a `ErrMode::Incomplete(Needed::new(1))` if the pattern reaches the end of the input or is too short. +/// +/// To recognize a series of tokens, use [`repeat`][crate::combinator::repeat] to [`Accumulate`][crate::stream::Accumulate] into a `()` and then [`Parser::recognize`][crate::Parser::recognize]. +/// +/// # Example +/// +/// Zero or more tokens: +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::take_while; +/// use winnow::stream::AsChar; +/// +/// fn alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { +/// take_while(0.., AsChar::is_alpha).parse_next(s) +/// } +/// +/// assert_eq!(alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); +/// assert_eq!(alpha(b"12345"), Ok((&b"12345"[..], &b""[..]))); +/// assert_eq!(alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); +/// assert_eq!(alpha(b""), Ok((&b""[..], &b""[..]))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::take_while; +/// use winnow::stream::AsChar; +/// +/// fn alpha(s: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { +/// take_while(0.., AsChar::is_alpha).parse_next(s) +/// } +/// +/// assert_eq!(alpha(Partial::new(b"latin123")), Ok((Partial::new(&b"123"[..]), &b"latin"[..]))); +/// assert_eq!(alpha(Partial::new(b"12345")), Ok((Partial::new(&b"12345"[..]), &b""[..]))); +/// assert_eq!(alpha(Partial::new(b"latin")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(alpha(Partial::new(b"")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +/// +/// One or more tokens: +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::take_while; +/// use winnow::stream::AsChar; +/// +/// fn alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { +/// take_while(1.., AsChar::is_alpha).parse_next(s) +/// } +/// +/// assert_eq!(alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); +/// assert_eq!(alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); +/// assert_eq!(alpha(b"12345"), Err(ErrMode::Backtrack(Error::new(&b"12345"[..], ErrorKind::Slice)))); +/// +/// fn hex(s: &str) -> IResult<&str, &str> { +/// take_while(1.., "1234567890ABCDEF").parse_next(s) +/// } +/// +/// assert_eq!(hex("123 and voila"), Ok((" and voila", "123"))); +/// assert_eq!(hex("DEADBEEF and others"), Ok((" and others", "DEADBEEF"))); +/// assert_eq!(hex("BADBABEsomething"), Ok(("something", "BADBABE"))); +/// assert_eq!(hex("D15EA5E"), Ok(("", "D15EA5E"))); +/// assert_eq!(hex(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::take_while; +/// use winnow::stream::AsChar; +/// +/// fn alpha(s: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { +/// take_while(1.., AsChar::is_alpha).parse_next(s) +/// } +/// +/// assert_eq!(alpha(Partial::new(b"latin123")), Ok((Partial::new(&b"123"[..]), &b"latin"[..]))); +/// assert_eq!(alpha(Partial::new(b"latin")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(alpha(Partial::new(b"12345")), Err(ErrMode::Backtrack(Error::new(Partial::new(&b"12345"[..]), ErrorKind::Slice)))); +/// +/// fn hex(s: Partial<&str>) -> IResult<Partial<&str>, &str> { +/// take_while(1.., "1234567890ABCDEF").parse_next(s) +/// } +/// +/// assert_eq!(hex(Partial::new("123 and voila")), Ok((Partial::new(" and voila"), "123"))); +/// assert_eq!(hex(Partial::new("DEADBEEF and others")), Ok((Partial::new(" and others"), "DEADBEEF"))); +/// assert_eq!(hex(Partial::new("BADBABEsomething")), Ok((Partial::new("something"), "BADBABE"))); +/// assert_eq!(hex(Partial::new("D15EA5E")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(hex(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +/// +/// Arbitrary amount of tokens: +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::take_while; +/// use winnow::stream::AsChar; +/// +/// fn short_alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { +/// take_while(3..=6, AsChar::is_alpha).parse_next(s) +/// } +/// +/// assert_eq!(short_alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); +/// assert_eq!(short_alpha(b"lengthy"), Ok((&b"y"[..], &b"length"[..]))); +/// assert_eq!(short_alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); +/// assert_eq!(short_alpha(b"ed"), Err(ErrMode::Backtrack(Error::new(&b"ed"[..], ErrorKind::Slice)))); +/// assert_eq!(short_alpha(b"12345"), Err(ErrMode::Backtrack(Error::new(&b"12345"[..], ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::take_while; +/// use winnow::stream::AsChar; +/// +/// fn short_alpha(s: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { +/// take_while(3..=6, AsChar::is_alpha).parse_next(s) +/// } +/// +/// assert_eq!(short_alpha(Partial::new(b"latin123")), Ok((Partial::new(&b"123"[..]), &b"latin"[..]))); +/// assert_eq!(short_alpha(Partial::new(b"lengthy")), Ok((Partial::new(&b"y"[..]), &b"length"[..]))); +/// assert_eq!(short_alpha(Partial::new(b"latin")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(short_alpha(Partial::new(b"ed")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(short_alpha(Partial::new(b"12345")), Err(ErrMode::Backtrack(Error::new(Partial::new(&b"12345"[..]), ErrorKind::Slice)))); +/// ``` +#[inline(always)] +#[doc(alias = "is_a")] +#[doc(alias = "take_while0")] +#[doc(alias = "take_while1")] +pub fn take_while<T, I, Error: ParseError<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_while", move |i: I| { + match (start_inclusive, end_inclusive) { + (0, None) => { + if <I as StreamIsPartial>::is_partial_supported() { + take_while0_::<_, _, _, true>(i, &list) + } else { + take_while0_::<_, _, _, false>(i, &list) + } + } + (1, None) => { + if <I as StreamIsPartial>::is_partial_supported() { + take_while1_::<_, _, _, true>(i, &list) + } else { + take_while1_::<_, _, _, false>(i, &list) + } + } + (start, end) => { + let end = end.unwrap_or(usize::MAX); + if <I as StreamIsPartial>::is_partial_supported() { + take_while_m_n_::<_, _, _, true>(i, start, end, &list) + } else { + take_while_m_n_::<_, _, _, false>(i, start, end, &list) + } + } + } + }) +} + +/// Deprecated, see [`take_while`] +#[deprecated(since = "0.4.6", note = "Replaced with `take_while`")] +#[inline(always)] +pub fn take_while0<T, I, Error: ParseError<I>>( + list: T, +) -> impl Parser<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<<I as Stream>::Token>, +{ + take_while(0.., list) +} + +/// Deprecated, see [`take_while`] +#[deprecated(since = "0.4.6", note = "Replaced with `take_while`")] +#[inline(always)] +pub fn take_while1<T, I, Error: ParseError<I>>( + list: T, +) -> impl Parser<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<<I as Stream>::Token>, +{ + take_while(1.., list) +} + +fn take_while0_<T, I, Error: ParseError<I>, const PARTIAL: bool>( + input: I, + list: &T, +) -> IResult<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<<I as Stream>::Token>, +{ + if PARTIAL && input.is_partial() { + split_at_offset_partial(&input, |c| !list.contains_token(c)) + } else { + split_at_offset_complete(&input, |c| !list.contains_token(c)) + } +} + +fn take_while1_<T, I, Error: ParseError<I>, const PARTIAL: bool>( + input: I, + list: &T, +) -> IResult<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<<I as Stream>::Token>, +{ + let e: ErrorKind = ErrorKind::Slice; + if PARTIAL && input.is_partial() { + split_at_offset1_partial(&input, |c| !list.contains_token(c), e) + } else { + split_at_offset1_complete(&input, |c| !list.contains_token(c), e) + } +} + +fn take_while_m_n_<T, I, Error: ParseError<I>, const PARTIAL: bool>( + input: I, + m: usize, + n: usize, + list: &T, +) -> IResult<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<<I as Stream>::Token>, +{ + if n < m { + return Err(ErrMode::assert(input, "`m` should be <= `n`")); + } + + let mut final_count = 0; + for (processed, (offset, token)) in input.iter_offsets().enumerate() { + if !list.contains_token(token) { + if processed < m { + return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); + } else { + return Ok(input.next_slice(offset)); + } + } else { + if processed == n { + return Ok(input.next_slice(offset)); + } + final_count = processed + 1; + } + } + if PARTIAL && input.is_partial() { + if final_count == n { + Ok(input.next_slice(input.eof_offset())) + } else { + let needed = if m > input.eof_offset() { + m - input.eof_offset() + } else { + 1 + }; + Err(ErrMode::Incomplete(Needed::new(needed))) + } + } else { + if m <= final_count { + Ok(input.next_slice(input.eof_offset())) + } else { + Err(ErrMode::from_error_kind(input, ErrorKind::Slice)) + } + } +} + +/// Recognize the longest input slice (if any) till a [pattern][ContainsToken] is met. +/// +/// *Partial version* will return a `ErrMode::Incomplete(Needed::new(1))` if the match reaches the +/// end of input or if there was not match. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::take_till0; +/// +/// fn till_colon(s: &str) -> IResult<&str, &str> { +/// take_till0(|c| c == ':').parse_next(s) +/// } +/// +/// assert_eq!(till_colon("latin:123"), Ok((":123", "latin"))); +/// assert_eq!(till_colon(":empty matched"), Ok((":empty matched", ""))); //allowed +/// assert_eq!(till_colon("12345"), Ok(("", "12345"))); +/// assert_eq!(till_colon(""), Ok(("", ""))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::take_till0; +/// +/// fn till_colon(s: Partial<&str>) -> IResult<Partial<&str>, &str> { +/// take_till0(|c| c == ':').parse_next(s) +/// } +/// +/// assert_eq!(till_colon(Partial::new("latin:123")), Ok((Partial::new(":123"), "latin"))); +/// assert_eq!(till_colon(Partial::new(":empty matched")), Ok((Partial::new(":empty matched"), ""))); //allowed +/// assert_eq!(till_colon(Partial::new("12345")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(till_colon(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +pub fn take_till0<T, I, Error: ParseError<I>>( + list: T, +) -> impl Parser<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<<I as Stream>::Token>, +{ + trace("take_till0", move |i: I| { + if <I as StreamIsPartial>::is_partial_supported() && i.is_partial() { + split_at_offset_partial(&i, |c| list.contains_token(c)) + } else { + split_at_offset_complete(&i, |c| list.contains_token(c)) + } + }) +} + +/// Recognize the longest (at least 1) input slice till a [pattern][ContainsToken] is met. +/// +/// It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Slice)))` if the input is empty or the +/// predicate matches the first input. +/// +/// *Partial version* will return a `ErrMode::Incomplete(Needed::new(1))` if the match reaches the +/// end of input or if there was not match. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::take_till1; +/// +/// fn till_colon(s: &str) -> IResult<&str, &str> { +/// take_till1(|c| c == ':').parse_next(s) +/// } +/// +/// assert_eq!(till_colon("latin:123"), Ok((":123", "latin"))); +/// assert_eq!(till_colon(":empty matched"), Err(ErrMode::Backtrack(Error::new(":empty matched", ErrorKind::Slice)))); +/// assert_eq!(till_colon("12345"), Ok(("", "12345"))); +/// assert_eq!(till_colon(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// +/// fn not_space(s: &str) -> IResult<&str, &str> { +/// take_till1(" \t\r\n").parse_next(s) +/// } +/// +/// assert_eq!(not_space("Hello, World!"), Ok((" World!", "Hello,"))); +/// assert_eq!(not_space("Sometimes\t"), Ok(("\t", "Sometimes"))); +/// assert_eq!(not_space("Nospace"), Ok(("", "Nospace"))); +/// assert_eq!(not_space(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::take_till1; +/// +/// fn till_colon(s: Partial<&str>) -> IResult<Partial<&str>, &str> { +/// take_till1(|c| c == ':').parse_next(s) +/// } +/// +/// assert_eq!(till_colon(Partial::new("latin:123")), Ok((Partial::new(":123"), "latin"))); +/// assert_eq!(till_colon(Partial::new(":empty matched")), Err(ErrMode::Backtrack(Error::new(Partial::new(":empty matched"), ErrorKind::Slice)))); +/// assert_eq!(till_colon(Partial::new("12345")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(till_colon(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// +/// fn not_space(s: Partial<&str>) -> IResult<Partial<&str>, &str> { +/// take_till1(" \t\r\n").parse_next(s) +/// } +/// +/// assert_eq!(not_space(Partial::new("Hello, World!")), Ok((Partial::new(" World!"), "Hello,"))); +/// assert_eq!(not_space(Partial::new("Sometimes\t")), Ok((Partial::new("\t"), "Sometimes"))); +/// assert_eq!(not_space(Partial::new("Nospace")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(not_space(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +#[doc(alias = "is_not")] +pub fn take_till1<T, I, Error: ParseError<I>>( + list: T, +) -> impl Parser<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<<I as Stream>::Token>, +{ + trace("take_till1", move |i: I| { + let e: ErrorKind = ErrorKind::Slice; + if <I as StreamIsPartial>::is_partial_supported() && i.is_partial() { + split_at_offset1_partial(&i, |c| list.contains_token(c), e) + } else { + split_at_offset1_complete(&i, |c| list.contains_token(c), e) + } + }) +} + +/// Recognize an input slice containing the first N input elements (I[..N]). +/// +/// *Complete version*: It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Slice)))` if the input is shorter than the argument. +/// +/// *Partial version*: if the input has less than N elements, `take` will +/// return a `ErrMode::Incomplete(Needed::new(M))` where M is the number of +/// additional bytes the parser would need to succeed. +/// It is well defined for `&[u8]` as the number of elements is the byte size, +/// but for types like `&str`, we cannot know how many bytes correspond for +/// the next few chars, so the result will be `ErrMode::Incomplete(Needed::Unknown)` +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::take; +/// +/// fn take6(s: &str) -> IResult<&str, &str> { +/// take(6usize).parse_next(s) +/// } +/// +/// assert_eq!(take6("1234567"), Ok(("7", "123456"))); +/// assert_eq!(take6("things"), Ok(("", "things"))); +/// assert_eq!(take6("short"), Err(ErrMode::Backtrack(Error::new("short", ErrorKind::Slice)))); +/// assert_eq!(take6(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// ``` +/// +/// The units that are taken will depend on the input type. For example, for a +/// `&str` it will take a number of `char`'s, whereas for a `&[u8]` it will +/// take that many `u8`'s: +/// +/// ```rust +/// # use winnow::prelude::*; +/// use winnow::error::Error; +/// use winnow::token::take; +/// +/// assert_eq!(take::<_, _, Error<_>>(1usize).parse_next("💙"), Ok(("", "💙"))); +/// assert_eq!(take::<_, _, Error<_>>(1usize).parse_next("💙".as_bytes()), Ok((b"\x9F\x92\x99".as_ref(), b"\xF0".as_ref()))); +/// ``` +/// +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::Partial; +/// use winnow::token::take; +/// +/// fn take6(s: Partial<&str>) -> IResult<Partial<&str>, &str> { +/// take(6usize).parse_next(s) +/// } +/// +/// assert_eq!(take6(Partial::new("1234567")), Ok((Partial::new("7"), "123456"))); +/// assert_eq!(take6(Partial::new("things")), Ok((Partial::new(""), "things"))); +/// // `Unknown` as we don't know the number of bytes that `count` corresponds to +/// assert_eq!(take6(Partial::new("short")), Err(ErrMode::Incomplete(Needed::Unknown))); +/// ``` +#[inline(always)] +pub fn take<C, I, Error: ParseError<I>>(count: C) -> impl Parser<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + C: ToUsize, +{ + let c = count.to_usize(); + trace("take", move |i: I| { + if <I as StreamIsPartial>::is_partial_supported() { + take_::<_, _, true>(i, c) + } else { + take_::<_, _, false>(i, c) + } + }) +} + +fn take_<I, Error: ParseError<I>, const PARTIAL: bool>( + i: I, + c: usize, +) -> IResult<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream, +{ + match i.offset_at(c) { + Ok(offset) => Ok(i.next_slice(offset)), + Err(e) if PARTIAL && i.is_partial() => Err(ErrMode::Incomplete(e)), + Err(_needed) => Err(ErrMode::from_error_kind(i, ErrorKind::Slice)), + } +} + +/// Recognize the input slice up to the first occurrence of the literal. +/// +/// It doesn't consume the pattern. +/// +/// *Complete version*: It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Slice)))` +/// if the pattern wasn't met. +/// +/// *Partial version*: will return a `ErrMode::Incomplete(Needed::new(N))` if the input doesn't +/// contain the pattern or if the input is smaller than the pattern. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::take_until0; +/// +/// fn until_eof(s: &str) -> IResult<&str, &str> { +/// take_until0("eof").parse_next(s) +/// } +/// +/// assert_eq!(until_eof("hello, worldeof"), Ok(("eof", "hello, world"))); +/// assert_eq!(until_eof("hello, world"), Err(ErrMode::Backtrack(Error::new("hello, world", ErrorKind::Slice)))); +/// assert_eq!(until_eof(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// assert_eq!(until_eof("1eof2eof"), Ok(("eof2eof", "1"))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Error, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::take_until0; +/// +/// fn until_eof(s: Partial<&str>) -> IResult<Partial<&str>, &str> { +/// take_until0("eof").parse_next(s) +/// } +/// +/// assert_eq!(until_eof(Partial::new("hello, worldeof")), Ok((Partial::new("eof"), "hello, world"))); +/// assert_eq!(until_eof(Partial::new("hello, world")), Err(ErrMode::Incomplete(Needed::Unknown))); +/// assert_eq!(until_eof(Partial::new("hello, worldeo")), Err(ErrMode::Incomplete(Needed::Unknown))); +/// assert_eq!(until_eof(Partial::new("1eof2eof")), Ok((Partial::new("eof2eof"), "1"))); +/// ``` +#[inline(always)] +pub fn take_until0<T, I, Error: ParseError<I>>( + tag: T, +) -> impl Parser<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream + FindSlice<T>, + T: SliceLen + Clone, +{ + trace("take_until0", move |i: I| { + if <I as StreamIsPartial>::is_partial_supported() { + take_until0_::<_, _, _, true>(i, tag.clone()) + } else { + take_until0_::<_, _, _, false>(i, tag.clone()) + } + }) +} + +fn take_until0_<T, I, Error: ParseError<I>, const PARTIAL: bool>( + i: I, + t: T, +) -> IResult<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream + FindSlice<T>, + T: SliceLen, +{ + match i.find_slice(t) { + Some(offset) => Ok(i.next_slice(offset)), + None if PARTIAL && i.is_partial() => Err(ErrMode::Incomplete(Needed::Unknown)), + None => Err(ErrMode::from_error_kind(i, ErrorKind::Slice)), + } +} + +/// Recognize the non empty input slice up to the first occurrence of the literal. +/// +/// It doesn't consume the pattern. +/// +/// *Complete version*: It will return `Err(ErrMode::Backtrack(Error::new(_, ErrorKind::Slice)))` +/// if the pattern wasn't met. +/// +/// *Partial version*: will return a `ErrMode::Incomplete(Needed::new(N))` if the input doesn't +/// contain the pattern or if the input is smaller than the pattern. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::take_until1; +/// +/// fn until_eof(s: &str) -> IResult<&str, &str> { +/// take_until1("eof").parse_next(s) +/// } +/// +/// assert_eq!(until_eof("hello, worldeof"), Ok(("eof", "hello, world"))); +/// assert_eq!(until_eof("hello, world"), Err(ErrMode::Backtrack(Error::new("hello, world", ErrorKind::Slice)))); +/// assert_eq!(until_eof(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Slice)))); +/// assert_eq!(until_eof("1eof2eof"), Ok(("eof2eof", "1"))); +/// assert_eq!(until_eof("eof"), Err(ErrMode::Backtrack(Error::new("eof", ErrorKind::Slice)))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::take_until1; +/// +/// fn until_eof(s: Partial<&str>) -> IResult<Partial<&str>, &str> { +/// take_until1("eof").parse_next(s) +/// } +/// +/// assert_eq!(until_eof(Partial::new("hello, worldeof")), Ok((Partial::new("eof"), "hello, world"))); +/// assert_eq!(until_eof(Partial::new("hello, world")), Err(ErrMode::Incomplete(Needed::Unknown))); +/// assert_eq!(until_eof(Partial::new("hello, worldeo")), Err(ErrMode::Incomplete(Needed::Unknown))); +/// assert_eq!(until_eof(Partial::new("1eof2eof")), Ok((Partial::new("eof2eof"), "1"))); +/// assert_eq!(until_eof(Partial::new("eof")), Err(ErrMode::Backtrack(Error::new(Partial::new("eof"), ErrorKind::Slice)))); +/// ``` +#[inline(always)] +pub fn take_until1<T, I, Error: ParseError<I>>( + tag: T, +) -> impl Parser<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream + FindSlice<T>, + T: SliceLen + Clone, +{ + trace("take_until1", move |i: I| { + if <I as StreamIsPartial>::is_partial_supported() { + take_until1_::<_, _, _, true>(i, tag.clone()) + } else { + take_until1_::<_, _, _, false>(i, tag.clone()) + } + }) +} + +fn take_until1_<T, I, Error: ParseError<I>, const PARTIAL: bool>( + i: I, + t: T, +) -> IResult<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream + FindSlice<T>, + T: SliceLen, +{ + match i.find_slice(t) { + None if PARTIAL && i.is_partial() => Err(ErrMode::Incomplete(Needed::Unknown)), + None | Some(0) => Err(ErrMode::from_error_kind(i, ErrorKind::Slice)), + Some(offset) => Ok(i.next_slice(offset)), + } +} diff --git a/vendor/winnow-0.4.7/src/token/tests.rs b/vendor/winnow-0.4.7/src/token/tests.rs new file mode 100644 index 000000000..e1c7999c2 --- /dev/null +++ b/vendor/winnow-0.4.7/src/token/tests.rs @@ -0,0 +1,700 @@ +use super::*; + +#[cfg(feature = "std")] +use proptest::prelude::*; + +use crate::binary::length_data; +use crate::combinator::delimited; +use crate::error::ErrMode; +use crate::error::Error; +use crate::error::ErrorKind; +use crate::error::Needed; +use crate::stream::AsChar; +use crate::token::tag; +use crate::IResult; +use crate::Parser; +use crate::Partial; + +#[test] +fn complete_take_while_m_n_utf8_all_matching() { + let result: IResult<&str, &str> = + take_while(1..=4, |c: char| c.is_alphabetic()).parse_next("øn"); + assert_eq!(result, Ok(("", "øn"))); +} + +#[test] +fn complete_take_while_m_n_utf8_all_matching_substring() { + let result: IResult<&str, &str> = take_while(1, |c: char| c.is_alphabetic()).parse_next("øn"); + assert_eq!(result, Ok(("n", "ø"))); +} + +#[cfg(feature = "std")] +fn model_complete_take_while_m_n( + m: usize, + n: usize, + valid: usize, + input: &str, +) -> IResult<&str, &str> { + if n < m { + Err(crate::error::ErrMode::from_error_kind( + input, + crate::error::ErrorKind::Slice, + )) + } else if m <= valid { + let offset = n.min(valid); + Ok((&input[offset..], &input[0..offset])) + } else { + Err(crate::error::ErrMode::from_error_kind( + input, + crate::error::ErrorKind::Slice, + )) + } +} + +#[cfg(feature = "std")] +proptest! { + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn complete_take_while_m_n_bounds(m in 0..20usize, n in 0..20usize, valid in 0..20usize, invalid in 0..20usize) { + let input = format!("{:a<valid$}{:b<invalid$}", "", "", valid=valid, invalid=invalid); + let expected = model_complete_take_while_m_n(m, n, valid, &input); + if m <= n { + let actual = take_while(m..=n, |c: char| c == 'a').parse_next(input.as_str()); + assert_eq!(expected, actual); + } + } +} + +#[test] +fn partial_any_str() { + use super::any; + assert_eq!( + any::<_, Error<Partial<&str>>>(Partial::new("Ә")), + Ok((Partial::new(""), 'Ә')) + ); +} + +#[test] +fn partial_one_of_test() { + fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, u8> { + one_of("ab").parse_next(i) + } + + let a = &b"abcd"[..]; + assert_eq!(f(Partial::new(a)), Ok((Partial::new(&b"bcd"[..]), b'a'))); + + let b = &b"cde"[..]; + assert_eq!( + f(Partial::new(b)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(b), + ErrorKind::Verify + ))) + ); + + fn utf8(i: Partial<&str>) -> IResult<Partial<&str>, char> { + one_of("+\u{FF0B}").parse_next(i) + } + + assert!(utf8(Partial::new("+")).is_ok()); + assert!(utf8(Partial::new("\u{FF0B}")).is_ok()); +} + +#[test] +fn char_byteslice() { + fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, u8> { + 'c'.parse_next(i) + } + + let a = &b"abcd"[..]; + assert_eq!( + f(Partial::new(a)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(a), + ErrorKind::Verify + ))) + ); + + let b = &b"cde"[..]; + assert_eq!(f(Partial::new(b)), Ok((Partial::new(&b"de"[..]), b'c'))); +} + +#[test] +fn char_str() { + fn f(i: Partial<&str>) -> IResult<Partial<&str>, char> { + 'c'.parse_next(i) + } + + let a = "abcd"; + assert_eq!( + f(Partial::new(a)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(a), + ErrorKind::Verify + ))) + ); + + let b = "cde"; + assert_eq!(f(Partial::new(b)), Ok((Partial::new("de"), 'c'))); +} + +#[test] +fn partial_none_of_test() { + fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, u8> { + none_of("ab").parse_next(i) + } + + let a = &b"abcd"[..]; + assert_eq!( + f(Partial::new(a)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(a), + ErrorKind::Verify + ))) + ); + + let b = &b"cde"[..]; + assert_eq!(f(Partial::new(b)), Ok((Partial::new(&b"de"[..]), b'c'))); +} + +#[test] +fn partial_is_a() { + fn a_or_b(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + take_while(1.., "ab").parse_next(i) + } + + let a = Partial::new(&b"abcd"[..]); + assert_eq!(a_or_b(a), Ok((Partial::new(&b"cd"[..]), &b"ab"[..]))); + + let b = Partial::new(&b"bcde"[..]); + assert_eq!(a_or_b(b), Ok((Partial::new(&b"cde"[..]), &b"b"[..]))); + + let c = Partial::new(&b"cdef"[..]); + assert_eq!( + a_or_b(c), + Err(ErrMode::Backtrack(error_position!(c, ErrorKind::Slice))) + ); + + let d = Partial::new(&b"bacdef"[..]); + assert_eq!(a_or_b(d), Ok((Partial::new(&b"cdef"[..]), &b"ba"[..]))); +} + +#[test] +fn partial_is_not() { + fn a_or_b(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + take_till1("ab").parse_next(i) + } + + let a = Partial::new(&b"cdab"[..]); + assert_eq!(a_or_b(a), Ok((Partial::new(&b"ab"[..]), &b"cd"[..]))); + + let b = Partial::new(&b"cbde"[..]); + assert_eq!(a_or_b(b), Ok((Partial::new(&b"bde"[..]), &b"c"[..]))); + + let c = Partial::new(&b"abab"[..]); + assert_eq!( + a_or_b(c), + Err(ErrMode::Backtrack(error_position!(c, ErrorKind::Slice))) + ); + + let d = Partial::new(&b"cdefba"[..]); + assert_eq!(a_or_b(d), Ok((Partial::new(&b"ba"[..]), &b"cdef"[..]))); + + let e = Partial::new(&b"e"[..]); + assert_eq!(a_or_b(e), Err(ErrMode::Incomplete(Needed::new(1)))); +} + +#[test] +fn partial_take_until_incomplete() { + fn y(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + take_until0("end").parse_next(i) + } + assert_eq!( + y(Partial::new(&b"nd"[..])), + Err(ErrMode::Incomplete(Needed::Unknown)) + ); + assert_eq!( + y(Partial::new(&b"123"[..])), + Err(ErrMode::Incomplete(Needed::Unknown)) + ); + assert_eq!( + y(Partial::new(&b"123en"[..])), + Err(ErrMode::Incomplete(Needed::Unknown)) + ); +} + +#[test] +fn partial_take_until_incomplete_s() { + fn ys(i: Partial<&str>) -> IResult<Partial<&str>, &str> { + take_until0("end").parse_next(i) + } + assert_eq!( + ys(Partial::new("123en")), + Err(ErrMode::Incomplete(Needed::Unknown)) + ); +} + +#[test] +fn partial_recognize() { + use crate::ascii::{ + alpha1 as alpha, alphanumeric1 as alphanumeric, digit1 as digit, hex_digit1 as hex_digit, + multispace1 as multispace, oct_digit1 as oct_digit, space1 as space, + }; + + fn x(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + delimited("<!--", take(5_usize), "-->") + .recognize() + .parse_next(i) + } + let r = x(Partial::new(&b"<!-- abc --> aaa"[..])); + assert_eq!(r, Ok((Partial::new(&b" aaa"[..]), &b"<!-- abc -->"[..]))); + + let semicolon = &b";"[..]; + + fn ya(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + alpha.recognize().parse_next(i) + } + let ra = ya(Partial::new(&b"abc;"[..])); + assert_eq!(ra, Ok((Partial::new(semicolon), &b"abc"[..]))); + + fn yd(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + digit.recognize().parse_next(i) + } + let rd = yd(Partial::new(&b"123;"[..])); + assert_eq!(rd, Ok((Partial::new(semicolon), &b"123"[..]))); + + fn yhd(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + hex_digit.recognize().parse_next(i) + } + let rhd = yhd(Partial::new(&b"123abcDEF;"[..])); + assert_eq!(rhd, Ok((Partial::new(semicolon), &b"123abcDEF"[..]))); + + fn yod(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + oct_digit.recognize().parse_next(i) + } + let rod = yod(Partial::new(&b"1234567;"[..])); + assert_eq!(rod, Ok((Partial::new(semicolon), &b"1234567"[..]))); + + fn yan(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + alphanumeric.recognize().parse_next(i) + } + let ran = yan(Partial::new(&b"123abc;"[..])); + assert_eq!(ran, Ok((Partial::new(semicolon), &b"123abc"[..]))); + + fn ys(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + space.recognize().parse_next(i) + } + let rs = ys(Partial::new(&b" \t;"[..])); + assert_eq!(rs, Ok((Partial::new(semicolon), &b" \t"[..]))); + + fn yms(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + multispace.recognize().parse_next(i) + } + let rms = yms(Partial::new(&b" \t\r\n;"[..])); + assert_eq!(rms, Ok((Partial::new(semicolon), &b" \t\r\n"[..]))); +} + +#[test] +fn partial_take_while0() { + fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + take_while(0.., AsChar::is_alpha).parse_next(i) + } + let a = &b""[..]; + let b = &b"abcd"[..]; + let c = &b"abcd123"[..]; + let d = &b"123"[..]; + + assert_eq!(f(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_eq!(f(Partial::new(b)), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_eq!(f(Partial::new(c)), Ok((Partial::new(d), b))); + assert_eq!(f(Partial::new(d)), Ok((Partial::new(d), a))); +} + +#[test] +fn partial_take_while1() { + fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + take_while(1.., AsChar::is_alpha).parse_next(i) + } + let a = &b""[..]; + let b = &b"abcd"[..]; + let c = &b"abcd123"[..]; + let d = &b"123"[..]; + + assert_eq!(f(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_eq!(f(Partial::new(b)), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_eq!(f(Partial::new(c)), Ok((Partial::new(&b"123"[..]), b))); + assert_eq!( + f(Partial::new(d)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(d), + ErrorKind::Slice + ))) + ); +} + +#[test] +fn partial_take_while_m_n() { + fn x(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + take_while(2..=4, AsChar::is_alpha).parse_next(i) + } + let a = &b""[..]; + let b = &b"a"[..]; + let c = &b"abc"[..]; + let d = &b"abc123"[..]; + let e = &b"abcde"[..]; + let f = &b"123"[..]; + + assert_eq!(x(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(2)))); + assert_eq!(x(Partial::new(b)), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_eq!(x(Partial::new(c)), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_eq!(x(Partial::new(d)), Ok((Partial::new(&b"123"[..]), c))); + assert_eq!( + x(Partial::new(e)), + Ok((Partial::new(&b"e"[..]), &b"abcd"[..])) + ); + assert_eq!( + x(Partial::new(f)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(f), + ErrorKind::Slice + ))) + ); +} + +#[test] +fn partial_take_till0() { + fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + take_till0(AsChar::is_alpha).parse_next(i) + } + let a = &b""[..]; + let b = &b"abcd"[..]; + let c = &b"123abcd"[..]; + let d = &b"123"[..]; + + assert_eq!(f(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_eq!( + f(Partial::new(b)), + Ok((Partial::new(&b"abcd"[..]), &b""[..])) + ); + assert_eq!( + f(Partial::new(c)), + Ok((Partial::new(&b"abcd"[..]), &b"123"[..])) + ); + assert_eq!(f(Partial::new(d)), Err(ErrMode::Incomplete(Needed::new(1)))); +} + +#[test] +fn partial_take_till1() { + fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + take_till1(AsChar::is_alpha).parse_next(i) + } + let a = &b""[..]; + let b = &b"abcd"[..]; + let c = &b"123abcd"[..]; + let d = &b"123"[..]; + + assert_eq!(f(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(1)))); + assert_eq!( + f(Partial::new(b)), + Err(ErrMode::Backtrack(error_position!( + Partial::new(b), + ErrorKind::Slice + ))) + ); + assert_eq!( + f(Partial::new(c)), + Ok((Partial::new(&b"abcd"[..]), &b"123"[..])) + ); + assert_eq!(f(Partial::new(d)), Err(ErrMode::Incomplete(Needed::new(1)))); +} + +#[test] +fn partial_take_while_utf8() { + fn f(i: Partial<&str>) -> IResult<Partial<&str>, &str> { + take_while(0.., |c| c != '點').parse_next(i) + } + + assert_eq!( + f(Partial::new("")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + f(Partial::new("abcd")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!(f(Partial::new("abcd點")), Ok((Partial::new("點"), "abcd"))); + assert_eq!( + f(Partial::new("abcd點a")), + Ok((Partial::new("點a"), "abcd")) + ); + + fn g(i: Partial<&str>) -> IResult<Partial<&str>, &str> { + take_while(0.., |c| c == '點').parse_next(i) + } + + assert_eq!( + g(Partial::new("")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!(g(Partial::new("點abcd")), Ok((Partial::new("abcd"), "點"))); + assert_eq!( + g(Partial::new("點點點a")), + Ok((Partial::new("a"), "點點點")) + ); +} + +#[test] +fn partial_take_till0_utf8() { + fn f(i: Partial<&str>) -> IResult<Partial<&str>, &str> { + take_till0(|c| c == '點').parse_next(i) + } + + assert_eq!( + f(Partial::new("")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + f(Partial::new("abcd")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!(f(Partial::new("abcd點")), Ok((Partial::new("點"), "abcd"))); + assert_eq!( + f(Partial::new("abcd點a")), + Ok((Partial::new("點a"), "abcd")) + ); + + fn g(i: Partial<&str>) -> IResult<Partial<&str>, &str> { + take_till0(|c| c != '點').parse_next(i) + } + + assert_eq!( + g(Partial::new("")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!(g(Partial::new("點abcd")), Ok((Partial::new("abcd"), "點"))); + assert_eq!( + g(Partial::new("點點點a")), + Ok((Partial::new("a"), "點點點")) + ); +} + +#[test] +fn partial_take_utf8() { + fn f(i: Partial<&str>) -> IResult<Partial<&str>, &str> { + take(3_usize).parse_next(i) + } + + assert_eq!( + f(Partial::new("")), + Err(ErrMode::Incomplete(Needed::Unknown)) + ); + assert_eq!( + f(Partial::new("ab")), + Err(ErrMode::Incomplete(Needed::Unknown)) + ); + assert_eq!( + f(Partial::new("點")), + Err(ErrMode::Incomplete(Needed::Unknown)) + ); + assert_eq!(f(Partial::new("ab點cd")), Ok((Partial::new("cd"), "ab點"))); + assert_eq!(f(Partial::new("a點bcd")), Ok((Partial::new("cd"), "a點b"))); + assert_eq!(f(Partial::new("a點b")), Ok((Partial::new(""), "a點b"))); + + fn g(i: Partial<&str>) -> IResult<Partial<&str>, &str> { + take_while(0.., |c| c == '點').parse_next(i) + } + + assert_eq!( + g(Partial::new("")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!(g(Partial::new("點abcd")), Ok((Partial::new("abcd"), "點"))); + assert_eq!( + g(Partial::new("點點點a")), + Ok((Partial::new("a"), "點點點")) + ); +} + +#[test] +fn partial_take_while_m_n_utf8_fixed() { + fn parser(i: Partial<&str>) -> IResult<Partial<&str>, &str> { + take_while(1, |c| c == 'A' || c == '😃').parse_next(i) + } + assert_eq!(parser(Partial::new("A!")), Ok((Partial::new("!"), "A"))); + assert_eq!(parser(Partial::new("😃!")), Ok((Partial::new("!"), "😃"))); +} + +#[test] +fn partial_take_while_m_n_utf8_range() { + fn parser(i: Partial<&str>) -> IResult<Partial<&str>, &str> { + take_while(1..=2, |c| c == 'A' || c == '😃').parse_next(i) + } + assert_eq!(parser(Partial::new("A!")), Ok((Partial::new("!"), "A"))); + assert_eq!(parser(Partial::new("😃!")), Ok((Partial::new("!"), "😃"))); +} + +#[test] +fn partial_take_while_m_n_utf8_full_match_fixed() { + fn parser(i: Partial<&str>) -> IResult<Partial<&str>, &str> { + take_while(1, |c: char| c.is_alphabetic()).parse_next(i) + } + assert_eq!(parser(Partial::new("øn")), Ok((Partial::new("n"), "ø"))); +} + +#[test] +fn partial_take_while_m_n_utf8_full_match_range() { + fn parser(i: Partial<&str>) -> IResult<Partial<&str>, &str> { + take_while(1..=2, |c: char| c.is_alphabetic()).parse_next(i) + } + assert_eq!(parser(Partial::new("øn")), Ok((Partial::new(""), "øn"))); +} + +#[test] +#[cfg(feature = "std")] +fn partial_recognize_take_while0() { + fn x(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + take_while(0.., AsChar::is_alphanum).parse_next(i) + } + fn y(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + x.recognize().parse_next(i) + } + assert_eq!( + x(Partial::new(&b"ab."[..])), + Ok((Partial::new(&b"."[..]), &b"ab"[..])) + ); + assert_eq!( + y(Partial::new(&b"ab."[..])), + Ok((Partial::new(&b"."[..]), &b"ab"[..])) + ); +} + +#[test] +fn partial_length_bytes() { + use crate::binary::le_u8; + + fn x(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + length_data(le_u8).parse_next(i) + } + assert_eq!( + x(Partial::new(b"\x02..>>")), + Ok((Partial::new(&b">>"[..]), &b".."[..])) + ); + assert_eq!( + x(Partial::new(b"\x02..")), + Ok((Partial::new(&[][..]), &b".."[..])) + ); + assert_eq!( + x(Partial::new(b"\x02.")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + x(Partial::new(b"\x02")), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + + fn y(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + let (i, _) = "magic".parse_next(i)?; + length_data(le_u8).parse_next(i) + } + assert_eq!( + y(Partial::new(b"magic\x02..>>")), + Ok((Partial::new(&b">>"[..]), &b".."[..])) + ); + assert_eq!( + y(Partial::new(b"magic\x02..")), + Ok((Partial::new(&[][..]), &b".."[..])) + ); + assert_eq!( + y(Partial::new(b"magic\x02.")), + Err(ErrMode::Incomplete(Needed::new(1))) + ); + assert_eq!( + y(Partial::new(b"magic\x02")), + Err(ErrMode::Incomplete(Needed::new(2))) + ); +} + +#[cfg(feature = "alloc")] +#[test] +fn partial_case_insensitive() { + fn test(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + tag_no_case("ABcd").parse_next(i) + } + assert_eq!( + test(Partial::new(&b"aBCdefgh"[..])), + Ok((Partial::new(&b"efgh"[..]), &b"aBCd"[..])) + ); + assert_eq!( + test(Partial::new(&b"abcdefgh"[..])), + Ok((Partial::new(&b"efgh"[..]), &b"abcd"[..])) + ); + assert_eq!( + test(Partial::new(&b"ABCDefgh"[..])), + Ok((Partial::new(&b"efgh"[..]), &b"ABCD"[..])) + ); + assert_eq!( + test(Partial::new(&b"ab"[..])), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_eq!( + test(Partial::new(&b"Hello"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"Hello"[..]), + ErrorKind::Tag + ))) + ); + assert_eq!( + test(Partial::new(&b"Hel"[..])), + Err(ErrMode::Backtrack(error_position!( + Partial::new(&b"Hel"[..]), + ErrorKind::Tag + ))) + ); + + fn test2(i: Partial<&str>) -> IResult<Partial<&str>, &str> { + tag_no_case("ABcd").parse_next(i) + } + assert_eq!( + test2(Partial::new("aBCdefgh")), + Ok((Partial::new("efgh"), "aBCd")) + ); + assert_eq!( + test2(Partial::new("abcdefgh")), + Ok((Partial::new("efgh"), "abcd")) + ); + assert_eq!( + test2(Partial::new("ABCDefgh")), + Ok((Partial::new("efgh"), "ABCD")) + ); + assert_eq!( + test2(Partial::new("ab")), + Err(ErrMode::Incomplete(Needed::new(2))) + ); + assert_eq!( + test2(Partial::new("Hello")), + Err(ErrMode::Backtrack(error_position!( + Partial::new("Hello"), + ErrorKind::Tag + ))) + ); + assert_eq!( + test2(Partial::new("Hel")), + Err(ErrMode::Backtrack(error_position!( + Partial::new("Hel"), + ErrorKind::Tag + ))) + ); +} + +#[test] +fn partial_tag_fixed_size_array() { + fn test(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + tag([0x42]).parse_next(i) + } + fn test2(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { + tag(&[0x42]).parse_next(i) + } + let input = Partial::new(&[0x42, 0x00][..]); + assert_eq!(test(input), Ok((Partial::new(&b"\x00"[..]), &b"\x42"[..]))); + assert_eq!(test2(input), Ok((Partial::new(&b"\x00"[..]), &b"\x42"[..]))); +} |