diff --git a/examples/json/bench.rs b/examples/json/bench.rs index f0633997..01bfda8b 100644 --- a/examples/json/bench.rs +++ b/examples/json/bench.rs @@ -1,3 +1,4 @@ +use winnow::prelude::*; use winnow::Partial; mod json; @@ -15,12 +16,12 @@ fn json_bench(c: &mut criterion::Criterion) { group.bench_with_input(criterion::BenchmarkId::new("basic", name), &len, |b, _| { type Error<'i> = winnow::error::Error>; - b.iter(|| parser::json::(sample).unwrap()); + b.iter(|| parser::json::.parse_peek(sample).unwrap()); }); group.bench_with_input(criterion::BenchmarkId::new("unit", name), &len, |b, _| { type Error<'i> = (); - b.iter(|| parser::json::(sample).unwrap()); + b.iter(|| parser::json::.parse_peek(sample).unwrap()); }); group.bench_with_input( criterion::BenchmarkId::new("verbose", name), @@ -28,7 +29,7 @@ fn json_bench(c: &mut criterion::Criterion) { |b, _| { type Error<'i> = winnow::error::VerboseError>; - b.iter(|| parser::json::(sample).unwrap()); + b.iter(|| parser::json::.parse_peek(sample).unwrap()); }, ); group.bench_with_input( @@ -37,7 +38,7 @@ fn json_bench(c: &mut criterion::Criterion) { |b, _| { type Error<'i> = winnow::error::Error>; - b.iter(|| parser_dispatch::json::(sample).unwrap()); + b.iter(|| parser_dispatch::json::.parse_peek(sample).unwrap()); }, ); group.bench_with_input( @@ -46,7 +47,11 @@ fn json_bench(c: &mut criterion::Criterion) { |b, _| { type Error<'i> = winnow::error::Error>; - b.iter(|| parser_partial::json::(Partial::new(sample)).unwrap()); + b.iter(|| { + parser_partial::json:: + .parse_peek(Partial::new(sample)) + .unwrap() + }); }, ); } diff --git a/examples/json/main.rs b/examples/json/main.rs index 04c9c9e8..f738a1f0 100644 --- a/examples/json/main.rs +++ b/examples/json/main.rs @@ -8,7 +8,6 @@ use winnow::error::convert_error; use winnow::error::Error; use winnow::error::VerboseError; use winnow::prelude::*; -use winnow::unpeek; fn main() -> Result<(), lexopt::Error> { let args = Args::parse()?; @@ -28,7 +27,7 @@ fn main() -> Result<(), lexopt::Error> { }); if args.verbose { - match unpeek(parser::json::>).parse(data) { + match parser::json::>.parse(data) { Ok(json) => { println!("{:#?}", json); } @@ -42,8 +41,8 @@ fn main() -> Result<(), lexopt::Error> { } } else { let result = match args.implementation { - Impl::Naive => unpeek(parser::json::>).parse(data), - Impl::Dispatch => unpeek(parser_dispatch::json::>).parse(data), + Impl::Naive => parser::json::>.parse(data), + Impl::Dispatch => parser_dispatch::json::>.parse(data), }; match result { Ok(json) => { diff --git a/examples/json/parser.rs b/examples/json/parser.rs index 4d1e339f..2dd30614 100644 --- a/examples/json/parser.rs +++ b/examples/json/parser.rs @@ -10,7 +10,6 @@ use winnow::{ combinator::{fold_repeat, separated0}, error::{ContextError, ParseError}, token::{any, none_of, take, take_while}, - unpeek, }; use crate::json::JsonValue; @@ -20,8 +19,8 @@ pub type Stream<'i> = &'i str; /// The root element of a JSON parser is any value /// /// A parser has the following signature: -/// `Stream -> IResult`, with `IResult` defined as: -/// `type IResult = Result<(I, O), Err>;` +/// `&mut Stream -> PResult`, with `PResult` defined as: +/// `type PResult = Result>;` /// /// most of the times you can ignore the error type and use the default (but this /// examples shows custom error types later on!) @@ -30,41 +29,41 @@ pub type Stream<'i> = &'i str; /// the input type, work directly with `&[u8]`, or any other type that /// implements the required traits. pub fn json<'i, E: ParseError> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, JsonValue, E> { - delimited(unpeek(ws), unpeek(json_value), unpeek(ws)).parse_peek(input) + input: &mut Stream<'i>, +) -> PResult { + delimited(ws, json_value, ws).parse_next(input) } /// `alt` is a combinator that tries multiple parsers one by one, until /// one of them succeeds fn json_value<'i, E: ParseError> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, JsonValue, E> { + input: &mut Stream<'i>, +) -> PResult { // `alt` combines the each value parser. It returns the result of the first // successful parser, or an error alt(( - unpeek(null).value(JsonValue::Null), - unpeek(boolean).map(JsonValue::Boolean), - unpeek(string).map(JsonValue::Str), + null.value(JsonValue::Null), + boolean.map(JsonValue::Boolean), + string.map(JsonValue::Str), float.map(JsonValue::Num), - unpeek(array).map(JsonValue::Array), - unpeek(object).map(JsonValue::Object), + array.map(JsonValue::Array), + object.map(JsonValue::Object), )) - .parse_peek(input) + .parse_next(input) } /// `tag(string)` generates a parser that recognizes the argument string. /// /// This also shows returning a sub-slice of the original input -fn null<'i, E: ParseError>>(input: Stream<'i>) -> IResult, &'i str, E> { +fn null<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult<&'i str, E> { // This is a parser that returns `"null"` if it sees the string "null", and // an error otherwise - "null".parse_peek(input) + "null".parse_next(input) } /// We can combine `tag` with other functions, like `value` which returns a given constant value on /// success. -fn boolean<'i, E: ParseError>>(input: Stream<'i>) -> IResult, bool, E> { +fn boolean<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult { // This is a parser that returns `true` if it sees the string "true", and // an error otherwise let parse_true = "true".value(true); @@ -73,14 +72,14 @@ fn boolean<'i, E: ParseError>>(input: Stream<'i>) -> IResult> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, String, E> { + input: &mut Stream<'i>, +) -> PResult { preceded( '\"', // `cut_err` transforms an `ErrMode::Backtrack(e)` to `ErrMode::Cut(e)`, signaling to @@ -88,7 +87,7 @@ fn string<'i, E: ParseError> + ContextError, &'static str> // right branch (since we found the `"` character) but encountered an error when // parsing the string cut_err(terminated( - fold_repeat(0.., unpeek(character), String::new, |mut string, c| { + fold_repeat(0.., character, String::new, |mut string, c| { string.push(c); string }), @@ -98,13 +97,13 @@ fn string<'i, E: ParseError> + ContextError, &'static str> // `context` lets you add a static string to errors to provide more information in the // error chain (to indicate which parser had an error) .context("string") - .parse_peek(input) + .parse_next(input) } /// You can mix the above declarative parsing with an imperative style to handle more unique cases, /// like escaping -fn character<'i, E: ParseError>>(input: Stream<'i>) -> IResult, char, E> { - let (input, c) = none_of('\"').parse_peek(input)?; +fn character<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult { + let c = none_of('\"').parse_next(input)?; if c == '\\' { alt(( any.verify_map(|c| { @@ -118,24 +117,22 @@ fn character<'i, E: ParseError>>(input: Stream<'i>) -> IResult return None, }) }), - preceded('u', unpeek(unicode_escape)), + preceded('u', unicode_escape), )) - .parse_peek(input) + .parse_next(input) } else { - Ok((input, c)) + Ok(c) } } -fn unicode_escape<'i, E: ParseError>>( - input: Stream<'i>, -) -> IResult, char, E> { +fn unicode_escape<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult { alt(( // Not a surrogate - unpeek(u16_hex) + u16_hex .verify(|cp| !(0xD800..0xE000).contains(cp)) .map(|cp| cp as u32), // See https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF for details - separated_pair(unpeek(u16_hex), "\\u", unpeek(u16_hex)) + separated_pair(u16_hex, "\\u", u16_hex) .verify(|(high, low)| (0xD800..0xDC00).contains(high) && (0xDC00..0xE000).contains(low)) .map(|(high, low)| { let high_ten = (high as u32) - 0xD800; @@ -147,13 +144,13 @@ fn unicode_escape<'i, E: ParseError>>( // Could be probably replaced with .unwrap() or _unchecked due to the verify checks std::char::from_u32, ) - .parse_peek(input) + .parse_next(input) } -fn u16_hex<'i, E: ParseError>>(input: Stream<'i>) -> IResult, u16, E> { +fn u16_hex<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult { take(4usize) .verify_map(|s| u16::from_str_radix(s, 16).ok()) - .parse_peek(input) + .parse_next(input) } /// Some combinators, like `separated0` or `many0`, will call a parser repeatedly, @@ -161,51 +158,40 @@ fn u16_hex<'i, E: ParseError>>(input: Stream<'i>) -> IResult> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, Vec, E> { + input: &mut Stream<'i>, +) -> PResult, E> { preceded( - ('[', unpeek(ws)), - cut_err(terminated( - separated0(unpeek(json_value), (unpeek(ws), ',', unpeek(ws))), - (unpeek(ws), ']'), - )), + ('[', ws), + cut_err(terminated(separated0(json_value, (ws, ',', ws)), (ws, ']'))), ) .context("array") - .parse_peek(input) + .parse_next(input) } fn object<'i, E: ParseError> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, HashMap, E> { + input: &mut Stream<'i>, +) -> PResult, E> { preceded( - ('{', unpeek(ws)), - cut_err(terminated( - separated0(unpeek(key_value), (unpeek(ws), ',', unpeek(ws))), - (unpeek(ws), '}'), - )), + ('{', ws), + cut_err(terminated(separated0(key_value, (ws, ',', ws)), (ws, '}'))), ) .context("object") - .parse_peek(input) + .parse_next(input) } fn key_value<'i, E: ParseError> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, (String, JsonValue), E> { - separated_pair( - unpeek(string), - cut_err((unpeek(ws), ':', unpeek(ws))), - unpeek(json_value), - ) - .parse_peek(input) + input: &mut Stream<'i>, +) -> PResult<(String, JsonValue), E> { + separated_pair(string, cut_err((ws, ':', ws)), json_value).parse_next(input) } /// Parser combinators are constructed from the bottom up: /// first we write parsers for the smallest elements (here a space character), /// then we'll combine them in larger parsers -fn ws<'i, E: ParseError>>(input: Stream<'i>) -> IResult, &'i str, E> { +fn ws<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult<&'i str, E> { // Combinators like `take_while` return a function. That function is the // parser,to which we can pass the input - take_while(0.., WS).parse_peek(input) + take_while(0.., WS).parse_next(input) } const WS: &[char] = &[' ', '\t', '\r', '\n']; @@ -222,24 +208,33 @@ mod test { #[test] fn json_string() { - assert_eq!(string::>("\"\""), Ok(("", "".to_string()))); - assert_eq!(string::>("\"abc\""), Ok(("", "abc".to_string()))); assert_eq!( - string::>("\"abc\\\"\\\\\\/\\b\\f\\n\\r\\t\\u0001\\u2014\u{2014}def\""), + string::>.parse_peek("\"\""), + Ok(("", "".to_string())) + ); + assert_eq!( + string::>.parse_peek("\"abc\""), + Ok(("", "abc".to_string())) + ); + assert_eq!( + string::> + .parse_peek("\"abc\\\"\\\\\\/\\b\\f\\n\\r\\t\\u0001\\u2014\u{2014}def\""), Ok(("", "abc\"\\/\x08\x0C\n\r\t\x01β€”β€”def".to_string())), ); assert_eq!( - string::>("\"\\uD83D\\uDE10\""), + string::>.parse_peek("\"\\uD83D\\uDE10\""), Ok(("", "😐".to_string())) ); - assert!(string::>("\"").is_err()); - assert!(string::>("\"abc").is_err()); - assert!(string::>("\"\\\"").is_err()); - assert!(string::>("\"\\u123\"").is_err()); - assert!(string::>("\"\\uD800\"").is_err()); - assert!(string::>("\"\\uD800\\uD800\"").is_err()); - assert!(string::>("\"\\uDC00\"").is_err()); + assert!(string::>.parse_peek("\"").is_err()); + assert!(string::>.parse_peek("\"abc").is_err()); + assert!(string::>.parse_peek("\"\\\"").is_err()); + assert!(string::>.parse_peek("\"\\u123\"").is_err()); + assert!(string::>.parse_peek("\"\\uD800\"").is_err()); + assert!(string::> + .parse_peek("\"\\uD800\\uD800\"") + .is_err()); + assert!(string::>.parse_peek("\"\\uDC00\"").is_err()); } #[test] @@ -257,7 +252,7 @@ mod test { .collect(), ); - assert_eq!(json::>(input), Ok(("", expected))); + assert_eq!(json::>.parse_peek(input), Ok(("", expected))); } #[test] @@ -268,7 +263,7 @@ mod test { let expected = Array(vec![Num(42.0), Str("x".to_string())]); - assert_eq!(json::>(input), Ok(("", expected))); + assert_eq!(json::>.parse_peek(input), Ok(("", expected))); } #[test] @@ -290,7 +285,7 @@ mod test { "#; assert_eq!( - json::>(input), + json::>.parse_peek(input), Ok(( "", Object( diff --git a/examples/json/parser_dispatch.rs b/examples/json/parser_dispatch.rs index e05d55fd..58aa3680 100644 --- a/examples/json/parser_dispatch.rs +++ b/examples/json/parser_dispatch.rs @@ -13,7 +13,6 @@ use winnow::{ combinator::{fold_repeat, separated0}, error::{ContextError, ParseError}, token::{any, none_of, take, take_while}, - unpeek, }; use crate::json::JsonValue; @@ -33,63 +32,63 @@ pub type Stream<'i> = &'i str; /// the input type, work directly with `&[u8]`, or any other type that /// implements the required traits. pub fn json<'i, E: ParseError> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, JsonValue, E> { - delimited(unpeek(ws), unpeek(json_value), unpeek(ws)).parse_peek(input) + input: &mut Stream<'i>, +) -> PResult { + delimited(ws, json_value, ws).parse_next(input) } /// `alt` is a combinator that tries multiple parsers one by one, until /// one of them succeeds fn json_value<'i, E: ParseError> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, JsonValue, E> { + input: &mut Stream<'i>, +) -> PResult { // `dispatch` gives you `match`-like behavior compared to `alt` successively trying different // implementations. dispatch!(peek(any); - 'n' => unpeek(null).value(JsonValue::Null), - 't' => unpeek(true_).map(JsonValue::Boolean), - 'f' => unpeek(false_).map(JsonValue::Boolean), - '"' => unpeek(string).map(JsonValue::Str), + 'n' => null.value(JsonValue::Null), + 't' => true_.map(JsonValue::Boolean), + 'f' => false_.map(JsonValue::Boolean), + '"' => string.map(JsonValue::Str), '+' => float.map(JsonValue::Num), '-' => float.map(JsonValue::Num), '0'..='9' => float.map(JsonValue::Num), - '[' => unpeek(array).map(JsonValue::Array), - '{' => unpeek(object).map(JsonValue::Object), + '[' => array.map(JsonValue::Array), + '{' => object.map(JsonValue::Object), _ => fail, ) - .parse_peek(input) + .parse_next(input) } /// `tag(string)` generates a parser that recognizes the argument string. /// /// This also shows returning a sub-slice of the original input -fn null<'i, E: ParseError>>(input: Stream<'i>) -> IResult, &'i str, E> { +fn null<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult<&'i str, E> { // This is a parser that returns `"null"` if it sees the string "null", and // an error otherwise - "null".parse_peek(input) + "null".parse_next(input) } /// We can combine `tag` with other functions, like `value` which returns a given constant value on /// success. -fn true_<'i, E: ParseError>>(input: Stream<'i>) -> IResult, bool, E> { +fn true_<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult { // This is a parser that returns `true` if it sees the string "true", and // an error otherwise - "true".value(true).parse_peek(input) + "true".value(true).parse_next(input) } /// We can combine `tag` with other functions, like `value` which returns a given constant value on /// success. -fn false_<'i, E: ParseError>>(input: Stream<'i>) -> IResult, bool, E> { +fn false_<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult { // This is a parser that returns `false` if it sees the string "false", and // an error otherwise - "false".value(false).parse_peek(input) + "false".value(false).parse_next(input) } /// This parser gathers all `char`s up into a `String`with a parse to recognize the double quote /// character, before the string (using `preceded`) and after the string (using `terminated`). fn string<'i, E: ParseError> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, String, E> { + input: &mut Stream<'i>, +) -> PResult { preceded( '\"', // `cut_err` transforms an `ErrMode::Backtrack(e)` to `ErrMode::Cut(e)`, signaling to @@ -97,7 +96,7 @@ fn string<'i, E: ParseError> + ContextError, &'static str> // right branch (since we found the `"` character) but encountered an error when // parsing the string cut_err(terminated( - fold_repeat(0.., unpeek(character), String::new, |mut string, c| { + fold_repeat(0.., character, String::new, |mut string, c| { string.push(c); string }), @@ -107,13 +106,13 @@ fn string<'i, E: ParseError> + ContextError, &'static str> // `context` lets you add a static string to errors to provide more information in the // error chain (to indicate which parser had an error) .context("string") - .parse_peek(input) + .parse_next(input) } /// You can mix the above declarative parsing with an imperative style to handle more unique cases, /// like escaping -fn character<'i, E: ParseError>>(input: Stream<'i>) -> IResult, char, E> { - let (input, c) = none_of('\"').parse_peek(input)?; +fn character<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult { + let c = none_of('\"').parse_next(input)?; if c == '\\' { dispatch!(any; '"' => success('"'), @@ -124,25 +123,23 @@ fn character<'i, E: ParseError>>(input: Stream<'i>) -> IResult success('\n'), 'r' => success('\r'), 't' => success('\t'), - 'u' => unpeek(unicode_escape), + 'u' => unicode_escape, _ => fail, ) - .parse_peek(input) + .parse_next(input) } else { - Ok((input, c)) + Ok(c) } } -fn unicode_escape<'i, E: ParseError>>( - input: Stream<'i>, -) -> IResult, char, E> { +fn unicode_escape<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult { alt(( // Not a surrogate - unpeek(u16_hex) + u16_hex .verify(|cp| !(0xD800..0xE000).contains(cp)) .map(|cp| cp as u32), // See https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF for details - separated_pair(unpeek(u16_hex), "\\u", unpeek(u16_hex)) + separated_pair(u16_hex, "\\u", u16_hex) .verify(|(high, low)| (0xD800..0xDC00).contains(high) && (0xDC00..0xE000).contains(low)) .map(|(high, low)| { let high_ten = (high as u32) - 0xD800; @@ -154,13 +151,13 @@ fn unicode_escape<'i, E: ParseError>>( // Could be probably replaced with .unwrap() or _unchecked due to the verify checks std::char::from_u32, ) - .parse_peek(input) + .parse_next(input) } -fn u16_hex<'i, E: ParseError>>(input: Stream<'i>) -> IResult, u16, E> { +fn u16_hex<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult { take(4usize) .verify_map(|s| u16::from_str_radix(s, 16).ok()) - .parse_peek(input) + .parse_next(input) } /// Some combinators, like `separated0` or `many0`, will call a parser repeatedly, @@ -168,51 +165,40 @@ fn u16_hex<'i, E: ParseError>>(input: Stream<'i>) -> IResult> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, Vec, E> { + input: &mut Stream<'i>, +) -> PResult, E> { preceded( - ('[', unpeek(ws)), - cut_err(terminated( - separated0(unpeek(json_value), (unpeek(ws), ',', unpeek(ws))), - (unpeek(ws), ']'), - )), + ('[', ws), + cut_err(terminated(separated0(json_value, (ws, ',', ws)), (ws, ']'))), ) .context("array") - .parse_peek(input) + .parse_next(input) } fn object<'i, E: ParseError> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, HashMap, E> { + input: &mut Stream<'i>, +) -> PResult, E> { preceded( - ('{', unpeek(ws)), - cut_err(terminated( - separated0(unpeek(key_value), (unpeek(ws), ',', unpeek(ws))), - (unpeek(ws), '}'), - )), + ('{', ws), + cut_err(terminated(separated0(key_value, (ws, ',', ws)), (ws, '}'))), ) .context("object") - .parse_peek(input) + .parse_next(input) } fn key_value<'i, E: ParseError> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, (String, JsonValue), E> { - separated_pair( - unpeek(string), - cut_err((unpeek(ws), ':', unpeek(ws))), - unpeek(json_value), - ) - .parse_peek(input) + input: &mut Stream<'i>, +) -> PResult<(String, JsonValue), E> { + separated_pair(string, cut_err((ws, ':', ws)), json_value).parse_next(input) } /// Parser combinators are constructed from the bottom up: /// first we write parsers for the smallest elements (here a space character), /// then we'll combine them in larger parsers -fn ws<'i, E: ParseError>>(input: Stream<'i>) -> IResult, &'i str, E> { +fn ws<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult<&'i str, E> { // Combinators like `take_while` return a function. That function is the // parser,to which we can pass the input - take_while(0.., WS).parse_peek(input) + take_while(0.., WS).parse_next(input) } const WS: &[char] = &[' ', '\t', '\r', '\n']; @@ -229,24 +215,33 @@ mod test { #[test] fn json_string() { - assert_eq!(string::>("\"\""), Ok(("", "".to_string()))); - assert_eq!(string::>("\"abc\""), Ok(("", "abc".to_string()))); assert_eq!( - string::>("\"abc\\\"\\\\\\/\\b\\f\\n\\r\\t\\u0001\\u2014\u{2014}def\""), + string::>.parse_peek("\"\""), + Ok(("", "".to_string())) + ); + assert_eq!( + string::>.parse_peek("\"abc\""), + Ok(("", "abc".to_string())) + ); + assert_eq!( + string::> + .parse_peek("\"abc\\\"\\\\\\/\\b\\f\\n\\r\\t\\u0001\\u2014\u{2014}def\""), Ok(("", "abc\"\\/\x08\x0C\n\r\t\x01β€”β€”def".to_string())), ); assert_eq!( - string::>("\"\\uD83D\\uDE10\""), + string::>.parse_peek("\"\\uD83D\\uDE10\""), Ok(("", "😐".to_string())) ); - assert!(string::>("\"").is_err()); - assert!(string::>("\"abc").is_err()); - assert!(string::>("\"\\\"").is_err()); - assert!(string::>("\"\\u123\"").is_err()); - assert!(string::>("\"\\uD800\"").is_err()); - assert!(string::>("\"\\uD800\\uD800\"").is_err()); - assert!(string::>("\"\\uDC00\"").is_err()); + assert!(string::>.parse_peek("\"").is_err()); + assert!(string::>.parse_peek("\"abc").is_err()); + assert!(string::>.parse_peek("\"\\\"").is_err()); + assert!(string::>.parse_peek("\"\\u123\"").is_err()); + assert!(string::>.parse_peek("\"\\uD800\"").is_err()); + assert!(string::> + .parse_peek("\"\\uD800\\uD800\"") + .is_err()); + assert!(string::>.parse_peek("\"\\uDC00\"").is_err()); } #[test] @@ -264,7 +259,7 @@ mod test { .collect(), ); - assert_eq!(json::>(input), Ok(("", expected))); + assert_eq!(json::>.parse_peek(input), Ok(("", expected))); } #[test] @@ -275,7 +270,7 @@ mod test { let expected = Array(vec![Num(42.0), Str("x".to_string())]); - assert_eq!(json::>(input), Ok(("", expected))); + assert_eq!(json::>.parse_peek(input), Ok(("", expected))); } #[test] @@ -297,7 +292,7 @@ mod test { "#; assert_eq!( - json::>(input), + json::>.parse_peek(input), Ok(( "", Object( diff --git a/examples/json/parser_partial.rs b/examples/json/parser_partial.rs index 5c54b38f..fb9142f4 100644 --- a/examples/json/parser_partial.rs +++ b/examples/json/parser_partial.rs @@ -11,7 +11,6 @@ use winnow::{ error::{ContextError, ParseError}, stream::Partial, token::{any, none_of, take, take_while}, - unpeek, }; use crate::json::JsonValue; @@ -31,41 +30,41 @@ pub type Stream<'i> = Partial<&'i str>; /// the input type, work directly with `&[u8]`, or any other type that /// implements the required traits. pub fn json<'i, E: ParseError> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, JsonValue, E> { - delimited(unpeek(ws), unpeek(json_value), unpeek(ws_or_eof)).parse_peek(input) + input: &mut Stream<'i>, +) -> PResult { + delimited(ws, json_value, ws_or_eof).parse_next(input) } /// `alt` is a combinator that tries multiple parsers one by one, until /// one of them succeeds fn json_value<'i, E: ParseError> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, JsonValue, E> { + input: &mut Stream<'i>, +) -> PResult { // `alt` combines the each value parser. It returns the result of the first // successful parser, or an error alt(( - unpeek(null).value(JsonValue::Null), - unpeek(boolean).map(JsonValue::Boolean), - unpeek(string).map(JsonValue::Str), + null.value(JsonValue::Null), + boolean.map(JsonValue::Boolean), + string.map(JsonValue::Str), float.map(JsonValue::Num), - unpeek(array).map(JsonValue::Array), - unpeek(object).map(JsonValue::Object), + array.map(JsonValue::Array), + object.map(JsonValue::Object), )) - .parse_peek(input) + .parse_next(input) } /// `tag(string)` generates a parser that recognizes the argument string. /// /// This also shows returning a sub-slice of the original input -fn null<'i, E: ParseError>>(input: Stream<'i>) -> IResult, &'i str, E> { +fn null<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult<&'i str, E> { // This is a parser that returns `"null"` if it sees the string "null", and // an error otherwise - "null".parse_peek(input) + "null".parse_next(input) } /// We can combine `tag` with other functions, like `value` which returns a given constant value on /// success. -fn boolean<'i, E: ParseError>>(input: Stream<'i>) -> IResult, bool, E> { +fn boolean<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult { // This is a parser that returns `true` if it sees the string "true", and // an error otherwise let parse_true = "true".value(true); @@ -74,14 +73,14 @@ fn boolean<'i, E: ParseError>>(input: Stream<'i>) -> IResult> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, String, E> { + input: &mut Stream<'i>, +) -> PResult { preceded( '\"', // `cut_err` transforms an `ErrMode::Backtrack(e)` to `ErrMode::Cut(e)`, signaling to @@ -89,7 +88,7 @@ fn string<'i, E: ParseError> + ContextError, &'static str> // right branch (since we found the `"` character) but encountered an error when // parsing the string cut_err(terminated( - fold_repeat(0.., unpeek(character), String::new, |mut string, c| { + fold_repeat(0.., character, String::new, |mut string, c| { string.push(c); string }), @@ -99,13 +98,13 @@ fn string<'i, E: ParseError> + ContextError, &'static str> // `context` lets you add a static string to errors to provide more information in the // error chain (to indicate which parser had an error) .context("string") - .parse_peek(input) + .parse_next(input) } /// You can mix the above declarative parsing with an imperative style to handle more unique cases, /// like escaping -fn character<'i, E: ParseError>>(input: Stream<'i>) -> IResult, char, E> { - let (input, c) = none_of('\"').parse_peek(input)?; +fn character<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult { + let c = none_of('\"').parse_next(input)?; if c == '\\' { alt(( any.verify_map(|c| { @@ -119,24 +118,22 @@ fn character<'i, E: ParseError>>(input: Stream<'i>) -> IResult return None, }) }), - preceded('u', unpeek(unicode_escape)), + preceded('u', unicode_escape), )) - .parse_peek(input) + .parse_next(input) } else { - Ok((input, c)) + Ok(c) } } -fn unicode_escape<'i, E: ParseError>>( - input: Stream<'i>, -) -> IResult, char, E> { +fn unicode_escape<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult { alt(( // Not a surrogate - unpeek(u16_hex) + u16_hex .verify(|cp| !(0xD800..0xE000).contains(cp)) .map(|cp| cp as u32), // See https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF for details - separated_pair(unpeek(u16_hex), "\\u", unpeek(u16_hex)) + separated_pair(u16_hex, "\\u", u16_hex) .verify(|(high, low)| (0xD800..0xDC00).contains(high) && (0xDC00..0xE000).contains(low)) .map(|(high, low)| { let high_ten = (high as u32) - 0xD800; @@ -148,13 +145,13 @@ fn unicode_escape<'i, E: ParseError>>( // Could be probably replaced with .unwrap() or _unchecked due to the verify checks std::char::from_u32, ) - .parse_peek(input) + .parse_next(input) } -fn u16_hex<'i, E: ParseError>>(input: Stream<'i>) -> IResult, u16, E> { +fn u16_hex<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult { take(4usize) .verify_map(|s| u16::from_str_radix(s, 16).ok()) - .parse_peek(input) + .parse_next(input) } /// Some combinators, like `separated0` or `many0`, will call a parser repeatedly, @@ -162,56 +159,45 @@ fn u16_hex<'i, E: ParseError>>(input: Stream<'i>) -> IResult> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, Vec, E> { + input: &mut Stream<'i>, +) -> PResult, E> { preceded( - ('[', unpeek(ws)), - cut_err(terminated( - separated0(unpeek(json_value), (unpeek(ws), ',', unpeek(ws))), - (unpeek(ws), ']'), - )), + ('[', ws), + cut_err(terminated(separated0(json_value, (ws, ',', ws)), (ws, ']'))), ) .context("array") - .parse_peek(input) + .parse_next(input) } fn object<'i, E: ParseError> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, HashMap, E> { + input: &mut Stream<'i>, +) -> PResult, E> { preceded( - ('{', unpeek(ws)), - cut_err(terminated( - separated0(unpeek(key_value), (unpeek(ws), ',', unpeek(ws))), - (unpeek(ws), '}'), - )), + ('{', ws), + cut_err(terminated(separated0(key_value, (ws, ',', ws)), (ws, '}'))), ) .context("object") - .parse_peek(input) + .parse_next(input) } fn key_value<'i, E: ParseError> + ContextError, &'static str>>( - input: Stream<'i>, -) -> IResult, (String, JsonValue), E> { - separated_pair( - unpeek(string), - cut_err((unpeek(ws), ':', unpeek(ws))), - unpeek(json_value), - ) - .parse_peek(input) + input: &mut Stream<'i>, +) -> PResult<(String, JsonValue), E> { + separated_pair(string, cut_err((ws, ':', ws)), json_value).parse_next(input) } /// Parser combinators are constructed from the bottom up: /// first we write parsers for the smallest elements (here a space character), /// then we'll combine them in larger parsers -fn ws<'i, E: ParseError>>(input: Stream<'i>) -> IResult, &'i str, E> { +fn ws<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult<&'i str, E> { // Combinators like `take_while` return a function. That function is the // parser,to which we can pass the input - take_while(0.., WS).parse_peek(input) + take_while(0.., WS).parse_next(input) } -fn ws_or_eof<'i, E: ParseError>>(input: Stream<'i>) -> IResult, &'i str, E> { +fn ws_or_eof<'i, E: ParseError>>(input: &mut Stream<'i>) -> PResult<&'i str, E> { rest.verify(|s: &str| s.chars().all(|c| WS.contains(&c))) - .parse_peek(input) + .parse_next(input) } const WS: &[char] = &[' ', '\t', '\r', '\n']; @@ -229,15 +215,15 @@ mod test { #[test] fn json_string() { assert_eq!( - string::>(Partial::new("\"\"")), + string::>.parse_peek(Partial::new("\"\"")), Ok((Partial::new(""), "".to_string())) ); assert_eq!( - string::>(Partial::new("\"abc\"")), + string::>.parse_peek(Partial::new("\"abc\"")), Ok((Partial::new(""), "abc".to_string())) ); assert_eq!( - string::>(Partial::new( + string::>.parse_peek(Partial::new( "\"abc\\\"\\\\\\/\\b\\f\\n\\r\\t\\u0001\\u2014\u{2014}def\"" )), Ok(( @@ -246,17 +232,29 @@ mod test { )), ); assert_eq!( - string::>(Partial::new("\"\\uD83D\\uDE10\"")), + string::>.parse_peek(Partial::new("\"\\uD83D\\uDE10\"")), Ok((Partial::new(""), "😐".to_string())) ); - assert!(string::>(Partial::new("\"")).is_err()); - assert!(string::>(Partial::new("\"abc")).is_err()); - assert!(string::>(Partial::new("\"\\\"")).is_err()); - assert!(string::>(Partial::new("\"\\u123\"")).is_err()); - assert!(string::>(Partial::new("\"\\uD800\"")).is_err()); - assert!(string::>(Partial::new("\"\\uD800\\uD800\"")).is_err()); - assert!(string::>(Partial::new("\"\\uDC00\"")).is_err()); + assert!(string::>.parse_peek(Partial::new("\"")).is_err()); + assert!(string::> + .parse_peek(Partial::new("\"abc")) + .is_err()); + assert!(string::> + .parse_peek(Partial::new("\"\\\"")) + .is_err()); + assert!(string::> + .parse_peek(Partial::new("\"\\u123\"")) + .is_err()); + assert!(string::> + .parse_peek(Partial::new("\"\\uD800\"")) + .is_err()); + assert!(string::> + .parse_peek(Partial::new("\"\\uD800\\uD800\"")) + .is_err()); + assert!(string::> + .parse_peek(Partial::new("\"\\uDC00\"")) + .is_err()); } #[test] @@ -275,7 +273,7 @@ mod test { ); assert_eq!( - json::>(Partial::new(input)), + json::>.parse_peek(Partial::new(input)), Ok((Partial::new(""), expected)) ); } @@ -289,7 +287,7 @@ mod test { let expected = Array(vec![Num(42.0), Str("x".to_string())]); assert_eq!( - json::>(Partial::new(input)), + json::>.parse_peek(Partial::new(input)), Ok((Partial::new(""), expected)) ); } @@ -313,7 +311,7 @@ mod test { "#; assert_eq!( - json::>(Partial::new(input)), + json::>.parse_peek(Partial::new(input)), Ok(( Partial::new(""), Object(