Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

1
vendor/winnow/.cargo-checksum.json vendored Normal file

File diff suppressed because one or more lines are too long

1560
vendor/winnow/Cargo.lock generated vendored Normal file

File diff suppressed because it is too large Load Diff

339
vendor/winnow/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,339 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.65.0"
name = "winnow"
version = "0.7.13"
build = false
include = [
"build.rs",
"src/**/*",
"Cargo.toml",
"Cargo.lock",
"LICENSE*",
"README.md",
"examples/**/*",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "A byte-oriented, zero-copy, parser combinators library"
readme = "README.md"
keywords = [
"parser",
"parser-combinators",
"parsing",
"streaming",
"bit",
]
categories = ["parsing"]
license = "MIT"
repository = "https://github.com/winnow-rs/winnow"
[package.metadata.docs.rs]
features = ["unstable-doc"]
rustdoc-args = [
"--cfg",
"docsrs",
"--generate-link-to-definition",
]
[[package.metadata.release.pre-release-replacements]]
file = "CHANGELOG.md"
search = "Unreleased"
replace = "{{version}}"
min = 1
[[package.metadata.release.pre-release-replacements]]
file = "CHANGELOG.md"
search = '\.\.\.HEAD'
replace = "...{{tag_name}}"
exactly = 1
[[package.metadata.release.pre-release-replacements]]
file = "CHANGELOG.md"
search = "ReleaseDate"
replace = "{{date}}"
min = 1
[[package.metadata.release.pre-release-replacements]]
file = "CHANGELOG.md"
search = "<!-- next-header -->"
replace = """
<!-- next-header -->
## [Unreleased] - ReleaseDate
"""
exactly = 1
[[package.metadata.release.pre-release-replacements]]
file = "CHANGELOG.md"
search = "<!-- next-url -->"
replace = """
<!-- next-url -->
[Unreleased]: https://github.com/winnow-rs/winnow/compare/{{tag_name}}...HEAD"""
exactly = 1
[[package.metadata.release.pre-release-replacements]]
file = "src/lib.rs"
search = 'blob/v.+\..+\..+/CHANGELOG.md'
replace = "blob/v{{version}}/CHANGELOG.md"
exactly = 1
[features]
alloc = []
debug = [
"std",
"dep:anstream",
"dep:anstyle",
"dep:is_terminal_polyfill",
"dep:terminal_size",
]
default = ["std"]
simd = ["dep:memchr"]
std = [
"alloc",
"memchr?/std",
]
unstable-doc = [
"alloc",
"std",
"simd",
"unstable-recover",
]
unstable-recover = []
[lib]
name = "winnow"
path = "src/lib.rs"
[[example]]
name = "arithmetic"
path = "examples/arithmetic/main.rs"
test = true
required-features = ["alloc"]
[[example]]
name = "css"
path = "examples/css/main.rs"
test = true
required-features = ["alloc"]
[[example]]
name = "custom_error"
path = "examples/custom_error.rs"
test = true
required-features = ["alloc"]
[[example]]
name = "http"
path = "examples/http/main.rs"
required-features = ["alloc"]
[[example]]
name = "ini"
path = "examples/ini/main.rs"
test = true
required-features = ["std"]
[[example]]
name = "iterator"
path = "examples/iterator.rs"
[[example]]
name = "json"
path = "examples/json/main.rs"
test = true
required-features = ["std"]
[[example]]
name = "json_iterator"
path = "examples/json_iterator.rs"
required-features = ["std"]
[[example]]
name = "ndjson"
path = "examples/ndjson/main.rs"
test = true
required-features = ["std"]
[[example]]
name = "s_expression"
path = "examples/s_expression/main.rs"
required-features = ["alloc"]
[[example]]
name = "string"
path = "examples/string/main.rs"
required-features = ["alloc"]
[[bench]]
name = "arithmetic"
path = "examples/arithmetic/bench.rs"
harness = false
required-features = ["alloc"]
[[bench]]
name = "http"
path = "examples/http/bench.rs"
harness = false
required-features = ["alloc"]
[[bench]]
name = "ini"
path = "examples/ini/bench.rs"
harness = false
required-features = ["std"]
[[bench]]
name = "json"
path = "examples/json/bench.rs"
harness = false
required-features = ["std"]
[dependencies.anstream]
version = "0.3.2"
optional = true
[dependencies.anstyle]
version = "1.0.1"
optional = true
[dependencies.is_terminal_polyfill]
version = "1.48.0"
optional = true
[dependencies.memchr]
version = "2.5"
optional = true
default-features = false
[dependencies.terminal_size]
version = "0.4.0"
optional = true
[dev-dependencies.annotate-snippets]
version = "0.11.3"
[dev-dependencies.anyhow]
version = "1.0.86"
[dev-dependencies.automod]
version = "1.0.14"
[dev-dependencies.circular]
version = "0.3.0"
[dev-dependencies.criterion]
version = "0.5.1"
[dev-dependencies.lexopt]
version = "0.3.0"
[dev-dependencies.proptest]
version = "1.2.0"
[dev-dependencies.rustc-hash]
version = "1.1.0"
[dev-dependencies.snapbox]
version = "0.6.21"
features = ["examples"]
[dev-dependencies.term-transcript]
version = "0.2.0"
[lints.clippy]
bool_assert_comparison = "allow"
branches_sharing_code = "allow"
checked_conversions = "warn"
collapsible_else_if = "allow"
create_dir = "warn"
dbg_macro = "warn"
debug_assert_with_mut_call = "warn"
doc_markdown = "warn"
empty_enum = "warn"
enum_glob_use = "warn"
expl_impl_clone_on_copy = "warn"
explicit_deref_methods = "warn"
explicit_into_iter_loop = "warn"
fallible_impl_from = "warn"
filter_map_next = "warn"
flat_map_option = "warn"
float_cmp_const = "warn"
fn_params_excessive_bools = "warn"
from_iter_instead_of_collect = "warn"
if_same_then_else = "allow"
implicit_clone = "warn"
imprecise_flops = "warn"
inconsistent_struct_constructor = "warn"
inefficient_to_string = "warn"
infinite_loop = "warn"
invalid_upcast_comparisons = "warn"
large_digit_groups = "warn"
large_stack_arrays = "warn"
large_types_passed_by_value = "warn"
let_and_return = "allow"
linkedlist = "warn"
lossy_float_literal = "warn"
macro_use_imports = "warn"
mem_forget = "warn"
mutex_integer = "warn"
needless_continue = "allow"
needless_for_each = "warn"
negative_feature_names = "warn"
path_buf_push_overwrite = "warn"
ptr_as_ptr = "warn"
rc_mutex = "warn"
redundant_feature_names = "warn"
ref_option_ref = "warn"
rest_pat_in_fully_bound_structs = "warn"
result_large_err = "allow"
same_functions_in_if_condition = "warn"
semicolon_if_nothing_returned = "warn"
str_to_string = "warn"
string_add = "warn"
string_add_assign = "warn"
string_lit_as_bytes = "warn"
string_to_string = "warn"
todo = "warn"
trait_duplication_in_bounds = "warn"
uninlined_format_args = "warn"
verbose_file_reads = "warn"
wildcard_imports = "allow"
zero_sized_map_values = "warn"
[lints.rust]
unnameable_types = "warn"
unreachable_pub = "warn"
unsafe_op_in_unsafe_fn = "warn"
unused_lifetimes = "warn"
unused_macro_rules = "warn"
[lints.rust.rust_2018_idioms]
level = "warn"
priority = -1
[profile.bench]
lto = true
codegen-units = 1
debug = 2
[profile.dev]
panic = "abort"
[profile.release]
lto = true
codegen-units = 1
panic = "abort"

18
vendor/winnow/LICENSE-MIT vendored Normal file
View File

@@ -0,0 +1,18 @@
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

27
vendor/winnow/README.md vendored Normal file
View File

@@ -0,0 +1,27 @@
# winnow, making parsing a breeze
[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Build Status](https://github.com/winnow-rs/winnow/actions/workflows/ci.yml/badge.svg)](https://github.com/winnow-rs/winnow/actions/workflows/ci.yml)
[![Coverage Status](https://coveralls.io/repos/github/winnow-rs/winnow/badge.svg?branch=main)](https://coveralls.io/github/winnow-rs/winnow?branch=main)
[![Crates.io Version](https://img.shields.io/crates/v/winnow.svg)](https://crates.io/crates/winnow)
## About
Build up a parser for your format of choice with the building blocks provided by `winnow`.
For more details, see:
- [Tutorial](https://docs.rs/winnow/latest/winnow/_tutorial/index.html)
- [Special Topics](https://docs.rs/winnow/latest/winnow/_topic/index.html)
- [Why winnow? How does it compare to ...?](https://docs.rs/winnow/latest/winnow/_topic/why/index.html)
- [API Reference](https://docs.rs/winnow)
- [List of combinators](https://docs.rs/winnow/latest/winnow/combinator/index.html)
# Contributors
winnow is the fruit of the work of many contributors over the years, many
thanks for your help! In particular, thanks to [Geal](https://github.com/Geal)
for the original [`nom` crate](https://crates.io/crates/nom).
<a href="https://github.com/winnow-rs/winnow/graphs/contributors">
<img src="https://contributors-img.web.app/image?repo=winnow-rs/winnow" />
</a>

View File

@@ -0,0 +1,33 @@
mod parser;
mod parser_ast;
mod parser_lexer;
use winnow::prelude::*;
#[allow(clippy::eq_op, clippy::erasing_op)]
fn arithmetic(c: &mut criterion::Criterion) {
let data = " 2*2 / ( 5 - 1) + 3 / 4 * (2 - 7 + 567 *12 /2) + 3*(1+2*( 45 /2))";
let expected = 2 * 2 / (5 - 1) + 3 * (1 + 2 * (45 / 2));
assert_eq!(parser::expr.parse(data), Ok(expected));
assert_eq!(
parser_ast::expr.parse(data).map(|ast| ast.eval()),
Ok(expected)
);
assert_eq!(
parser_lexer::expr2.parse(data).map(|ast| ast.eval()),
Ok(expected)
);
c.bench_function("direct", |b| {
b.iter(|| parser::expr.parse(data).unwrap());
});
c.bench_function("ast", |b| {
b.iter(|| parser_ast::expr.parse(data).unwrap().eval());
});
c.bench_function("lexer", |b| {
b.iter(|| parser_lexer::expr2.parse_peek(data).unwrap());
});
}
criterion::criterion_group!(benches, arithmetic);
criterion::criterion_main!(benches);

View File

@@ -0,0 +1,93 @@
use winnow::prelude::*;
mod parser;
mod parser_ast;
mod parser_lexer;
#[cfg(test)]
mod test_parser;
#[cfg(test)]
mod test_parser_ast;
#[cfg(test)]
mod test_parser_lexer;
fn main() -> Result<(), lexopt::Error> {
let args = Args::parse()?;
let input = args.input.as_deref().unwrap_or("1 + 1");
if let Err(err) = calc(input, args.implementation) {
println!("FAILED");
println!("{err}");
}
Ok(())
}
fn calc(
input: &str,
imp: Impl,
) -> Result<(), winnow::error::ParseError<&str, winnow::error::ContextError>> {
println!("{input} =");
match imp {
Impl::Eval => {
let result = parser::expr.parse(input)?;
println!(" {result}");
}
Impl::Ast => {
let result = parser_ast::expr.parse(input)?;
println!(" {:#?}={}", result, result.eval());
}
Impl::Lexer => {
let tokens = parser_lexer::tokens.parse(input)?;
println!(" {tokens:#?}");
let tokens = parser_lexer::Tokens::new(&tokens);
let result = parser_lexer::expr.parse(tokens).unwrap();
println!(" {:#?}={}", result, result.eval());
}
}
Ok(())
}
#[derive(Default)]
struct Args {
input: Option<String>,
implementation: Impl,
}
enum Impl {
Eval,
Ast,
Lexer,
}
impl Default for Impl {
fn default() -> Self {
Self::Eval
}
}
impl Args {
fn parse() -> Result<Self, lexopt::Error> {
use lexopt::prelude::*;
let mut res = Args::default();
let mut args = lexopt::Parser::from_env();
while let Some(arg) = args.next()? {
match arg {
Long("impl") => {
res.implementation = args.value()?.parse_with(|s| match s {
"eval" => Ok(Impl::Eval),
"ast" => Ok(Impl::Ast),
"lexer" => Ok(Impl::Lexer),
_ => Err("expected `eval`, `ast`"),
})?;
}
Value(input) => {
res.input = Some(input.string()?);
}
_ => return Err(arg.unexpected()),
}
}
Ok(res)
}
}

View File

@@ -0,0 +1,68 @@
use std::str::FromStr;
use winnow::prelude::*;
use winnow::Result;
use winnow::{
ascii::{digit1 as digits, multispace0 as multispaces},
combinator::alt,
combinator::delimited,
combinator::repeat,
token::one_of,
};
// Parser definition
pub(crate) fn expr(i: &mut &str) -> Result<i64> {
let init = term.parse_next(i)?;
repeat(0.., (one_of(['+', '-']), term))
.fold(
move || init,
|acc, (op, val): (char, i64)| {
if op == '+' {
acc + val
} else {
acc - val
}
},
)
.parse_next(i)
}
// We read an initial factor and for each time we find
// a * or / operator followed by another factor, we do
// the math by folding everything
pub(crate) fn term(i: &mut &str) -> Result<i64> {
let init = factor.parse_next(i)?;
repeat(0.., (one_of(['*', '/']), factor))
.fold(
move || init,
|acc, (op, val): (char, i64)| {
if op == '*' {
acc * val
} else {
acc / val
}
},
)
.parse_next(i)
}
// We transform an integer string into a i64, ignoring surrounding whitespace
// We look for a digit suite, and try to convert it.
// If either str::from_utf8 or FromStr::from_str fail,
// we fallback to the parens parser defined above
pub(crate) fn factor(i: &mut &str) -> Result<i64> {
delimited(
multispaces,
alt((digits.try_map(FromStr::from_str), parens)),
multispaces,
)
.parse_next(i)
}
// We parse any expr surrounded by parens, ignoring all whitespace around those
fn parens(i: &mut &str) -> Result<i64> {
delimited('(', expr, ')').parse_next(i)
}

View File

@@ -0,0 +1,100 @@
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
use std::str::FromStr;
use winnow::prelude::*;
use winnow::Result;
use winnow::{
ascii::{digit1 as digits, multispace0 as multispaces},
combinator::alt,
combinator::delimited,
combinator::repeat,
token::one_of,
};
#[derive(Debug, Clone)]
pub(crate) enum Expr {
Value(i64),
Add(Box<Expr>, Box<Expr>),
Sub(Box<Expr>, Box<Expr>),
Mul(Box<Expr>, Box<Expr>),
Div(Box<Expr>, Box<Expr>),
Paren(Box<Expr>),
}
impl Expr {
pub(crate) fn eval(&self) -> i64 {
match self {
Self::Value(v) => *v,
Self::Add(lhs, rhs) => lhs.eval() + rhs.eval(),
Self::Sub(lhs, rhs) => lhs.eval() - rhs.eval(),
Self::Mul(lhs, rhs) => lhs.eval() * rhs.eval(),
Self::Div(lhs, rhs) => lhs.eval() / rhs.eval(),
Self::Paren(expr) => expr.eval(),
}
}
}
impl Display for Expr {
fn fmt(&self, format: &mut Formatter<'_>) -> fmt::Result {
use Expr::{Add, Div, Mul, Paren, Sub, Value};
match *self {
Value(val) => write!(format, "{val}"),
Add(ref left, ref right) => write!(format, "{left} + {right}"),
Sub(ref left, ref right) => write!(format, "{left} - {right}"),
Mul(ref left, ref right) => write!(format, "{left} * {right}"),
Div(ref left, ref right) => write!(format, "{left} / {right}"),
Paren(ref expr) => write!(format, "({expr})"),
}
}
}
pub(crate) fn expr(i: &mut &str) -> Result<Expr> {
let init = term.parse_next(i)?;
repeat(0.., (one_of(['+', '-']), term))
.fold(
move || init.clone(),
|acc, (op, val): (char, Expr)| {
if op == '+' {
Expr::Add(Box::new(acc), Box::new(val))
} else {
Expr::Sub(Box::new(acc), Box::new(val))
}
},
)
.parse_next(i)
}
pub(crate) fn term(i: &mut &str) -> Result<Expr> {
let init = factor.parse_next(i)?;
repeat(0.., (one_of(['*', '/']), factor))
.fold(
move || init.clone(),
|acc, (op, val): (char, Expr)| {
if op == '*' {
Expr::Mul(Box::new(acc), Box::new(val))
} else {
Expr::Div(Box::new(acc), Box::new(val))
}
},
)
.parse_next(i)
}
pub(crate) fn factor(i: &mut &str) -> Result<Expr> {
delimited(
multispaces,
alt((digits.try_map(FromStr::from_str).map(Expr::Value), parens)),
multispaces,
)
.parse_next(i)
}
fn parens(i: &mut &str) -> Result<Expr> {
delimited("(", expr, ")")
.map(|e| Expr::Paren(Box::new(e)))
.parse_next(i)
}

View File

@@ -0,0 +1,246 @@
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
use winnow::prelude::*;
use winnow::Result;
use winnow::{
ascii::{digit1 as digits, multispace0 as multispaces},
combinator::alt,
combinator::dispatch,
combinator::eof,
combinator::fail,
combinator::opt,
combinator::peek,
combinator::repeat,
combinator::{delimited, preceded, terminated},
error::ContextError,
stream::TokenSlice,
token::any,
token::literal,
token::one_of,
token::take_till,
};
/// Lex and parse
#[allow(dead_code)]
pub(crate) fn expr2(i: &mut &str) -> Result<Expr> {
let tokens = tokens.parse_next(i)?;
let mut tokens = Tokens::new(&tokens);
expr.parse_next(&mut tokens)
}
#[derive(Clone, PartialEq, Eq)]
pub(crate) struct Token<'s> {
kind: TokenKind,
raw: &'s str,
}
impl fmt::Debug for Token<'_> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
// Customized for brevity for a better `winnow/debug` experience
match self.kind {
TokenKind::Value => Debug::fmt(self.raw, fmt),
TokenKind::Oper(oper) => Debug::fmt(&oper, fmt),
TokenKind::OpenParen => fmt.write_str("OpenParen"),
TokenKind::CloseParen => fmt.write_str("CloseParen"),
TokenKind::Unknown => fmt.write_str("Unknown"),
TokenKind::Eof => fmt.write_str("Eof"),
}
}
}
impl PartialEq<TokenKind> for Token<'_> {
fn eq(&self, other: &TokenKind) -> bool {
self.kind == *other
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum TokenKind {
Value,
Oper(Oper),
OpenParen,
CloseParen,
Unknown,
Eof,
}
impl<'i> Parser<Tokens<'i>, &'i Token<'i>, ContextError> for TokenKind {
fn parse_next(&mut self, input: &mut Tokens<'i>) -> Result<&'i Token<'i>> {
literal(*self).parse_next(input).map(|t| &t[0])
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum Oper {
Add,
Sub,
Mul,
Div,
}
impl winnow::stream::ContainsToken<&'_ Token<'_>> for TokenKind {
#[inline(always)]
fn contains_token(&self, token: &'_ Token<'_>) -> bool {
*self == token.kind
}
}
impl winnow::stream::ContainsToken<&'_ Token<'_>> for &'_ [TokenKind] {
#[inline]
fn contains_token(&self, token: &'_ Token<'_>) -> bool {
self.iter().any(|t| *t == token.kind)
}
}
impl<const LEN: usize> winnow::stream::ContainsToken<&'_ Token<'_>> for &'_ [TokenKind; LEN] {
#[inline]
fn contains_token(&self, token: &'_ Token<'_>) -> bool {
self.iter().any(|t| *t == token.kind)
}
}
impl<const LEN: usize> winnow::stream::ContainsToken<&'_ Token<'_>> for [TokenKind; LEN] {
#[inline]
fn contains_token(&self, token: &'_ Token<'_>) -> bool {
self.iter().any(|t| *t == token.kind)
}
}
/// Lex tokens
///
/// See [`expr`] to parse the tokens
pub(crate) fn tokens<'s>(i: &mut &'s str) -> Result<Vec<Token<'s>>> {
let mut tokens: Vec<_> =
preceded(multispaces, repeat(1.., terminated(token, multispaces))).parse_next(i)?;
if let Some(eof) = opt(eof.map(|raw| Token {
kind: TokenKind::Eof,
raw,
}))
.parse_next(i)?
{
tokens.push(eof);
}
Ok(tokens)
}
fn token<'s>(i: &mut &'s str) -> Result<Token<'s>> {
dispatch! {peek(any);
'0'..='9' => digits.value(TokenKind::Value),
'(' => '('.value(TokenKind::OpenParen),
')' => ')'.value(TokenKind::CloseParen),
'+' => '+'.value(TokenKind::Oper(Oper::Add)),
'-' => '-'.value(TokenKind::Oper(Oper::Sub)),
'*' => '*'.value(TokenKind::Oper(Oper::Mul)),
'/' => '/'.value(TokenKind::Oper(Oper::Div)),
' '| '\t'| '\r'| '\n' => fail,
_ => take_till(.., ('0'..='9', '(', ')', '+', '-', '*', '/')).value(TokenKind::Unknown),
}
.with_taken()
.map(|(kind, raw)| Token { kind, raw })
.parse_next(i)
}
#[derive(Debug, Clone)]
pub(crate) enum Expr {
Value(i64),
Add(Box<Expr>, Box<Expr>),
Sub(Box<Expr>, Box<Expr>),
Mul(Box<Expr>, Box<Expr>),
Div(Box<Expr>, Box<Expr>),
Paren(Box<Expr>),
}
impl Expr {
pub(crate) fn eval(&self) -> i64 {
match self {
Self::Value(v) => *v,
Self::Add(lhs, rhs) => lhs.eval() + rhs.eval(),
Self::Sub(lhs, rhs) => lhs.eval() - rhs.eval(),
Self::Mul(lhs, rhs) => lhs.eval() * rhs.eval(),
Self::Div(lhs, rhs) => lhs.eval() / rhs.eval(),
Self::Paren(expr) => expr.eval(),
}
}
}
impl Display for Expr {
fn fmt(&self, format: &mut Formatter<'_>) -> fmt::Result {
use Expr::{Add, Div, Mul, Paren, Sub, Value};
match *self {
Value(val) => write!(format, "{val}"),
Add(ref left, ref right) => write!(format, "{left} + {right}"),
Sub(ref left, ref right) => write!(format, "{left} - {right}"),
Mul(ref left, ref right) => write!(format, "{left} * {right}"),
Div(ref left, ref right) => write!(format, "{left} / {right}"),
Paren(ref expr) => write!(format, "({expr})"),
}
}
}
pub(crate) type Tokens<'i> = TokenSlice<'i, Token<'i>>;
/// Parse the tokens lexed in [`tokens`]
pub(crate) fn expr(i: &mut Tokens<'_>) -> Result<Expr> {
let init = term.parse_next(i)?;
let expr = repeat(
0..,
(
one_of([TokenKind::Oper(Oper::Add), TokenKind::Oper(Oper::Sub)]),
term,
),
)
.fold(
move || init.clone(),
|acc, (op, val): (&Token<'_>, Expr)| {
if op.kind == TokenKind::Oper(Oper::Add) {
Expr::Add(Box::new(acc), Box::new(val))
} else {
Expr::Sub(Box::new(acc), Box::new(val))
}
},
)
.parse_next(i)?;
opt(TokenKind::Eof).parse_next(i)?;
Ok(expr)
}
pub(crate) fn term(i: &mut Tokens<'_>) -> Result<Expr> {
let init = factor.parse_next(i)?;
repeat(
0..,
(
one_of([TokenKind::Oper(Oper::Mul), TokenKind::Oper(Oper::Div)]),
factor,
),
)
.fold(
move || init.clone(),
|acc, (op, val): (&Token<'_>, Expr)| {
if op.kind == TokenKind::Oper(Oper::Mul) {
Expr::Mul(Box::new(acc), Box::new(val))
} else {
Expr::Div(Box::new(acc), Box::new(val))
}
},
)
.parse_next(i)
}
pub(crate) fn factor(i: &mut Tokens<'_>) -> Result<Expr> {
alt((
TokenKind::Value.try_map(|t: &Token<'_>| t.raw.parse::<i64>().map(Expr::Value)),
parens,
))
.parse_next(i)
}
fn parens(i: &mut Tokens<'_>) -> Result<Expr> {
delimited(TokenKind::OpenParen, expr, TokenKind::CloseParen)
.map(|e| Expr::Paren(Box::new(e)))
.parse_next(i)
}

View File

@@ -0,0 +1,186 @@
use snapbox::assert_data_eq;
use snapbox::prelude::*;
use snapbox::str;
use winnow::prelude::*;
use crate::parser::*;
#[test]
fn factor_test() {
let input = "3";
let expected = str![[r#"
Ok(
(
"",
3,
),
)
"#]];
assert_data_eq!(factor.parse_peek(input).to_debug(), expected);
let input = " 12";
let expected = str![[r#"
Ok(
(
"",
12,
),
)
"#]];
assert_data_eq!(factor.parse_peek(input).to_debug(), expected);
let input = "537 ";
let expected = str![[r#"
Ok(
(
"",
537,
),
)
"#]];
assert_data_eq!(factor.parse_peek(input).to_debug(), expected);
let input = " 24 ";
let expected = str![[r#"
Ok(
(
"",
24,
),
)
"#]];
assert_data_eq!(factor.parse_peek(input).to_debug(), expected);
}
#[test]
fn term_test() {
let input = " 12 *2 / 3";
let expected = str![[r#"
Ok(
(
"",
8,
),
)
"#]];
assert_data_eq!(term.parse_peek(input).to_debug(), expected);
let input = " 12 *2 / 3";
let expected = str![[r#"
Ok(
(
"",
8,
),
)
"#]];
assert_data_eq!(term.parse_peek(input).to_debug(), expected);
let input = " 2* 3 *2 *2 / 3";
let expected = str![[r#"
Ok(
(
"",
8,
),
)
"#]];
assert_data_eq!(term.parse_peek(input).to_debug(), expected);
let input = " 48 / 3/2";
let expected = str![[r#"
Ok(
(
"",
8,
),
)
"#]];
assert_data_eq!(term.parse_peek(input).to_debug(), expected);
}
#[test]
fn expr_test() {
let input = " 1 + 2 ";
let expected = str![[r#"
Ok(
(
"",
3,
),
)
"#]];
assert_data_eq!(expr.parse_peek(input).to_debug(), expected);
let input = " 12 + 6 - 4+ 3";
let expected = str![[r#"
Ok(
(
"",
17,
),
)
"#]];
assert_data_eq!(expr.parse_peek(input).to_debug(), expected);
let input = " 1 + 2*3 + 4";
let expected = str![[r#"
Ok(
(
"",
11,
),
)
"#]];
assert_data_eq!(expr.parse_peek(input).to_debug(), expected);
}
#[test]
fn parens_test() {
let input = " ( 2 )";
let expected = str![[r#"
Ok(
(
"",
2,
),
)
"#]];
assert_data_eq!(expr.parse_peek(input).to_debug(), expected);
let input = " 2* ( 3 + 4 ) ";
let expected = str![[r#"
Ok(
(
"",
14,
),
)
"#]];
assert_data_eq!(expr.parse_peek(input).to_debug(), expected);
let input = " 2*2 / ( 5 - 1) + 3";
let expected = str![[r#"
Ok(
(
"",
4,
),
)
"#]];
assert_data_eq!(expr.parse_peek(input).to_debug(), expected);
}

View File

@@ -0,0 +1,317 @@
use snapbox::assert_data_eq;
use snapbox::prelude::*;
use snapbox::str;
use winnow::prelude::*;
use crate::parser_ast::*;
#[test]
fn factor_test() {
let input = "3";
let expected = str![[r#"
Ok(
(
"",
Value(
3,
),
),
)
"#]];
assert_data_eq!(factor.parse_peek(input).to_debug(), expected);
let input = " 12";
let expected = str![[r#"
Ok(
(
"",
Value(
12,
),
),
)
"#]];
assert_data_eq!(factor.parse_peek(input).to_debug(), expected);
let input = "537 ";
let expected = str![[r#"
Ok(
(
"",
Value(
537,
),
),
)
"#]];
assert_data_eq!(factor.parse_peek(input).to_debug(), expected);
let input = " 24 ";
let expected = str![[r#"
Ok(
(
"",
Value(
24,
),
),
)
"#]];
assert_data_eq!(factor.parse_peek(input).to_debug(), expected);
}
#[test]
fn term_test() {
let input = " 12 *2 / 3";
let expected = str![[r#"
Ok(
(
"",
Div(
Mul(
Value(
12,
),
Value(
2,
),
),
Value(
3,
),
),
),
)
"#]];
assert_data_eq!(term.parse_peek(input).to_debug(), expected);
let input = " 12 *2 / 3";
let expected = str![[r#"
Ok(
(
"",
Div(
Mul(
Value(
12,
),
Value(
2,
),
),
Value(
3,
),
),
),
)
"#]];
assert_data_eq!(term.parse_peek(input).to_debug(), expected);
let input = " 2* 3 *2 *2 / 3";
let expected = str![[r#"
Ok(
(
"",
Div(
Mul(
Mul(
Mul(
Value(
2,
),
Value(
3,
),
),
Value(
2,
),
),
Value(
2,
),
),
Value(
3,
),
),
),
)
"#]];
assert_data_eq!(term.parse_peek(input).to_debug(), expected);
let input = " 48 / 3/2";
let expected = str![[r#"
Ok(
(
"",
Div(
Div(
Value(
48,
),
Value(
3,
),
),
Value(
2,
),
),
),
)
"#]];
assert_data_eq!(term.parse_peek(input).to_debug(), expected);
}
#[test]
fn expr_test() {
let input = " 1 + 2 ";
let expected = str![[r#"
Ok(
Add(
Value(
1,
),
Value(
2,
),
),
)
"#]];
assert_data_eq!(expr.parse(input).to_debug(), expected);
let input = " 12 + 6 - 4+ 3";
let expected = str![[r#"
Ok(
Add(
Sub(
Add(
Value(
12,
),
Value(
6,
),
),
Value(
4,
),
),
Value(
3,
),
),
)
"#]];
assert_data_eq!(expr.parse(input).to_debug(), expected);
let input = " 1 + 2*3 + 4";
let expected = str![[r#"
Ok(
Add(
Add(
Value(
1,
),
Mul(
Value(
2,
),
Value(
3,
),
),
),
Value(
4,
),
),
)
"#]];
assert_data_eq!(expr.parse(input).to_debug(), expected);
}
#[test]
fn parens_test() {
let input = " ( 2 )";
let expected = str![[r#"
Ok(
Paren(
Value(
2,
),
),
)
"#]];
assert_data_eq!(expr.parse(input).to_debug(), expected);
let input = " 2* ( 3 + 4 ) ";
let expected = str![[r#"
Ok(
Mul(
Value(
2,
),
Paren(
Add(
Value(
3,
),
Value(
4,
),
),
),
),
)
"#]];
assert_data_eq!(expr.parse(input).to_debug(), expected);
let input = " 2*2 / ( 5 - 1) + 3";
let expected = str![[r#"
Ok(
Add(
Div(
Mul(
Value(
2,
),
Value(
2,
),
),
Paren(
Sub(
Value(
5,
),
Value(
1,
),
),
),
),
Value(
3,
),
),
)
"#]];
assert_data_eq!(expr.parse(input).to_debug(), expected);
}

View File

@@ -0,0 +1,438 @@
use snapbox::assert_data_eq;
use snapbox::prelude::*;
use snapbox::str;
use winnow::prelude::*;
use crate::parser_lexer::*;
#[test]
fn lex_test() {
let input = "3";
let expected = str![[r#"
Ok(
(
"",
[
"3",
Eof,
],
),
)
"#]];
assert_data_eq!(tokens.parse_peek(input).to_debug(), expected);
let input = " 24 ";
let expected = str![[r#"
Ok(
(
"",
[
"24",
Eof,
],
),
)
"#]];
assert_data_eq!(tokens.parse_peek(input).to_debug(), expected);
let input = " 12 *2 / 3";
let expected = str![[r#"
Ok(
(
"",
[
"12",
Mul,
"2",
Div,
"3",
Eof,
],
),
)
"#]];
assert_data_eq!(tokens.parse_peek(input).to_debug(), expected);
let input = " 2*2 / ( 5 - 1) + 3";
let expected = str![[r#"
Ok(
(
"",
[
"2",
Mul,
"2",
Div,
OpenParen,
"5",
Sub,
"1",
CloseParen,
Add,
"3",
Eof,
],
),
)
"#]];
assert_data_eq!(tokens.parse_peek(input).to_debug(), expected);
}
#[test]
fn factor_test() {
let input = "3";
let expected = str![[r#"
Ok(
(
[
Eof,
],
Value(
3,
),
),
)
"#]];
let input = tokens.parse(input).unwrap();
let input = Tokens::new(&input);
assert_data_eq!(factor.parse_peek(input).to_debug(), expected);
let input = " 12";
let expected = str![[r#"
Ok(
(
[
Eof,
],
Value(
12,
),
),
)
"#]];
let input = tokens.parse(input).unwrap();
let input = Tokens::new(&input);
assert_data_eq!(factor.parse_peek(input).to_debug(), expected);
let input = "537 ";
let expected = str![[r#"
Ok(
(
[
Eof,
],
Value(
537,
),
),
)
"#]];
let input = tokens.parse(input).unwrap();
let input = Tokens::new(&input);
assert_data_eq!(factor.parse_peek(input).to_debug(), expected);
let input = " 24 ";
let expected = str![[r#"
Ok(
(
[
Eof,
],
Value(
24,
),
),
)
"#]];
let input = tokens.parse(input).unwrap();
let input = Tokens::new(&input);
assert_data_eq!(factor.parse_peek(input).to_debug(), expected);
}
#[test]
fn term_test() {
let input = " 12 *2 / 3";
let expected = str![[r#"
Ok(
(
[
Eof,
],
Div(
Mul(
Value(
12,
),
Value(
2,
),
),
Value(
3,
),
),
),
)
"#]];
let input = tokens.parse(input).unwrap();
let input = Tokens::new(&input);
assert_data_eq!(term.parse_peek(input).to_debug(), expected);
let input = " 12 *2 / 3";
let expected = str![[r#"
Ok(
(
[
Eof,
],
Div(
Mul(
Value(
12,
),
Value(
2,
),
),
Value(
3,
),
),
),
)
"#]];
let input = tokens.parse(input).unwrap();
let input = Tokens::new(&input);
assert_data_eq!(term.parse_peek(input).to_debug(), expected);
let input = " 2* 3 *2 *2 / 3";
let expected = str![[r#"
Ok(
(
[
Eof,
],
Div(
Mul(
Mul(
Mul(
Value(
2,
),
Value(
3,
),
),
Value(
2,
),
),
Value(
2,
),
),
Value(
3,
),
),
),
)
"#]];
let input = tokens.parse(input).unwrap();
let input = Tokens::new(&input);
assert_data_eq!(term.parse_peek(input).to_debug(), expected);
let input = " 48 / 3/2";
let expected = str![[r#"
Ok(
(
[
Eof,
],
Div(
Div(
Value(
48,
),
Value(
3,
),
),
Value(
2,
),
),
),
)
"#]];
let input = tokens.parse(input).unwrap();
let input = Tokens::new(&input);
assert_data_eq!(term.parse_peek(input).to_debug(), expected);
}
#[test]
fn expr_test() {
let input = " 1 + 2 ";
let expected = str![[r#"
Ok(
Add(
Value(
1,
),
Value(
2,
),
),
)
"#]];
let input = tokens.parse(input).unwrap();
let input = Tokens::new(&input);
assert_data_eq!(expr.parse(input).to_debug(), expected);
let input = " 12 + 6 - 4+ 3";
let expected = str![[r#"
Ok(
Add(
Sub(
Add(
Value(
12,
),
Value(
6,
),
),
Value(
4,
),
),
Value(
3,
),
),
)
"#]];
let input = tokens.parse(input).unwrap();
let input = Tokens::new(&input);
assert_data_eq!(expr.parse(input).to_debug(), expected);
let input = " 1 + 2*3 + 4";
let expected = str![[r#"
Ok(
Add(
Add(
Value(
1,
),
Mul(
Value(
2,
),
Value(
3,
),
),
),
Value(
4,
),
),
)
"#]];
let input = tokens.parse(input).unwrap();
let input = Tokens::new(&input);
assert_data_eq!(expr.parse(input).to_debug(), expected);
}
#[test]
fn parens_test() {
let input = " ( 2 )";
let expected = str![[r#"
Ok(
Paren(
Value(
2,
),
),
)
"#]];
let input = tokens.parse(input).unwrap();
let input = Tokens::new(&input);
assert_data_eq!(expr.parse(input).to_debug(), expected);
let input = " 2* ( 3 + 4 ) ";
let expected = str![[r#"
Ok(
Mul(
Value(
2,
),
Paren(
Add(
Value(
3,
),
Value(
4,
),
),
),
),
)
"#]];
let input = tokens.parse(input).unwrap();
let input = Tokens::new(&input);
assert_data_eq!(expr.parse(input).to_debug(), expected);
let input = " 2*2 / ( 5 - 1) + 3";
let expected = str![[r#"
Ok(
Add(
Div(
Mul(
Value(
2,
),
Value(
2,
),
),
Paren(
Sub(
Value(
5,
),
Value(
1,
),
),
),
),
Value(
3,
),
),
)
"#]];
let input = tokens.parse(input).unwrap();
let input = Tokens::new(&input);
assert_data_eq!(expr.parse(input).to_debug(), expected);
}

62
vendor/winnow/examples/css/main.rs vendored Normal file
View File

@@ -0,0 +1,62 @@
use winnow::prelude::*;
mod parser;
use parser::hex_color;
fn main() -> Result<(), lexopt::Error> {
let args = Args::parse()?;
let input = args.input.as_deref().unwrap_or("#AAAAAA");
println!("{input} =");
match hex_color.parse(input) {
Ok(result) => {
println!(" {result:?}");
}
Err(err) => {
println!(" {err}");
}
}
Ok(())
}
#[derive(Default)]
struct Args {
input: Option<String>,
}
impl Args {
fn parse() -> Result<Self, lexopt::Error> {
use lexopt::prelude::*;
let mut res = Args::default();
let mut args = lexopt::Parser::from_env();
while let Some(arg) = args.next()? {
match arg {
Value(input) => {
res.input = Some(input.string()?);
}
_ => return Err(arg.unexpected()),
}
}
Ok(res)
}
}
#[test]
fn parse_color() {
assert_eq!(
hex_color.parse_peek("#2F14DF"),
Ok((
"",
parser::Color {
red: 47,
green: 20,
blue: 223,
}
))
);
}

36
vendor/winnow/examples/css/parser.rs vendored Normal file
View File

@@ -0,0 +1,36 @@
use winnow::combinator::seq;
use winnow::prelude::*;
use winnow::token::take_while;
use winnow::Result;
#[derive(Debug, Eq, PartialEq)]
pub(crate) struct Color {
pub(crate) red: u8,
pub(crate) green: u8,
pub(crate) blue: u8,
}
impl std::str::FromStr for Color {
// The error must be owned
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
hex_color.parse(s).map_err(|e| e.to_string())
}
}
pub(crate) fn hex_color(input: &mut &str) -> Result<Color> {
seq!(Color {
_: '#',
red: hex_primary,
green: hex_primary,
blue: hex_primary
})
.parse_next(input)
}
fn hex_primary(input: &mut &str) -> Result<u8> {
take_while(2, |c: char| c.is_ascii_hexdigit())
.try_map(|input| u8::from_str_radix(input, 16))
.parse_next(input)
}

69
vendor/winnow/examples/custom_error.rs vendored Normal file
View File

@@ -0,0 +1,69 @@
use winnow::error::AddContext;
use winnow::error::ErrMode;
use winnow::error::FromExternalError;
use winnow::error::ParserError;
use winnow::prelude::*;
use winnow::stream::Stream;
#[derive(Debug)]
pub enum CustomError<I> {
MyError,
Winnow(I),
External {
cause: Box<dyn std::error::Error + Send + Sync + 'static>,
input: I,
},
}
impl<I: Stream + Clone> ParserError<I> for CustomError<I> {
type Inner = Self;
fn from_input(input: &I) -> Self {
CustomError::Winnow(input.clone())
}
fn into_inner(self) -> Result<Self::Inner, Self> {
Ok(self)
}
}
impl<C, I: Stream> AddContext<I, C> for CustomError<I> {
#[inline]
fn add_context(
self,
_input: &I,
_token_start: &<I as Stream>::Checkpoint,
_context: C,
) -> Self {
self
}
}
impl<I: Stream + Clone, E: std::error::Error + Send + Sync + 'static> FromExternalError<I, E>
for CustomError<I>
{
#[inline]
fn from_external_error(input: &I, e: E) -> Self {
CustomError::External {
cause: Box::new(e),
input: input.clone(),
}
}
}
pub fn parse<'s>(_input: &mut &'s str) -> ModalResult<&'s str, CustomError<&'s str>> {
Err(ErrMode::Backtrack(CustomError::MyError))
}
fn main() {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let err = parse.parse_next(&mut "").unwrap_err();
assert!(matches!(err, ErrMode::Backtrack(CustomError::MyError)));
}
}

36
vendor/winnow/examples/http/bench.rs vendored Normal file
View File

@@ -0,0 +1,36 @@
mod parser;
mod parser_streaming;
fn one_test(c: &mut criterion::Criterion) {
let data = &b"GET / HTTP/1.1
Host: www.reddit.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
"[..];
let mut http_group = c.benchmark_group("http");
http_group.throughput(criterion::Throughput::Bytes(data.len() as u64));
http_group.bench_with_input(
criterion::BenchmarkId::new("complete", data.len()),
data,
|b, data| {
b.iter(|| parser::parse(data).unwrap());
},
);
http_group.bench_with_input(
criterion::BenchmarkId::new("streaming", data.len()),
data,
|b, data| {
b.iter(|| parser_streaming::parse(data).unwrap());
},
);
http_group.finish();
}
criterion::criterion_group!(http, one_test);
criterion::criterion_main!(http);

47
vendor/winnow/examples/http/main.rs vendored Normal file
View File

@@ -0,0 +1,47 @@
mod parser;
fn main() -> Result<(), lexopt::Error> {
let args = Args::parse()?;
let input = args.input.as_deref().unwrap_or(
"GET / HTTP/1.1
Host: www.reddit.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
",
);
if let Some(result) = parser::parse(input.as_bytes()) {
println!(" {result:#?}");
}
Ok(())
}
#[derive(Default)]
struct Args {
input: Option<String>,
}
impl Args {
fn parse() -> Result<Self, lexopt::Error> {
use lexopt::prelude::*;
let mut res = Args::default();
let mut args = lexopt::Parser::from_env();
while let Some(arg) = args.next()? {
match arg {
Value(input) => {
res.input = Some(input.string()?);
}
_ => return Err(arg.unexpected()),
}
}
Ok(res)
}
}

137
vendor/winnow/examples/http/parser.rs vendored Normal file
View File

@@ -0,0 +1,137 @@
use winnow::combinator::seq;
use winnow::prelude::*;
use winnow::{ascii::line_ending, combinator::repeat, token::take_while};
pub(crate) type Stream<'i> = &'i [u8];
#[rustfmt::skip]
#[derive(Debug)]
#[allow(dead_code)]
pub(crate) struct Request<'a> {
method: &'a [u8],
uri: &'a [u8],
version: &'a [u8],
}
#[derive(Debug)]
#[allow(dead_code)]
pub(crate) struct Header<'a> {
name: &'a [u8],
value: Vec<&'a [u8]>,
}
pub(crate) fn parse(data: &[u8]) -> Option<Vec<(Request<'_>, Vec<Header<'_>>)>> {
let mut buf = data;
let mut v = Vec::new();
loop {
match request(&mut buf) {
Ok(r) => {
v.push(r);
if buf.is_empty() {
//println!("{}", i);
break;
}
}
Err(e) => {
println!("error: {e:?}");
return None;
}
}
}
Some(v)
}
fn request<'s>(input: &mut Stream<'s>) -> ModalResult<(Request<'s>, Vec<Header<'s>>)> {
let req = request_line(input)?;
let h = repeat(1.., message_header).parse_next(input)?;
let _ = line_ending.parse_next(input)?;
Ok((req, h))
}
fn request_line<'s>(input: &mut Stream<'s>) -> ModalResult<Request<'s>> {
seq!( Request {
method: take_while(1.., is_token),
_: take_while(1.., is_space),
uri: take_while(1.., is_not_space),
_: take_while(1.., is_space),
version: http_version,
_: line_ending,
})
.parse_next(input)
}
fn http_version<'s>(input: &mut Stream<'s>) -> ModalResult<&'s [u8]> {
let _ = "HTTP/".parse_next(input)?;
let version = take_while(1.., is_version).parse_next(input)?;
Ok(version)
}
fn message_header_value<'s>(input: &mut Stream<'s>) -> ModalResult<&'s [u8]> {
let _ = take_while(1.., is_horizontal_space).parse_next(input)?;
let data = take_while(1.., till_line_ending).parse_next(input)?;
let _ = line_ending.parse_next(input)?;
Ok(data)
}
fn message_header<'s>(input: &mut Stream<'s>) -> ModalResult<Header<'s>> {
seq!(Header {
name: take_while(1.., is_token),
_: ':',
value: repeat(1.., message_header_value),
})
.parse_next(input)
}
#[rustfmt::skip]
#[allow(clippy::match_same_arms)]
#[allow(clippy::match_like_matches_macro)]
fn is_token(c: u8) -> bool {
match c {
128..=255 => false,
0..=31 => false,
b'(' => false,
b')' => false,
b'<' => false,
b'>' => false,
b'@' => false,
b',' => false,
b';' => false,
b':' => false,
b'\\' => false,
b'"' => false,
b'/' => false,
b'[' => false,
b']' => false,
b'?' => false,
b'=' => false,
b'{' => false,
b'}' => false,
b' ' => false,
_ => true,
}
}
fn is_version(c: u8) -> bool {
c.is_ascii_digit() || c == b'.'
}
fn till_line_ending(c: u8) -> bool {
c != b'\r' && c != b'\n'
}
fn is_space(c: u8) -> bool {
c == b' '
}
fn is_not_space(c: u8) -> bool {
c != b' '
}
fn is_horizontal_space(c: u8) -> bool {
c == b' ' || c == b'\t'
}

View File

@@ -0,0 +1,138 @@
use winnow::combinator::seq;
use winnow::{
ascii::line_ending, combinator::repeat, prelude::*, stream::Partial, token::take_while,
};
pub(crate) type Stream<'i> = Partial<&'i [u8]>;
#[rustfmt::skip]
#[derive(Debug)]
#[allow(dead_code)]
pub(crate) struct Request<'a> {
method: &'a [u8],
uri: &'a [u8],
version: &'a [u8],
}
#[derive(Debug)]
#[allow(dead_code)]
pub(crate) struct Header<'a> {
name: &'a [u8],
value: Vec<&'a [u8]>,
}
pub(crate) fn parse(data: &[u8]) -> Option<Vec<(Request<'_>, Vec<Header<'_>>)>> {
let mut buf = Partial::new(data);
let mut v = Vec::new();
loop {
match request(&mut buf) {
Ok(r) => {
v.push(r);
if buf.is_empty() {
//println!("{}", i);
break;
}
}
Err(e) => {
println!("error: {e:?}");
return None;
}
}
}
Some(v)
}
fn request<'s>(input: &mut Stream<'s>) -> ModalResult<(Request<'s>, Vec<Header<'s>>)> {
let req = request_line(input)?;
let h = repeat(1.., message_header).parse_next(input)?;
let _ = line_ending.parse_next(input)?;
Ok((req, h))
}
fn request_line<'s>(input: &mut Stream<'s>) -> ModalResult<Request<'s>> {
seq!( Request {
method: take_while(1.., is_token),
_: take_while(1.., is_space),
uri: take_while(1.., is_not_space),
_: take_while(1.., is_space),
version: http_version,
_: line_ending,
})
.parse_next(input)
}
fn http_version<'s>(input: &mut Stream<'s>) -> ModalResult<&'s [u8]> {
let _ = "HTTP/".parse_next(input)?;
let version = take_while(1.., is_version).parse_next(input)?;
Ok(version)
}
fn message_header_value<'s>(input: &mut Stream<'s>) -> ModalResult<&'s [u8]> {
let _ = take_while(1.., is_horizontal_space).parse_next(input)?;
let data = take_while(1.., till_line_ending).parse_next(input)?;
let _ = line_ending.parse_next(input)?;
Ok(data)
}
fn message_header<'s>(input: &mut Stream<'s>) -> ModalResult<Header<'s>> {
seq!(Header {
name: take_while(1.., is_token),
_: ':',
value: repeat(1.., message_header_value),
})
.parse_next(input)
}
#[rustfmt::skip]
#[allow(clippy::match_same_arms)]
#[allow(clippy::match_like_matches_macro)]
fn is_token(c: u8) -> bool {
match c {
128..=255 => false,
0..=31 => false,
b'(' => false,
b')' => false,
b'<' => false,
b'>' => false,
b'@' => false,
b',' => false,
b';' => false,
b':' => false,
b'\\' => false,
b'"' => false,
b'/' => false,
b'[' => false,
b']' => false,
b'?' => false,
b'=' => false,
b'{' => false,
b'}' => false,
b' ' => false,
_ => true,
}
}
fn is_version(c: u8) -> bool {
c.is_ascii_digit() || c == b'.'
}
fn till_line_ending(c: u8) -> bool {
c != b'\r' && c != b'\n'
}
fn is_space(c: u8) -> bool {
c == b' '
}
fn is_not_space(c: u8) -> bool {
c != b' '
}
fn is_horizontal_space(c: u8) -> bool {
c == b' ' || c == b'\t'
}

62
vendor/winnow/examples/ini/bench.rs vendored Normal file
View File

@@ -0,0 +1,62 @@
use winnow::combinator::repeat;
use winnow::prelude::*;
use winnow::Result;
mod parser;
mod parser_str;
fn bench_ini(c: &mut criterion::Criterion) {
let str = "[owner]
name=John Doe
organization=Acme Widgets Inc.
[database]
server=192.0.2.62
port=143
file=payroll.dat
\0";
let mut group = c.benchmark_group("ini");
group.throughput(criterion::Throughput::Bytes(str.len() as u64));
group.bench_function(criterion::BenchmarkId::new("bytes", str.len()), |b| {
b.iter(|| parser::categories.parse_peek(str.as_bytes()).unwrap());
});
group.bench_function(criterion::BenchmarkId::new("str", str.len()), |b| {
b.iter(|| parser_str::categories.parse_peek(str).unwrap());
});
}
fn bench_ini_keys_and_values(c: &mut criterion::Criterion) {
let str = "server=192.0.2.62
port=143
file=payroll.dat
\0";
fn acc<'s>(i: &mut parser::Stream<'s>) -> Result<Vec<(&'s str, &'s str)>> {
repeat(0.., parser::key_value).parse_next(i)
}
let mut group = c.benchmark_group("ini keys and values");
group.throughput(criterion::Throughput::Bytes(str.len() as u64));
group.bench_function(criterion::BenchmarkId::new("bytes", str.len()), |b| {
b.iter(|| acc.parse_peek(str.as_bytes()).unwrap());
});
}
fn bench_ini_key_value(c: &mut criterion::Criterion) {
let str = "server=192.0.2.62\n";
let mut group = c.benchmark_group("ini key value");
group.throughput(criterion::Throughput::Bytes(str.len() as u64));
group.bench_function(criterion::BenchmarkId::new("bytes", str.len()), |b| {
b.iter(|| parser::key_value.parse_peek(str.as_bytes()).unwrap());
});
}
criterion::criterion_group!(
benches,
bench_ini,
bench_ini_keys_and_values,
bench_ini_key_value
);
criterion::criterion_main!(benches);

60
vendor/winnow/examples/ini/main.rs vendored Normal file
View File

@@ -0,0 +1,60 @@
use winnow::prelude::*;
mod parser;
mod parser_str;
fn main() -> Result<(), lexopt::Error> {
let args = Args::parse()?;
let input = args.input.as_deref().unwrap_or("1 + 1");
if args.binary {
match parser::categories.parse(input.as_bytes()) {
Ok(result) => {
println!(" {result:?}");
}
Err(err) => {
println!(" {err:?}");
}
}
} else {
match parser_str::categories.parse(input) {
Ok(result) => {
println!(" {result:?}");
}
Err(err) => {
println!(" {err}");
}
}
}
Ok(())
}
#[derive(Default)]
struct Args {
input: Option<String>,
binary: bool,
}
impl Args {
fn parse() -> Result<Self, lexopt::Error> {
use lexopt::prelude::*;
let mut res = Args::default();
let mut args = lexopt::Parser::from_env();
while let Some(arg) = args.next()? {
match arg {
Long("binary") => {
res.binary = true;
}
Value(input) => {
res.input = Some(input.string()?);
}
_ => return Err(arg.unexpected()),
}
}
Ok(res)
}
}

149
vendor/winnow/examples/ini/parser.rs vendored Normal file
View File

@@ -0,0 +1,149 @@
use std::collections::HashMap;
use std::str;
use winnow::prelude::*;
use winnow::Result;
use winnow::{
ascii::{alphanumeric1 as alphanumeric, multispace0 as multispace, space0 as space},
combinator::opt,
combinator::repeat,
combinator::{delimited, separated_pair, terminated},
token::take_while,
};
pub(crate) type Stream<'i> = &'i [u8];
pub(crate) fn categories<'s>(
i: &mut Stream<'s>,
) -> Result<HashMap<&'s str, HashMap<&'s str, &'s str>>> {
repeat(
0..,
separated_pair(
category,
opt(multispace),
repeat(0.., terminated(key_value, opt(multispace))),
),
)
.parse_next(i)
}
fn category<'s>(i: &mut Stream<'s>) -> Result<&'s str> {
delimited('[', take_while(0.., |c| c != b']'), ']')
.try_map(str::from_utf8)
.parse_next(i)
}
pub(crate) fn key_value<'s>(i: &mut Stream<'s>) -> Result<(&'s str, &'s str)> {
let key = alphanumeric.try_map(str::from_utf8).parse_next(i)?;
let _ = (opt(space), '=', opt(space)).parse_next(i)?;
let val = take_while(0.., |c| c != b'\n' && c != b';')
.try_map(str::from_utf8)
.parse_next(i)?;
let _ = opt((';', take_while(0.., |c| c != b'\n'))).parse_next(i)?;
Ok((key, val))
}
#[test]
fn parse_category_test() {
let ini_file = &b"[category]
parameter=value
key = value2"[..];
let ini_without_category = &b"\n\nparameter=value
key = value2"[..];
let res = category.parse_peek(ini_file);
println!("{res:?}");
match res {
Ok((i, o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
_ => println!("error"),
}
assert_eq!(res, Ok((ini_without_category, "category")));
}
#[test]
fn parse_key_value_test() {
let ini_file = &b"parameter=value
key = value2"[..];
let ini_without_key_value = &b"\nkey = value2"[..];
let res = key_value.parse_peek(ini_file);
println!("{res:?}");
match res {
Ok((i, (o1, o2))) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
_ => println!("error"),
}
assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value"))));
}
#[test]
fn parse_key_value_with_space_test() {
let ini_file = &b"parameter = value
key = value2"[..];
let ini_without_key_value = &b"\nkey = value2"[..];
let res = key_value.parse_peek(ini_file);
println!("{res:?}");
match res {
Ok((i, (o1, o2))) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
_ => println!("error"),
}
assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value"))));
}
#[test]
fn parse_key_value_with_comment_test() {
let ini_file = &b"parameter=value;abc
key = value2"[..];
let ini_without_key_value = &b"\nkey = value2"[..];
let res = key_value.parse_peek(ini_file);
println!("{res:?}");
match res {
Ok((i, (o1, o2))) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
_ => println!("error"),
}
assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value"))));
}
#[test]
fn parse_multiple_categories_test() {
let ini_file = &b"[abcd]
parameter=value;abc
key = value2
[category]
parameter3=value3
key4 = value4
"[..];
let ini_after_parser = &b""[..];
let res = categories.parse_peek(ini_file);
//println!("{:?}", res);
match res {
Ok((i, ref o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
_ => println!("error"),
}
let mut expected_1: HashMap<&str, &str> = HashMap::new();
expected_1.insert("parameter", "value");
expected_1.insert("key", "value2");
let mut expected_2: HashMap<&str, &str> = HashMap::new();
expected_2.insert("parameter3", "value3");
expected_2.insert("key4", "value4");
let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
expected_h.insert("abcd", expected_1);
expected_h.insert("category", expected_2);
assert_eq!(res, Ok((ini_after_parser, expected_h)));
}

209
vendor/winnow/examples/ini/parser_str.rs vendored Normal file
View File

@@ -0,0 +1,209 @@
use std::collections::HashMap;
use winnow::prelude::*;
use winnow::Result;
use winnow::{
ascii::{alphanumeric1 as alphanumeric, space0 as space},
combinator::opt,
combinator::repeat,
combinator::{delimited, terminated},
token::{take_till, take_while},
};
pub(crate) type Stream<'i> = &'i str;
pub(crate) fn categories<'s>(
input: &mut Stream<'s>,
) -> Result<HashMap<&'s str, HashMap<&'s str, &'s str>>> {
repeat(0.., category_and_keys).parse_next(input)
}
fn category_and_keys<'s>(i: &mut Stream<'s>) -> Result<(&'s str, HashMap<&'s str, &'s str>)> {
(category, keys_and_values).parse_next(i)
}
fn category<'s>(i: &mut Stream<'s>) -> Result<&'s str> {
terminated(
delimited('[', take_while(0.., |c| c != ']'), ']'),
opt(take_while(1.., [' ', '\r', '\n'])),
)
.parse_next(i)
}
fn keys_and_values<'s>(input: &mut Stream<'s>) -> Result<HashMap<&'s str, &'s str>> {
repeat(0.., key_value).parse_next(input)
}
fn key_value<'s>(i: &mut Stream<'s>) -> Result<(&'s str, &'s str)> {
let key = alphanumeric.parse_next(i)?;
let _ = (opt(space), "=", opt(space)).parse_next(i)?;
let val = take_till(0.., is_line_ending_or_comment).parse_next(i)?;
let _ = opt(space).parse_next(i)?;
let _ = opt((";", till_line_ending)).parse_next(i)?;
let _ = opt(space_or_line_ending).parse_next(i)?;
Ok((key, val))
}
fn is_line_ending_or_comment(chr: char) -> bool {
chr == ';' || chr == '\n'
}
fn till_line_ending<'s>(i: &mut Stream<'s>) -> Result<&'s str> {
take_while(0.., |c| c != '\r' && c != '\n').parse_next(i)
}
fn space_or_line_ending<'s>(i: &mut Stream<'s>) -> Result<&'s str> {
take_while(1.., [' ', '\r', '\n']).parse_next(i)
}
#[test]
fn parse_category_test() {
let ini_file = "[category]
parameter=value
key = value2";
let ini_without_category = "parameter=value
key = value2";
let res = category.parse_peek(ini_file);
println!("{res:?}");
match res {
Ok((i, o)) => println!("i: {i} | o: {o:?}"),
_ => println!("error"),
}
assert_eq!(res, Ok((ini_without_category, "category")));
}
#[test]
fn parse_key_value_test() {
let ini_file = "parameter=value
key = value2";
let ini_without_key_value = "key = value2";
let res = key_value.parse_peek(ini_file);
println!("{res:?}");
match res {
Ok((i, (o1, o2))) => println!("i: {i} | o: ({o1:?},{o2:?})"),
_ => println!("error"),
}
assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value"))));
}
#[test]
fn parse_key_value_with_space_test() {
let ini_file = "parameter = value
key = value2";
let ini_without_key_value = "key = value2";
let res = key_value.parse_peek(ini_file);
println!("{res:?}");
match res {
Ok((i, (o1, o2))) => println!("i: {i} | o: ({o1:?},{o2:?})"),
_ => println!("error"),
}
assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value"))));
}
#[test]
fn parse_key_value_with_comment_test() {
let ini_file = "parameter=value;abc
key = value2";
let ini_without_key_value = "key = value2";
let res = key_value.parse_peek(ini_file);
println!("{res:?}");
match res {
Ok((i, (o1, o2))) => println!("i: {i} | o: ({o1:?},{o2:?})"),
_ => println!("error"),
}
assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value"))));
}
#[test]
fn parse_multiple_keys_and_values_test() {
let ini_file = "parameter=value;abc
key = value2
[category]";
let ini_without_key_value = "[category]";
let res = keys_and_values.parse_peek(ini_file);
println!("{res:?}");
match res {
Ok((i, ref o)) => println!("i: {i} | o: {o:?}"),
_ => println!("error"),
}
let mut expected: HashMap<&str, &str> = HashMap::new();
expected.insert("parameter", "value");
expected.insert("key", "value2");
assert_eq!(res, Ok((ini_without_key_value, expected)));
}
#[test]
fn parse_category_then_multiple_keys_and_values_test() {
//FIXME: there can be an empty line or a comment line after a category
let ini_file = "[abcd]
parameter=value;abc
key = value2
[category]";
let ini_after_parser = "[category]";
let res = category_and_keys.parse_peek(ini_file);
println!("{res:?}");
match res {
Ok((i, ref o)) => println!("i: {i} | o: {o:?}"),
_ => println!("error"),
}
let mut expected_h: HashMap<&str, &str> = HashMap::new();
expected_h.insert("parameter", "value");
expected_h.insert("key", "value2");
assert_eq!(res, Ok((ini_after_parser, ("abcd", expected_h))));
}
#[test]
fn parse_multiple_categories_test() {
let ini_file = "[abcd]
parameter=value;abc
key = value2
[category]
parameter3=value3
key4 = value4
";
let res = categories.parse_peek(ini_file);
//println!("{:?}", res);
match res {
Ok((i, ref o)) => println!("i: {i} | o: {o:?}"),
_ => println!("error"),
}
let mut expected_1: HashMap<&str, &str> = HashMap::new();
expected_1.insert("parameter", "value");
expected_1.insert("key", "value2");
let mut expected_2: HashMap<&str, &str> = HashMap::new();
expected_2.insert("parameter3", "value3");
expected_2.insert("key4", "value4");
let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
expected_h.insert("abcd", expected_1);
expected_h.insert("category", expected_2);
assert_eq!(res, Ok(("", expected_h)));
}

65
vendor/winnow/examples/iterator.rs vendored Normal file
View File

@@ -0,0 +1,65 @@
use std::collections::HashMap;
use std::iter::Iterator;
use winnow::ascii::alphanumeric1;
use winnow::combinator::iterator;
use winnow::combinator::{separated_pair, terminated};
use winnow::prelude::*;
fn main() {
let mut data = "abcabcabcabc";
fn parser<'s>(i: &mut &'s str) -> ModalResult<&'s str> {
"abc".parse_next(i)
}
// `from_fn` (available from Rust 1.34) can create an iterator
// from a closure
let it = std::iter::from_fn(move || parser.parse_next(&mut data).ok());
for value in it {
println!("parser returned: {value}");
}
println!("\n********************\n");
let mut data = "abcabcabcabc";
// if `from_fn` is not available, it is possible to fold
// over an iterator of functions
let res = std::iter::repeat(parser)
.take(3)
.try_fold(Vec::new(), |mut acc, mut parser| {
parser.parse_next(&mut data).map(|o| {
acc.push(o);
acc
})
});
// will print "parser iterator returned: Ok(("abc", ["abc", "abc", "abc"]))"
println!("\nparser iterator returned: {res:?}");
println!("\n********************\n");
let data = "key1:value1,key2:value2,key3:value3,;";
// `winnow::combinator::iterator` will return an iterator
// producing the parsed values. Compared to the previous
// solutions:
// - we can work with a normal iterator like `from_fn`
// - we can get the remaining input afterwards, like with the `try_fold` trick
let mut winnow_it = iterator(
data,
terminated(separated_pair(alphanumeric1, ":", alphanumeric1), ","),
);
let res = winnow_it
.map(|(k, v)| (k.to_uppercase(), v))
.collect::<HashMap<_, _>>();
let parser_result: ModalResult<(_, _), ()> = winnow_it.finish();
let (remaining_input, ()) = parser_result.unwrap();
// will print "iterator returned {"key1": "value1", "key3": "value3", "key2": "value2"}, remaining input is ';'"
println!("iterator returned {res:?}, remaining input is '{remaining_input}'");
}

78
vendor/winnow/examples/json/bench.rs vendored Normal file
View File

@@ -0,0 +1,78 @@
use winnow::prelude::*;
use winnow::Partial;
mod json;
mod parser_alt;
mod parser_dispatch;
mod parser_partial;
fn json_bench(c: &mut criterion::Criterion) {
let data = [("small", SMALL), ("canada", CANADA)];
let mut group = c.benchmark_group("json");
for (name, sample) in data {
let len = sample.len();
group.throughput(criterion::Throughput::Bytes(len as u64));
group.bench_with_input(
criterion::BenchmarkId::new("dispatch", name),
&len,
|b, _| {
type Error = winnow::error::ErrMode<winnow::error::ContextError>;
b.iter(|| parser_dispatch::json::<Error>.parse_peek(sample).unwrap());
},
);
group.bench_with_input(
criterion::BenchmarkId::new("modeless", name),
&len,
|b, _| {
type Error = winnow::error::ContextError;
b.iter(|| parser_dispatch::json::<Error>.parse_peek(sample).unwrap());
},
);
group.bench_with_input(
criterion::BenchmarkId::new("empty-error", name),
&len,
|b, _| {
type Error<'i> = winnow::error::EmptyError;
b.iter(|| {
parser_dispatch::json::<Error<'_>>
.parse_peek(sample)
.unwrap()
});
},
);
group.bench_with_input(criterion::BenchmarkId::new("alt", name), &len, |b, _| {
type Error = winnow::error::ContextError;
b.iter(|| parser_alt::json::<Error>.parse_peek(sample).unwrap());
});
group.bench_with_input(
criterion::BenchmarkId::new("streaming", name),
&len,
|b, _| {
type Error = winnow::error::ContextError;
b.iter(|| {
parser_partial::json::<Error>
.parse_peek(Partial::new(sample))
.unwrap()
});
},
);
}
group.finish();
}
const SMALL: &str = " { \"a\"\t: 42,
\"b\": [ \"x\", \"y\", 12 ,\"\\u2014\", \"\\uD83D\\uDE10\"] ,
\"c\": { \"hello\" : \"world\"
}
} ";
const CANADA: &str = include_str!("../../third_party/nativejson-benchmark/data/canada.json");
criterion::criterion_group!(benches, json_bench,);
criterion::criterion_main!(benches);

11
vendor/winnow/examples/json/json.rs vendored Normal file
View File

@@ -0,0 +1,11 @@
use std::collections::HashMap;
#[derive(Debug, PartialEq, Clone)]
pub(crate) enum JsonValue {
Null,
Boolean(bool),
Str(String),
Num(f64),
Array(Vec<JsonValue>),
Object(HashMap<String, JsonValue>),
}

98
vendor/winnow/examples/json/main.rs vendored Normal file
View File

@@ -0,0 +1,98 @@
mod json;
mod parser_alt;
mod parser_dispatch;
#[allow(dead_code)]
mod parser_partial;
use winnow::error::EmptyError;
use winnow::prelude::*;
fn main() -> Result<(), lexopt::Error> {
let args = Args::parse()?;
let data = args.input.as_deref().unwrap_or(if args.invalid {
" { \"a\"\t: 42,
\"b\": [ \"x\", \"y\", 12 ] ,
\"c\": { 1\"hello\" : \"world\"
}
} "
} else {
" { \"a\"\t: 42,
\"b\": [ \"x\", \"y\", 12 ] ,
\"c\": { \"hello\" : \"world\"
}
} "
});
let result = match args.implementation {
Impl::Naive => parser_alt::json::<EmptyError>.parse(data),
Impl::Dispatch => parser_dispatch::json::<EmptyError>.parse(data),
};
match result {
Ok(json) => {
println!("{json:#?}");
}
Err(err) => {
if args.pretty {
println!("{err}");
} else {
println!("{err:#?}");
}
}
}
Ok(())
}
#[derive(Default)]
struct Args {
input: Option<String>,
invalid: bool,
pretty: bool,
implementation: Impl,
}
enum Impl {
Naive,
Dispatch,
}
impl Default for Impl {
fn default() -> Self {
Self::Naive
}
}
impl Args {
fn parse() -> Result<Self, lexopt::Error> {
use lexopt::prelude::*;
let mut res = Args::default();
let mut args = lexopt::Parser::from_env();
while let Some(arg) = args.next()? {
match arg {
Long("invalid") => {
res.invalid = true;
}
Long("pretty") => {
// Only case where pretty matters
res.pretty = true;
res.invalid = true;
}
Long("impl") => {
res.implementation = args.value()?.parse_with(|s| match s {
"naive" => Ok(Impl::Naive),
"dispatch" => Ok(Impl::Dispatch),
_ => Err("expected `naive`, `dispatch`"),
})?;
}
Value(input) => {
res.input = Some(input.string()?);
}
_ => return Err(arg.unexpected()),
}
}
Ok(res)
}
}

View File

@@ -0,0 +1,323 @@
use std::collections::HashMap;
use std::str;
use winnow::prelude::*;
use winnow::{
ascii::float,
combinator::alt,
combinator::cut_err,
combinator::{delimited, preceded, separated_pair, terminated},
combinator::{repeat, separated},
error::{AddContext, ParserError, StrContext},
token::{any, none_of, take, take_while},
};
use crate::json::JsonValue;
pub(crate) type Stream<'i> = &'i str;
/// The root element of a JSON parser is any value
///
/// A parser has the following signature:
/// `&mut Stream -> ModalResult<Output, ContextError>`, with `ModalResult` defined as:
/// `type ModalResult<O, E = (I, ErrorKind)> = Result<O, Err<E>>;`
///
/// most of the times you can ignore the error type and use the default (but this
/// examples shows custom error types later on!)
///
/// Here we use `&str` as input type, but parsers can be generic over
/// the input type, work directly with `&[u8]`, or any other type that
/// implements the required traits.
pub(crate) fn json<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<JsonValue, E> {
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: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<JsonValue, E> {
// `alt` combines the each value parser. It returns the result of the first
// successful parser, or an error
alt((
null.value(JsonValue::Null),
boolean.map(JsonValue::Boolean),
string.map(JsonValue::Str),
float.map(JsonValue::Num),
array.map(JsonValue::Array),
object.map(JsonValue::Object),
))
.parse_next(input)
}
/// `literal(string)` generates a parser that takes the argument string.
///
/// This also shows returning a sub-slice of the original input
fn null<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<&'i str, E> {
// This is a parser that returns `"null"` if it sees the string "null", and
// an error otherwise
"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: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<bool, E> {
// This is a parser that returns `true` if it sees the string "true", and
// an error otherwise
let parse_true = "true".value(true);
// This is a parser that returns `false` if it sees the string "false", and
// an error otherwise
let parse_false = "false".value(false);
alt((parse_true, parse_false)).parse_next(input)
}
/// This parser gathers all `char`s up into a `String`with a parse to take the double quote
/// character, before the string (using `preceded`) and after the string (using `terminated`).
fn string<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<String, E> {
preceded(
'\"',
// `cut_err` transforms an `ErrMode::Backtrack(e)` to `ErrMode::Cut(e)`, signaling to
// combinators like `alt` that they should not try other parsers. We were in the
// right branch (since we found the `"` character) but encountered an error when
// parsing the string
cut_err(terminated(
repeat(0.., character).fold(String::new, |mut string, c| {
string.push(c);
string
}),
'\"',
)),
)
// `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(StrContext::Expected("string".into()))
.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: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<char, E> {
let c = none_of('\"').parse_next(input)?;
if c == '\\' {
alt((
any.verify_map(|c| {
Some(match c {
'"' | '\\' | '/' => c,
'b' => '\x08',
'f' => '\x0C',
'n' => '\n',
'r' => '\r',
't' => '\t',
_ => return None,
})
}),
preceded('u', unicode_escape),
))
.parse_next(input)
} else {
Ok(c)
}
}
fn unicode_escape<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<char, E> {
alt((
// Not a surrogate
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(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;
let low_ten = (low as u32) - 0xDC00;
(high_ten << 10) + low_ten + 0x10000
}),
))
.verify_map(
// Could be probably replaced with .unwrap() or _unchecked due to the verify checks
std::char::from_u32,
)
.parse_next(input)
}
fn u16_hex<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<u16, E> {
take(4usize)
.verify_map(|s| u16::from_str_radix(s, 16).ok())
.parse_next(input)
}
/// Some combinators, like `separated` or `repeat`, will call a parser repeatedly,
/// accumulating results in a `Vec`, until it encounters an error.
/// If you want more control on the parser application, check out the `iterator`
/// combinator (cf `examples/iterator.rs`)
fn array<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<Vec<JsonValue>, E> {
preceded(
('[', ws),
cut_err(terminated(
separated(0.., json_value, (ws, ',', ws)),
(ws, ']'),
)),
)
.context(StrContext::Expected("array".into()))
.parse_next(input)
}
fn object<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<HashMap<String, JsonValue>, E> {
preceded(
('{', ws),
cut_err(terminated(
separated(0.., key_value, (ws, ',', ws)),
(ws, '}'),
)),
)
.context(StrContext::Expected("object".into()))
.parse_next(input)
}
fn key_value<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<(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: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<&'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_next(input)
}
const WS: &[char] = &[' ', '\t', '\r', '\n'];
#[cfg(test)]
mod test {
#[allow(clippy::useless_attribute)]
#[allow(unused_imports)] // its dead for benches
use super::*;
#[allow(clippy::useless_attribute)]
#[allow(dead_code)] // its dead for benches
type Error = winnow::error::ContextError;
#[test]
fn json_string() {
assert_eq!(string::<Error>.parse_peek("\"\""), Ok(("", "".to_owned())));
assert_eq!(
string::<Error>.parse_peek("\"abc\""),
Ok(("", "abc".to_owned()))
);
assert_eq!(
string::<Error>
.parse_peek("\"abc\\\"\\\\\\/\\b\\f\\n\\r\\t\\u0001\\u2014\u{2014}def\""),
Ok(("", "abc\"\\/\x08\x0C\n\r\t\x01——def".to_owned())),
);
assert_eq!(
string::<Error>.parse_peek("\"\\uD83D\\uDE10\""),
Ok(("", "😐".to_owned()))
);
assert!(string::<Error>.parse_peek("\"").is_err());
assert!(string::<Error>.parse_peek("\"abc").is_err());
assert!(string::<Error>.parse_peek("\"\\\"").is_err());
assert!(string::<Error>.parse_peek("\"\\u123\"").is_err());
assert!(string::<Error>.parse_peek("\"\\uD800\"").is_err());
assert!(string::<Error>.parse_peek("\"\\uD800\\uD800\"").is_err());
assert!(string::<Error>.parse_peek("\"\\uDC00\"").is_err());
}
#[test]
fn json_object() {
use JsonValue::{Num, Object, Str};
let input = r#"{"a":42,"b":"x"}"#;
let expected = Object(
vec![
("a".to_owned(), Num(42.0)),
("b".to_owned(), Str("x".to_owned())),
]
.into_iter()
.collect(),
);
assert_eq!(json::<Error>.parse_peek(input), Ok(("", expected)));
}
#[test]
fn json_array() {
use JsonValue::{Array, Num, Str};
let input = r#"[42,"x"]"#;
let expected = Array(vec![Num(42.0), Str("x".to_owned())]);
assert_eq!(json::<Error>.parse_peek(input), Ok(("", expected)));
}
#[test]
fn json_whitespace() {
use JsonValue::{Array, Boolean, Null, Num, Object, Str};
let input = r#"
{
"null" : null,
"true" :true ,
"false": false ,
"number" : 123e4 ,
"string" : " abc 123 " ,
"array" : [ false , 1 , "two" ] ,
"object" : { "a" : 1.0 , "b" : "c" } ,
"empty_array" : [ ] ,
"empty_object" : { }
}
"#;
assert_eq!(
json::<Error>.parse_peek(input),
Ok((
"",
Object(
vec![
("null".to_owned(), Null),
("true".to_owned(), Boolean(true)),
("false".to_owned(), Boolean(false)),
("number".to_owned(), Num(123e4)),
("string".to_owned(), Str(" abc 123 ".to_owned())),
(
"array".to_owned(),
Array(vec![Boolean(false), Num(1.0), Str("two".to_owned())])
),
(
"object".to_owned(),
Object(
vec![
("a".to_owned(), Num(1.0)),
("b".to_owned(), Str("c".to_owned())),
]
.into_iter()
.collect()
)
),
("empty_array".to_owned(), Array(vec![]),),
("empty_object".to_owned(), Object(HashMap::new()),),
]
.into_iter()
.collect()
)
))
);
}
}

View File

@@ -0,0 +1,319 @@
use std::collections::HashMap;
use std::str;
use winnow::prelude::*;
use winnow::Result;
use winnow::{
ascii::float,
combinator::empty,
combinator::fail,
combinator::peek,
combinator::{alt, dispatch},
combinator::{delimited, preceded, separated_pair, terminated},
combinator::{repeat, separated},
error::{AddContext, ParserError, StrContext},
token::{any, none_of, take, take_while},
};
use crate::json::JsonValue;
pub(crate) type Stream<'i> = &'i str;
/// The root element of a JSON parser is any value
///
/// A parser has the following signature:
/// `&mut Stream -> Result<Output ContextError>`
///
/// most of the times you can ignore the error type and use the default (but this
/// examples shows custom error types later on!)
///
/// Here we use `&str` as input type, but parsers can be generic over
/// the input type, work directly with `&[u8]`, or any other type that
/// implements the required traits.
pub(crate) fn json<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> Result<JsonValue, E> {
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: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> Result<JsonValue, E> {
// `dispatch` gives you `match`-like behavior compared to `alt` successively trying different
// implementations.
dispatch!(peek(any);
'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),
'[' => array.map(JsonValue::Array),
'{' => object.map(JsonValue::Object),
_ => fail,
)
.parse_next(input)
}
/// `literal(string)` generates a parser that takes the argument string.
///
/// This also shows returning a sub-slice of the original input
fn null<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> Result<&'i str, E> {
// This is a parser that returns `"null"` if it sees the string "null", and
// an error otherwise
"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: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> Result<bool, E> {
// This is a parser that returns `true` if it sees the string "true", and
// an error otherwise
"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: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> Result<bool, E> {
// This is a parser that returns `false` if it sees the string "false", and
// an error otherwise
"false".value(false).parse_next(input)
}
/// This parser gathers all `char`s up into a `String`with a parse to take the double quote
/// character, before the string (using `preceded`) and after the string (using `terminated`).
fn string<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> Result<String, E> {
preceded(
'\"',
terminated(
repeat(0.., character).fold(String::new, |mut string, c| {
string.push(c);
string
}),
'\"',
),
)
// `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(StrContext::Expected("string".into()))
.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: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> Result<char, E> {
let c = none_of('\"').parse_next(input)?;
if c == '\\' {
dispatch!(any;
'"' => empty.value('"'),
'\\' => empty.value('\\'),
'/' => empty.value('/'),
'b' => empty.value('\x08'),
'f' => empty.value('\x0C'),
'n' => empty.value('\n'),
'r' => empty.value('\r'),
't' => empty.value('\t'),
'u' => unicode_escape,
_ => fail,
)
.parse_next(input)
} else {
Ok(c)
}
}
fn unicode_escape<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> Result<char, E> {
alt((
// Not a surrogate
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(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;
let low_ten = (low as u32) - 0xDC00;
(high_ten << 10) + low_ten + 0x10000
}),
))
.verify_map(
// Could be probably replaced with .unwrap() or _unchecked due to the verify checks
std::char::from_u32,
)
.parse_next(input)
}
fn u16_hex<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> Result<u16, E> {
take(4usize)
.verify_map(|s| u16::from_str_radix(s, 16).ok())
.parse_next(input)
}
/// Some combinators, like `separated` or `repeat`, will call a parser repeatedly,
/// accumulating results in a `Vec`, until it encounters an error.
/// If you want more control on the parser application, check out the `iterator`
/// combinator (cf `examples/iterator.rs`)
fn array<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> Result<Vec<JsonValue>, E> {
preceded(
('[', ws),
terminated(separated(0.., json_value, (ws, ',', ws)), (ws, ']')),
)
.context(StrContext::Expected("array".into()))
.parse_next(input)
}
fn object<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> Result<HashMap<String, JsonValue>, E> {
preceded(
('{', ws),
terminated(separated(0.., key_value, (ws, ',', ws)), (ws, '}')),
)
.context(StrContext::Expected("object".into()))
.parse_next(input)
}
fn key_value<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> Result<(String, JsonValue), E> {
separated_pair(string, (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: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> Result<&'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_next(input)
}
const WS: &[char] = &[' ', '\t', '\r', '\n'];
#[cfg(test)]
mod test {
#[allow(clippy::useless_attribute)]
#[allow(unused_imports)] // its dead for benches
use super::*;
#[allow(clippy::useless_attribute)]
#[allow(dead_code)] // its dead for benches
type Error = winnow::error::ContextError;
#[test]
fn json_string() {
assert_eq!(string::<Error>.parse_peek("\"\""), Ok(("", "".to_owned())));
assert_eq!(
string::<Error>.parse_peek("\"abc\""),
Ok(("", "abc".to_owned()))
);
assert_eq!(
string::<Error>
.parse_peek("\"abc\\\"\\\\\\/\\b\\f\\n\\r\\t\\u0001\\u2014\u{2014}def\""),
Ok(("", "abc\"\\/\x08\x0C\n\r\t\x01——def".to_owned())),
);
assert_eq!(
string::<Error>.parse_peek("\"\\uD83D\\uDE10\""),
Ok(("", "😐".to_owned()))
);
assert!(string::<Error>.parse_peek("\"").is_err());
assert!(string::<Error>.parse_peek("\"abc").is_err());
assert!(string::<Error>.parse_peek("\"\\\"").is_err());
assert!(string::<Error>.parse_peek("\"\\u123\"").is_err());
assert!(string::<Error>.parse_peek("\"\\uD800\"").is_err());
assert!(string::<Error>.parse_peek("\"\\uD800\\uD800\"").is_err());
assert!(string::<Error>.parse_peek("\"\\uDC00\"").is_err());
}
#[test]
fn json_object() {
use JsonValue::{Num, Object, Str};
let input = r#"{"a":42,"b":"x"}"#;
let expected = Object(
vec![
("a".to_owned(), Num(42.0)),
("b".to_owned(), Str("x".to_owned())),
]
.into_iter()
.collect(),
);
assert_eq!(json::<Error>.parse_peek(input), Ok(("", expected)));
}
#[test]
fn json_array() {
use JsonValue::{Array, Num, Str};
let input = r#"[42,"x"]"#;
let expected = Array(vec![Num(42.0), Str("x".to_owned())]);
assert_eq!(json::<Error>.parse_peek(input), Ok(("", expected)));
}
#[test]
fn json_whitespace() {
use JsonValue::{Array, Boolean, Null, Num, Object, Str};
let input = r#"
{
"null" : null,
"true" :true ,
"false": false ,
"number" : 123e4 ,
"string" : " abc 123 " ,
"array" : [ false , 1 , "two" ] ,
"object" : { "a" : 1.0 , "b" : "c" } ,
"empty_array" : [ ] ,
"empty_object" : { }
}
"#;
assert_eq!(
json::<Error>.parse_peek(input),
Ok((
"",
Object(
vec![
("null".to_owned(), Null),
("true".to_owned(), Boolean(true)),
("false".to_owned(), Boolean(false)),
("number".to_owned(), Num(123e4)),
("string".to_owned(), Str(" abc 123 ".to_owned())),
(
"array".to_owned(),
Array(vec![Boolean(false), Num(1.0), Str("two".to_owned())])
),
(
"object".to_owned(),
Object(
vec![
("a".to_owned(), Num(1.0)),
("b".to_owned(), Str("c".to_owned())),
]
.into_iter()
.collect()
)
),
("empty_array".to_owned(), Array(vec![]),),
("empty_object".to_owned(), Object(HashMap::new()),),
]
.into_iter()
.collect()
)
))
);
}
}

View File

@@ -0,0 +1,350 @@
use std::collections::HashMap;
use std::str;
use winnow::prelude::*;
use winnow::{
ascii::float,
combinator::alt,
combinator::cut_err,
combinator::{delimited, preceded, separated_pair, terminated},
combinator::{repeat, separated},
error::{AddContext, ParserError, StrContext},
stream::Partial,
token::{any, none_of, rest, take, take_while},
};
use crate::json::JsonValue;
pub(crate) type Stream<'i> = Partial<&'i str>;
/// The root element of a JSON parser is any value
///
/// A parser has the following signature:
/// `&mut Stream -> ModalResult<Output, ContextError>`, with `ModalResult` defined as:
/// `type ModalResult<O, E = ErrorKind> = Result<O, ErrMode<E>>;`
///
/// most of the times you can ignore the error type and use the default (but this
/// examples shows custom error types later on!)
///
/// Here we use `&str` as input type, but parsers can be generic over
/// the input type, work directly with `&[u8]`, or any other type that
/// implements the required traits.
pub(crate) fn json<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<JsonValue, E> {
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: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<JsonValue, E> {
// `alt` combines the each value parser. It returns the result of the first
// successful parser, or an error
alt((
null.value(JsonValue::Null),
boolean.map(JsonValue::Boolean),
string.map(JsonValue::Str),
float.map(JsonValue::Num),
array.map(JsonValue::Array),
object.map(JsonValue::Object),
))
.parse_next(input)
}
/// `literal(string)` generates a parser that takes the argument string.
///
/// This also shows returning a sub-slice of the original input
fn null<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<&'i str, E> {
// This is a parser that returns `"null"` if it sees the string "null", and
// an error otherwise
"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: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<bool, E> {
// This is a parser that returns `true` if it sees the string "true", and
// an error otherwise
let parse_true = "true".value(true);
// This is a parser that returns `false` if it sees the string "false", and
// an error otherwise
let parse_false = "false".value(false);
alt((parse_true, parse_false)).parse_next(input)
}
/// This parser gathers all `char`s up into a `String`with a parse to take the double quote
/// character, before the string (using `preceded`) and after the string (using `terminated`).
fn string<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<String, E> {
preceded(
'\"',
// `cut_err` transforms an `ErrMode::Backtrack(e)` to `ErrMode::Cut(e)`, signaling to
// combinators like `alt` that they should not try other parsers. We were in the
// right branch (since we found the `"` character) but encountered an error when
// parsing the string
cut_err(terminated(
repeat(0.., character).fold(String::new, |mut string, c| {
string.push(c);
string
}),
'\"',
)),
)
// `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(StrContext::Expected("string".into()))
.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: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<char, E> {
let c = none_of('\"').parse_next(input)?;
if c == '\\' {
alt((
any.verify_map(|c| {
Some(match c {
'"' | '\\' | '/' => c,
'b' => '\x08',
'f' => '\x0C',
'n' => '\n',
'r' => '\r',
't' => '\t',
_ => return None,
})
}),
preceded('u', unicode_escape),
))
.parse_next(input)
} else {
Ok(c)
}
}
fn unicode_escape<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<char, E> {
alt((
// Not a surrogate
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(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;
let low_ten = (low as u32) - 0xDC00;
(high_ten << 10) + low_ten + 0x10000
}),
))
.verify_map(
// Could be probably replaced with .unwrap() or _unchecked due to the verify checks
std::char::from_u32,
)
.parse_next(input)
}
fn u16_hex<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<u16, E> {
take(4usize)
.verify_map(|s| u16::from_str_radix(s, 16).ok())
.parse_next(input)
}
/// Some combinators, like `separated` or `repeat`, will call a parser repeatedly,
/// accumulating results in a `Vec`, until it encounters an error.
/// If you want more control on the parser application, check out the `iterator`
/// combinator (cf `examples/iterator.rs`)
fn array<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<Vec<JsonValue>, E> {
preceded(
('[', ws),
cut_err(terminated(
separated(0.., json_value, (ws, ',', ws)),
(ws, ']'),
)),
)
.context(StrContext::Expected("array".into()))
.parse_next(input)
}
fn object<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<HashMap<String, JsonValue>, E> {
preceded(
('{', ws),
cut_err(terminated(
separated(0.., key_value, (ws, ',', ws)),
(ws, '}'),
)),
)
.context(StrContext::Expected("object".into()))
.parse_next(input)
}
fn key_value<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<(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: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<&'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_next(input)
}
fn ws_or_eof<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<&'i str, E> {
rest.verify(|s: &str| s.chars().all(|c| WS.contains(&c)))
.parse_next(input)
}
const WS: &[char] = &[' ', '\t', '\r', '\n'];
#[cfg(test)]
mod test {
#[allow(clippy::useless_attribute)]
#[allow(unused_imports)] // its dead for benches
use super::*;
#[allow(clippy::useless_attribute)]
#[allow(dead_code)] // its dead for benches
type Error = winnow::error::ContextError;
#[test]
fn json_string() {
assert_eq!(
string::<Error>.parse_peek(Partial::new("\"\"")),
Ok((Partial::new(""), "".to_owned()))
);
assert_eq!(
string::<Error>.parse_peek(Partial::new("\"abc\"")),
Ok((Partial::new(""), "abc".to_owned()))
);
assert_eq!(
string::<Error>.parse_peek(Partial::new(
"\"abc\\\"\\\\\\/\\b\\f\\n\\r\\t\\u0001\\u2014\u{2014}def\""
)),
Ok((
Partial::new(""),
"abc\"\\/\x08\x0C\n\r\t\x01——def".to_owned()
)),
);
assert_eq!(
string::<Error>.parse_peek(Partial::new("\"\\uD83D\\uDE10\"")),
Ok((Partial::new(""), "😐".to_owned()))
);
assert!(string::<Error>.parse_peek(Partial::new("\"")).is_err());
assert!(string::<Error>.parse_peek(Partial::new("\"abc")).is_err());
assert!(string::<Error>.parse_peek(Partial::new("\"\\\"")).is_err());
assert!(string::<Error>
.parse_peek(Partial::new("\"\\u123\""))
.is_err());
assert!(string::<Error>
.parse_peek(Partial::new("\"\\uD800\""))
.is_err());
assert!(string::<Error>
.parse_peek(Partial::new("\"\\uD800\\uD800\""))
.is_err());
assert!(string::<Error>
.parse_peek(Partial::new("\"\\uDC00\""))
.is_err());
}
#[test]
fn json_object() {
use JsonValue::{Num, Object, Str};
let input = r#"{"a":42,"b":"x"}"#;
let expected = Object(
vec![
("a".to_owned(), Num(42.0)),
("b".to_owned(), Str("x".to_owned())),
]
.into_iter()
.collect(),
);
assert_eq!(
json::<Error>.parse_peek(Partial::new(input)),
Ok((Partial::new(""), expected))
);
}
#[test]
fn json_array() {
use JsonValue::{Array, Num, Str};
let input = r#"[42,"x"]"#;
let expected = Array(vec![Num(42.0), Str("x".to_owned())]);
assert_eq!(
json::<Error>.parse_peek(Partial::new(input)),
Ok((Partial::new(""), expected))
);
}
#[test]
fn json_whitespace() {
use JsonValue::{Array, Boolean, Null, Num, Object, Str};
let input = r#"
{
"null" : null,
"true" :true ,
"false": false ,
"number" : 123e4 ,
"string" : " abc 123 " ,
"array" : [ false , 1 , "two" ] ,
"object" : { "a" : 1.0 , "b" : "c" } ,
"empty_array" : [ ] ,
"empty_object" : { }
}
"#;
assert_eq!(
json::<Error>.parse_peek(Partial::new(input)),
Ok((
Partial::new(""),
Object(
vec![
("null".to_owned(), Null),
("true".to_owned(), Boolean(true)),
("false".to_owned(), Boolean(false)),
("number".to_owned(), Num(123e4)),
("string".to_owned(), Str(" abc 123 ".to_owned())),
(
"array".to_owned(),
Array(vec![Boolean(false), Num(1.0), Str("two".to_owned())])
),
(
"object".to_owned(),
Object(
vec![
("a".to_owned(), Num(1.0)),
("b".to_owned(), Str("c".to_owned())),
]
.into_iter()
.collect()
)
),
("empty_array".to_owned(), Array(vec![]),),
("empty_object".to_owned(), Object(HashMap::new()),),
]
.into_iter()
.collect()
)
))
);
}
}

311
vendor/winnow/examples/json_iterator.rs vendored Normal file
View File

@@ -0,0 +1,311 @@
use std::collections::HashMap;
use winnow::prelude::*;
use winnow::{
ascii::{alphanumeric1 as alphanumeric, float, take_escaped},
combinator::alt,
combinator::cut_err,
combinator::separated,
combinator::{preceded, separated_pair, terminated},
error::ParserError,
error::StrContext,
stream::Offset,
token::one_of,
token::{literal, take_while},
};
use std::cell::Cell;
use std::str;
#[derive(Clone, Debug)]
pub struct JsonValue<'a, 'b> {
input: &'a str,
pub offset: &'b Cell<usize>,
}
impl<'a, 'b: 'a> JsonValue<'a, 'b> {
pub fn new(input: &'a str, offset: &'b Cell<usize>) -> JsonValue<'a, 'b> {
JsonValue { input, offset }
}
pub fn offset(&self, input: &'a str) {
let offset = input.offset_from(&self.input);
self.offset.set(offset);
}
pub fn data(&self) -> &'a str {
&self.input[self.offset.get()..]
}
pub fn string(&self) -> Option<&'a str> {
println!("string()");
let mut data = self.data();
match string(&mut data) {
Ok(s) => {
self.offset(data);
println!("-> {s}");
Some(s)
}
_ => None,
}
}
pub fn boolean(&self) -> Option<bool> {
println!("boolean()");
let mut data = self.data();
match boolean(&mut data) {
Ok(o) => {
self.offset(data);
println!("-> {o}");
Some(o)
}
_ => None,
}
}
pub fn number(&self) -> Option<f64> {
println!("number()");
let mut data = self.data();
match float::<_, _, ()>.parse_next(&mut data) {
Ok(o) => {
self.offset(data);
println!("-> {o}");
Some(o)
}
_ => None,
}
}
pub fn array(&self) -> Option<impl Iterator<Item = JsonValue<'a, 'b>>> {
println!("array()");
let mut data = self.data();
match literal::<_, _, ()>("[").parse_next(&mut data) {
Err(_) => None,
Ok(_) => {
println!("[");
self.offset(data);
let mut first = true;
let mut done = false;
let mut previous = usize::MAX;
let v = self.clone();
Some(std::iter::from_fn(move || {
if done {
return None;
}
// if we ignored one of the items, skip over the value
if v.offset.get() == previous {
println!("skipping value");
if value(&mut data).is_ok() {
v.offset(data);
}
}
if literal::<_, _, ()>("]").parse_next(&mut data).is_ok() {
println!("]");
v.offset(data);
done = true;
return None;
}
if first {
first = false;
} else {
match literal::<_, _, ()>(",").parse_next(&mut data) {
Ok(_) => {
println!(",");
v.offset(data);
}
Err(_) => {
done = true;
return None;
}
}
}
println!("-> {}", v.data());
previous = v.offset.get();
Some(v.clone())
}))
}
}
}
pub fn object(&self) -> Option<impl Iterator<Item = (&'a str, JsonValue<'a, 'b>)>> {
println!("object()");
let mut data = self.data();
match literal::<_, _, ()>("{").parse_next(&mut data) {
Err(_) => None,
Ok(_) => {
self.offset(data);
println!("{{");
let mut first = true;
let mut done = false;
let mut previous = usize::MAX;
let v = self.clone();
Some(std::iter::from_fn(move || {
if done {
return None;
}
// if we ignored one of the items, skip over the value
if v.offset.get() == previous {
println!("skipping value");
if value(&mut data).is_ok() {
v.offset(data);
}
}
if literal::<_, _, ()>("}").parse_next(&mut data).is_ok() {
println!("}}");
v.offset(data);
done = true;
return None;
}
if first {
first = false;
} else {
match literal::<_, _, ()>(",").parse_next(&mut data) {
Ok(_) => {
println!(",");
v.offset(data);
}
Err(_) => {
done = true;
return None;
}
}
}
match string(&mut data) {
Ok(key) => {
v.offset(data);
match literal::<_, _, ()>(":").parse_next(&mut data) {
Err(_) => None,
Ok(_) => {
v.offset(data);
previous = v.offset.get();
println!("-> {} => {}", key, v.data());
Some((key, v.clone()))
}
}
}
_ => None,
}
}))
}
}
}
}
fn sp<'a, E: ParserError<&'a str>>(i: &mut &'a str) -> ModalResult<&'a str, E> {
let chars = " \t\r\n";
take_while(0.., move |c| chars.contains(c)).parse_next(i)
}
fn parse_str<'a, E: ParserError<&'a str>>(i: &mut &'a str) -> ModalResult<&'a str, E> {
take_escaped(alphanumeric, '\\', one_of(['"', 'n', '\\'])).parse_next(i)
}
fn string<'s>(i: &mut &'s str) -> ModalResult<&'s str> {
preceded('\"', cut_err(terminated(parse_str, '\"')))
.context(StrContext::Label("string"))
.parse_next(i)
}
fn boolean(input: &mut &str) -> ModalResult<bool> {
alt(("false".map(|_| false), "true".map(|_| true))).parse_next(input)
}
fn array(i: &mut &str) -> ModalResult<()> {
preceded(
'[',
cut_err(terminated(
separated(0.., value, preceded(sp, ',')),
preceded(sp, ']'),
)),
)
.context(StrContext::Label("array"))
.parse_next(i)
}
fn key_value<'s>(i: &mut &'s str) -> ModalResult<(&'s str, ())> {
separated_pair(preceded(sp, string), cut_err(preceded(sp, ':')), value).parse_next(i)
}
fn hash(i: &mut &str) -> ModalResult<()> {
preceded(
'{',
cut_err(terminated(
separated(0.., key_value, preceded(sp, ',')),
preceded(sp, '}'),
)),
)
.context(StrContext::Label("map"))
.parse_next(i)
}
fn value(i: &mut &str) -> ModalResult<()> {
preceded(
sp,
alt((
hash,
array,
string.map(|_| ()),
float::<_, f64, _>.map(|_| ()),
boolean.map(|_| ()),
)),
)
.parse_next(i)
}
/// object(input) -> iterator over (key, `JsonValue`)
/// array(input) -> iterator over `JsonValue`
///
/// JsonValue.string -> iterator over String (returns None after first successful call)
///
/// object(input).filter(|(k, _)| k == "users").flatten(|(_, v)| v.object()).filter(|(k, _)| k == "city").flatten(|(_,v)| `v.string()`)
fn main() {
/*let data = "{
\"users\": {
\"user1\" : { \"city\": \"Nantes\", \"country\": \"France\" },
\"user2\" : { \"city\": \"Bruxelles\", \"country\": \"Belgium\" },
\"user3\": { \"city\": \"Paris\", \"country\": \"France\", \"age\": 30 }
},
\"countries\": [\"France\", \"Belgium\"]
}";
*/
let data = "{\"users\":{\"user1\":{\"city\":\"Nantes\",\"country\":\"France\"},\"user2\":{\"city\":\"Bruxelles\",\"country\":\"Belgium\"},\"user3\":{\"city\":\"Paris\",\"country\":\"France\",\"age\":30}},\"countries\":[\"France\",\"Belgium\"]}";
let offset = Cell::new(0);
{
let parser = JsonValue::new(data, &offset);
if let Some(o) = parser.object() {
let s: HashMap<&str, &str> = o
.filter(|(k, _)| *k == "users")
.filter_map(|(_, v)| v.object())
.flatten()
.filter_map(|(user, v)| v.object().map(|o| (user, o)))
.flat_map(|(user, o)| {
o.filter(|(k, _)| *k == "city")
.filter_map(move |(_, v)| v.string().map(|s| (user, s)))
})
.collect();
println!("res = {s:?}");
}
};
}

View File

@@ -0,0 +1,158 @@
{"reason":"compiler-artifact","package_id":"proc-macro2 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-1.0.46/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-1.0.46/build.rs","edition":"2018","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","proc-macro"],"filenames":["/home/epage/src/personal/winnow/target/debug/build/proc-macro2-d6a7808ec27a845d/build-script-build"],"executable":null,"fresh":true}
{"reason":"build-script-executed","package_id":"proc-macro2 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":["use_proc_macro","wrap_proc_macro"],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/proc-macro2-e500f83d0dabcc00/out"}
{"reason":"compiler-artifact","package_id":"quote 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/quote-1.0.21/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/quote-1.0.21/build.rs","edition":"2018","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","proc-macro"],"filenames":["/home/epage/src/personal/winnow/target/debug/build/quote-e70da9bace8e108a/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"libc 0.2.139 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.139/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.139/build.rs","edition":"2015","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","extra_traits","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/build/libc-ea536a8e67e0b7eb/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"unicode-ident 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/unicode-ident-1.0.5/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"unicode-ident","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/unicode-ident-1.0.5/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libunicode_ident-e72d3e3fa5fdcbf4.rlib","/home/epage/src/personal/winnow/target/debug/deps/libunicode_ident-e72d3e3fa5fdcbf4.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"proc-macro2 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-1.0.46/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"proc-macro2","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-1.0.46/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","proc-macro"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libproc_macro2-559e547b03a7ac1e.rlib","/home/epage/src/personal/winnow/target/debug/deps/libproc_macro2-559e547b03a7ac1e.rmeta"],"executable":null,"fresh":true}
{"reason":"build-script-executed","package_id":"libc 0.2.139 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":["freebsd11","libc_priv_mod_use","libc_union","libc_const_size_of","libc_align","libc_int128","libc_core_cvoid","libc_packedN","libc_cfg_target_vendor","libc_non_exhaustive","libc_ptr_addr_of","libc_underscore_const_names","libc_const_extern_fn"],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/libc-94d2f48bd38a8056/out"}
{"reason":"build-script-executed","package_id":"quote 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":[],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/quote-a2754428d152a498/out"}
{"reason":"compiler-artifact","package_id":"syn 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.102/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.102/build.rs","edition":"2018","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["clone-impls","default","derive","parsing","printing","proc-macro","quote"],"filenames":["/home/epage/src/personal/winnow/target/debug/build/syn-c9e8af729632e4e4/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/cfg-if-1.0.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"cfg-if","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/cfg-if-1.0.0/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libcfg_if-047a17fcf848a7e5.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"autocfg 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/autocfg-1.1.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"autocfg","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/autocfg-1.1.0/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libautocfg-25db3455927a66e1.rlib","/home/epage/src/personal/winnow/target/debug/deps/libautocfg-25db3455927a66e1.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"serde_derive 1.0.145 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_derive-1.0.145/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_derive-1.0.145/build.rs","edition":"2015","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default"],"filenames":["/home/epage/src/personal/winnow/target/debug/build/serde_derive-fcc2f4aec2a2d4ab/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"serde 1.0.145 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.145/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.145/build.rs","edition":"2015","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","derive","serde_derive","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/build/serde-3f78a53b92e21d4d/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"libc 0.2.139 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.139/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"libc","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.139/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","extra_traits","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/liblibc-5b6dd9f3e6fc0120.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"quote 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/quote-1.0.21/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"quote","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/quote-1.0.21/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","proc-macro"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libquote-9a0c3a96b2cdc59c.rlib","/home/epage/src/personal/winnow/target/debug/deps/libquote-9a0c3a96b2cdc59c.rmeta"],"executable":null,"fresh":true}
{"reason":"build-script-executed","package_id":"syn 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":["syn_disable_nightly_tests"],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/syn-0a9a191063f1b2fc/out"}
{"reason":"build-script-executed","package_id":"serde_derive 1.0.145 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":[],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/serde_derive-ead5e900bac8546f/out"}
{"reason":"build-script-executed","package_id":"serde 1.0.145 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":[],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/serde-03f4af86861cbc3e/out"}
{"reason":"compiler-artifact","package_id":"thiserror 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.38/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.38/build.rs","edition":"2018","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/build/thiserror-66462325c558a4d5/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"ryu 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/ryu-1.0.11/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"ryu","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/ryu-1.0.11/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libryu-0e7b0d46c4589f15.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"crossbeam-utils 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-utils-0.8.12/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-utils-0.8.12/build.rs","edition":"2018","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/build/crossbeam-utils-c9170234d86239e2/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/memchr-2.5.0/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/memchr-2.5.0/build.rs","edition":"2018","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/build/memchr-99ffc1dfd2c517c1/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"serde_json 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.86/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.86/build.rs","edition":"2018","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/build/serde_json-3051866d1babe853/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"memoffset 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/memoffset-0.6.5/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/memoffset-0.6.5/build.rs","edition":"2015","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default"],"filenames":["/home/epage/src/personal/winnow/target/debug/build/memoffset-37767cb27e2441e6/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/bitflags-1.3.2/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"bitflags","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/bitflags-1.3.2/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libbitflags-ea9a4e086e887550.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"itoa 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/itoa-1.0.4/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"itoa","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/itoa-1.0.4/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libitoa-69c375d2fd4189a8.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"crossbeam-epoch 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-epoch-0.9.11/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-epoch-0.9.11/build.rs","edition":"2018","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/build/crossbeam-epoch-ec0452f91ac732bb/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"ucd-trie 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/ucd-trie-0.1.5/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"ucd-trie","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/ucd-trie-0.1.5/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libucd_trie-eb38f7c85a03bb9d.rlib","/home/epage/src/personal/winnow/target/debug/deps/libucd_trie-eb38f7c85a03bb9d.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"io-lifetimes 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/io-lifetimes-1.0.5/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/io-lifetimes-1.0.5/build.rs","edition":"2018","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["close","default","libc","windows-sys"],"filenames":["/home/epage/src/personal/winnow/target/debug/build/io-lifetimes-18d168bedd0c64e8/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/log-0.4.17/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/log-0.4.17/build.rs","edition":"2015","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/build/log-52c513d099058ca0/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"num-traits 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.15/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.15/build.rs","edition":"2015","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/build/num-traits-77d338745cc017c3/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"rayon-core 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.3/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.3/build.rs","edition":"2018","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/build/rayon-core-eecac7c574986103/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"rustix 0.36.8 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rustix-0.36.8/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rustix-0.36.8/build.rs","edition":"2018","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","io-lifetimes","libc","std","termios","use-libc-auxv"],"filenames":["/home/epage/src/personal/winnow/target/debug/build/rustix-32859c5d0061115d/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"syn 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.102/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"syn","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.102/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["clone-impls","default","derive","parsing","printing","proc-macro","quote"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libsyn-c9741af862298610.rlib","/home/epage/src/personal/winnow/target/debug/deps/libsyn-c9741af862298610.rmeta"],"executable":null,"fresh":true}
{"reason":"build-script-executed","package_id":"thiserror 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":[],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/thiserror-37d8ebe1b01cc51d/out"}
{"reason":"build-script-executed","package_id":"memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":["memchr_runtime_simd","memchr_runtime_sse2","memchr_runtime_sse42","memchr_runtime_avx"],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/memchr-743d739a8480f48a/out"}
{"reason":"build-script-executed","package_id":"crossbeam-utils 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":[],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/crossbeam-utils-1975bdb7ecfbff2a/out"}
{"reason":"build-script-executed","package_id":"serde_json 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":["limb_width_64"],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/serde_json-3f569e9655a7cd7e/out"}
{"reason":"build-script-executed","package_id":"memoffset 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":["tuple_ty","allow_clippy","maybe_uninit","doctests","raw_ref_macros"],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/memoffset-27100c1e8e709074/out"}
{"reason":"build-script-executed","package_id":"crossbeam-epoch 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":[],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/crossbeam-epoch-7f643445aebfa633/out"}
{"reason":"compiler-artifact","package_id":"getrandom 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/getrandom-0.2.7/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"getrandom","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/getrandom-0.2.7/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libgetrandom-d2efdd8bbd217458.rmeta"],"executable":null,"fresh":true}
{"reason":"build-script-executed","package_id":"log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":["atomic_cas","has_atomics"],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/log-b56bc898d3207792/out"}
{"reason":"build-script-executed","package_id":"io-lifetimes 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":["io_safety_is_in_std","panic_in_const_fn"],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/io-lifetimes-701560b8574ef205/out"}
{"reason":"compiler-artifact","package_id":"once_cell 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/once_cell-1.15.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"once_cell","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/once_cell-1.15.0/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","default","race","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libonce_cell-c9f9ea925d35da52.rlib","/home/epage/src/personal/winnow/target/debug/deps/libonce_cell-c9f9ea925d35da52.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/scopeguard-1.1.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"scopeguard","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/scopeguard-1.1.0/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libscopeguard-13a4bbff1ce24cc7.rmeta"],"executable":null,"fresh":true}
{"reason":"build-script-executed","package_id":"rayon-core 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":[],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/rayon-core-b008d521ccec1e7b/out"}
{"reason":"build-script-executed","package_id":"rustix 0.36.8 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":["linux_raw","asm"],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/rustix-e16304a596230d21/out"}
{"reason":"build-script-executed","package_id":"num-traits 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":["has_i128","has_to_int_unchecked","has_reverse_bits","has_leading_trailing_ones","has_int_assignop_ref","has_div_euclid","has_copysign"],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/num-traits-6888d3d0832572a9/out"}
{"reason":"compiler-artifact","package_id":"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/lazy_static-1.4.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"lazy_static","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/lazy_static-1.4.0/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/liblazy_static-afa8b761bb5d6b57.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"unicode-width 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/unicode-width-0.1.10/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"unicode-width","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/unicode-width-0.1.10/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libunicode_width-8dcd31c030e77d42.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"either 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/either-1.8.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"either","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/either-1.8.0/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["use_std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libeither-3c87d508139ef632.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"linux-raw-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/linux-raw-sys-0.1.4/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"linux-raw-sys","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/linux-raw-sys-0.1.4/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["errno","general","ioctl","no_std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/liblinux_raw_sys-297593f8ceab708f.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"num_cpus 1.13.1 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/num_cpus-1.13.1/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"num_cpus","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/num_cpus-1.13.1/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libnum_cpus-539d2b6f1744794b.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"serde_derive 1.0.145 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_derive-1.0.145/Cargo.toml","target":{"kind":["proc-macro"],"crate_types":["proc-macro"],"name":"serde_derive","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_derive-1.0.145/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libserde_derive-7934298a61c1a1a2.so"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"thiserror-impl 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-impl-1.0.38/Cargo.toml","target":{"kind":["proc-macro"],"crate_types":["proc-macro"],"name":"thiserror-impl","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-impl-1.0.38/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libthiserror_impl-213d86e6d4b69b5f.so"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/memchr-2.5.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"memchr","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/memchr-2.5.0/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libmemchr-ae9722f3894e3314.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"crossbeam-utils 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-utils-0.8.12/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"crossbeam-utils","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-utils-0.8.12/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libcrossbeam_utils-59f0a08b7eefe073.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"memoffset 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/memoffset-0.6.5/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"memoffset","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/memoffset-0.6.5/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libmemoffset-4787845978faa8b8.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"io-lifetimes 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/io-lifetimes-1.0.5/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"io-lifetimes","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/io-lifetimes-1.0.5/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["close","default","libc","windows-sys"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libio_lifetimes-0d158e24024d572c.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/log-0.4.17/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"log","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/log-0.4.17/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/liblog-3242a8c3b3d72769.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"rand_core 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rand_core-0.6.4/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"rand_core","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rand_core-0.6.4/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","getrandom","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/librand_core-aa1df72cb81e420e.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"num-traits 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.15/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"num-traits","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.15/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libnum_traits-1c8d0251ac4ea61d.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"rayon 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.3/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.3/build.rs","edition":"2018","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/build/rayon-4f0513187044c0f2/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"escargot 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/escargot-0.5.7/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/escargot-0.5.7/build.rs","edition":"2018","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/build/escargot-44a89e78cfd0d26f/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"yansi 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/yansi-0.5.1/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"yansi","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/yansi-0.5.1/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libyansi-62809433fc3ff8e9.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"regex-automata 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/regex-automata-0.1.10/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"regex-automata","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/regex-automata-0.1.10/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libregex_automata-741e79c4b6938d7d.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/remove_dir_all-0.5.3/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"remove_dir_all","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/remove_dir_all-0.5.3/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libremove_dir_all-bcafaf4f00d8e4a4.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"regex-syntax 0.6.27 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/regex-syntax-0.6.27/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"regex-syntax","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/regex-syntax-0.6.27/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","unicode","unicode-age","unicode-bool","unicode-case","unicode-gencat","unicode-perl","unicode-script","unicode-segment"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libregex_syntax-3fe0a07eb00f644f.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"ucd-trie 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/ucd-trie-0.1.5/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"ucd-trie","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/ucd-trie-0.1.5/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libucd_trie-b01a07ea40c7e7ed.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"plotters-backend 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/plotters-backend-0.3.4/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"plotters-backend","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/plotters-backend-0.3.4/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libplotters_backend-34c8fa8c2b121eeb.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"ppv-lite86 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/ppv-lite86-0.2.16/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"ppv-lite86","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/ppv-lite86-0.2.16/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["simd","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libppv_lite86-3b9c603c4b32aff6.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"fastrand 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/fastrand-1.8.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"fastrand","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/fastrand-1.8.0/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libfastrand-52ad6b37c39c8a90.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"itertools 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.5/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"itertools","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.5/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","use_alloc","use_std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libitertools-ba05d1064477b941.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"serde 1.0.145 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.145/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"serde","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.145/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","derive","serde_derive","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libserde-e026f194fb97de03.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"thiserror 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.38/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"thiserror","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.38/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libthiserror-4481f6326f711f93.rlib","/home/epage/src/personal/winnow/target/debug/deps/libthiserror-4481f6326f711f93.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"crossbeam-epoch 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-epoch-0.9.11/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"crossbeam-epoch","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-epoch-0.9.11/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libcrossbeam_epoch-caa786e06425cee9.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"thiserror 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.38/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"thiserror","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.38/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libthiserror-9187d79370422188.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"rustix 0.36.8 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rustix-0.36.8/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"rustix","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rustix-0.36.8/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","io-lifetimes","libc","std","termios","use-libc-auxv"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/librustix-ec48622574cca747.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"crossbeam-channel 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-channel-0.5.6/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"crossbeam-channel","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-channel-0.5.6/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["crossbeam-utils","default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libcrossbeam_channel-a9b11ccef7773884.rmeta"],"executable":null,"fresh":true}
{"reason":"build-script-executed","package_id":"escargot 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":[],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/escargot-5711ac23b4781245/out"}
{"reason":"compiler-artifact","package_id":"tempfile 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/tempfile-3.3.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"tempfile","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/tempfile-3.3.0/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libtempfile-8b83de608c2a0658.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"rand_chacha 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rand_chacha-0.3.1/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"rand_chacha","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rand_chacha-0.3.1/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/librand_chacha-5967d0068d39b018.rmeta"],"executable":null,"fresh":true}
{"reason":"build-script-executed","package_id":"rayon 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":["has_step_by_rev","has_min_const_generics","has_control_flow"],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/rayon-d01aa17f59a1e98f/out"}
{"reason":"compiler-artifact","package_id":"plotters-svg 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/plotters-svg-0.3.3/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"plotters-svg","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/plotters-svg-0.3.3/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libplotters_svg-2bb014e4a5d863b1.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/csv-core-0.1.10/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"csv-core","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/csv-core-0.1.10/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libcsv_core-bf47a6ecf716f212.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/textwrap-0.11.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"textwrap","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/textwrap-0.11.0/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libtextwrap-1f9a5b633ba2872d.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/atty-0.2.14/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"atty","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/atty-0.2.14/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libatty-7590cc9da5872c3b.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/wait-timeout-0.2.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"wait-timeout","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/wait-timeout-0.2.0/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libwait_timeout-d79299ed1c2df76b.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"diff 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/diff-0.1.13/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"diff","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/diff-0.1.13/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libdiff-a3c1327ada950886.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"concolor-query 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/concolor-query-0.1.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"concolor-query","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/concolor-query-0.1.0/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["windows"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libconcolor_query-1b1f33bda6da9636.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/same-file-1.0.6/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"same-file","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/same-file-1.0.6/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libsame_file-8dba8c6e6bbcef0a.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"bit-vec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/bit-vec-0.6.3/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"bit-vec","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/bit-vec-0.6.3/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libbit_vec-5cc1be6dbbb7d172.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/fnv-1.0.7/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"fnv","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/fnv-1.0.7/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libfnv-e811c8615aede027.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"serde_json 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.86/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"serde_json","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.86/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libserde_json-10d232e85191c379.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"pest 2.5.5 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/pest-2.5.5/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"pest","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/pest-2.5.5/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std","thiserror"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libpest-c28124a2ace8ce41.rlib","/home/epage/src/personal/winnow/target/debug/deps/libpest-c28124a2ace8ce41.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"crossbeam-deque 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-deque-0.8.2/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"crossbeam-deque","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-deque-0.8.2/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["crossbeam-epoch","crossbeam-utils","default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libcrossbeam_deque-a531937c1e514cf3.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"bstr 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/bstr-0.2.17/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"bstr","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/bstr-0.2.17/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","lazy_static","regex-automata","serde","serde1","serde1-nostd","std","unicode"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libbstr-3245cbc7e1b4eee0.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"is-terminal 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/is-terminal-0.4.3/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"is-terminal","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/is-terminal-0.4.3/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libis_terminal-ddb4d6f1cea88415.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"pest 2.5.5 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/pest-2.5.5/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"pest","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/pest-2.5.5/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std","thiserror"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libpest-3fe2406158c36e91.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"doc-comment 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/doc-comment-0.3.3/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/doc-comment-0.3.3/build.rs","edition":"2015","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/build/doc-comment-476a3be5ae9523a0/build-script-build"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"cast 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/cast-0.3.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"cast","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/cast-0.3.0/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libcast-0f6ca0f808d89c22.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"half 1.8.2 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/half-1.8.2/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"half","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/half-1.8.2/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libhalf-ec0164f76c2e0030.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/quick-error-1.2.3/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"quick-error","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/quick-error-1.2.3/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libquick_error-e7675fcf1fdb276d.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"once_cell 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/once_cell-1.15.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"once_cell","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/once_cell-1.15.0/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","default","race","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libonce_cell-6a83ca81f3790104.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"itoa 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/itoa-0.4.8/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"itoa","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/itoa-0.4.8/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libitoa-af0357b7d39004b0.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"plotters 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/plotters-0.3.4/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"plotters","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/plotters-0.3.4/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["area_series","line_series","plotters-svg","svg_backend"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libplotters-c6ddec411d8166e5.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"walkdir 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/walkdir-2.3.2/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"walkdir","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/walkdir-2.3.2/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libwalkdir-9e7e41a0b2bf038d.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"bit-set 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/bit-set-0.5.3/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"bit-set","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/bit-set-0.5.3/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libbit_set-2aef4909cbe7f4dc.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"pretty_assertions 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/pretty_assertions-1.3.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"pretty_assertions","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/pretty_assertions-1.3.0/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libpretty_assertions-917f731810bb748b.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"clap 2.34.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/clap-2.34.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"clap","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/clap-2.34.0/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libclap-af397f0f338fc8b9.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"rand 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rand-0.8.5/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"rand","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rand-0.8.5/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","getrandom","libc","rand_chacha","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/librand-79231f927b479fcb.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"quick-xml 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/quick-xml-0.23.1/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"quick-xml","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/quick-xml-0.23.1/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libquick_xml-56f1f63175d80ec8.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"rand_xorshift 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rand_xorshift-0.3.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"rand_xorshift","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rand_xorshift-0.3.0/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/librand_xorshift-52cda07a05fef0b5.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"pest_meta 2.5.5 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/pest_meta-2.5.5/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"pest_meta","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/pest_meta-2.5.5/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libpest_meta-e592b8a19ab895e0.rlib","/home/epage/src/personal/winnow/target/debug/deps/libpest_meta-e592b8a19ab895e0.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"rayon-core 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.3/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"rayon-core","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.3/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/librayon_core-28c7fd349d6eb8a3.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"tinytemplate 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/tinytemplate-1.2.1/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"tinytemplate","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/tinytemplate-1.2.1/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libtinytemplate-1e34f9b3f54388b1.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"serde_cbor 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_cbor-0.11.2/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"serde_cbor","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_cbor-0.11.2/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libserde_cbor-a6696a57f0dc1b3e.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"escargot 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/escargot-0.5.7/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"escargot","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/escargot-0.5.7/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libescargot-8a922c953f0ce0d3.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"csv 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/csv-1.1.6/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"csv","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/csv-1.1.6/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libcsv-66898c2026240d6e.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"rusty-fork 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rusty-fork-0.3.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"rusty-fork","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rusty-fork-0.3.0/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["timeout","wait-timeout"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/librusty_fork-3ff190906b9b0c88.rmeta"],"executable":null,"fresh":true}
{"reason":"build-script-executed","package_id":"doc-comment 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)","linked_libs":[],"linked_paths":[],"cfgs":[],"env":[],"out_dir":"/home/epage/src/personal/winnow/target/debug/build/doc-comment-9f27b6aeba0913e7/out"}
{"reason":"compiler-artifact","package_id":"criterion-plot 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/criterion-plot-0.4.5/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"criterion-plot","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/criterion-plot-0.4.5/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libcriterion_plot-dc7b9242779f53d6.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"concolor 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/concolor-0.0.11/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"concolor","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/concolor-0.0.11/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["auto","bitflags","clicolor","concolor-query","core","interactive","no_color","std","term","windows"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libconcolor-c2d97e9aa66666d7.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"regex 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/regex-1.6.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"regex","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/regex-1.6.0/src/lib.rs","edition":"2018","doc":true,"doctest":false,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libregex-14a9fe50552aac49.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"os_pipe 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/os_pipe-1.1.3/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"os_pipe","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/os_pipe-1.1.3/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libos_pipe-be2a22288f932a49.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"quick-error 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/quick-error-2.0.1/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"quick-error","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/quick-error-2.0.1/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libquick_error-280edfc32cc83812.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"normalize-line-endings 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/normalize-line-endings-0.3.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"normalize-line-endings","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/normalize-line-endings-0.3.0/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libnormalize_line_endings-8a66ba357a389996.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"bytecount 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/bytecount-0.6.3/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"bytecount","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/bytecount-0.6.3/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libbytecount-c083e2cdbbb4f003.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"snapbox-macros 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/snapbox-macros-0.3.1/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"snapbox-macros","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/snapbox-macros-0.3.1/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libsnapbox_macros-d9da77d55f4279bc.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"oorandom 11.1.3 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/oorandom-11.1.3/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"oorandom","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/oorandom-11.1.3/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/liboorandom-052fb0be6ac16c94.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"byteorder 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/byteorder-1.4.3/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"byteorder","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/byteorder-1.4.3/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libbyteorder-9f6a3ecb302657b0.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"similar 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/similar-2.2.1/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"similar","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/similar-2.2.1/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","inline","text"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libsimilar-ca2082771c207a3c.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/termcolor-1.2.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"termcolor","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/termcolor-1.2.0/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libtermcolor-dad1a04bc5d2f742.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"pest_generator 2.5.5 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/pest_generator-2.5.5/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"pest_generator","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/pest_generator-2.5.5/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libpest_generator-17d62a3fe28e46f5.rlib","/home/epage/src/personal/winnow/target/debug/deps/libpest_generator-17d62a3fe28e46f5.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"rayon 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.3/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"rayon","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.3/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/librayon-41dd0a10f9292557.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"proptest 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/proptest-1.0.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"proptest","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/proptest-1.0.0/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["bit-set","break-dead-code","default","fork","lazy_static","quick-error","regex-syntax","rusty-fork","std","tempfile","timeout"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libproptest-7f94966e4936da95.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"snapbox 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/snapbox-0.4.6/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"snapbox","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/snapbox-0.4.6/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["color","color-auto","concolor","default","diff","examples"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libsnapbox-d99468a5201f9b87.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"doc-comment 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/doc-comment-0.3.3/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"doc_comment","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/doc-comment-0.3.3/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libdoc_comment-5644793091a6953d.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"lexopt 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/lexopt-0.3.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"lexopt","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/lexopt-0.3.0/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/liblexopt-c945e030a97b8e1f.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"circular 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/circular-0.3.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"circular","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/circular-0.3.0/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libcircular-6190d46717d189a0.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"winnow 0.3.1 (path+file:///home/epage/src/personal/winnow)","manifest_path":"/home/epage/src/personal/winnow/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"winnow","src_path":"/home/epage/src/personal/winnow/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libwinnow-a64b99fd45b2e97c.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"pest_derive 2.5.5 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/pest_derive-2.5.5/Cargo.toml","target":{"kind":["proc-macro"],"crate_types":["proc-macro"],"name":"pest_derive","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/pest_derive-2.5.5/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libpest_derive-23acec6b80f586aa.so"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"criterion 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/criterion-0.3.6/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"criterion","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/criterion-0.3.6/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["cargo_bench_support","default"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libcriterion-864d2d30e85a25cf.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"handlebars 4.3.6 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/handlebars-4.3.6/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"handlebars","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/handlebars-4.3.6/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libhandlebars-8f7ca769e2915c7a.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"term-transcript 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)","manifest_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/term-transcript-0.2.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"term-transcript","src_path":"/home/epage/.cargo/registry/src/github.com-1ecc6299db9ec823/term-transcript-0.2.0/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["atty","default","handlebars","pretty_assertions","quick-xml","serde","svg","test"],"filenames":["/home/epage/src/personal/winnow/target/debug/deps/libterm_transcript-67537cf74f0568cc.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"winnow 0.3.1 (path+file:///home/epage/src/personal/winnow)","manifest_path":"/home/epage/src/personal/winnow/Cargo.toml","target":{"kind":["example"],"crate_types":["bin"],"name":"ini","src_path":"/home/epage/src/personal/winnow/examples/ini/main.rs","edition":"2021","required-features":["std"],"doc":false,"doctest":false,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/examples/libini-029ff669d11d054a.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"winnow 0.3.1 (path+file:///home/epage/src/personal/winnow)","manifest_path":"/home/epage/src/personal/winnow/Cargo.toml","target":{"kind":["example"],"crate_types":["bin"],"name":"custom_error","src_path":"/home/epage/src/personal/winnow/examples/custom_error.rs","edition":"2021","required-features":["alloc"],"doc":false,"doctest":false,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/examples/libcustom_error-8382fb7d49937909.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"winnow 0.3.1 (path+file:///home/epage/src/personal/winnow)","manifest_path":"/home/epage/src/personal/winnow/Cargo.toml","target":{"kind":["example"],"crate_types":["bin"],"name":"s_expression","src_path":"/home/epage/src/personal/winnow/examples/s_expression/main.rs","edition":"2021","required-features":["alloc"],"doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/examples/libs_expression-0161e16eb3795e0c.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"winnow 0.3.1 (path+file:///home/epage/src/personal/winnow)","manifest_path":"/home/epage/src/personal/winnow/Cargo.toml","target":{"kind":["example"],"crate_types":["bin"],"name":"css","src_path":"/home/epage/src/personal/winnow/examples/css/main.rs","edition":"2021","doc":false,"doctest":false,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/examples/libcss-d003331b0eaf24a5.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"winnow 0.3.1 (path+file:///home/epage/src/personal/winnow)","manifest_path":"/home/epage/src/personal/winnow/Cargo.toml","target":{"kind":["example"],"crate_types":["bin"],"name":"json","src_path":"/home/epage/src/personal/winnow/examples/json/main.rs","edition":"2021","required-features":["std"],"doc":false,"doctest":false,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/examples/libjson-20da0c01e9db35aa.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"winnow 0.3.1 (path+file:///home/epage/src/personal/winnow)","manifest_path":"/home/epage/src/personal/winnow/Cargo.toml","target":{"kind":["example"],"crate_types":["bin"],"name":"ndjson","src_path":"/home/epage/src/personal/winnow/examples/ndjson/main.rs","edition":"2021","required-features":["std"],"doc":false,"doctest":false,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/examples/libndjson-17afbe6b158251ab.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"winnow 0.3.1 (path+file:///home/epage/src/personal/winnow)","manifest_path":"/home/epage/src/personal/winnow/Cargo.toml","target":{"kind":["example"],"crate_types":["bin"],"name":"http","src_path":"/home/epage/src/personal/winnow/examples/http/main.rs","edition":"2021","required-features":["alloc"],"doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/examples/libhttp-08613cd431f59551.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"winnow 0.3.1 (path+file:///home/epage/src/personal/winnow)","manifest_path":"/home/epage/src/personal/winnow/Cargo.toml","target":{"kind":["example"],"crate_types":["bin"],"name":"iterator","src_path":"/home/epage/src/personal/winnow/examples/iterator.rs","edition":"2021","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/examples/libiterator-46a33f71a5378497.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"winnow 0.3.1 (path+file:///home/epage/src/personal/winnow)","manifest_path":"/home/epage/src/personal/winnow/Cargo.toml","target":{"kind":["example"],"crate_types":["bin"],"name":"string","src_path":"/home/epage/src/personal/winnow/examples/string/main.rs","edition":"2021","required-features":["alloc"],"doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/examples/libstring-73fadc9999eff689.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"winnow 0.3.1 (path+file:///home/epage/src/personal/winnow)","manifest_path":"/home/epage/src/personal/winnow/Cargo.toml","target":{"kind":["example"],"crate_types":["bin"],"name":"arithmetic","src_path":"/home/epage/src/personal/winnow/examples/arithmetic/main.rs","edition":"2021","required-features":["alloc"],"doc":false,"doctest":false,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/examples/libarithmetic-04ca5fb45c28ebc2.rmeta"],"executable":null,"fresh":true}
{"reason":"compiler-artifact","package_id":"winnow 0.3.1 (path+file:///home/epage/src/personal/winnow)","manifest_path":"/home/epage/src/personal/winnow/Cargo.toml","target":{"kind":["example"],"crate_types":["bin"],"name":"json_iterator","src_path":"/home/epage/src/personal/winnow/examples/json_iterator.rs","edition":"2021","required-features":["std"],"doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","default","std"],"filenames":["/home/epage/src/personal/winnow/target/debug/examples/libjson_iterator-9bb330a957b0d53d.rmeta"],"executable":null,"fresh":true}
{"reason":"build-finished","success":true}

116
vendor/winnow/examples/ndjson/main.rs vendored Normal file
View File

@@ -0,0 +1,116 @@
mod parser;
use std::io::Read;
use winnow::error::ContextError;
use winnow::error::ErrMode;
use winnow::error::Needed;
use winnow::prelude::*;
use winnow::stream::Offset;
fn main() -> Result<(), lexopt::Error> {
let args = Args::parse()?;
let input = args.input.ok_or_else(|| lexopt::Error::MissingValue {
option: Some("<PATH>".to_owned()),
})?;
let mut file = std::fs::File::open(input).map_err(to_lexopt)?;
// Intentionally starting with a small buffer to make it easier to show `Incomplete` handling
let buffer_size = 10;
let min_buffer_growth = 100;
let buffer_growth_factor = 2;
let mut buffer = circular::Buffer::with_capacity(buffer_size);
loop {
let read = file.read(buffer.space()).map_err(to_lexopt)?;
eprintln!("read {read}");
if read == 0 {
// Should be EOF since we always make sure there is `available_space`
assert_ne!(buffer.available_space(), 0);
assert_eq!(
buffer.available_data(),
0,
"leftover data: {}",
String::from_utf8_lossy(buffer.data())
);
break;
}
buffer.fill(read);
loop {
let mut input =
parser::Stream::new(std::str::from_utf8(buffer.data()).map_err(to_lexopt)?);
let start = input.checkpoint();
match parser::ndjson::<ContextError>.parse_next(&mut input) {
Ok(value) => {
println!("{value:?}");
println!();
// Tell the buffer how much we read
let consumed = input.offset_from(&start);
buffer.consume(consumed);
}
Err(ErrMode::Backtrack(e)) | Err(ErrMode::Cut(e)) => {
return Err(fmt_lexopt(e.to_string()));
}
Err(ErrMode::Incomplete(Needed::Size(size))) => {
// Without the format telling us how much space is required, we really should
// treat this the same as `Unknown` but are doing this to demonstrate how to
// handle `Size`.
//
// Even when the format has a header to tell us `Size`, we could hit incidental
// `Size(1)`s, so make sure we buffer more space than that to avoid reading
// one byte at a time
let head_room = size.get().max(min_buffer_growth);
let new_capacity = buffer.available_data() + head_room;
eprintln!("growing buffer to {new_capacity}");
buffer.grow(new_capacity);
if buffer.available_space() < head_room {
eprintln!("buffer shift");
buffer.shift();
}
break;
}
Err(ErrMode::Incomplete(Needed::Unknown)) => {
let new_capacity = buffer_growth_factor * buffer.capacity();
eprintln!("growing buffer to {new_capacity}");
buffer.grow(new_capacity);
break;
}
}
}
}
Ok(())
}
#[derive(Default)]
struct Args {
input: Option<std::path::PathBuf>,
}
impl Args {
fn parse() -> Result<Self, lexopt::Error> {
use lexopt::prelude::*;
let mut res = Args::default();
let mut args = lexopt::Parser::from_env();
while let Some(arg) = args.next()? {
match arg {
Value(input) => {
res.input = Some(input.into());
}
_ => return Err(arg.unexpected()),
}
}
Ok(res)
}
}
fn to_lexopt(e: impl std::error::Error + Send + Sync + 'static) -> lexopt::Error {
lexopt::Error::Custom(Box::new(e))
}
fn fmt_lexopt(e: String) -> lexopt::Error {
lexopt::Error::Custom(e.into())
}

340
vendor/winnow/examples/ndjson/parser.rs vendored Normal file
View File

@@ -0,0 +1,340 @@
use std::collections::HashMap;
use std::str;
use winnow::prelude::*;
use winnow::{
ascii::float,
ascii::line_ending,
combinator::alt,
combinator::cut_err,
combinator::{delimited, preceded, separated_pair, terminated},
combinator::{repeat, separated},
error::{AddContext, ParserError, StrContext},
stream::Partial,
token::{any, none_of, take, take_while},
};
#[derive(Debug, PartialEq, Clone)]
pub(crate) enum JsonValue {
Null,
Boolean(bool),
Str(String),
Num(f64),
Array(Vec<JsonValue>),
Object(HashMap<String, JsonValue>),
}
/// Use `Partial` to cause `ErrMode::Incomplete` while parsing
pub(crate) type Stream<'i> = Partial<&'i str>;
pub(crate) fn ndjson<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<Option<JsonValue>, E> {
alt((
terminated(delimited(ws, json_value, ws), line_ending).map(Some),
line_ending.value(None),
))
.parse_next(input)
}
// --Besides `WS`, same as a regular json parser ----------------------------
/// `alt` is a combinator that tries multiple parsers one by one, until
/// one of them succeeds
fn json_value<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<JsonValue, E> {
// `alt` combines the each value parser. It returns the result of the first
// successful parser, or an error
alt((
null.value(JsonValue::Null),
boolean.map(JsonValue::Boolean),
string.map(JsonValue::Str),
float.map(JsonValue::Num),
array.map(JsonValue::Array),
object.map(JsonValue::Object),
))
.parse_next(input)
}
/// `literal(string)` generates a parser that takes the argument string.
///
/// This also shows returning a sub-slice of the original input
fn null<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<&'i str, E> {
// This is a parser that returns `"null"` if it sees the string "null", and
// an error otherwise
"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: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<bool, E> {
// This is a parser that returns `true` if it sees the string "true", and
// an error otherwise
let parse_true = "true".value(true);
// This is a parser that returns `false` if it sees the string "false", and
// an error otherwise
let parse_false = "false".value(false);
alt((parse_true, parse_false)).parse_next(input)
}
/// This parser gathers all `char`s up into a `String`with a parse to take the double quote
/// character, before the string (using `preceded`) and after the string (using `terminated`).
fn string<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<String, E> {
preceded(
'\"',
// `cut_err` transforms an `ErrMode::Backtrack(e)` to `ErrMode::Cut(e)`, signaling to
// combinators like `alt` that they should not try other parsers. We were in the
// right branch (since we found the `"` character) but encountered an error when
// parsing the string
cut_err(terminated(
repeat(0.., character).fold(String::new, |mut string, c| {
string.push(c);
string
}),
'\"',
)),
)
// `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(StrContext::Expected("string".into()))
.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: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<char, E> {
let c = none_of('"').parse_next(input)?;
if c == '\\' {
alt((
any.verify_map(|c| {
Some(match c {
'"' | '\\' | '/' => c,
'b' => '\x08',
'f' => '\x0C',
'n' => '\n',
'r' => '\r',
't' => '\t',
_ => return None,
})
}),
preceded('u', unicode_escape),
))
.parse_next(input)
} else {
Ok(c)
}
}
fn unicode_escape<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<char, E> {
alt((
// Not a surrogate
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(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;
let low_ten = (low as u32) - 0xDC00;
(high_ten << 10) + low_ten + 0x10000
}),
))
.verify_map(
// Could be probably replaced with .unwrap() or _unchecked due to the verify checks
std::char::from_u32,
)
.parse_next(input)
}
fn u16_hex<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<u16, E> {
take(4usize)
.verify_map(|s| u16::from_str_radix(s, 16).ok())
.parse_next(input)
}
/// Some combinators, like `separated` or `repeat`, will call a parser repeatedly,
/// accumulating results in a `Vec`, until it encounters an error.
/// If you want more control on the parser application, check out the `iterator`
/// combinator (cf `examples/iterator.rs`)
fn array<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<Vec<JsonValue>, E> {
preceded(
('[', ws),
cut_err(terminated(
separated(0.., json_value, (ws, ',', ws)),
(ws, ']'),
)),
)
.context(StrContext::Expected("array".into()))
.parse_next(input)
}
fn object<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<HashMap<String, JsonValue>, E> {
preceded(
('{', ws),
cut_err(terminated(
separated(0.., key_value, (ws, ',', ws)),
(ws, '}'),
)),
)
.context(StrContext::Expected("object".into()))
.parse_next(input)
}
fn key_value<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, StrContext>>(
input: &mut Stream<'i>,
) -> ModalResult<(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: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> ModalResult<&'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_next(input)
}
const WS: &[char] = &[' ', '\t'];
#[cfg(test)]
mod test {
#[allow(clippy::useless_attribute)]
#[allow(unused_imports)] // its dead for benches
use super::*;
#[allow(clippy::useless_attribute)]
#[allow(dead_code)] // its dead for benches
type Error = winnow::error::ContextError;
#[test]
fn json_string() {
assert_eq!(
string::<Error>.parse_peek(Partial::new("\"\"")),
Ok((Partial::new(""), "".to_owned()))
);
assert_eq!(
string::<Error>.parse_peek(Partial::new("\"abc\"")),
Ok((Partial::new(""), "abc".to_owned()))
);
assert_eq!(
string::<Error>.parse_peek(Partial::new(
"\"abc\\\"\\\\\\/\\b\\f\\n\\r\\t\\u0001\\u2014\u{2014}def\""
)),
Ok((
Partial::new(""),
"abc\"\\/\x08\x0C\n\r\t\x01——def".to_owned()
)),
);
assert_eq!(
string::<Error>.parse_peek(Partial::new("\"\\uD83D\\uDE10\"")),
Ok((Partial::new(""), "😐".to_owned()))
);
assert!(string::<Error>.parse_peek(Partial::new("\"")).is_err());
assert!(string::<Error>.parse_peek(Partial::new("\"abc")).is_err());
assert!(string::<Error>.parse_peek(Partial::new("\"\\\"")).is_err());
assert!(string::<Error>
.parse_peek(Partial::new("\"\\u123\""))
.is_err());
assert!(string::<Error>
.parse_peek(Partial::new("\"\\uD800\""))
.is_err());
assert!(string::<Error>
.parse_peek(Partial::new("\"\\uD800\\uD800\""))
.is_err());
assert!(string::<Error>
.parse_peek(Partial::new("\"\\uDC00\""))
.is_err());
}
#[test]
fn json_object() {
use JsonValue::{Num, Object, Str};
let input = r#"{"a":42,"b":"x"}
"#;
let expected = Object(
vec![
("a".to_owned(), Num(42.0)),
("b".to_owned(), Str("x".to_owned())),
]
.into_iter()
.collect(),
);
assert_eq!(
ndjson::<Error>.parse_peek(Partial::new(input)),
Ok((Partial::new(""), Some(expected)))
);
}
#[test]
fn json_array() {
use JsonValue::{Array, Num, Str};
let input = r#"[42,"x"]
"#;
let expected = Array(vec![Num(42.0), Str("x".to_owned())]);
assert_eq!(
ndjson::<Error>.parse_peek(Partial::new(input)),
Ok((Partial::new(""), Some(expected)))
);
}
#[test]
fn json_whitespace() {
use JsonValue::{Array, Boolean, Null, Num, Object, Str};
let input = r#" { "null" : null, "true" :true , "false": false , "number" : 123e4 , "string" : " abc 123 " , "array" : [ false , 1 , "two" ] , "object" : { "a" : 1.0 , "b" : "c" } , "empty_array" : [ ] , "empty_object" : { } }
"#;
assert_eq!(
ndjson::<Error>.parse_peek(Partial::new(input)),
Ok((
Partial::new(""),
Some(Object(
vec![
("null".to_owned(), Null),
("true".to_owned(), Boolean(true)),
("false".to_owned(), Boolean(false)),
("number".to_owned(), Num(123e4)),
("string".to_owned(), Str(" abc 123 ".to_owned())),
(
"array".to_owned(),
Array(vec![Boolean(false), Num(1.0), Str("two".to_owned())])
),
(
"object".to_owned(),
Object(
vec![
("a".to_owned(), Num(1.0)),
("b".to_owned(), Str("c".to_owned())),
]
.into_iter()
.collect()
)
),
("empty_array".to_owned(), Array(vec![]),),
("empty_object".to_owned(), Object(HashMap::new()),),
]
.into_iter()
.collect()
))
))
);
}
}

View File

@@ -0,0 +1,20 @@
//! In this example we build an [S-expression](https://en.wikipedia.org/wiki/S-expression)
//! parser and tiny [lisp](https://en.wikipedia.org/wiki/Lisp_(programming_language)) interpreter.
//! Lisp is a simple type of language made up of Atoms and Lists, forming easily parsable trees.
#![cfg(feature = "alloc")]
mod parser;
fn main() {
let expression_1 = "((if (= (+ 3 (/ 9 3))
(* 2 3))
*
/)
456 123)";
println!(
"\"{}\"\nevaled gives us: {:?}",
expression_1,
parser::eval_from_str(expression_1)
);
}

View File

@@ -0,0 +1,361 @@
//! In this example we build an [S-expression](https://en.wikipedia.org/wiki/S-expression)
//! parser and tiny [lisp](https://en.wikipedia.org/wiki/Lisp_(programming_language)) interpreter.
//! Lisp is a simple type of language made up of Atoms and Lists, forming easily parsable trees.
use winnow::{
ascii::{alpha1, digit1, multispace0, multispace1},
combinator::alt,
combinator::repeat,
combinator::{cut_err, opt},
combinator::{delimited, preceded, terminated},
error::ContextError,
error::StrContext,
prelude::*,
token::one_of,
};
/// We start with a top-level function to tie everything together, letting
/// us call eval on a string directly
pub(crate) fn eval_from_str(src: &str) -> Result<Expr, String> {
parse_expr
.parse(src)
.map_err(|e| e.to_string())
.and_then(|exp| eval_expression(exp).ok_or_else(|| "Eval failed".to_owned()))
}
/// For parsing, we start by defining the types that define the shape of data that we want.
/// In this case, we want something tree-like
///
/// The remaining half is Lists. We implement these as recursive Expressions.
/// For a list of numbers, we have `'(1 2 3)`, which we'll parse to:
/// ```
/// Expr::Quote(vec![Expr::Constant(Atom::Num(1)),
/// Expr::Constant(Atom::Num(2)),
/// Expr::Constant(Atom::Num(3))])
/// Quote takes an S-expression and prevents evaluation of it, making it a data
/// structure that we can deal with programmatically. Thus any valid expression
/// is also a valid data structure in Lisp itself.
#[derive(Debug, Eq, PartialEq, Clone)]
pub(crate) enum Expr {
Constant(Atom),
/// (func-name arg1 arg2)
Application(Box<Expr>, Vec<Expr>),
/// (if predicate do-this)
If(Box<Expr>, Box<Expr>),
/// (if predicate do-this otherwise-do-this)
IfElse(Box<Expr>, Box<Expr>, Box<Expr>),
/// '(3 (if (+ 3 3) 4 5) 7)
Quote(Vec<Expr>),
}
/// We now wrap this type and a few other primitives into our Atom type.
/// Remember from before that Atoms form one half of our language.
#[derive(Debug, Eq, PartialEq, Clone)]
pub(crate) enum Atom {
Num(i32),
Keyword(String),
Boolean(bool),
BuiltIn(BuiltIn),
}
/// Now, the most basic type. We define some built-in functions that our lisp has
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub(crate) enum BuiltIn {
Plus,
Minus,
Times,
Divide,
Equal,
Not,
}
/// With types defined, we move onto the top-level expression parser!
fn parse_expr(i: &mut &'_ str) -> ModalResult<Expr> {
preceded(
multispace0,
alt((parse_constant, parse_application, parse_if, parse_quote)),
)
.parse_next(i)
}
/// We then add the Expr layer on top
fn parse_constant(i: &mut &'_ str) -> ModalResult<Expr> {
parse_atom.map(Expr::Constant).parse_next(i)
}
/// Now we take all these simple parsers and connect them.
/// We can now parse half of our language!
fn parse_atom(i: &mut &'_ str) -> ModalResult<Atom> {
alt((
parse_num,
parse_bool,
parse_builtin.map(Atom::BuiltIn),
parse_keyword,
))
.parse_next(i)
}
/// Next up is number parsing. We're keeping it simple here by accepting any number (> 1)
/// of digits but ending the program if it doesn't fit into an i32.
fn parse_num(i: &mut &'_ str) -> ModalResult<Atom> {
alt((
digit1.try_map(|digit_str: &str| digit_str.parse::<i32>().map(Atom::Num)),
preceded("-", digit1).map(|digit_str: &str| Atom::Num(-digit_str.parse::<i32>().unwrap())),
))
.parse_next(i)
}
/// Our boolean values are also constant, so we can do it the same way
fn parse_bool(i: &mut &'_ str) -> ModalResult<Atom> {
alt((
"#t".map(|_| Atom::Boolean(true)),
"#f".map(|_| Atom::Boolean(false)),
))
.parse_next(i)
}
fn parse_builtin(i: &mut &'_ str) -> ModalResult<BuiltIn> {
// alt gives us the result of first parser that succeeds, of the series of
// parsers we give it
alt((
parse_builtin_op,
// map lets us process the parsed output, in this case we know what we parsed,
// so we ignore the input and return the BuiltIn directly
"not".map(|_| BuiltIn::Not),
))
.parse_next(i)
}
/// Continuing the trend of starting from the simplest piece and building up,
/// we start by creating a parser for the built-in operator functions.
fn parse_builtin_op(i: &mut &'_ str) -> ModalResult<BuiltIn> {
// one_of matches one of the characters we give it
let t = one_of(['+', '-', '*', '/', '=']).parse_next(i)?;
// because we are matching single character tokens, we can do the matching logic
// on the returned value
Ok(match t {
'+' => BuiltIn::Plus,
'-' => BuiltIn::Minus,
'*' => BuiltIn::Times,
'/' => BuiltIn::Divide,
'=' => BuiltIn::Equal,
_ => unreachable!(),
})
}
/// The next easiest thing to parse are keywords.
/// We introduce some error handling combinators: `context` for human readable errors
/// and `cut_err` to prevent back-tracking.
///
/// Put plainly: `preceded(":", cut_err(alpha1))` means that once we see the `:`
/// character, we have to see one or more alphabetic characters or the input is invalid.
fn parse_keyword(i: &mut &'_ str) -> ModalResult<Atom> {
preceded(":", cut_err(alpha1))
.context(StrContext::Label("keyword"))
.map(|sym_str: &str| Atom::Keyword(sym_str.to_owned()))
.parse_next(i)
}
/// We can now use our new combinator to define the rest of the `Expr`s.
///
/// Starting with function application, we can see how the parser mirrors our data
/// definitions: our definition is `Application(Box<Expr>, Vec<Expr>)`, so we know
/// that we need to parse an expression and then parse 0 or more expressions, all
/// wrapped in an S-expression.
///
/// tuples are themselves a parser, used to sequence parsers together, so we can translate this
/// directly and then map over it to transform the output into an `Expr::Application`
fn parse_application(i: &mut &'_ str) -> ModalResult<Expr> {
let application_inner = (parse_expr, repeat(0.., parse_expr))
.map(|(head, tail)| Expr::Application(Box::new(head), tail));
// finally, we wrap it in an s-expression
s_exp(application_inner).parse_next(i)
}
/// Because `Expr::If` and `Expr::IfElse` are so similar (we easily could have
/// defined `Expr::If` to have an `Option` for the else block), we parse both
/// in a single function.
///
/// In fact, we define our parser as if `Expr::If` was defined with an Option in it,
/// we have the `opt` combinator which fits very nicely here.
fn parse_if(i: &mut &'_ str) -> ModalResult<Expr> {
let if_inner = preceded(
// here to avoid ambiguity with other names starting with `if`, if we added
// variables to our language, we say that if must be terminated by at least
// one whitespace character
terminated("if", multispace1),
cut_err((parse_expr, parse_expr, opt(parse_expr))),
)
.map(|(pred, true_branch, maybe_false_branch)| {
if let Some(false_branch) = maybe_false_branch {
Expr::IfElse(
Box::new(pred),
Box::new(true_branch),
Box::new(false_branch),
)
} else {
Expr::If(Box::new(pred), Box::new(true_branch))
}
})
.context(StrContext::Label("if expression"));
s_exp(if_inner).parse_next(i)
}
/// A quoted S-expression is list data structure.
///
/// This example doesn't have the symbol atom, but by adding variables and changing
/// the definition of quote to not always be around an S-expression, we'd get them
/// naturally.
fn parse_quote(i: &mut &'_ str) -> ModalResult<Expr> {
// this should look very straight-forward after all we've done:
// we find the `'` (quote) character, use cut_err to say that we're unambiguously
// looking for an s-expression of 0 or more expressions, and then parse them
preceded("'", cut_err(s_exp(repeat(0.., parse_expr))))
.context(StrContext::Label("quote"))
.map(Expr::Quote)
.parse_next(i)
}
/// Before continuing, we need a helper function to parse lists.
/// A list starts with `(` and ends with a matching `)`.
/// By putting whitespace and newline parsing here, we can avoid having to worry about it
/// in much of the rest of the parser.
//.parse_next/
/// Unlike the previous functions, this function doesn't take or consume input, instead it
/// takes a parsing function and returns a new parsing function.
fn s_exp<'a, O1, F>(inner: F) -> impl ModalParser<&'a str, O1, ContextError>
where
F: ModalParser<&'a str, O1, ContextError>,
{
delimited(
'(',
preceded(multispace0, inner),
cut_err(preceded(multispace0, ')')).context(StrContext::Label("closing paren")),
)
}
/// And that's it!
/// We can now parse our entire lisp language.
///
/// But in order to make it a little more interesting, we can hack together
/// a little interpreter to take an Expr, which is really an
/// [Abstract Syntax Tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) (AST),
/// and give us something back
///
/// This function tries to reduce the AST.
/// This has to return an Expression rather than an Atom because quoted `s_expressions`
/// can't be reduced
fn eval_expression(e: Expr) -> Option<Expr> {
match e {
// Constants and quoted s-expressions are our base-case
Expr::Constant(_) | Expr::Quote(_) => Some(e),
// we then recursively `eval_expression` in the context of our special forms
// and built-in operators
Expr::If(pred, true_branch) => {
let reduce_pred = eval_expression(*pred)?;
if get_bool_from_expr(reduce_pred)? {
eval_expression(*true_branch)
} else {
None
}
}
Expr::IfElse(pred, true_branch, false_branch) => {
let reduce_pred = eval_expression(*pred)?;
if get_bool_from_expr(reduce_pred)? {
eval_expression(*true_branch)
} else {
eval_expression(*false_branch)
}
}
Expr::Application(head, tail) => {
let reduced_head = eval_expression(*head)?;
let reduced_tail = tail
.into_iter()
.map(eval_expression)
.collect::<Option<Vec<Expr>>>()?;
if let Expr::Constant(Atom::BuiltIn(bi)) = reduced_head {
Some(Expr::Constant(match bi {
BuiltIn::Plus => Atom::Num(
reduced_tail
.into_iter()
.map(get_num_from_expr)
.collect::<Option<Vec<i32>>>()?
.into_iter()
.sum(),
),
BuiltIn::Times => Atom::Num(
reduced_tail
.into_iter()
.map(get_num_from_expr)
.collect::<Option<Vec<i32>>>()?
.into_iter()
.product(),
),
BuiltIn::Equal => Atom::Boolean(
reduced_tail
.iter()
.zip(reduced_tail.iter().skip(1))
.all(|(a, b)| a == b),
),
BuiltIn::Not => {
if reduced_tail.len() != 1 {
return None;
} else {
Atom::Boolean(!get_bool_from_expr(
reduced_tail.first().cloned().unwrap(),
)?)
}
}
BuiltIn::Minus => {
Atom::Num(if let Some(first_elem) = reduced_tail.first().cloned() {
let fe = get_num_from_expr(first_elem)?;
reduced_tail
.into_iter()
.map(get_num_from_expr)
.collect::<Option<Vec<i32>>>()?
.into_iter()
.skip(1)
.fold(fe, |a, b| a - b)
} else {
Default::default()
})
}
BuiltIn::Divide => {
Atom::Num(if let Some(first_elem) = reduced_tail.first().cloned() {
let fe = get_num_from_expr(first_elem)?;
reduced_tail
.into_iter()
.map(get_num_from_expr)
.collect::<Option<Vec<i32>>>()?
.into_iter()
.skip(1)
.fold(fe, |a, b| a / b)
} else {
Default::default()
})
}
}))
} else {
None
}
}
}
}
/// To start we define a couple of helper functions
fn get_num_from_expr(e: Expr) -> Option<i32> {
if let Expr::Constant(Atom::Num(n)) = e {
Some(n)
} else {
None
}
}
fn get_bool_from_expr(e: Expr) -> Option<bool> {
if let Expr::Constant(Atom::Boolean(b)) = e {
Some(b)
} else {
None
}
}

70
vendor/winnow/examples/string/main.rs vendored Normal file
View File

@@ -0,0 +1,70 @@
//! This example shows an example of how to parse an escaped string. The
//! rules for the string are similar to JSON and rust. A string is:
//!
//! - Enclosed by double quotes
//! - Can contain any raw unescaped code point besides \ and "
//! - Matches the following escape sequences: \b, \f, \n, \r, \t, \", \\, \/
//! - Matches code points like Rust: \u{XXXX}, where XXXX can be up to 6
//! hex characters
//! - an escape followed by whitespace consumes all whitespace between the
//! escape and the next non-whitespace character
#![cfg(feature = "alloc")]
mod parser;
use winnow::prelude::*;
fn main() -> Result<(), lexopt::Error> {
let args = Args::parse()?;
let data = args.input.as_deref().unwrap_or("\"abc\"");
let result = parser::parse_string::<()>.parse(data);
match result {
Ok(data) => println!("{data}"),
Err(err) => println!("{err:?}"),
}
Ok(())
}
#[derive(Default)]
struct Args {
input: Option<String>,
}
impl Args {
fn parse() -> Result<Self, lexopt::Error> {
use lexopt::prelude::*;
let mut res = Args::default();
let mut args = lexopt::Parser::from_env();
while let Some(arg) = args.next()? {
match arg {
Value(input) => {
res.input = Some(input.string()?);
}
_ => return Err(arg.unexpected()),
}
}
Ok(res)
}
}
#[test]
fn simple() {
let data = "\"abc\"";
let result = parser::parse_string::<()>.parse(data);
assert_eq!(result, Ok(String::from("abc")));
}
#[test]
fn escaped() {
let data = "\"tab:\\tafter tab, newline:\\nnew line, quote: \\\", emoji: \\u{1F602}, newline:\\nescaped whitespace: \\ abc\"";
let result = parser::parse_string::<()>.parse(data);
assert_eq!(
result,
Ok(String::from("tab:\tafter tab, newline:\nnew line, quote: \", emoji: 😂, newline:\nescaped whitespace: abc"))
);
}

168
vendor/winnow/examples/string/parser.rs vendored Normal file
View File

@@ -0,0 +1,168 @@
//! This example shows an example of how to parse an escaped string. The
//! rules for the string are similar to JSON and rust. A string is:
//!
//! - Enclosed by double quotes
//! - Can contain any raw unescaped code point besides \ and "
//! - Matches the following escape sequences: \b, \f, \n, \r, \t, \", \\, \/
//! - Matches code points like Rust: \u{XXXX}, where XXXX can be up to 6
//! hex characters
//! - an escape followed by whitespace consumes all whitespace between the
//! escape and the next non-whitespace character
use winnow::ascii::multispace1;
use winnow::combinator::alt;
use winnow::combinator::repeat;
use winnow::combinator::{delimited, preceded};
use winnow::error::{FromExternalError, ParserError};
use winnow::prelude::*;
use winnow::token::{take_till, take_while};
use winnow::Result;
/// Parse a string. Use a loop of `parse_fragment` and push all of the fragments
/// into an output string.
pub(crate) fn parse_string<'a, E>(input: &mut &'a str) -> Result<String, E>
where
E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
{
// Repeat::fold is the equivalent of iterator::fold. It runs a parser in a loop,
// and for each output value, calls a folding function on each output value.
let build_string = repeat(
0..,
// Our parser function parses a single string fragment
parse_fragment,
)
.fold(
// Our init value, an empty string
String::new,
// Our folding function. For each fragment, append the fragment to the
// string.
|mut string, fragment| {
match fragment {
StringFragment::Literal(s) => string.push_str(s),
StringFragment::EscapedChar(c) => string.push(c),
StringFragment::EscapedWS => {}
}
string
},
);
// Finally, parse the string. Note that, if `build_string` could accept a raw
// " character, the closing delimiter " would never match. When using
// `delimited` with a looping parser (like Repeat::fold), be sure that the
// loop won't accidentally match your closing delimiter!
delimited('"', build_string, '"').parse_next(input)
}
/// A string fragment contains a fragment of a string being parsed: either
/// a non-empty Literal (a series of non-escaped characters), a single
/// parsed escaped character, or a block of escaped whitespace.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum StringFragment<'a> {
Literal(&'a str),
EscapedChar(char),
EscapedWS,
}
/// Combine `parse_literal`, `parse_escaped_whitespace`, and `parse_escaped_char`
/// into a `StringFragment`.
fn parse_fragment<'a, E>(input: &mut &'a str) -> Result<StringFragment<'a>, E>
where
E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
{
alt((
// The `map` combinator runs a parser, then applies a function to the output
// of that parser.
parse_literal.map(StringFragment::Literal),
parse_escaped_char.map(StringFragment::EscapedChar),
parse_escaped_whitespace.value(StringFragment::EscapedWS),
))
.parse_next(input)
}
/// Parse a non-empty block of text that doesn't include \ or "
fn parse_literal<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> Result<&'a str, E> {
// `take_till` parses a string of 0 or more characters that aren't one of the
// given characters.
let not_quote_slash = take_till(1.., ['"', '\\']);
// `verify` runs a parser, then runs a verification function on the output of
// the parser. The verification function accepts the output only if it
// returns true. In this case, we want to ensure that the output of take_till
// is non-empty.
not_quote_slash
.verify(|s: &str| !s.is_empty())
.parse_next(input)
}
// parser combinators are constructed from the bottom up:
// first we write parsers for the smallest elements (escaped characters),
// then combine them into larger parsers.
/// Parse an escaped character: \n, \t, \r, \u{00AC}, etc.
fn parse_escaped_char<'a, E>(input: &mut &'a str) -> Result<char, E>
where
E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
{
preceded(
'\\',
// `alt` tries each parser in sequence, returning the result of
// the first successful match
alt((
parse_unicode,
// The `value` parser returns a fixed value (the first argument) if its
// parser (the second argument) succeeds. In these cases, it looks for
// the marker characters (n, r, t, etc) and returns the matching
// character (\n, \r, \t, etc).
'n'.value('\n'),
'r'.value('\r'),
't'.value('\t'),
'b'.value('\u{08}'),
'f'.value('\u{0C}'),
'\\'.value('\\'),
'/'.value('/'),
'"'.value('"'),
)),
)
.parse_next(input)
}
/// Parse a unicode sequence, of the form u{XXXX}, where XXXX is 1 to 6
/// hexadecimal numerals. We will combine this later with `parse_escaped_char`
/// to parse sequences like \u{00AC}.
fn parse_unicode<'a, E>(input: &mut &'a str) -> Result<char, E>
where
E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
{
// `take_while` parses between `m` and `n` bytes (inclusive) that match
// a predicate. `parse_hex` here parses between 1 and 6 hexadecimal numerals.
let parse_hex = take_while(1..=6, |c: char| c.is_ascii_hexdigit());
// `preceded` takes a prefix parser, and if it succeeds, returns the result
// of the body parser. In this case, it parses u{XXXX}.
let parse_delimited_hex = preceded(
'u',
// `delimited` is like `preceded`, but it parses both a prefix and a suffix.
// It returns the result of the middle parser. In this case, it parses
// {XXXX}, where XXXX is 1 to 6 hex numerals, and returns XXXX
delimited('{', parse_hex, '}'),
);
// `try_map` takes the result of a parser and applies a function that returns
// a Result. In this case we take the hex bytes from parse_hex and attempt to
// convert them to a u32.
let parse_u32 = parse_delimited_hex.try_map(move |hex| u32::from_str_radix(hex, 16));
// verify_map is like try_map, but it takes an Option instead of a Result. If
// the function returns None, verify_map returns an error. In this case, because
// not all u32 values are valid unicode code points, we have to fallibly
// convert to char with from_u32.
parse_u32.verify_map(std::char::from_u32).parse_next(input)
}
/// Parse a backslash, followed by any amount of whitespace. This is used later
/// to discard any escaped whitespace.
fn parse_escaped_whitespace<'a, E: ParserError<&'a str>>(
input: &mut &'a str,
) -> Result<&'a str, E> {
preceded('\\', multispace1).parse_next(input)
}

View File

@@ -0,0 +1,6 @@
//! # Arithmetic
//!
//! This parses arithmetic expressions and directly evaluates them.
//! ```rust
#![doc = include_str!("../../examples/arithmetic/parser.rs")]
//! ```

44
vendor/winnow/src/_topic/error.rs vendored Normal file
View File

@@ -0,0 +1,44 @@
//! # Custom Errors
//!
//! A lot can be accomplished with the built-in error tools, like:
//! - [`ContextError`]
//! - [`Parser::context`]
//! - [`cut_err`]
//!
//! *(see [tutorial][chapter_7])*
//!
//! Most other needs can likely be met by using a custom context type with [`ContextError`] instead
//! of [`StrContext`].
//! This will require implementing a custom renderer.
//!
//! ## `ParserError` Trait
//!
//! When needed, you can also create your own type that implements [`ParserError`].
//!
//! Optional traits include:
//! - [`AddContext`]
//! - [`FromExternalError`]
//! - [`ErrorConvert`]
//!
//! There are multiple strategies for implementing support for [`AddContext`] and [`FromExternalError`]:
//! - Make your error type generic over the context or external error
//! - Require a trait for the context or external error and `Box` it
//! - Make the context an enum like [`StrContext`]
//! - Implement the trait multiple times, one for each concrete context or external error type,
//! allowing custom behavior per type
//!
//! Example:
//!```rust
#![doc = include_str!("../../examples/custom_error.rs")]
//!```
#![allow(unused_imports)]
use crate::combinator::cut_err;
use crate::error::ContextError;
use crate::error::ErrorConvert;
use crate::error::StrContext;
use crate::Parser;
use crate::_tutorial::chapter_7;
use crate::error::AddContext;
use crate::error::FromExternalError;
use crate::error::ParserError;

8
vendor/winnow/src/_topic/fromstr.rs vendored Normal file
View File

@@ -0,0 +1,8 @@
//! # Implementing `FromStr`
//!
//! The [`FromStr` trait][std::str::FromStr] provides
//! a common interface to parse from a string.
//!
//! ```rust
#![doc = include_str!("../../examples/css/parser.rs")]
//! ```

5
vendor/winnow/src/_topic/http.rs vendored Normal file
View File

@@ -0,0 +1,5 @@
//! # HTTP
//!
//! ```rust
#![doc = include_str!("../../examples/http/parser.rs")]
//! ```

5
vendor/winnow/src/_topic/ini.rs vendored Normal file
View File

@@ -0,0 +1,5 @@
//! # INI
//!
//! ```rust
#![doc = include_str!("../../examples/ini/parser.rs")]
//! ```

5
vendor/winnow/src/_topic/json.rs vendored Normal file
View File

@@ -0,0 +1,5 @@
//! # json
//!
//! ```rust,ignore
#![doc = include_str!("../../examples/json/parser_dispatch.rs")]
//! ```

326
vendor/winnow/src/_topic/language.rs vendored Normal file
View File

@@ -0,0 +1,326 @@
//! # Elements of Programming Languages
//!
//! These are short recipes for accomplishing common tasks.
//!
//! * [Whitespace](#whitespace)
//! + [Wrapper combinators that eat whitespace before and after a parser](#wrapper-combinators-that-eat-whitespace-before-and-after-a-parser)
//! * [Comments](#comments)
//! + [`// C++/EOL-style comments`](#-ceol-style-comments)
//! + [`/* C-style comments */`](#-c-style-comments-)
//! * [Identifiers](#identifiers)
//! + [`Rust-Style Identifiers`](#rust-style-identifiers)
//! * [Literal Values](#literal-values)
//! + [Escaped Strings](#escaped-strings)
//! + [Integers](#integers)
//! - [Hexadecimal](#hexadecimal)
//! - [Octal](#octal)
//! - [Binary](#binary)
//! - [Decimal](#decimal)
//! + [Floating Point Numbers](#floating-point-numbers)
//!
//! ## Whitespace
//!
//!
//!
//! ### Wrapper combinators that eat whitespace before and after a parser
//!
//! ```rust
//! use winnow::prelude::*;
//! use winnow::{
//! error::ParserError,
//! combinator::delimited,
//! ascii::multispace0,
//! };
//!
//! /// A combinator that takes a parser `inner` and produces a parser that also consumes both leading and
//! /// trailing whitespace, returning the output of `inner`.
//! fn ws<'a, F, O, E: ParserError<&'a str>>(inner: F) -> impl Parser<&'a str, O, E>
//! where
//! F: Parser<&'a str, O, E>,
//! {
//! delimited(
//! multispace0,
//! inner,
//! multispace0
//! )
//! }
//! ```
//!
//! To eat only trailing whitespace, replace `delimited(...)` with `terminated(&inner, multispace0)`.
//! Likewise, the eat only leading whitespace, replace `delimited(...)` with `preceded(multispace0,
//! &inner)`. You can use your own parser instead of `multispace0` if you want to skip a different set
//! of lexemes.
//!
//! ## Comments
//!
//! ### `// C++/EOL-style comments`
//!
//! This version uses `%` to start a comment, does not consume the newline character, and returns an
//! output of `()`.
//!
//! ```rust
//! use winnow::prelude::*;
//! use winnow::{
//! error::ParserError,
//! token::take_till,
//! };
//!
//! pub fn peol_comment<'a, E: ParserError<&'a str>>(i: &mut &'a str) -> ModalResult<(), E>
//! {
//! ('%', take_till(1.., ['\n', '\r']))
//! .void() // Output is thrown away.
//! .parse_next(i)
//! }
//! ```
//!
//! ### `/* C-style comments */`
//!
//! Inline comments surrounded with sentinel literals `(*` and `*)`. This version returns an output of `()`
//! and does not handle nested comments.
//!
//! ```rust
//! use winnow::prelude::*;
//! use winnow::{
//! error::ParserError,
//! token::take_until,
//! };
//!
//! pub fn pinline_comment<'a, E: ParserError<&'a str>>(i: &mut &'a str) -> ModalResult<(), E> {
//! (
//! "(*",
//! take_until(0.., "*)"),
//! "*)"
//! )
//! .void() // Output is thrown away.
//! .parse_next(i)
//! }
//! ```
//!
//! ## Identifiers
//!
//! ### `Rust-Style Identifiers`
//!
//! Parsing identifiers that may start with a letter (or underscore) and may contain underscores,
//! letters and numbers may be parsed like this:
//!
//! ```rust
//! use winnow::prelude::*;
//! use winnow::{
//! stream::AsChar,
//! token::take_while,
//! token::one_of,
//! };
//!
//! pub fn identifier<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! (
//! one_of(|c: char| c.is_alpha() || c == '_'),
//! take_while(0.., |c: char| c.is_alphanum() || c == '_')
//! )
//! .take()
//! .parse_next(input)
//! }
//! ```
//!
//! Let's say we apply this to the identifier `hello_world123abc`. The first element of the tuple
//! would uses [`one_of`][crate::token::one_of] which would take `h`. The tuple ensures that
//! `ello_world123abc` will be piped to the next [`take_while`][crate::token::take_while] parser,
//! which takes every remaining character. However, the tuple returns a tuple of the results
//! of its sub-parsers. The [`take`][crate::Parser::take] parser produces a `&str` of the
//! input text that was parsed, which in this case is the entire `&str` `hello_world123abc`.
//!
//! ## Literal Values
//!
//! ### Escaped Strings
//!
//! ```rust
#![doc = include_str!("../../examples/string/parser.rs")]
//! ```
//!
//! See also [`take_escaped`] and [`escaped`].
//!
//! ### Integers
//!
//! The following recipes all return string slices rather than integer values. How to obtain an
//! integer value instead is demonstrated for hexadecimal integers. The others are similar.
//!
//! The parsers allow the grouping character `_`, which allows one to group the digits by byte, for
//! example: `0xA4_3F_11_28`. If you prefer to exclude the `_` character, the lambda to convert from a
//! string slice to an integer value is slightly simpler. You can also strip the `_` from the string
//! slice that is returned, which is demonstrated in the second hexadecimal number parser.
//!
//! #### Hexadecimal
//!
//! The parser outputs the string slice of the digits without the leading `0x`/`0X`.
//!
//! ```rust
//! use winnow::prelude::*;
//! use winnow::{
//! combinator::alt,
//! combinator::repeat,
//! combinator::{preceded, terminated},
//! token::one_of,
//! };
//!
//! fn hexadecimal<'s>(input: &mut &'s str) -> ModalResult<&'s str> { // <'a, E: ParserError<&'a str>>
//! preceded(
//! alt(("0x", "0X")),
//! repeat(1..,
//! terminated(one_of(('0'..='9', 'a'..='f', 'A'..='F')), repeat(0.., '_').map(|()| ()))
//! ).map(|()| ()).take()
//! ).parse_next(input)
//! }
//! ```
//!
//! If you want it to return the integer value instead, use map:
//!
//! ```rust
//! use winnow::prelude::*;
//! use winnow::{
//! combinator::alt,
//! combinator::repeat,
//! combinator::{preceded, terminated},
//! token::one_of,
//! };
//!
//! fn hexadecimal_value(input: &mut &str) -> ModalResult<i64> {
//! preceded(
//! alt(("0x", "0X")),
//! repeat(1..,
//! terminated(one_of(('0'..='9', 'a'..='f', 'A'..='F')), repeat(0.., '_').map(|()| ()))
//! ).map(|()| ()).take()
//! ).try_map(
//! |out: &str| i64::from_str_radix(&str::replace(&out, "_", ""), 16)
//! ).parse_next(input)
//! }
//! ```
//!
//! See also [`hex_uint`]
//!
//! #### Octal
//!
//! ```rust
//! use winnow::prelude::*;
//! use winnow::{
//! combinator::alt,
//! combinator::repeat,
//! combinator::{preceded, terminated},
//! token::one_of,
//! };
//!
//! fn octal<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! preceded(
//! alt(("0o", "0O")),
//! repeat(1..,
//! terminated(one_of('0'..='7'), repeat(0.., '_').map(|()| ()))
//! ).map(|()| ()).take()
//! ).parse_next(input)
//! }
//! ```
//!
//! #### Binary
//!
//! ```rust
//! use winnow::prelude::*;
//! use winnow::{
//! combinator::alt,
//! combinator::repeat,
//! combinator::{preceded, terminated},
//! token::one_of,
//! };
//!
//! fn binary<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! preceded(
//! alt(("0b", "0B")),
//! repeat(1..,
//! terminated(one_of('0'..='1'), repeat(0.., '_').map(|()| ()))
//! ).map(|()| ()).take()
//! ).parse_next(input)
//! }
//! ```
//!
//! #### Decimal
//!
//! ```rust
//! use winnow::prelude::*;
//! use winnow::{
//! combinator::repeat,
//! combinator::terminated,
//! token::one_of,
//! };
//!
//! fn decimal<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! repeat(1..,
//! terminated(one_of('0'..='9'), repeat(0.., '_').map(|()| ()))
//! ).map(|()| ())
//! .take()
//! .parse_next(input)
//! }
//! ```
//!
//! See also [`dec_uint`] and [`dec_int`]
//!
//! ### Floating Point Numbers
//!
//! The following is adapted from [the Python parser by Valentin Lorentz](https://github.com/ProgVal/rust-python-parser/blob/master/src/numbers.rs).
//!
//! ```rust
//! use winnow::prelude::*;
//! use winnow::{
//! combinator::alt,
//! combinator::repeat,
//! combinator::opt,
//! combinator::{preceded, terminated},
//! token::one_of,
//! };
//!
//! fn float<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! alt((
//! // Case one: .42
//! (
//! '.',
//! decimal,
//! opt((
//! one_of(['e', 'E']),
//! opt(one_of(['+', '-'])),
//! decimal
//! ))
//! ).take()
//! , // Case two: 42e42 and 42.42e42
//! (
//! decimal,
//! opt(preceded(
//! '.',
//! decimal,
//! )),
//! one_of(['e', 'E']),
//! opt(one_of(['+', '-'])),
//! decimal
//! ).take()
//! , // Case three: 42. and 42.42
//! (
//! decimal,
//! '.',
//! opt(decimal)
//! ).take()
//! )).parse_next(input)
//! }
//!
//! fn decimal<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! repeat(1..,
//! terminated(one_of('0'..='9'), repeat(0.., '_').map(|()| ()))
//! ).
//! map(|()| ())
//! .take()
//! .parse_next(input)
//! }
//! ```
//!
//! See also [`float`]
#![allow(unused_imports)]
use crate::ascii::dec_int;
use crate::ascii::dec_uint;
use crate::ascii::escaped;
use crate::ascii::float;
use crate::ascii::hex_uint;
use crate::ascii::take_escaped;

23
vendor/winnow/src/_topic/lexing.rs vendored Normal file
View File

@@ -0,0 +1,23 @@
//! # Lexing and Parsing
//!
//! ## Parse to AST
//!
//! The simplest way to write a parser is to parse directly to the AST.
//!
//! Example:
//! ```rust
#![doc = include_str!("../../examples/arithmetic/parser_ast.rs")]
//! ```
//!
//! ## Lexing
//!
//! However, there are times when you may want to separate lexing from parsing.
//! Winnow provides [`TokenSlice`] to simplify this.
//!
//! Example:
//! ```rust
#![doc = include_str!("../../examples/arithmetic/parser_lexer.rs")]
//! ```
#![allow(unused_imports)]
use crate::stream::TokenSlice;

42
vendor/winnow/src/_topic/mod.rs vendored Normal file
View File

@@ -0,0 +1,42 @@
//! # Special Topics
//!
//! These are short recipes for accomplishing common tasks.
//!
//! - [Why `winnow`?][why]
//! - [For `nom` users][nom]
//! - Formats:
//! - [Elements of Programming Languages][language]
//! - [Arithmetic][arithmetic]
//! - [s-expression][s_expression]
//! - [json]
//! - [INI][ini]
//! - [HTTP][http]
//! - Special Topics:
//! - [Implementing `FromStr`][fromstr]
//! - [Performance][performance]
//! - [Parsing Partial Input][partial]
//! - [Lexing and Parsing][lexing]
//! - [Custom stream or token][stream]
//! - [Custom errors][error]
//! - [Debugging][crate::_tutorial::chapter_8]
//!
//! See also parsers written with `winnow`:
//!
//! - [`toml_edit`](https://crates.io/crates/toml_edit)
//! - [`hcl-edit`](https://crates.io/crates/hcl-edit)
#![allow(clippy::std_instead_of_core)]
pub mod arithmetic;
pub mod error;
pub mod fromstr;
pub mod http;
pub mod ini;
pub mod json;
pub mod language;
pub mod lexing;
pub mod nom;
pub mod partial;
pub mod performance;
pub mod s_expression;
pub mod stream;
pub mod why;

240
vendor/winnow/src/_topic/nom.rs vendored Normal file
View File

@@ -0,0 +1,240 @@
//! # For `nom` users
//!
//! ## Migrating from `nom`
//!
//! For comparisons with `nom`, see
//! - [Why `winnow`][super::why]
//! - [parse-rosetta-rs](https://github.com/rosetta-rs/parse-rosetta-rs/)
//!
//! What approach you take depends on the size and complexity of your parser.
//! For small, simple parsers, its likely easiest to directly port from `nom`.
//! When trying to look for the equivalent of a `nom` combinator, search in the docs for the name
//! of the `nom` combinator. It is expected that, where names diverge, a doc alias exists.
//! See also the [List of combinators][crate::combinator].
//!
//! ### Complex migrations
//!
//! For larger parsers, it is likely best to take smaller steps
//! - Easier to debug when something goes wrong
//! - Deprecation messages will help assist through the process
//!
//! The workflow goes something like:
//! 1. Run `cargo rm nom && cargo add winnow@0.3`
//! 1. Ensure everything compiles and tests pass, ignoring deprecation messages (see [migration
//! notes](https://github.com/winnow-rs/winnow/blob/main/CHANGELOG.md#nom-migration-guide))
//! 1. Commit
//! 1. Switch any `impl FnMut(I) -> IResult<I, O, E>` to `impl Parser<I, O, E>`
//! 1. Resolve deprecation messages
//! 1. Commit
//! 1. Run `cargo add winnow@0.4`
//! 1. Ensure everything compiles and tests pass, ignoring deprecation messages (see [changelog](https://github.com/winnow-rs/winnow/blob/main/CHANGELOG.md#040---2023-03-18) for more details)
//! 1. Commit
//! 1. Resolve deprecation messages
//! 1. Commit
//! 1. Run `cargo add winnow@0.5`
//! 1. Ensure everything compiles and tests pass, ignoring deprecation messages
//! (see [migration notes](https://github.com/winnow-rs/winnow/blob/main/CHANGELOG.md#050---2023-07-13))
//! 1. Commit
//! 1. Resolve deprecation messages
//! 1. Commit
//!
//! ### Examples
//!
//! For example migrations, see
//! - [git-config-env](https://github.com/gitext-rs/git-config-env/pull/11) (nom to winnow 0.3)
//! - [git-conventional](https://github.com/crate-ci/git-conventional/pull/37) (nom to winnow 0.3,
//! adds explicit tracing for easier debugging)
//! - [typos](https://github.com/crate-ci/typos/pull/664) (nom to winnow 0.3)
//! - [cargo-smart-release](https://github.com/Byron/gitoxide/pull/948) (gradual migration from nom
//! to winnow 0.5)
//! - [gix-config](https://github.com/Byron/gitoxide/pull/951) (gradual migration from nom
//! to winnow 0.5)
//! - [gix-protocol](https://github.com/Byron/gitoxide/pull/1009) (gradual migration from nom
//! to winnow 0.5)
//! - [gitoxide](https://github.com/Byron/gitoxide/pull/956) (gradual migration from nom
//! to winnow 0.5)
//!
//! ## Differences
//!
//! These are key differences to help Nom users adapt to writing parsers with Winnow.
//!
//! ### Renamed APIs
//!
//! Names have changed for consistency or clarity.
//!
//! To find a parser you are looking for,
//! - Search the docs for the `nom` parser
//! - See the [List of combinators][crate::combinator]
//!
//! ### GATs
//!
//! `nom` v8 back-propagates how you will use a parser to parser functions using a language feature
//! called GATs.
//! Winnow has made the conscious choice not to use this feature, finding alternative ways of
//! getting most of the benefits.
//!
//! Benefits of GATs:
//! - Performance as the compiler is able to instantiate copies of a parser that are
//! better tailored to how it will be used, like discarding unused allocations for output or
//! errors.
//!
//! Benefits of not using GATs:
//! - Predictable performance:
//! With GATs, seemingly innocuous changes like choosing to hand write a parser using idiomatic function parsers
//! (`fn(&mut I) -> Result<O>`) can cause surprising slow downs because these functions sever the back-propagation from GATs.
//! The causes of these slowdowns could be hard to identify by inspection or profiling.
//! - No "eek out X% perf improvement" pressure to contort a parser
//! that is more easily written imperatively
//! to be written declaratively
//! so it can preserve the back-propagation from GATs.
//! - Built-in parsers serve are can serve as examples to users of idiomatic function parsers
//! (`fn(&mut I) -> Result<O>`).
//! With GATs, built-in parsers tend to be complex implementations of traits.
//! - Faster build times and smaller binary size as parsers only need to be generated for one mode,
//! not upto 8
//!
//! #### Partial/streaming parsers
//!
//! `nom` v8 back-propagates whether `Parser::parse_complete` was used to select `complete`
//! parsers.
//! Previously, users had ensure consistently using a parser from the `streaming` or `complete` module.
//!
//! Instead, you tag the input type (`I`) by wrapping it in [`Partial<I>`] and parsers will adjust
//! their behavior accordingly.
//! See [partial] special topic.
//!
//! #### Eliding Output
//!
//! `nom` v8 back-propagates whether an Output will be used and skips its creation.
//! For example, `value(Null, many0(_))` will avoid creating and pushing to a `Vec`.
//! Previously, users had to select `count_many0` over `many0` to avoid creating a `Vec`.
//!
//! Instead, `repeat` returns an `impl Accumulate<T>` which could be a `Vec`, a `usize` for `count`
//! variants, or `()` to do no extra work.
//!
//! #### Eliding Backtracked Errors
//!
//! Under the hood, [`alt`] is an `if-not-error-else` ladder, see [`_tutorial::chapter_3`].
//! nom v8 back-propagates whether the error will be discarded and avoids any expensive work done
//! for rich error messages.
//!
//! Instead, [`ContextError`] and other changes have made it so errors have very little overhead.
//! [`dispatch!`] can also be used in some situations to avoid `alt`s overhead.
//!
//! ### Parsers return [`Stream::Slice`], rather than [`Stream`]
//!
//! In `nom`, parsers like [`take_while`] parse a [`Stream`] and return a [`Stream`].
//! When wrapping the input, like with [`Stateful`],
//! you have to unwrap the input to integrate it in your application,
//! and it requires [`Stream`] to be `Clone`
//! (which requires `RefCell` for mutable external state and can be expensive).
//!
//! Instead, [`Stream::Slice`] was added to track the intended type for parsers to return.
//! If you want to then parse the slice, you then need to take it and turn it back into a
//! [`Stream`].
//!
//! ### `&mut I`
//!
//! `winnow` switched from pure-function parser (`Fn(I) -> (I, O)` to `Fn(&mut I) -> O`).
//! On error, `i` is left pointing at where the error happened.
//!
//! Benefits of `Fn(&mut I) -> O`:
//! - Cleaner code: Removes need to pass `i` everywhere and makes changes to `i` more explicit
//! - Correctness: No forgetting to chain `i` through a parser
//! - Flexibility: `I` does not need to be `Copy` or even `Clone`. For example, [`Stateful`] can use `&mut S` instead of `RefCell<S>`.
//! - Performance: `Result::Ok` is smaller without `i`, reducing the risk that the output will be
//! returned on the stack, rather than the much faster CPU registers.
//! `Result::Err` can also be smaller because the error type does not need to carry `i` to point
//! to the error.
//! See also [#72](https://github.com/winnow-rs/winnow/issues/72).
//!
//! Benefits of `Fn(I) -> (I, O)`:
//! - Pure functions can be easier to reason about
//! - Less boilerplate in some situations (see below)
//! - Less syntactic noise in some situations (see below)
//!
//! When returning a slice from the input, you have to add a lifetime:
//! ```rust
//! # use winnow::prelude::*;
//! fn foo<'i>(i: &mut &'i str) -> ModalResult<&'i str> {
//! # Ok("")
//! // ...
//! }
//! ```
//!
//! When writing a closure, you need to annotate the type
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::combinator::alt;
//! # use winnow::error::ContextError;
//! # let mut input = "";
//! # fn foo<'i>() -> impl ModalParser<&'i str, &'i str, ContextError> {
//! alt((
//! |i: &mut _| {
//! # Ok("")
//! // ...
//! },
//! |i: &mut _| {
//! # Ok("")
//! // ...
//! },
//! ))
//! # }
//! ```
//! *(at least the full type isn't needed)*
//!
//! To save and restore from intermediate states, [`Stream::checkpoint`] and [`Stream::reset`] can help:
//! ```rust
//! use winnow::prelude::*;
//! # let mut i = "";
//! # let i = &mut i;
//!
//! let start = i.checkpoint();
//! // ...
//! i.reset(&start);
//! ```
//!
//! When the Output of a parser is a slice, you have to add a lifetime:
//! ```rust
//! # use winnow::prelude::*;
//! fn foo<'i>(i: &mut &'i str) -> ModalResult<&'i str> {
//! // ...
//! # winnow::token::rest.parse_next(i)
//! }
//! ```
//!
//! When writing a closure, you need to annotate the type:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::combinator::trace;
//! fn foo(i: &mut &str) -> ModalResult<usize> {
//! trace("foo", |i: &mut _| {
//! // ...
//! # Ok(0)
//! }).parse_next(i)
//! }
//! ```
//!
//! ### Optional [`ErrMode`]
//!
//! Called `Err` in `nom`, [`ErrMode`] is responsible for
//! - Deciding whether to backtrack and try another branch in cases like `alt` or report back to
//! the error back to users
//! - Tracking incomplete input on partial parsing
//!
//! As this isn't needed in every parser, it was made optional. [`ModalResult`] is a convenience
//! type for using [`ErrMode`].
#![allow(unused_imports)]
use crate::_topic::partial;
use crate::_tutorial;
use crate::combinator::alt;
use crate::combinator::dispatch;
use crate::error::ContextError;
use crate::error::ErrMode;
use crate::error::ModalResult;
use crate::stream::Accumulate;
use crate::stream::Partial;
use crate::stream::Stateful;
use crate::stream::Stream;
use crate::token::take_while;

46
vendor/winnow/src/_topic/partial.rs vendored Normal file
View File

@@ -0,0 +1,46 @@
//! # Parsing Partial Input
//!
//! Typically, the input being parsed is all in-memory, or is complete. Some data sources are too
//! large to fit into memory, only allowing parsing an incomplete or [`Partial`] subset of the
//! data, requiring incrementally parsing.
//!
//! By wrapping a stream, like `&[u8]`, with [`Partial`], parsers will report when the data is
//! [`Incomplete`] and more input is [`Needed`], allowing the caller to stream-in additional data
//! to be parsed. The data is then parsed a chunk at a time.
//!
//! Chunks are typically defined by either:
//! - A header reporting the number of bytes, like with [`length_and_then`]
//! - [`Partial`] can explicitly be changed to being complete once the specified bytes are
//! acquired via [`StreamIsPartial::complete`].
//! - A delimiter, like with [ndjson](https://github.com/ndjson/ndjson-spec/)
//! - You can parse up-to the delimiter or do a `take_until(0.., delim).and_then(parser)`
//!
//! If the chunks are not homogeneous, a state machine will be needed to track what the expected
//! parser is for the next chunk.
//!
//! Caveats:
//! - `winnow` takes the approach of re-parsing from scratch. Chunks should be relatively small to
//! prevent the re-parsing overhead from dominating.
//! - Parsers like [`repeat`] do not know when an `eof` is from insufficient data or the end of the
//! stream, causing them to always report [`Incomplete`].
//!
//! # Example
//!
//! `main.rs`:
//! ```rust,ignore
#![doc = include_str!("../../examples/ndjson/main.rs")]
//! ```
//!
//! `parser.rs`:
//! ```rust,ignore
#![doc = include_str!("../../examples/ndjson/parser.rs")]
//! ```
#![allow(unused_imports)] // Used for intra-doc links
use crate::binary::length_and_then;
use crate::combinator::repeat;
use crate::error::ErrMode::Incomplete;
use crate::error::Needed;
use crate::stream::Partial;
use crate::stream::StreamIsPartial;

55
vendor/winnow/src/_topic/performance.rs vendored Normal file
View File

@@ -0,0 +1,55 @@
//! # Performance
//!
//! ## Runtime Performance
//!
//! 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)
//! - Find simplified subsets of the grammar to parse, falling back to the full grammar when it
//! doesn't work. For example, when parsing json strings, parse them without support for escapes,
//! falling back to escape support if it fails.
//! - Watch for large return types. A surprising place these can show up is when chaining parsers
//! with a tuple.
//!
//! ## Build-time Performance
//!
//! Returning complex types as `impl Trait` can negatively impact build times. This can hit in
//! surprising cases like:
//! ```rust
//! # use winnow::prelude::*;
//! fn foo<I, O, E>() -> impl Parser<I, O, E>
//! # where
//! # I: winnow::stream::Stream<Token=O>,
//! # I: winnow::stream::StreamIsPartial,
//! # E: winnow::error::ParserError<I>,
//! {
//! // ...some chained combinators...
//! # winnow::token::any
//! }
//! ```
//!
//! Instead, wrap the combinators in a closure to simplify the type:
//! ```rust
//! # use winnow::prelude::*;
//! fn foo<I, O, E>() -> impl Parser<I, O, E>
//! # where
//! # I: winnow::stream::Stream<Token=O>,
//! # I: winnow::stream::StreamIsPartial,
//! # E: winnow::error::ParserError<I>,
//! {
//! move |input: &mut I| {
//! // ...some chained combinators...
//! # winnow::token::any
//! .parse_next(input)
//! }
//! }
//! ```
#![allow(unused_imports)]
use crate::combinator::alt;
use crate::combinator::dispatch;
use crate::stream::BStr;

View File

@@ -0,0 +1,5 @@
//! # s-expression
//!
//! ```rust
#![doc = include_str!("../../examples/s_expression/parser.rs")]
//! ```

63
vendor/winnow/src/_topic/stream.rs vendored Normal file
View File

@@ -0,0 +1,63 @@
//! # Custom [`Stream`]
//!
//! `winnow` is batteries included with support for
//! - Basic inputs like `&str`, newtypes with
//! - Improved debug output like [`Bytes`]
//! - [`Stateful`] for passing state through your parser, like tracking recursion
//! depth
//! - [`LocatingSlice`] for looking up the absolute position of a token
//!
//! ## Implementing a custom token
//!
//! The first level of customization is parsing [`&[MyItem]`][Stream#impl-Stream-for-%26%5BT%5D]
//! or [`TokenSlice<MyItem>`].
//!
//! The basic traits you may want for a custom token type are:
//!
//! | trait | usage |
//! |---|---|
//! | [`AsChar`] |Transforms common types to a char for basic token parsing|
//! | [`ContainsToken`] |Look for the token in the given set|
//!
//! See also [`TokenSlice<MyItem>`], [lexing].
//!
//! ## Implementing a custom stream
//!
//! Let's assume we have an input type we'll call `MyStream`.
//! `MyStream` is a sequence of `MyItem` tokens.
//!
//! The goal is to define parsers with this signature: `&mut MyStream -> ModalResult<Output>`.
//! ```rust
//! # use winnow::prelude::*;
//! # type MyStream<'i> = &'i str;
//! # type Output<'i> = &'i str;
//! fn parser<'s>(i: &mut MyStream<'s>) -> ModalResult<Output<'s>> {
//! "test".parse_next(i)
//! }
//! ```
//!
//! Like above, you'll need to implement the related token traits for `MyItem`.
//!
//! The traits you may want to implement for `MyStream` include:
//!
//! | trait | usage |
//! |---|---|
//! | [`Stream`] |Core trait for driving parsing|
//! | [`StreamIsPartial`] | Marks the input as being the complete buffer or a partial buffer for streaming input |
//! | [`AsBytes`] |Casts the input type to a byte slice|
//! | [`AsBStr`] |Casts the input type to a slice of ASCII / UTF-8-like bytes|
//! | [`Compare`] |Character comparison operations|
//! | [`FindSlice`] |Look for a substring in self|
//! | [`Location`] |Calculate location within initial input|
//! | [`Offset`] |Calculate the offset between slices|
//!
//! And for `&[MyItem]` (slices returned by [`Stream`]):
//!
//! | trait | usage |
//! |---|---|
//! | [`SliceLen`] |Calculate the input length|
//! | [`ParseSlice`] |Used to integrate `&str`'s `parse()` method|
#![allow(unused_imports)] // Here for intra-dock links
use super::lexing;
use crate::stream::*;

110
vendor/winnow/src/_topic/why.rs vendored Normal file
View File

@@ -0,0 +1,110 @@
//! # Why `winnow`?
//!
//! To answer this question, it will be useful to contrast this with other approaches to parsing.
//!
//! <div class="warning">
//!
//! **Note:** This will focus on principles and priorities. For a deeper and wider
//! comparison with other Rust parser libraries, see
//! [parse-rosetta-rs](https://github.com/rosetta-rs/parse-rosetta-rs).
//!
//! </div>
//!
//! ## Hand-written parsers
//!
//! Typically, a hand-written parser gives you the flexibility to get
//! - Fast parse performance
//! - Fast compile-time
//! - Small binary sizes
//! - High quality error message
//! - Fewer dependencies to audit
//!
//! However, this comes at the cost of doing it all yourself, including
//! - 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
//! ["Ive implemented a production-grade Pratt parser once, but I no longer immediately understand that code :-)"](https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html)
//!
//! This approach works well if:
//! - Your format is small and is unlikely to change
//! - Your format is large but you have people who can focus solely on parsing, like with large
//! programming languages
//!
//! ## `winnow`
//!
//! Unlike traditional programming language parsers that use
//! [lex](https://en.wikipedia.org/wiki/Lex_(software)) or
//! [yacc](https://en.wikipedia.org/wiki/Yacc), you can think of `winnow` as a general version of
//! the helpers you would create along the way to writing a hand-written parser.
//!
//! `winnow` includes support for:
//! - Zero-copy parsing
//! - [Parse traces][trace] for easier debugging
//! - [Streaming parsing][Partial] for network communication or large file
//! - [Stateful] parsers
//!
//! For binary formats, `winnow` includes:
//! - [A hexadecimal view][crate::Bytes] in [trace]
//! - [TLV](https://en.wikipedia.org/wiki/Type-length-value) (e.g. [`length_take`])
//! - Some common parsers to help get started, like numbers
//!
//! For text formats, `winnow` includes:
//! - [Tracking of spans][crate::LocatingSlice]
//! - [A textual view when parsing as bytes][crate::BStr] in [trace]
//! - Ability to evaluate directly, parse to an AST, or lex and parse the format
//!
//! This works well for:
//! - Prototyping for what will be a hand-written parser
//! - 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.
//!
//! ## `nom`
//!
//! `winnow` is a fork of the venerable [`nom`](https://crates.io/crates/nom). The difference
//! between them is largely in priorities. `nom` prioritizes:
//! - Lower churn for existing users while `winnow` is trying to find ways to make things better
//! for the parsers yet to be written.
//! - Having a small core, relying on external crates like
//! [`nom-locate`](https://crates.io/crates/nom_locate) and
//! [`nom-supreme`](https://crates.io/crates/nom-supreme), encouraging flexibility among users
//! and to not block users on new features being merged while `winnow` aims to include all the
//! fundamentals for parsing to ensure the experience is cohesive and high quality.
//!
//! For more details, see the [design differences][super::nom#api-differences].
//!
//! See also our [nom migration guide][super::nom#migrating-from-nom].
//!
//! ## `chumsky`
//!
//! [`chumsky`](https://crates.io/crates/chumsky) is an up and coming parser-combinator library
//! that includes advanced features like error recovery.
//!
//! Probably the biggest diverging philosophy is `chumsky`s stance:
//!
//! > "If you need to implement either `Parser` or `Strategy` by hand, that's a problem that needs fixing".
//!
//! This is under "batteries included" but it also ties into the feeling that `chumsky` acts more like
//! a framework. Instead of composing together helpers, you are expected to do everything through
//! their system to the point that it is non-trivial to implement their `Parser` trait and are
//! encouraged to use the
//! [`custom`](https://docs.rs/chumsky/0.9.0/chumsky/primitive/fn.custom.html) helper. This
//! requires re-framing everything to fit within their model and makes the code harder to understand
//! and debug as you are working with abstract operations that will eventually be applied
//! rather than directly with the parsers.
//!
//! In contrast, `winnow` is an introspectable toolbox that can easily be customized at any level.
//! Probably the biggest thing that `winnow` loses out on is optimizations from ["parse modes" via
//! GATs](https://github.com/zesterer/chumsky/pull/82) which allows downstream parsers to tell
//! upstream parsers when information will be discarded, allowing bypassing expensive operations,
//! like allocations. This requires a lot more complex interaction with parsers that isn't as
//! trivial to do with bare functions which would lose out on any of that side-band information.
//! Instead, we work around this with things like the [`Accumulate`] trait.
#![allow(unused_imports)]
use crate::binary::length_take;
use crate::combinator::trace;
use crate::stream::Accumulate;
use crate::stream::Partial;
use crate::stream::Stateful;

View File

@@ -0,0 +1,38 @@
//! # Chapter 0: Introduction
//!
//! This tutorial assumes that you are:
//! - Already familiar with Rust
//! - Using `winnow` for the first time
//!
//! The focus will be on parsing in-memory strings (`&str`). Once done, you might want to check the
//! [Special Topics][_topic] for more specialized topics or examples.
//!
//! ## About
//!
//! `winnow` is a parser-combinator library. In other words, it gives you tools to define:
//! - "parsers", or functions that take an input and give back an output
//! - "combinators", or functions that take parsers and _combine_ them together!
//!
//! While "combinator" might be an unfamiliar word, you are likely using them in your rust code
//! today, like with the [`Iterator`] trait:
//! ```rust
//! let data = vec![1, 2, 3, 4, 5];
//! let even_count = data.iter()
//! .copied() // combinator
//! .filter(|d| d % 2 == 0) // combinator
//! .count(); // combinator
//! ```
//!
//! Parser combinators are great because:
//!
//! - Individual parser functions are small, focused on one thing, ignoring the rest
//! - You can write tests focused on individual parsers (unit tests and property-based tests)
//! in addition to testing the top-level parser as a whole.
//! - Top-level parsing code looks close to the grammar you would have written
#![allow(unused_imports)]
use crate::_topic;
use std::iter::Iterator;
pub use super::chapter_1 as next;
pub use crate::_tutorial as table_of_contents;

View File

@@ -0,0 +1,88 @@
//! # Chapter 1: The Winnow Way
//!
//! First of all, we need to understand the way that winnow thinks about parsing.
//! As discussed in the introduction, winnow lets us compose more complex parsers from more simple
//! ones (using "combinators").
//!
//! Let's discuss what a "parser" actually does. A parser takes an input and advances it until it returns
//! a result, where:
//! - `Ok` indicates the parser successfully found what it was looking for; or
//! - `Err` indicates the parser could not find what it was looking for.
//!
//! Parsers do more than just return a binary "success"/"failure" code.
//! - On success, the parser will return the processed data. The input will be advanced to the end of
//! what was processed, pointing to what will be parsed next.
//! - If the parser failed, then there are multiple errors that could be returned.
//! We'll explore this further in [`chapter_7`].
//!
//! ```text
//! ┌─► Ok(what matched the parser)
//! ┌────────┐ │
//! my input───►│a parser├──►either──┤
//! └────────┘ └─► Err(...)
//! ```
//!
//!
//! To represent this model of the world, winnow uses the [`Result<O>`] type.
//! The `Ok` variant has `output: O`;
//! whereas the `Err` variant stores an error.
//!
//! You can import that from:
//!
//! ```rust
//! use winnow::Result;
//! ```
//!
//! To combine parsers, we need a common way to refer to them which is where the [`Parser<I, O, E>`]
//! trait comes in with [`Parser::parse_next`] being the primary way to drive
//! parsing forward.
//! In [`chapter_6`], we'll cover how to integrate these into your application, particularly with
//! [`Parser::parse`].
//!
//! You'll note that `I` and `O` are parameterized -- while most of the examples in this book
//! will be with `&str` (i.e. parsing a string); [they do not have to be strings][stream]; nor do they
//! have to be the same type (consider the simple example where `I = &str`, and `O = u64` -- this
//! parses a string into an unsigned integer.)
//!
//! # Let's write our first parser!
//!
//! The simplest parser we can write is one which successfully does nothing.
//!
//! To make it easier to implement a [`Parser`], the trait is implemented for
//! functions of the form `Fn(&mut I) -> Result<O>`.
//!
//! This parser function should take in a `&str`:
//!
//! - Since it is supposed to succeed, we know it will return the `Ok` variant.
//! - Since it does nothing to our input, the input will be left where it started.
//! - Since it doesn't parse anything, it also should just return an empty string.
//!
//! ```rust
//! use winnow::Result;
//! use winnow::Parser;
//!
//! pub fn do_nothing_parser<'s>(input: &mut &'s str) -> Result<&'s str> {
//! Ok("")
//! }
//!
//! fn main() {
//! let mut input = "0x1a2b Hello";
//!
//! let output = do_nothing_parser.parse_next(&mut input).unwrap();
//! // Same as:
//! // let output = do_nothing_parser(&mut input).unwrap();
//!
//! assert_eq!(input, "0x1a2b Hello");
//! assert_eq!(output, "");
//! }
//! ```
#![allow(unused_imports)]
use super::chapter_6;
use super::chapter_7;
use crate::Parser;
use crate::_topic::stream;
pub use super::chapter_0 as previous;
pub use super::chapter_2 as next;
pub use crate::_tutorial as table_of_contents;

301
vendor/winnow/src/_tutorial/chapter_2.rs vendored Normal file
View File

@@ -0,0 +1,301 @@
//! # Chapter 2: Tokens and Tags
//!
//! The simplest *useful* parser you can write is one which matches tokens.
//! In our case, tokens are `char`.
//!
//! ## Tokens
//!
//! [`Stream`] provides some core operations to help with parsing. For example, to process a
//! single token, you can do:
//! ```rust
//! # use winnow::Parser;
//! # use winnow::Result;
//! use winnow::stream::Stream;
//! use winnow::error::ParserError;
//!
//! fn parse_prefix(input: &mut &str) -> Result<char> {
//! let c = input.next_token().ok_or_else(|| {
//! ParserError::from_input(input)
//! })?;
//! if c != '0' {
//! return Err(ParserError::from_input(input));
//! }
//! Ok(c)
//! }
//!
//! fn main() {
//! let mut input = "0x1a2b Hello";
//!
//! let output = parse_prefix.parse_next(&mut input).unwrap();
//!
//! assert_eq!(input, "x1a2b Hello");
//! assert_eq!(output, '0');
//!
//! assert!(parse_prefix.parse_next(&mut "d").is_err());
//! }
//! ```
//!
//! This extraction of a token is encapsulated in the [`any`] parser:
//! ```rust
//! # use winnow::Result;
//! # use winnow::error::ParserError;
//! use winnow::Parser;
//! use winnow::token::any;
//!
//! fn parse_prefix(input: &mut &str) -> Result<char> {
//! let c = any
//! .parse_next(input)?;
//! if c != '0' {
//! return Err(ParserError::from_input(input));
//! }
//! Ok(c)
//! }
//! #
//! # fn main() {
//! # let mut input = "0x1a2b Hello";
//! #
//! # let output = parse_prefix.parse_next(&mut input).unwrap();
//! #
//! # assert_eq!(input, "x1a2b Hello");
//! # assert_eq!(output, '0');
//! #
//! # assert!(parse_prefix.parse_next(&mut "d").is_err());
//! # }
//! ```
//!
//! Using the higher level [`any`] parser opens `parse_prefix` to the helpers on the [`Parser`] trait,
//! like [`Parser::verify`] which fails a parse if a condition isn't met, like our check above:
//! ```rust
//! # use winnow::Result;
//! use winnow::Parser;
//! use winnow::token::any;
//!
//! fn parse_prefix(input: &mut &str) -> Result<char> {
//! let c = any
//! .verify(|c| *c == '0')
//! .parse_next(input)?;
//! Ok(c)
//! }
//! #
//! # fn main() {
//! # let mut input = "0x1a2b Hello";
//! #
//! # let output = parse_prefix.parse_next(&mut input).unwrap();
//! #
//! # assert_eq!(input, "x1a2b Hello");
//! # assert_eq!(output, '0');
//! #
//! # assert!(parse_prefix.parse_next(&mut "d").is_err());
//! # }
//! ```
//!
//! Matching a single token literal is common enough that [`Parser`] is implemented for
//! the `char` type, encapsulating both [`any`] and [`Parser::verify`]:
//! ```rust
//! # use winnow::Result;
//! use winnow::Parser;
//!
//! fn parse_prefix(input: &mut &str) -> Result<char> {
//! let c = '0'.parse_next(input)?;
//! Ok(c)
//! }
//! #
//! # fn main() {
//! # let mut input = "0x1a2b Hello";
//! #
//! # let output = parse_prefix.parse_next(&mut input).unwrap();
//! #
//! # assert_eq!(input, "x1a2b Hello");
//! # assert_eq!(output, '0');
//! #
//! # assert!(parse_prefix.parse_next(&mut "d").is_err());
//! # }
//! ```
//!
//! ## Tags
//!
//! [`Stream`] also supports processing slices of tokens:
//! ```rust
//! # use winnow::Parser;
//! # use winnow::Result;
//! use winnow::stream::Stream;
//! use winnow::error::ParserError;
//!
//! fn parse_prefix<'s>(input: &mut &'s str) -> Result<&'s str> {
//! let expected = "0x";
//! if input.len() < expected.len() {
//! return Err(ParserError::from_input(input));
//! }
//! let actual = input.next_slice(expected.len());
//! if actual != expected {
//! return Err(ParserError::from_input(input));
//! }
//! Ok(actual)
//! }
//!
//! fn main() {
//! let mut input = "0x1a2b Hello";
//!
//! let output = parse_prefix.parse_next(&mut input).unwrap();
//! assert_eq!(input, "1a2b Hello");
//! assert_eq!(output, "0x");
//!
//! assert!(parse_prefix.parse_next(&mut "0o123").is_err());
//! }
//! ```
//!
//! Matching the input position against a string literal is encapsulated in the [`literal`] parser:
//! ```rust
//! # use winnow::Result;
//! # use winnow::Parser;
//! use winnow::token::literal;
//!
//! fn parse_prefix<'s>(input: &mut &'s str) -> Result<&'s str> {
//! let expected = "0x";
//! let actual = literal(expected).parse_next(input)?;
//! Ok(actual)
//! }
//! #
//! # fn main() {
//! # let mut input = "0x1a2b Hello";
//! #
//! # let output = parse_prefix.parse_next(&mut input).unwrap();
//! # assert_eq!(input, "1a2b Hello");
//! # assert_eq!(output, "0x");
//! #
//! # assert!(parse_prefix.parse_next(&mut "0o123").is_err());
//! # }
//! ```
//!
//! Like for a single token, matching a string literal is common enough that [`Parser`] is implemented for the `&str` type:
//! ```rust
//! # use winnow::Result;
//! use winnow::Parser;
//!
//! fn parse_prefix<'s>(input: &mut &'s str) -> Result<&'s str> {
//! let actual = "0x".parse_next(input)?;
//! Ok(actual)
//! }
//! #
//! # fn main() {
//! # let mut input = "0x1a2b Hello";
//! #
//! # let output = parse_prefix.parse_next(&mut input).unwrap();
//! # assert_eq!(input, "1a2b Hello");
//! # assert_eq!(output, "0x");
//! #
//! # assert!(parse_prefix.parse_next(&mut "0o123").is_err());
//! # }
//! ```
//!
//! See [`token`] for additional individual and token-slice parsers.
//!
//! ## Character Classes
//!
//! Selecting a single `char` or a [`literal`] is fairly limited. Sometimes, you will want to select one of several
//! `chars` of a specific class, like digits. For this, we use the [`one_of`] parser:
//!
//! ```rust
//! # use winnow::Parser;
//! # use winnow::Result;
//! use winnow::token::one_of;
//!
//! fn parse_digits(input: &mut &str) -> Result<char> {
//! one_of(('0'..='9', 'a'..='f', 'A'..='F')).parse_next(input)
//! }
//!
//! fn main() {
//! let mut input = "1a2b Hello";
//!
//! let output = parse_digits.parse_next(&mut input).unwrap();
//! assert_eq!(input, "a2b Hello");
//! assert_eq!(output, '1');
//!
//! assert!(parse_digits.parse_next(&mut "Z").is_err());
//! }
//! ```
//!
//! > **Aside:** [`one_of`] might look straightforward, a function returning a value that implements `Parser`.
//! > Let's look at it more closely as its used above (resolving all generic parameters):
//! > ```rust
//! > # use winnow::prelude::*;
//! > # use winnow::error::ContextError;
//! > pub fn one_of<'i>(
//! > list: &'static [char]
//! > ) -> impl Parser<&'i str, char, ContextError> {
//! > // ...
//! > # winnow::token::one_of(list)
//! > }
//! > ```
//! > If you have not programmed in a language where functions are values, the type signature of the
//! > [`one_of`] function might be a surprise.
//! > The function [`one_of`] *returns a function*. The function it returns is a
//! > [`Parser`], taking a `&str` and returning an [`Result`]. This is a common pattern in winnow for
//! > configurable or stateful parsers.
//!
//! Some of character classes are common enough that a named parser is provided, like with:
//! - [`line_ending`][crate::ascii::line_ending]: Recognizes an end of line (both `\n` and `\r\n`)
//! - [`newline`][crate::ascii::newline]: Matches a newline character `\n`
//! - [`tab`][crate::ascii::tab]: Matches a tab character `\t`
//!
//! You can then capture sequences of these characters with parsers like [`take_while`].
//! ```rust
//! # use winnow::Parser;
//! # use winnow::Result;
//! use winnow::token::take_while;
//!
//! fn parse_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! take_while(1.., ('0'..='9', 'a'..='f', 'A'..='F')).parse_next(input)
//! }
//!
//! fn main() {
//! let mut input = "1a2b Hello";
//!
//! let output = parse_digits.parse_next(&mut input).unwrap();
//! assert_eq!(input, " Hello");
//! assert_eq!(output, "1a2b");
//!
//! assert!(parse_digits.parse_next(&mut "Z").is_err());
//! }
//! ```
//!
//! We could simplify this further by using one of the built-in character classes, [`hex_digit1`]:
//! ```rust
//! # use winnow::Parser;
//! # use winnow::Result;
//! use winnow::ascii::hex_digit1;
//!
//! fn parse_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! hex_digit1.parse_next(input)
//! }
//!
//! fn main() {
//! let mut input = "1a2b Hello";
//!
//! let output = parse_digits.parse_next(&mut input).unwrap();
//! assert_eq!(input, " Hello");
//! assert_eq!(output, "1a2b");
//!
//! assert!(parse_digits.parse_next(&mut "Z").is_err());
//! }
//! ```
//!
//! See [`ascii`] for more text-based parsers.
#![allow(unused_imports)]
use crate::ascii;
use crate::ascii::hex_digit1;
use crate::stream::ContainsToken;
use crate::stream::Stream;
use crate::token;
use crate::token::any;
use crate::token::literal;
use crate::token::one_of;
use crate::token::take_while;
use crate::Parser;
use crate::Result;
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;

394
vendor/winnow/src/_tutorial/chapter_3.rs vendored Normal file
View File

@@ -0,0 +1,394 @@
//! # Chapter 3: Sequencing and Alternatives
//!
//! In the last chapter, we saw how to create parsers using prebuilt parsers.
//!
//! In this chapter, we explore two other widely used features:
//! sequencing and alternatives.
//!
//! ## Sequencing
//!
//! Now that we can create more interesting parsers, we can sequence them together, like:
//!
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! #
//! fn parse_prefix<'s>(input: &mut &'s str) -> Result<&'s str> {
//! "0x".parse_next(input)
//! }
//!
//! fn parse_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! take_while(1.., (
//! ('0'..='9'),
//! ('A'..='F'),
//! ('a'..='f'),
//! )).parse_next(input)
//! }
//!
//! fn main() {
//! let mut input = "0x1a2b Hello";
//!
//! let prefix = parse_prefix.parse_next(&mut input).unwrap();
//! let digits = parse_digits.parse_next(&mut input).unwrap();
//!
//! assert_eq!(prefix, "0x");
//! assert_eq!(digits, "1a2b");
//! assert_eq!(input, " Hello");
//! }
//! ```
//!
//! To sequence these together, you can just put them in a tuple:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! #
//! # fn parse_prefix<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # "0x".parse_next(input)
//! # }
//! #
//! # fn parse_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//! #
//! //...
//!
//! fn main() {
//! let mut input = "0x1a2b Hello";
//!
//! let (prefix, digits) = (
//! parse_prefix,
//! parse_digits
//! ).parse_next(&mut input).unwrap();
//!
//! assert_eq!(prefix, "0x");
//! assert_eq!(digits, "1a2b");
//! assert_eq!(input, " Hello");
//! }
//! ```
//!
//! Frequently, you won't care about the literal and you can instead use one of the provided combinators,
//! like [`preceded`]:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! use winnow::combinator::preceded;
//!
//! # fn parse_prefix<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # "0x".parse_next(input)
//! # }
//! #
//! # fn parse_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//! #
//! //...
//!
//! fn main() {
//! let mut input = "0x1a2b Hello";
//!
//! let digits = preceded(
//! parse_prefix,
//! parse_digits
//! ).parse_next(&mut input).unwrap();
//!
//! assert_eq!(digits, "1a2b");
//! assert_eq!(input, " Hello");
//! }
//! ```
//!
//! See [`combinator`] for more sequencing parsers.
//!
//! ## Alternatives
//!
//! Sometimes, we might want to choose between two parsers; and we're happy with
//! either being used.
//!
//! To retry a parse result, we can save off a [`Stream::checkpoint`] and later restore the parser
//! back to that position with [`Stream::reset`]:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! use winnow::stream::Stream;
//!
//! fn parse_digits<'s>(input: &mut &'s str) -> Result<(&'s str, &'s str)> {
//! let start = input.checkpoint();
//! if let Ok(output) = ("0b", parse_bin_digits).parse_next(input) {
//! return Ok(output);
//! }
//!
//! input.reset(&start);
//! if let Ok(output) = ("0o", parse_oct_digits).parse_next(input) {
//! return Ok(output);
//! }
//!
//! input.reset(&start);
//! if let Ok(output) = ("0d", parse_dec_digits).parse_next(input) {
//! return Ok(output);
//! }
//!
//! input.reset(&start);
//! ("0x", parse_hex_digits).parse_next(input)
//! }
//!
//! // ...
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//!
//! fn main() {
//! let mut input = "0x1a2b Hello";
//!
//! let (prefix, digits) = parse_digits.parse_next(&mut input).unwrap();
//!
//! assert_eq!(input, " Hello");
//! assert_eq!(prefix, "0x");
//! assert_eq!(digits, "1a2b");
//!
//! assert!(parse_digits(&mut "ghiWorld").is_err());
//! }
//! ```
//!
//! <div class="warning">
//!
//! **Warning:** the above example is for illustrative purposes and relying on `Result::Ok` or
//! `Result::Err` can lead to incorrect behavior. This will be clarified in later when covering
//! [error handling][`chapter_7`#error-cuts]
//!
//! </div>
//!
//! [`opt`] is a parser that encapsulates this pattern of "retry on failure":
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! use winnow::combinator::opt;
//!
//! fn parse_digits<'s>(input: &mut &'s str) -> Result<(&'s str, &'s str)> {
//! if let Some(output) = opt(("0b", parse_bin_digits)).parse_next(input)? {
//! Ok(output)
//! } else if let Some(output) = opt(("0o", parse_oct_digits)).parse_next(input)? {
//! Ok(output)
//! } else if let Some(output) = opt(("0d", parse_dec_digits)).parse_next(input)? {
//! Ok(output)
//! } else {
//! ("0x", parse_hex_digits).parse_next(input)
//! }
//! }
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn main() {
//! # let mut input = "0x1a2b Hello";
//! #
//! # let (prefix, digits) = parse_digits.parse_next(&mut input).unwrap();
//! #
//! # assert_eq!(input, " Hello");
//! # assert_eq!(prefix, "0x");
//! # assert_eq!(digits, "1a2b");
//! #
//! # assert!(parse_digits(&mut "ghiWorld").is_err());
//! # }
//! ```
//!
//! [`alt`] encapsulates this if/else-if ladder pattern, with the last case being the "else":
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! use winnow::combinator::alt;
//!
//! fn parse_digits<'s>(input: &mut &'s str) -> Result<(&'s str, &'s str)> {
//! alt((
//! ("0b", parse_bin_digits),
//! ("0o", parse_oct_digits),
//! ("0d", parse_dec_digits),
//! ("0x", parse_hex_digits),
//! )).parse_next(input)
//! }
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn main() {
//! # let mut input = "0x1a2b Hello";
//! #
//! # let (prefix, digits) = parse_digits.parse_next(&mut input).unwrap();
//! #
//! # assert_eq!(input, " Hello");
//! # assert_eq!(prefix, "0x");
//! # assert_eq!(digits, "1a2b");
//! #
//! # assert!(parse_digits(&mut "ghiWorld").is_err());
//! # }
//! ```
//!
//! <div class="warning">
//!
//! **Note:** [`empty`] and [`fail`] are parsers that might be useful in the "else" case.
//!
//! </div>
//!
//! Sometimes a giant if/else-if ladder can be slow and you'd rather have a `match` statement for
//! branches of your parser that have unique prefixes. In this case, you can use the
//! [`dispatch`] macro:
//!
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! use winnow::combinator::dispatch;
//! use winnow::token::take;
//! use winnow::combinator::fail;
//!
//! fn parse_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! dispatch!(take(2usize);
//! "0b" => parse_bin_digits,
//! "0o" => parse_oct_digits,
//! "0d" => parse_dec_digits,
//! "0x" => parse_hex_digits,
//! _ => fail,
//! ).parse_next(input)
//! }
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn main() {
//! # let mut input = "0x1a2b Hello";
//! #
//! # let digits = parse_digits.parse_next(&mut input).unwrap();
//! #
//! # assert_eq!(input, " Hello");
//! # assert_eq!(digits, "1a2b");
//! #
//! # assert!(parse_digits(&mut "ghiWorld").is_err());
//! # }
//! ```
//!
//! <div class="warning">
//!
//! **Note:** [`peek`] may be useful when [`dispatch`]ing from hints from each case's parser.
//!
//! </div>
//!
//! See [`combinator`] for more alternative parsers.
#![allow(unused_imports)]
use super::chapter_7;
use crate::combinator;
use crate::combinator::alt;
use crate::combinator::dispatch;
use crate::combinator::empty;
use crate::combinator::fail;
use crate::combinator::opt;
use crate::combinator::peek;
use crate::combinator::preceded;
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;

109
vendor/winnow/src/_tutorial/chapter_4.rs vendored Normal file
View File

@@ -0,0 +1,109 @@
//! # Chapter 4: Parsers With Custom Return Types
//!
//! So far, we have seen mostly functions that take an `&str`, and return a
//! [`Result<&str>`]. Splitting strings into smaller strings and characters is certainly
//! useful, but it's not the only thing winnow is capable of!
//!
//! A useful operation when parsing is to convert between types; for example
//! parsing from `&str` to another primitive, like [`usize`].
//!
//! All we need to do for our parser to return a different type is to change
//! the type parameter of [`Result`] to the desired return type.
//! For example, to return a `usize`, return a `Result<usize>`.
//!
//! One winnow-native way of doing a type conversion is to use the
//! [`Parser::parse_to`] combinator
//! to convert from a successful parse to a particular type using [`FromStr`].
//!
//! The following code converts from a string containing a number to `usize`:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::ascii::digit1;
//! #
//! fn parse_digits(input: &mut &str) -> Result<usize> {
//! digit1
//! .parse_to()
//! .parse_next(input)
//! }
//!
//! fn main() {
//! let mut input = "1024 Hello";
//!
//! let output = parse_digits.parse_next(&mut input).unwrap();
//! assert_eq!(input, " Hello");
//! assert_eq!(output, 1024);
//!
//! assert!(parse_digits(&mut "Z").is_err());
//! }
//! ```
//!
//! `Parser::parse_to` is just a convenient form of [`Parser::try_map`] which we can use to handle
//! all radices of numbers:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! use winnow::combinator::dispatch;
//! use winnow::token::take;
//! use winnow::combinator::fail;
//!
//! fn parse_digits(input: &mut &str) -> Result<usize> {
//! dispatch!(take(2usize);
//! "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)),
//! "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)),
//! "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)),
//! "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)),
//! _ => fail,
//! ).parse_next(input)
//! }
//!
//! // ...
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//!
//! fn main() {
//! let mut input = "0x1a2b Hello";
//!
//! let digits = parse_digits.parse_next(&mut input).unwrap();
//!
//! assert_eq!(input, " Hello");
//! assert_eq!(digits, 0x1a2b);
//!
//! assert!(parse_digits(&mut "ghiWorld").is_err());
//! }
//! ```
//!
//! See also [`Parser`] for more output-modifying parsers.
#![allow(unused_imports)]
use crate::Parser;
use crate::Result;
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;

300
vendor/winnow/src/_tutorial/chapter_5.rs vendored Normal file
View File

@@ -0,0 +1,300 @@
//! # Chapter 5: Repetition
//!
//! In [`chapter_3`], we covered how to sequence different parsers into a tuple but sometimes you need to run a
//! single parser multiple times, collecting the result into a container, like `Vec`.
//!
//! Let's collect the result of `parse_digits`:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! # use winnow::combinator::dispatch;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! use winnow::combinator::opt;
//! use winnow::combinator::repeat;
//! use winnow::combinator::terminated;
//!
//! fn parse_list(input: &mut &str) -> Result<Vec<usize>> {
//! let mut list = Vec::new();
//! while let Some(output) = opt(terminated(parse_digits, opt(','))).parse_next(input)? {
//! list.push(output);
//! }
//! Ok(list)
//! }
//!
//! // ...
//! # fn parse_digits(input: &mut &str) -> Result<usize> {
//! # dispatch!(take(2usize);
//! # "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)),
//! # "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)),
//! # "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)),
//! # "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)),
//! # _ => fail,
//! # ).parse_next(input)
//! # }
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//!
//! fn main() {
//! let mut input = "0x1a2b,0x3c4d,0x5e6f Hello";
//!
//! let digits = parse_list.parse_next(&mut input).unwrap();
//!
//! assert_eq!(input, " Hello");
//! assert_eq!(digits, vec![0x1a2b, 0x3c4d, 0x5e6f]);
//!
//! assert!(parse_digits(&mut "ghiWorld").is_err());
//! }
//! ```
//!
//! We can implement this declaratively with [`repeat`]:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! # use winnow::combinator::dispatch;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! use winnow::combinator::opt;
//! use winnow::combinator::repeat;
//! use winnow::combinator::terminated;
//!
//! fn parse_list(input: &mut &str) -> Result<Vec<usize>> {
//! repeat(0..,
//! terminated(parse_digits, opt(','))
//! ).parse_next(input)
//! }
//! #
//! # fn parse_digits(input: &mut &str) -> Result<usize> {
//! # dispatch!(take(2usize);
//! # "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)),
//! # "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)),
//! # "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)),
//! # "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)),
//! # _ => fail,
//! # ).parse_next(input)
//! # }
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn main() {
//! # let mut input = "0x1a2b,0x3c4d,0x5e6f Hello";
//! #
//! # let digits = parse_list.parse_next(&mut input).unwrap();
//! #
//! # assert_eq!(input, " Hello");
//! # assert_eq!(digits, vec![0x1a2b, 0x3c4d, 0x5e6f]);
//! #
//! # assert!(parse_digits(&mut "ghiWorld").is_err());
//! # }
//! ```
//!
//! You'll notice that the above allows trailing `,`. However, if that's not desired, it
//! can easily be fixed by using [`separated`] instead of [`repeat`]:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! # use winnow::combinator::dispatch;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! use winnow::combinator::separated;
//!
//! fn parse_list(input: &mut &str) -> Result<Vec<usize>> {
//! separated(0.., parse_digits, ",").parse_next(input)
//! }
//!
//! // ...
//! # fn parse_digits(input: &mut &str) -> Result<usize> {
//! # dispatch!(take(2usize);
//! # "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)),
//! # "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)),
//! # "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)),
//! # "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)),
//! # _ => fail,
//! # ).parse_next(input)
//! # }
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//!
//! fn main() {
//! let mut input = "0x1a2b,0x3c4d,0x5e6f Hello";
//!
//! let digits = parse_list.parse_next(&mut input).unwrap();
//!
//! assert_eq!(input, " Hello");
//! assert_eq!(digits, vec![0x1a2b, 0x3c4d, 0x5e6f]);
//!
//! assert!(parse_digits(&mut "ghiWorld").is_err());
//! }
//! ```
//!
//! If you look closely at [`separated`] and [`repeat`], they aren't limited to collecting
//! the result into a `Vec`, but rather anything that implements the [`Accumulate`] trait.
//! [`Accumulate`] is for instance also implemented for [`HashSet`], [`String`] and `()`.
//!
//! This lets us build more complex parsers than we did in
//! [`chapter_2`] by accumulating the results into a `()` and [`take`][Parser::take]-ing
//! the consumed input.
//!
//! `take` works by
//! 1. Creating a [`checkpoint`][Stream::checkpoint]
//! 2. Running the inner parser, in our case the `parse_list` parser, which will advance the input
//! 3. Returning the slice from the first checkpoint to the current position.
//!
//! Since the result of `parse_list` gets thrown away, we
//! accumulates into a `()` to not waste work creating an unused `Vec`.
//!
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! # use winnow::combinator::dispatch;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! # use winnow::combinator::separated;
//! #
//! fn take_list<'s>(input: &mut &'s str) -> Result<&'s str> {
//! parse_list.take().parse_next(input)
//! }
//!
//! fn parse_list(input: &mut &str) -> Result<()> {
//! separated(0.., parse_digits, ",").parse_next(input)
//! }
//!
//! # fn parse_digits(input: &mut &str) -> Result<usize> {
//! # dispatch!(take(2usize);
//! # "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)),
//! # "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)),
//! # "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)),
//! # "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)),
//! # _ => fail,
//! # ).parse_next(input)
//! # }
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//!
//! fn main() {
//! let mut input = "0x1a2b,0x3c4d,0x5e6f Hello";
//!
//! let digits = take_list.parse_next(&mut input).unwrap();
//!
//! assert_eq!(input, " Hello");
//! assert_eq!(digits, "0x1a2b,0x3c4d,0x5e6f");
//!
//! assert!(parse_digits(&mut "ghiWorld").is_err());
//! }
//! ```
//! See [`combinator`] for more repetition parsers.
#![allow(unused_imports)]
use super::chapter_2;
use super::chapter_3;
use crate::combinator;
use crate::combinator::repeat;
use crate::combinator::separated;
use crate::stream::Accumulate;
use crate::stream::Stream;
use crate::Parser;
use std::collections::HashSet;
pub use super::chapter_4 as previous;
pub use super::chapter_6 as next;
pub use crate::_tutorial as table_of_contents;

120
vendor/winnow/src/_tutorial/chapter_6.rs vendored Normal file
View File

@@ -0,0 +1,120 @@
//! # Chapter 6: Integrating the Parser
//!
//! So far, we've highlighted how to incrementally parse, but how do we bring this all together
//! into our application?
//!
//! Parsers we've been working with look like:
//! ```rust
//! # use winnow::error::ContextError;
//! # use winnow::Parser;
//! use winnow::Result;
//!
//! pub fn parser<'s>(input: &mut &'s str) -> Result<&'s str> {
//! // ...
//! # Ok("")
//! }
//! ```
//! 1. We have to decide what to do about the "remainder" of the `input`.
//! 2. The [`Result`] may not be compatible with the rest of the Rust ecosystem.
//! Normally, Rust applications want errors that are `std::error::Error + Send + Sync + 'static`
//! meaning:
//! - They implement the [`std::error::Error`] trait
//! - They can be sent across threads
//! - They are safe to be referenced across threads
//! - They do not borrow
//!
//! winnow provides [`Parser::parse`] to help with this:
//! - Ensures we hit [`eof`]
//! - Wraps the error in [`ParseError`]
//! - For simple cases, [`ParseError`] provides a [`std::fmt::Display`] impl to render the error.
//! - For more involved cases, [`ParseError`] provides the original [`input`][ParseError::input] and the
//! [`offset`][ParseError::offset] of where it failed so you can capture this information in
//! your error, [rendering it as you wish][chapter_7#error-adaptation-and-rendering].
//! - Converts from [`ModalResult`] to [`Result`] (if used, more on this in [`chapter_7`])
//!
//! However, [`ParseError`] will still need some level of adaptation to integrate with your
//! application's error type (like with `?`).
//!
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! # use winnow::combinator::dispatch;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! use winnow::Parser;
//!
//! #[derive(Debug, PartialEq, Eq)]
//! pub struct Hex(usize);
//!
//! impl std::str::FromStr for Hex {
//! type Err = anyhow::Error;
//!
//! fn from_str(input: &str) -> Result<Self, Self::Err> {
//! parse_digits
//! .map(Hex)
//! .parse(input)
//! .map_err(|e| anyhow::format_err!("{e}"))
//! }
//! }
//!
//! // ...
//! # fn parse_digits<'s>(input: &mut &'s str) -> Result<usize> {
//! # dispatch!(take(2usize);
//! # "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)),
//! # "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)),
//! # "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)),
//! # "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)),
//! # _ => fail,
//! # ).parse_next(input)
//! # }
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//!
//! fn main() {
//! let input = "0x1a2b";
//! assert_eq!(input.parse::<Hex>().unwrap(), Hex(0x1a2b));
//!
//! let input = "0x1a2b Hello";
//! assert!(input.parse::<Hex>().is_err());
//! let input = "ghiHello";
//! assert!(input.parse::<Hex>().is_err());
//! }
//! ```
#![allow(unused_imports)]
use super::chapter_1;
use super::chapter_7;
use crate::combinator::eof;
use crate::error::ErrMode;
use crate::error::ParseError;
use crate::ModalResult;
use crate::Parser;
pub use super::chapter_5 as previous;
pub use super::chapter_7 as next;
pub use crate::_tutorial as table_of_contents;

736
vendor/winnow/src/_tutorial/chapter_7.rs vendored Normal file
View File

@@ -0,0 +1,736 @@
//! # Chapter 7: Error Reporting
//!
//! ## Context
//!
//! With [`Parser::parse`] we get errors that point to the failure but don't explain the reason for
//! the failure:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! # use winnow::combinator::alt;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! # use winnow::Parser;
//! #
//! # #[derive(Debug, PartialEq, Eq)]
//! # pub struct Hex(usize);
//! #
//! # impl std::str::FromStr for Hex {
//! # type Err = String;
//! #
//! # fn from_str(input: &str) -> Result<Self, Self::Err> {
//! # parse_digits
//! # .try_map(|(t, v)| match t {
//! # "0b" => usize::from_str_radix(v, 2),
//! # "0o" => usize::from_str_radix(v, 8),
//! # "0d" => usize::from_str_radix(v, 10),
//! # "0x" => usize::from_str_radix(v, 16),
//! # _ => unreachable!("`parse_digits` doesn't return `{t}`"),
//! # })
//! # .map(Hex)
//! # .parse(input)
//! # .map_err(|e| e.to_string())
//! # }
//! # }
//! #
//! // ...
//!
//! # fn parse_digits<'s>(input: &mut &'s str) -> Result<(&'s str, &'s str)> {
//! # alt((
//! # ("0b", parse_bin_digits),
//! # ("0o", parse_oct_digits),
//! # ("0d", parse_dec_digits),
//! # ("0x", parse_hex_digits),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//! fn main() {
//! let input = "0xZZ";
//! let error = "\
//! 0xZZ
//! ^
//! ";
//! assert_eq!(input.parse::<Hex>().unwrap_err(), error);
//! }
//! ```
//!
//! Back in [`chapter_1`], we glossed over the `Err` variant of [`Result`]. `Result<O>` is
//! actually short for `Result<O, E=ContextError>` where [`ContextError`] is a relatively cheap
//! way of building up reasonable errors for humans.
//!
//! You can use [`Parser::context`] to annotate the error with custom types
//! while unwinding to further clarify the error:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! # use winnow::combinator::alt;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! # use winnow::Parser;
//! use winnow::error::StrContext;
//! use winnow::error::StrContextValue;
//!
//! #
//! # #[derive(Debug, PartialEq, Eq)]
//! # pub struct Hex(usize);
//! #
//! # impl std::str::FromStr for Hex {
//! # type Err = String;
//! #
//! # fn from_str(input: &str) -> Result<Self, Self::Err> {
//! # parse_digits
//! # .try_map(|(t, v)| match t {
//! # "0b" => usize::from_str_radix(v, 2),
//! # "0o" => usize::from_str_radix(v, 8),
//! # "0d" => usize::from_str_radix(v, 10),
//! # "0x" => usize::from_str_radix(v, 16),
//! # _ => unreachable!("`parse_digits` doesn't return `{t}`"),
//! # })
//! # .map(Hex)
//! # .parse(input)
//! # .map_err(|e| e.to_string())
//! # }
//! # }
//! #
//! fn parse_digits<'s>(input: &mut &'s str) -> Result<(&'s str, &'s str)> {
//! alt((
//! ("0b", parse_bin_digits)
//! .context(StrContext::Label("digit"))
//! .context(StrContext::Expected(StrContextValue::Description("binary"))),
//! ("0o", parse_oct_digits)
//! .context(StrContext::Label("digit"))
//! .context(StrContext::Expected(StrContextValue::Description("octal"))),
//! ("0d", parse_dec_digits)
//! .context(StrContext::Label("digit"))
//! .context(StrContext::Expected(StrContextValue::Description("decimal"))),
//! ("0x", parse_hex_digits)
//! .context(StrContext::Label("digit"))
//! .context(StrContext::Expected(StrContextValue::Description("hexadecimal"))),
//! )).parse_next(input)
//! }
//!
//! // ...
//!
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//! fn main() {
//! let input = "0xZZ";
//! let error = "\
//! 0xZZ
//! ^
//! invalid digit
//! expected hexadecimal";
//! assert_eq!(input.parse::<Hex>().unwrap_err(), error);
//! }
//! ```
//!
//! If you remember back to [`chapter_3`], [`alt`] will only report the last error.
//! So if the parsers fail for any reason, like a bad radix, it will be reported as an invalid
//! hexadecimal value:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! # use winnow::combinator::alt;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! # use winnow::Parser;
//! # use winnow::error::StrContext;
//! # use winnow::error::StrContextValue;
//! #
//! #
//! # #[derive(Debug, PartialEq, Eq)]
//! # pub struct Hex(usize);
//! #
//! # impl std::str::FromStr for Hex {
//! # type Err = String;
//! #
//! # fn from_str(input: &str) -> Result<Self, Self::Err> {
//! # parse_digits
//! # .try_map(|(t, v)| match t {
//! # "0b" => usize::from_str_radix(v, 2),
//! # "0o" => usize::from_str_radix(v, 8),
//! # "0d" => usize::from_str_radix(v, 10),
//! # "0x" => usize::from_str_radix(v, 16),
//! # _ => unreachable!("`parse_digits` doesn't return `{t}`"),
//! # })
//! # .map(Hex)
//! # .parse(input)
//! # .map_err(|e| e.to_string())
//! # }
//! # }
//! #
//! # fn parse_digits<'s>(input: &mut &'s str) -> Result<(&'s str, &'s str)> {
//! # alt((
//! # ("0b", parse_bin_digits)
//! # .context(StrContext::Label("digit"))
//! # .context(StrContext::Expected(StrContextValue::Description("binary"))),
//! # ("0o", parse_oct_digits)
//! # .context(StrContext::Label("digit"))
//! # .context(StrContext::Expected(StrContextValue::Description("octal"))),
//! # ("0d", parse_dec_digits)
//! # .context(StrContext::Label("digit"))
//! # .context(StrContext::Expected(StrContextValue::Description("decimal"))),
//! # ("0x", parse_hex_digits)
//! # .context(StrContext::Label("digit"))
//! # .context(StrContext::Expected(StrContextValue::Description("hexadecimal"))),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//! fn main() {
//! let input = "100";
//! let error = "\
//! 100
//! ^
//! invalid digit
//! expected hexadecimal";
//! assert_eq!(input.parse::<Hex>().unwrap_err(), error);
//! }
//! ```
//! We can improve this with [`fail`]:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! # use winnow::combinator::alt;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! # use winnow::Parser;
//! use winnow::error::StrContext;
//! use winnow::error::StrContextValue;
//!
//! #
//! # #[derive(Debug, PartialEq, Eq)]
//! # pub struct Hex(usize);
//! #
//! # impl std::str::FromStr for Hex {
//! # type Err = String;
//! #
//! # fn from_str(input: &str) -> Result<Self, Self::Err> {
//! # parse_digits
//! # .try_map(|(t, v)| match t {
//! # "0b" => usize::from_str_radix(v, 2),
//! # "0o" => usize::from_str_radix(v, 8),
//! # "0d" => usize::from_str_radix(v, 10),
//! # "0x" => usize::from_str_radix(v, 16),
//! # _ => unreachable!("`parse_digits` doesn't return `{t}`"),
//! # })
//! # .map(Hex)
//! # .parse(input)
//! # .map_err(|e| e.to_string())
//! # }
//! # }
//! #
//! fn parse_digits<'s>(input: &mut &'s str) -> Result<(&'s str, &'s str)> {
//! alt((
//! ("0b", parse_bin_digits)
//! .context(StrContext::Label("digit"))
//! .context(StrContext::Expected(StrContextValue::Description("binary"))),
//! ("0o", parse_oct_digits)
//! .context(StrContext::Label("digit"))
//! .context(StrContext::Expected(StrContextValue::Description("octal"))),
//! ("0d", parse_dec_digits)
//! .context(StrContext::Label("digit"))
//! .context(StrContext::Expected(StrContextValue::Description("decimal"))),
//! ("0x", parse_hex_digits)
//! .context(StrContext::Label("digit"))
//! .context(StrContext::Expected(StrContextValue::Description("hexadecimal"))),
//! fail
//! .context(StrContext::Label("radix prefix"))
//! .context(StrContext::Expected(StrContextValue::StringLiteral("0b")))
//! .context(StrContext::Expected(StrContextValue::StringLiteral("0o")))
//! .context(StrContext::Expected(StrContextValue::StringLiteral("0d")))
//! .context(StrContext::Expected(StrContextValue::StringLiteral("0x"))),
//! )).parse_next(input)
//! }
//!
//! // ...
//!
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//! fn main() {
//! let input = "100";
//! let error = "\
//! 100
//! ^
//! invalid radix prefix
//! expected `0b`, `0o`, `0d`, `0x`";
//! assert_eq!(input.parse::<Hex>().unwrap_err(), error);
//! }
//! ```
//!
//! ## Error Cuts
//!
//! We still have the issue that we are falling-through when the radix is valid but the digits
//! don't match it:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! # use winnow::combinator::alt;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! # use winnow::Parser;
//! # use winnow::error::StrContext;
//! # use winnow::error::StrContextValue;
//! #
//! #
//! # #[derive(Debug, PartialEq, Eq)]
//! # pub struct Hex(usize);
//! #
//! # impl std::str::FromStr for Hex {
//! # type Err = String;
//! #
//! # fn from_str(input: &str) -> Result<Self, Self::Err> {
//! # parse_digits
//! # .try_map(|(t, v)| match t {
//! # "0b" => usize::from_str_radix(v, 2),
//! # "0o" => usize::from_str_radix(v, 8),
//! # "0d" => usize::from_str_radix(v, 10),
//! # "0x" => usize::from_str_radix(v, 16),
//! # _ => unreachable!("`parse_digits` doesn't return `{t}`"),
//! # })
//! # .map(Hex)
//! # .parse(input)
//! # .map_err(|e| e.to_string())
//! # }
//! # }
//! #
//! # fn parse_digits<'s>(input: &mut &'s str) -> Result<(&'s str, &'s str)> {
//! # alt((
//! # ("0b", parse_bin_digits)
//! # .context(StrContext::Label("digit"))
//! # .context(StrContext::Expected(StrContextValue::Description("binary"))),
//! # ("0o", parse_oct_digits)
//! # .context(StrContext::Label("digit"))
//! # .context(StrContext::Expected(StrContextValue::Description("octal"))),
//! # ("0d", parse_dec_digits)
//! # .context(StrContext::Label("digit"))
//! # .context(StrContext::Expected(StrContextValue::Description("decimal"))),
//! # ("0x", parse_hex_digits)
//! # .context(StrContext::Label("digit"))
//! # .context(StrContext::Expected(StrContextValue::Description("hexadecimal"))),
//! # fail
//! # .context(StrContext::Label("radix prefix"))
//! # .context(StrContext::Expected(StrContextValue::StringLiteral("0b")))
//! # .context(StrContext::Expected(StrContextValue::StringLiteral("0o")))
//! # .context(StrContext::Expected(StrContextValue::StringLiteral("0d")))
//! # .context(StrContext::Expected(StrContextValue::StringLiteral("0x"))),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//! fn main() {
//! let input = "0b5";
//! let error = "\
//! 0b5
//! ^
//! invalid radix prefix
//! expected `0b`, `0o`, `0d`, `0x`";
//! assert_eq!(input.parse::<Hex>().unwrap_err(), error);
//! }
//! ```
//!
//! Winnow provides an error wrapper, [`ErrMode<ContextError>`], so different failure modes can affect parsing.
//! [`ErrMode`] is an enum with [`Backtrack`] and [`Cut`] variants (ignore [`Incomplete`] as its only
//! relevant for [streaming][_topic::stream]). By default, errors are [`Backtrack`], meaning that
//! other parsing branches will be attempted on failure, like the next case of an [`alt`]. [`Cut`]
//! shortcircuits all other branches, immediately reporting the error.
//!
//! To make [`ErrMode`] more convenient, Winnow provides [`ModalResult`]:
//! ```rust
//! # use winnow::error::ContextError;
//! # use winnow::error::ErrMode;
//! pub type ModalResult<O, E = ContextError> = Result<O, ErrMode<E>>;
//! ```
//!
//! So we can get the correct `context` by changing to [`ModalResult`] and adding [`cut_err`]:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::token::take_while;
//! # use winnow::combinator::alt;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! # use winnow::Parser;
//! # use winnow::error::StrContext;
//! # use winnow::error::StrContextValue;
//! use winnow::combinator::cut_err;
//!
//! #
//! # #[derive(Debug, PartialEq, Eq)]
//! # pub struct Hex(usize);
//! #
//! # impl std::str::FromStr for Hex {
//! # type Err = String;
//! #
//! # fn from_str(input: &str) -> Result<Self, Self::Err> {
//! # parse_digits
//! # .try_map(|(t, v)| match t {
//! # "0b" => usize::from_str_radix(v, 2),
//! # "0o" => usize::from_str_radix(v, 8),
//! # "0d" => usize::from_str_radix(v, 10),
//! # "0x" => usize::from_str_radix(v, 16),
//! # _ => unreachable!("`parse_digits` doesn't return `{t}`"),
//! # })
//! # .map(Hex)
//! # .parse(input)
//! # .map_err(|e| e.to_string())
//! # }
//! # }
//! #
//! fn parse_digits<'s>(input: &mut &'s str) -> ModalResult<(&'s str, &'s str)> {
//! alt((
//! ("0b", cut_err(parse_bin_digits))
//! .context(StrContext::Label("digit"))
//! .context(StrContext::Expected(StrContextValue::Description("binary"))),
//! ("0o", cut_err(parse_oct_digits))
//! .context(StrContext::Label("digit"))
//! .context(StrContext::Expected(StrContextValue::Description("octal"))),
//! ("0d", cut_err(parse_dec_digits))
//! .context(StrContext::Label("digit"))
//! .context(StrContext::Expected(StrContextValue::Description("decimal"))),
//! ("0x", cut_err(parse_hex_digits))
//! .context(StrContext::Label("digit"))
//! .context(StrContext::Expected(StrContextValue::Description("hexadecimal"))),
//! fail
//! .context(StrContext::Label("radix prefix"))
//! .context(StrContext::Expected(StrContextValue::StringLiteral("0b")))
//! .context(StrContext::Expected(StrContextValue::StringLiteral("0o")))
//! .context(StrContext::Expected(StrContextValue::StringLiteral("0d")))
//! .context(StrContext::Expected(StrContextValue::StringLiteral("0x"))),
//! )).parse_next(input)
//! }
//!
//! // ...
//!
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//! fn main() {
//! let input = "0b5";
//! let error = "\
//! 0b5
//! ^
//! invalid digit
//! expected binary";
//! assert_eq!(input.parse::<Hex>().unwrap_err(), error);
//! }
//! ```
//!
//! ## Error Adaptation and Rendering
//!
//! While Winnow can provide basic rendering of errors, your application can have various demands
//! beyond the basics provided like
//! - Correctly reporting columns with unicode
//! - Conforming to a specific layout
//!
//! For example, to get rustc-like errors with [`annotate-snippets`](https://crates.io/crates/annotate-snippets):
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::token::take_while;
//! # use winnow::combinator::alt;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! # use winnow::Parser;
//! # use winnow::error::ParseError;
//! # use winnow::error::ContextError;
//! # use winnow::error::StrContext;
//! # use winnow::error::StrContextValue;
//! # use winnow::combinator::cut_err;
//! #
//! #
//! #[derive(Debug, PartialEq, Eq)]
//! pub struct Hex(usize);
//!
//! impl std::str::FromStr for Hex {
//! type Err = HexError;
//!
//! fn from_str(input: &str) -> Result<Self, Self::Err> {
//! // ...
//! # parse_digits
//! # .try_map(|(t, v)| match t {
//! # "0b" => usize::from_str_radix(v, 2),
//! # "0o" => usize::from_str_radix(v, 8),
//! # "0d" => usize::from_str_radix(v, 10),
//! # "0x" => usize::from_str_radix(v, 16),
//! # _ => unreachable!("`parse_digits` doesn't return `{t}`"),
//! # })
//! # .map(Hex)
//! .parse(input)
//! .map_err(|e| HexError::from_parse(e))
//! }
//! }
//!
//! #[derive(Debug)]
//! pub struct HexError {
//! message: String,
//! // Byte spans are tracked, rather than line and column.
//! // This makes it easier to operate on programmatically
//! // and doesn't limit us to one definition for column count
//! // which can depend on the output medium and application.
//! span: std::ops::Range<usize>,
//! input: String,
//! }
//!
//! impl HexError {
//! // Avoiding `From` so `winnow` types don't become part of our public API
//! fn from_parse(error: ParseError<&str, ContextError>) -> Self {
//! // The default renderer for `ContextError` is still used but that can be
//! // customized as well to better fit your needs.
//! let message = error.inner().to_string();
//! let input = (*error.input()).to_owned();
//! // Assume the error span is only for the first `char`.
//! let span = error.char_span();
//! Self {
//! message,
//! span,
//! input,
//! }
//! }
//! }
//!
//! impl std::fmt::Display for HexError {
//! fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
//! let message = annotate_snippets::Level::Error.title(&self.message)
//! .snippet(annotate_snippets::Snippet::source(&self.input)
//! .fold(true)
//! .annotation(annotate_snippets::Level::Error.span(self.span.clone()))
//! );
//! let renderer = annotate_snippets::Renderer::plain();
//! let rendered = renderer.render(message);
//! rendered.fmt(f)
//! }
//! }
//!
//! impl std::error::Error for HexError {}
//!
//! # fn parse_digits<'s>(input: &mut &'s str) -> ModalResult<(&'s str, &'s str)> {
//! # alt((
//! # ("0b", cut_err(parse_bin_digits))
//! # .context(StrContext::Label("digit"))
//! # .context(StrContext::Expected(StrContextValue::Description("binary"))),
//! # ("0o", cut_err(parse_oct_digits))
//! # .context(StrContext::Label("digit"))
//! # .context(StrContext::Expected(StrContextValue::Description("octal"))),
//! # ("0d", cut_err(parse_dec_digits))
//! # .context(StrContext::Label("digit"))
//! # .context(StrContext::Expected(StrContextValue::Description("decimal"))),
//! # ("0x", cut_err(parse_hex_digits))
//! # .context(StrContext::Label("digit"))
//! # .context(StrContext::Expected(StrContextValue::Description("hexadecimal"))),
//! # fail
//! # .context(StrContext::Label("radix prefix"))
//! # .context(StrContext::Expected(StrContextValue::StringLiteral("0b")))
//! # .context(StrContext::Expected(StrContextValue::StringLiteral("0o")))
//! # .context(StrContext::Expected(StrContextValue::StringLiteral("0d")))
//! # .context(StrContext::Expected(StrContextValue::StringLiteral("0x"))),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! # take_while(1.., (
//! # ('0'..='1'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! # take_while(1.., (
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! # take_while(1.., (
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//! fn main() {
//! let input = "0b5";
//! let error = "\
//! error: invalid digit
//! expected binary
//! |
//! 1 | 0b5
//! | ^
//! |";
//! assert_eq!(input.parse::<Hex>().unwrap_err().to_string(), error);
//! }
//! ```
//!
//! To add spans to your parsed data for inclusion in semantic errors, see [`Parser::with_span`].
//!
//! For richer syntactic with spans,
//! consider separating lexing and parsing and annotating your tokens with [`Parser::with_span`].
#![allow(unused_imports)]
use super::chapter_1;
use super::chapter_3;
use crate::combinator::alt;
use crate::combinator::cut_err;
use crate::combinator::fail;
use crate::error::ContextError;
use crate::error::ErrMode;
use crate::error::ErrMode::*;
use crate::ModalResult;
use crate::Parser;
use crate::Result;
use crate::_topic;
pub use super::chapter_6 as previous;
pub use super::chapter_8 as next;
pub use crate::_tutorial as table_of_contents;

View File

@@ -0,0 +1,37 @@
//! # Chapter 8: Debugging
//!
//! When things inevitably go wrong, you can introspect the parsing state by running your test case
//! with `--features winnow/debug`.
//!
//! For example, the trace output of an [escaped string parser][crate::_topic::language#escaped-strings]:
//! ![Trace output from string example](https://raw.githubusercontent.com/winnow-rs/winnow/main/assets/trace.svg "Example output")
//!
//! You can extend your own parsers to show up by wrapping their body with
//! [`trace`][crate::combinator::trace]. Going back to [`do_nothing_parser`][super::chapter_1].
//! ```rust
//! # use winnow::ModalResult;
//! # use winnow::Parser;
//! use winnow::combinator::trace;
//!
//! pub fn do_nothing_parser<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! trace(
//! "do_nothing_parser",
//! |i: &mut _| Ok("")
//! ).parse_next(input)
//! }
//! #
//! # fn main() {
//! # let mut input = "0x1a2b Hello";
//! #
//! # let output = do_nothing_parser.parse_next(&mut input).unwrap();
//! # // Same as:
//! # // let output = do_nothing_parser(&mut input).unwrap();
//! #
//! # assert_eq!(input, "0x1a2b Hello");
//! # assert_eq!(output, "");
//! # }
//! ```
pub use super::chapter_7 as previous;
pub use crate::_topic as next;
pub use crate::_tutorial as table_of_contents;

14
vendor/winnow/src/_tutorial/mod.rs vendored Normal file
View File

@@ -0,0 +1,14 @@
//! # Tutorial
//!
//! Table of Contents
#![allow(clippy::std_instead_of_core)]
pub mod chapter_0;
pub mod chapter_1;
pub mod chapter_2;
pub mod chapter_3;
pub mod chapter_4;
pub mod chapter_5;
pub mod chapter_6;
pub mod chapter_7;
pub mod chapter_8;

1864
vendor/winnow/src/ascii/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

4656
vendor/winnow/src/ascii/tests.rs vendored Normal file

File diff suppressed because it is too large Load Diff

398
vendor/winnow/src/binary/bits/mod.rs vendored Normal file
View File

@@ -0,0 +1,398 @@
//! Bit level parsers
//!
#[cfg(test)]
mod tests;
use crate::combinator::trace;
use crate::error::{ErrorConvert, Needed, ParserError};
use crate::lib::std::ops::{AddAssign, Div, Shl, Shr};
use crate::stream::{Stream, StreamIsPartial, ToUsize};
use crate::{Parser, Result};
/// 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.
///
/// # Example
/// ```rust
/// # use winnow::prelude::*;
/// # use winnow::Bytes;
/// # use winnow::binary::bits::{bits, take};
/// # use winnow::error::ContextError;
/// # use winnow::error::ErrMode;
/// type Stream<'i> = &'i Bytes;
///
/// fn stream(b: &[u8]) -> Stream<'_> {
/// Bytes::new(b)
/// }
///
/// fn parse(input: &mut Stream<'_>) -> ModalResult<(u8, u8)> {
/// bits::<_, _, ErrMode<ContextError>, _, _>((take(4usize), take(8usize))).parse_next(input)
/// }
///
/// let input = stream(&[0x12, 0x34, 0xff, 0xff]);
///
/// let output = parse.parse_peek(input).expect("We take 1.5 bytes and the input is longer than 2 bytes");
///
/// // The first byte is consumed, the second byte is partially consumed and dropped.
/// let remaining = output.0;
/// assert_eq!(remaining, stream(&[0xff, 0xff]));
///
/// let parsed = output.1;
/// assert_eq!(parsed.0, 0x01);
/// assert_eq!(parsed.1, 0x23);
/// ```
pub fn bits<Input, Output, BitError, ByteError, ParseNext>(
mut parser: ParseNext,
) -> impl Parser<Input, Output, ByteError>
where
BitError: ParserError<(Input, usize)> + ErrorConvert<ByteError>,
ByteError: ParserError<Input>,
(Input, usize): Stream,
Input: Stream + Clone,
ParseNext: Parser<(Input, usize), Output, BitError>,
{
trace("bits", move |input: &mut Input| {
let mut bit_input = (input.clone(), 0);
match parser.parse_next(&mut bit_input) {
Ok(result) => {
let (mut rest, offset) = bit_input;
// 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 / BYTE` isn't necessarily needed at all times.
let remaining_bytes_index = offset / BYTE + if offset % BYTE == 0 { 0 } else { 1 };
let _ = rest.next_slice(remaining_bytes_index);
*input = rest;
Ok(result)
}
Err(e) => match e.needed() {
Some(n) => Err(ParserError::incomplete(
input,
n.map(|u| u.get() / BYTE + 1),
)),
None => Err(ErrorConvert::convert(e)),
},
}
})
}
/// Convert a [`bits`] stream back into a byte stream
///
/// <div class="warning">
///
/// **Warning:** A partial byte remaining in the input will be ignored and the given parser will
/// start parsing at the next full byte.
///
/// </div>
///
/// # Examples
///
/// ```
/// # use winnow::prelude::*;
/// # use winnow::Bytes;
/// # use winnow::token::rest;
/// # use winnow::error::ContextError;
/// # use winnow::error::ErrMode;
/// use winnow::binary::bits::{bits, bytes, take};
///
/// type Stream<'i> = &'i Bytes;
///
/// fn stream(b: &[u8]) -> Stream<'_> {
/// Bytes::new(b)
/// }
///
/// fn parse<'i>(input: &mut Stream<'i>) -> ModalResult<(u8, u8, &'i [u8])> {
/// bits::<_, _, ErrMode<ContextError>, _, _>((
/// take(4usize),
/// take(8usize),
/// bytes::<_, _, ErrMode<ContextError>, _, _>(rest)
/// )).parse_next(input)
/// }
///
/// let input = stream(&[0x12, 0x34, 0xff, 0xff]);
///
/// assert_eq!(parse.parse_peek(input), Ok(( stream(&[]), (0x01, 0x23, &[0xff, 0xff][..]) )));
/// ```
pub fn bytes<Input, Output, ByteError, BitError, ParseNext>(
mut parser: ParseNext,
) -> impl Parser<(Input, usize), Output, BitError>
where
ByteError: ParserError<Input> + ErrorConvert<BitError>,
BitError: ParserError<(Input, usize)>,
Input: Stream<Token = u8> + Clone,
ParseNext: Parser<Input, Output, ByteError>,
{
trace("bytes", move |bit_input: &mut (Input, usize)| {
let (mut input, offset) = bit_input.clone();
let _ = if offset % BYTE != 0 {
input.next_slice(1 + offset / BYTE)
} else {
input.next_slice(offset / BYTE)
};
match parser.parse_next(&mut input) {
Ok(res) => {
*bit_input = (input, 0);
Ok(res)
}
Err(e) => match e.needed() {
Some(Needed::Unknown) => Err(ParserError::incomplete(bit_input, Needed::Unknown)),
Some(Needed::Size(sz)) => Err(match sz.get().checked_mul(BYTE) {
Some(v) => ParserError::incomplete(bit_input, Needed::new(v)),
None => ParserError::assert(
bit_input,
"overflow in turning needed bytes into needed bits",
),
}),
None => Err(ErrorConvert::convert(e)),
},
}
})
}
/// Parse taking `count` bits
///
/// # Effective Signature
///
/// Assuming you are parsing a `(&[u8], usize)` bit [Stream]:
/// ```rust
/// # use winnow::prelude::*;;
/// # use winnow::error::ContextError;
/// pub fn take<'i>(count: usize) -> impl Parser<(&'i [u8], usize), u8, ContextError>
/// # {
/// # winnow::binary::bits::take(count)
/// # }
/// ```
///
/// # Example
/// ```rust
/// # use winnow::prelude::*;
/// # use winnow::Bytes;
/// # use winnow::error::ContextError;
/// use winnow::binary::bits::take;
///
/// type Stream<'i> = &'i Bytes;
///
/// fn stream(b: &[u8]) -> Stream<'_> {
/// Bytes::new(b)
/// }
///
/// // Consumes 0 bits, returns 0
/// assert_eq!(take::<_, usize, _, ContextError>(0usize).parse_peek((stream(&[0b00010010]), 0)), Ok(((stream(&[0b00010010]), 0), 0)));
///
/// // Consumes 4 bits, returns their values and increase offset to 4
/// assert_eq!(take::<_, usize, _, ContextError>(4usize).parse_peek((stream(&[0b00010010]), 0)), Ok(((stream(&[0b00010010]), 4), 0b00000001)));
///
/// // Consumes 4 bits, offset is 4, returns their values and increase offset to 0 of next byte
/// assert_eq!(take::<_, usize, _, ContextError>(4usize).parse_peek((stream(&[0b00010010]), 4)), Ok(((stream(&[]), 0), 0b00000010)));
///
/// // Tries to consume 12 bits but only 8 are available
/// assert!(take::<_, usize, _, ContextError>(12usize).parse_peek((stream(&[0b00010010]), 0)).is_err());
/// ```
#[inline(always)]
pub fn take<Input, Output, Count, Error>(count: Count) -> impl Parser<(Input, usize), Output, Error>
where
Input: Stream<Token = u8> + StreamIsPartial + Clone,
Output: From<u8> + AddAssign + Shl<usize, Output = Output> + Shr<usize, Output = Output>,
Count: ToUsize,
Error: ParserError<(Input, usize)>,
{
let count = count.to_usize();
trace("take", move |input: &mut (Input, usize)| {
if <Input as StreamIsPartial>::is_partial_supported() {
take_::<_, _, _, true>(input, count)
} else {
take_::<_, _, _, false>(input, count)
}
})
}
fn take_<I, O, E: ParserError<(I, usize)>, const PARTIAL: bool>(
bit_input: &mut (I, usize),
count: usize,
) -> Result<O, E>
where
I: StreamIsPartial,
I: Stream<Token = u8> + Clone,
O: From<u8> + AddAssign + Shl<usize, Output = O> + Shr<usize, Output = O>,
{
if count == 0 {
Ok(0u8.into())
} else {
let (mut input, bit_offset) = bit_input.clone();
if input.eof_offset() * BYTE < count + bit_offset {
if PARTIAL && input.is_partial() {
Err(ParserError::incomplete(bit_input, Needed::new(count)))
} else {
Err(ParserError::from_input(&(input, bit_offset)))
}
} 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;
let mut end_offset: usize = 0;
for (_, byte) in input.iter_offsets().take(cnt + 1) {
if remaining == 0 {
break;
}
let val: O = if offset == 0 {
byte.into()
} else {
(byte << offset >> offset).into()
};
if remaining < BYTE - offset {
acc += val >> (BYTE - offset - remaining);
end_offset = remaining + offset;
break;
} else {
acc += val << (remaining - (BYTE - offset));
remaining -= BYTE - offset;
offset = 0;
}
}
let _ = input.next_slice(cnt);
*bit_input = (input, end_offset);
Ok(acc)
}
}
}
/// Parse taking `count` bits and comparing them to `pattern`
///
/// # Effective Signature
///
/// Assuming you are parsing a `(&[u8], usize)` bit [Stream]:
/// ```rust
/// # use winnow::prelude::*;;
/// # use winnow::error::ContextError;
/// pub fn pattern<'i>(pattern: u8, count: usize) -> impl Parser<(&'i [u8], usize), u8, ContextError>
/// # {
/// # winnow::binary::bits::pattern(pattern, count)
/// # }
/// ```
///
/// # Example
///
/// ```rust
/// # use winnow::prelude::*;
/// # use winnow::Bytes;
/// # use winnow::error::ContextError;
/// use winnow::binary::bits::pattern;
///
/// type Stream<'i> = &'i Bytes;
///
/// fn stream(b: &[u8]) -> Stream<'_> {
/// Bytes::new(b)
/// }
///
/// /// Compare the lowest `count` bits of `input` against the lowest `count` bits of `pattern`.
/// /// Return Ok and the matching section of `input` if there's a match.
/// /// Return Err if there's no match.
/// fn parser(bits: u8, count: u8, input: &mut (Stream<'_>, usize)) -> ModalResult<u8> {
/// pattern(bits, count).parse_next(input)
/// }
///
/// // The lowest 4 bits of 0b00001111 match the lowest 4 bits of 0b11111111.
/// assert_eq!(
/// pattern::<_, usize, _, ContextError>(0b0000_1111, 4usize).parse_peek((stream(&[0b1111_1111]), 0)),
/// Ok(((stream(&[0b1111_1111]), 4), 0b0000_1111))
/// );
///
/// // The lowest bit of 0b00001111 matches the lowest bit of 0b11111111 (both are 1).
/// assert_eq!(
/// pattern::<_, usize, _, ContextError>(0b00000001, 1usize).parse_peek((stream(&[0b11111111]), 0)),
/// Ok(((stream(&[0b11111111]), 1), 0b00000001))
/// );
///
/// // The lowest 2 bits of 0b11111111 and 0b00000001 are different.
/// assert!(pattern::<_, usize, _, ContextError>(0b000000_01, 2usize).parse_peek((stream(&[0b111111_11]), 0)).is_err());
///
/// // The lowest 8 bits of 0b11111111 and 0b11111110 are different.
/// assert!(pattern::<_, usize, _, ContextError>(0b11111110, 8usize).parse_peek((stream(&[0b11111111]), 0)).is_err());
/// ```
#[inline(always)]
#[doc(alias = "literal")]
#[doc(alias = "just")]
#[doc(alias = "tag")]
pub fn pattern<Input, Output, Count, Error: ParserError<(Input, usize)>>(
pattern: Output,
count: Count,
) -> impl Parser<(Input, usize), Output, Error>
where
Input: Stream<Token = u8> + StreamIsPartial + Clone,
Count: ToUsize,
Output: From<u8>
+ AddAssign
+ Shl<usize, Output = Output>
+ Shr<usize, Output = Output>
+ PartialEq,
{
let count = count.to_usize();
trace("pattern", move |input: &mut (Input, usize)| {
let start = input.checkpoint();
take(count).parse_next(input).and_then(|o| {
if pattern == o {
Ok(o)
} else {
input.reset(&start);
Err(ParserError::from_input(input))
}
})
})
}
/// Parses one specific bit as a bool.
///
/// # Effective Signature
///
/// Assuming you are parsing a `(&[u8], usize)` bit [Stream]:
/// ```rust
/// # use winnow::prelude::*;;
/// # use winnow::error::ContextError;
/// pub fn bool(input: &mut (&[u8], usize)) -> ModalResult<bool>
/// # {
/// # winnow::binary::bits::bool.parse_next(input)
/// # }
/// ```
///
/// # Example
///
/// ```rust
/// # use winnow::prelude::*;
/// # use winnow::Bytes;
/// # use winnow::error::InputError;
/// use winnow::binary::bits::bool;
///
/// type Stream<'i> = &'i Bytes;
///
/// fn stream(b: &[u8]) -> Stream<'_> {
/// Bytes::new(b)
/// }
///
/// fn parse(input: &mut (Stream<'_>, usize)) -> ModalResult<bool> {
/// bool.parse_next(input)
/// }
///
/// assert_eq!(parse.parse_peek((stream(&[0b10000000]), 0)), Ok(((stream(&[0b10000000]), 1), true)));
/// assert_eq!(parse.parse_peek((stream(&[0b10000000]), 1)), Ok(((stream(&[0b10000000]), 2), false)));
/// ```
#[doc(alias = "any")]
pub fn bool<Input, Error: ParserError<(Input, usize)>>(
input: &mut (Input, usize),
) -> Result<bool, Error>
where
Input: Stream<Token = u8> + StreamIsPartial + Clone,
{
trace("bool", |input: &mut (Input, usize)| {
let bit: u32 = take(1usize).parse_next(input)?;
Ok(bit != 0)
})
.parse_next(input)
}

204
vendor/winnow/src/binary/bits/tests.rs vendored Normal file
View File

@@ -0,0 +1,204 @@
use super::*;
use crate::error::ErrMode;
use crate::error::InputError;
use crate::prelude::*;
use crate::Partial;
#[test]
/// Take the `bits` function and assert that remaining bytes are correctly returned, if the
/// previous bytes are fully consumed
fn test_complete_byte_consumption_bits() {
let input = &[0x12, 0x34, 0x56, 0x78][..];
// Take 3 bit slices with sizes [4, 8, 4].
#[allow(clippy::type_complexity)]
let result: ModalResult<(&[u8], (u8, u8, u8)), InputError<_>> =
bits::<_, _, ErrMode<InputError<(&[u8], usize)>>, _, _>((
take(4usize),
take(8usize),
take(4usize),
))
.parse_peek(input);
let output = result.expect("We take 2 bytes and the input is longer than 2 bytes");
let remaining = output.0;
assert_eq!(remaining, [0x56, 0x78]);
let parsed = output.1;
assert_eq!(parsed.0, 0x01);
assert_eq!(parsed.1, 0x23);
assert_eq!(parsed.2, 0x04);
}
#[test]
/// Take the `bits` function and assert that remaining bytes are correctly returned, if the
/// previous bytes are NOT fully consumed. Partially consumed bytes are supposed to be dropped.
/// I.e. if we consume 1.5 bytes of 4 bytes, 2 bytes will be returned, bits 13-16 will be
/// dropped.
fn test_partial_byte_consumption_bits() {
let input = &[0x12, 0x34, 0x56, 0x78][..];
// Take bit slices with sizes [4, 8].
let result: ModalResult<(&[u8], (u8, u8)), InputError<_>> =
bits::<_, _, ErrMode<InputError<(&[u8], usize)>>, _, _>((take(4usize), take(8usize)))
.parse_peek(input);
let output = result.expect("We take 1.5 bytes and the input is longer than 2 bytes");
let remaining = output.0;
assert_eq!(remaining, [0x56, 0x78]);
let parsed = output.1;
assert_eq!(parsed.0, 0x01);
assert_eq!(parsed.1, 0x23);
}
#[test]
#[cfg(feature = "std")]
/// Ensure that in Incomplete error is thrown, if too few bytes are passed for a given parser.
fn test_incomplete_bits() {
let input = Partial::new(&[0x12][..]);
// Take bit slices with sizes [4, 8].
let result: ModalResult<(_, (u8, u8)), InputError<_>> =
bits::<_, _, ErrMode<InputError<(_, usize)>>, _, _>((take(4usize), take(8usize)))
.parse_peek(input);
assert!(result.is_err());
let error = result.err().unwrap();
assert_eq!("Parsing requires 2 more data", error.to_string());
}
#[test]
fn test_take_complete_0() {
let input = &[0b00010010][..];
let count = 0usize;
assert_eq!(count, 0usize);
let offset = 0usize;
let result: ModalResult<((&[u8], usize), usize), InputError<_>> =
take(count).parse_peek((input, offset));
assert_eq!(result, Ok(((input, offset), 0)));
}
#[test]
fn test_take_complete_eof() {
let input = &[0b00010010][..];
let result: ModalResult<((&[u8], usize), usize), InputError<_>> =
take(1usize).parse_peek((input, 8));
assert_eq!(
result,
Err(crate::error::ErrMode::Backtrack(
InputError::at((input, 8),)
))
);
}
#[test]
fn test_take_complete_span_over_multiple_bytes() {
let input = &[0b00010010, 0b00110100, 0b11111111, 0b11111111][..];
let result: ModalResult<((&[u8], usize), usize), InputError<_>> =
take(24usize).parse_peek((input, 4));
assert_eq!(
result,
Ok((([0b11111111].as_ref(), 4), 0b1000110100111111111111))
);
}
#[test]
fn test_take_partial_0() {
let input = Partial::new(&[][..]);
let count = 0usize;
assert_eq!(count, 0usize);
let offset = 0usize;
let result: ModalResult<((_, usize), usize), InputError<_>> =
take(count).parse_peek((input, offset));
assert_eq!(result, Ok(((input, offset), 0)));
}
#[test]
fn test_pattern_partial_ok() {
let input = Partial::new(&[0b00011111][..]);
let offset = 0usize;
let bits_to_take = 4usize;
let value_to_pattern = 0b0001;
let result: ModalResult<((_, usize), usize), InputError<_>> =
pattern(value_to_pattern, bits_to_take).parse_peek((input, offset));
assert_eq!(result, Ok(((input, bits_to_take), value_to_pattern)));
}
#[test]
fn test_pattern_partial_err() {
let input = Partial::new(&[0b00011111][..]);
let offset = 0usize;
let bits_to_take = 4usize;
let value_to_pattern = 0b1111;
let result: ModalResult<((_, usize), usize), InputError<_>> =
pattern(value_to_pattern, bits_to_take).parse_peek((input, offset));
assert_eq!(
result,
Err(crate::error::ErrMode::Backtrack(InputError::at((
input, offset
),)))
);
}
#[test]
fn test_bool_0_complete() {
let input = [0b10000000].as_ref();
let result: ModalResult<((&[u8], usize), bool), InputError<_>> = bool.parse_peek((input, 0));
assert_eq!(result, Ok(((input, 1), true)));
}
#[test]
fn test_bool_eof_complete() {
let input = [0b10000000].as_ref();
let result: ModalResult<((&[u8], usize), bool), InputError<_>> = bool.parse_peek((input, 8));
assert_eq!(
result,
Err(crate::error::ErrMode::Backtrack(
InputError::at((input, 8),)
))
);
}
#[test]
fn test_bool_0_partial() {
let input = Partial::new([0b10000000].as_ref());
#[allow(clippy::type_complexity)]
let result: ModalResult<((Partial<&[u8]>, usize), bool), InputError<_>> =
bool.parse_peek((input, 0));
assert_eq!(result, Ok(((input, 1), true)));
}
#[test]
fn test_bool_eof_partial() {
let input = Partial::new([0b10000000].as_ref());
#[allow(clippy::type_complexity)]
let result: ModalResult<((Partial<&[u8]>, usize), bool), InputError<_>> =
bool.parse_peek((input, 8));
assert_eq!(
result,
Err(crate::error::ErrMode::Incomplete(Needed::new(1)))
);
}

2533
vendor/winnow/src/binary/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

3718
vendor/winnow/src/binary/tests.rs vendored Normal file

File diff suppressed because it is too large Load Diff

366
vendor/winnow/src/combinator/branch.rs vendored Normal file
View File

@@ -0,0 +1,366 @@
use crate::combinator::trace;
use crate::error::ParserError;
use crate::stream::Stream;
use crate::*;
#[doc(inline)]
pub use crate::dispatch;
/// Helper trait for the [`alt()`] combinator.
///
/// This trait is implemented for tuples of up to 21 elements
pub trait Alt<I, O, E> {
/// Tests each parser in the tuple and returns the result of the first one that succeeds
fn choice(&mut self, input: &mut I) -> Result<O, E>;
}
/// Pick the first successful parser
///
/// To stop on an error, rather than trying further cases, see
/// [`cut_err`][crate::combinator::cut_err] ([example][crate::_tutorial::chapter_7]).
///
/// For tight control over the error when no match is found, add a final case using [`fail`][crate::combinator::fail].
/// Alternatively, with a [custom error type][crate::_topic::error], it is possible to track all
/// errors or return the error of the parser that went the farthest in the input data.
///
/// When the alternative cases have unique prefixes, [`dispatch`] can offer better performance.
///
/// # Example
///
/// ```rust
/// # use winnow::{error::ErrMode, error::Needed};
/// # use winnow::prelude::*;
/// use winnow::ascii::{alpha1, digit1};
/// use winnow::combinator::alt;
/// # fn main() {
/// fn parser<'i>(input: &mut &'i str) -> ModalResult<&'i str> {
/// alt((alpha1, digit1)).parse_next(input)
/// };
///
/// // the first parser, alpha1, takes the input
/// assert_eq!(parser.parse_peek("abc"), Ok(("", "abc")));
///
/// // the first parser returns an error, so alt tries the second one
/// assert_eq!(parser.parse_peek("123456"), Ok(("", "123456")));
///
/// // both parsers failed, and with the default error type, alt will return the last error
/// assert!(parser.parse_peek(" ").is_err());
/// # }
/// ```
#[doc(alias = "choice")]
#[inline(always)]
pub fn alt<Input: Stream, Output, Error, Alternatives>(
mut alternatives: Alternatives,
) -> impl Parser<Input, Output, Error>
where
Alternatives: Alt<Input, Output, Error>,
Error: ParserError<Input>,
{
trace("alt", move |i: &mut Input| alternatives.choice(i))
}
/// Helper trait for the [`permutation()`] combinator.
///
/// This trait is implemented for tuples of up to 21 elements
pub trait Permutation<I, O, E> {
/// Tries to apply all parsers in the tuple in various orders until all of them succeed
fn permutation(&mut self, input: &mut I) -> Result<O, E>;
}
/// Applies a list of parsers in any order.
///
/// Permutation will succeed if all of the child parsers succeeded.
/// It takes as argument a tuple of parsers, and returns a
/// tuple of the parser results.
///
/// To stop on an error, rather than trying further permutations, see
/// [`cut_err`][crate::combinator::cut_err] ([example][crate::_tutorial::chapter_7]).
///
/// # Example
///
/// ```rust
/// # use winnow::{error::ErrMode, error::Needed};
/// # use winnow::prelude::*;
/// use winnow::ascii::{alpha1, digit1};
/// use winnow::combinator::permutation;
/// # fn main() {
/// fn parser<'i>(input: &mut &'i str) -> ModalResult<(&'i str, &'i str)> {
/// permutation((alpha1, digit1)).parse_next(input)
/// }
///
/// // permutation takes alphabetic characters then digit
/// assert_eq!(parser.parse_peek("abc123"), Ok(("", ("abc", "123"))));
///
/// // but also in inverse order
/// assert_eq!(parser.parse_peek("123abc"), Ok(("", ("abc", "123"))));
///
/// // it will fail if one of the parsers failed
/// assert!(parser.parse_peek("abc;").is_err());
/// # }
/// ```
///
/// The parsers are applied greedily: if there are multiple unapplied parsers
/// that could parse the next slice of input, the first one is used.
/// ```rust
/// # use winnow::error::ErrMode;
/// # use winnow::prelude::*;
/// use winnow::combinator::permutation;
/// use winnow::token::any;
///
/// fn parser(input: &mut &str) -> ModalResult<(char, char)> {
/// permutation((any, 'a')).parse_next(input)
/// }
///
/// // any parses 'b', then char('a') parses 'a'
/// assert_eq!(parser.parse_peek("ba"), Ok(("", ('b', 'a'))));
///
/// // any parses 'a', then char('a') fails on 'b',
/// // even though char('a') followed by any would succeed
/// assert!(parser.parse_peek("ab").is_err());
/// ```
///
#[inline(always)]
pub fn permutation<I: Stream, O, E: ParserError<I>, List: Permutation<I, O, E>>(
mut l: List,
) -> impl Parser<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) -> Result<O, E> {
let mut error: Option<E> = None;
let start = input.checkpoint();
for branch in self {
input.reset(&start);
match branch.parse_next(input) {
Err(e) if e.is_backtrack() => {
error = match error {
Some(error) => Some(error.or(e)),
None => Some(e),
};
}
res => return res,
}
}
match error {
Some(e) => Err(e.append(input, &start)),
None => Err(ParserError::assert(
input,
"`alt` needs at least one parser",
)),
}
}
}
impl<I: Stream, O, E: ParserError<I>, P: Parser<I, O, E>> Alt<I, O, E> for &mut [P] {
fn choice(&mut self, input: &mut I) -> Result<O, E> {
let mut error: Option<E> = None;
let start = input.checkpoint();
for branch in self.iter_mut() {
input.reset(&start);
match branch.parse_next(input) {
Err(e) if e.is_backtrack() => {
error = match error {
Some(error) => Some(error.or(e)),
None => Some(e),
};
}
res => return res,
}
}
match error {
Some(e) => Err(e.append(input, &start)),
None => Err(ParserError::assert(
input,
"`alt` needs at least one parser",
)),
}
}
}
macro_rules! alt_trait(
($first:ident $second:ident $($id: ident)+) => (
alt_trait!(__impl $first $second; $($id)+);
);
(__impl $($current:ident)*; $head:ident $($id: ident)+) => (
alt_trait_impl!($($current)*);
alt_trait!(__impl $($current)* $head; $($id)+);
);
(__impl $($current:ident)*; $head:ident) => (
alt_trait_impl!($($current)*);
alt_trait_impl!($($current)* $head);
);
);
macro_rules! alt_trait_impl(
($($id:ident)+) => (
impl<
I: Stream, Output, Error: ParserError<I>,
$($id: Parser<I, Output, Error>),+
> Alt<I, Output, Error> for ( $($id),+ ) {
fn choice(&mut self, input: &mut I) -> Result<Output, Error> {
let start = input.checkpoint();
match self.0.parse_next(input) {
Err(e) if e.is_backtrack() => alt_trait_inner!(1, self, input, start, e, $($id)+),
res => res,
}
}
}
);
);
macro_rules! succ (
(0, $submac:ident ! ($($rest:tt)*)) => ($submac!(1, $($rest)*));
(1, $submac:ident ! ($($rest:tt)*)) => ($submac!(2, $($rest)*));
(2, $submac:ident ! ($($rest:tt)*)) => ($submac!(3, $($rest)*));
(3, $submac:ident ! ($($rest:tt)*)) => ($submac!(4, $($rest)*));
(4, $submac:ident ! ($($rest:tt)*)) => ($submac!(5, $($rest)*));
(5, $submac:ident ! ($($rest:tt)*)) => ($submac!(6, $($rest)*));
(6, $submac:ident ! ($($rest:tt)*)) => ($submac!(7, $($rest)*));
(7, $submac:ident ! ($($rest:tt)*)) => ($submac!(8, $($rest)*));
(8, $submac:ident ! ($($rest:tt)*)) => ($submac!(9, $($rest)*));
(9, $submac:ident ! ($($rest:tt)*)) => ($submac!(10, $($rest)*));
(10, $submac:ident ! ($($rest:tt)*)) => ($submac!(11, $($rest)*));
(11, $submac:ident ! ($($rest:tt)*)) => ($submac!(12, $($rest)*));
(12, $submac:ident ! ($($rest:tt)*)) => ($submac!(13, $($rest)*));
(13, $submac:ident ! ($($rest:tt)*)) => ($submac!(14, $($rest)*));
(14, $submac:ident ! ($($rest:tt)*)) => ($submac!(15, $($rest)*));
(15, $submac:ident ! ($($rest:tt)*)) => ($submac!(16, $($rest)*));
(16, $submac:ident ! ($($rest:tt)*)) => ($submac!(17, $($rest)*));
(17, $submac:ident ! ($($rest:tt)*)) => ($submac!(18, $($rest)*));
(18, $submac:ident ! ($($rest:tt)*)) => ($submac!(19, $($rest)*));
(19, $submac:ident ! ($($rest:tt)*)) => ($submac!(20, $($rest)*));
(20, $submac:ident ! ($($rest:tt)*)) => ($submac!(21, $($rest)*));
);
macro_rules! alt_trait_inner(
($it:tt, $self:expr, $input:expr, $start:ident, $err:expr, $head:ident $($id:ident)+) => ({
$input.reset(&$start);
match $self.$it.parse_next($input) {
Err(e) if e.is_backtrack() => {
let err = $err.or(e);
succ!($it, alt_trait_inner!($self, $input, $start, err, $($id)+))
}
res => res,
}
});
($it:tt, $self:expr, $input:expr, $start:ident, $err:expr, $head:ident) => ({
Err($err.append($input, &$start))
});
);
alt_trait!(Alt2 Alt3 Alt4 Alt5 Alt6 Alt7 Alt8 Alt9 Alt10 Alt11 Alt12 Alt13 Alt14 Alt15 Alt16 Alt17 Alt18 Alt19 Alt20 Alt21 Alt22);
// Manually implement Alt for (A,), the 1-tuple type
impl<I: Stream, O, E: ParserError<I>, A: Parser<I, O, E>> Alt<I, O, E> for (A,) {
fn choice(&mut self, input: &mut I) -> Result<O, E> {
self.0.parse_next(input)
}
}
macro_rules! permutation_trait(
(
$name1:ident $ty1:ident $item1:ident
$name2:ident $ty2:ident $item2:ident
$($name3:ident $ty3:ident $item3:ident)*
) => (
permutation_trait!(__impl $name1 $ty1 $item1, $name2 $ty2 $item2; $($name3 $ty3 $item3)*);
);
(
__impl $($name:ident $ty:ident $item:ident),+;
$name1:ident $ty1:ident $item1:ident $($name2:ident $ty2:ident $item2:ident)*
) => (
permutation_trait_impl!($($name $ty $item),+);
permutation_trait!(__impl $($name $ty $item),+ , $name1 $ty1 $item1; $($name2 $ty2 $item2)*);
);
(__impl $($name:ident $ty:ident $item:ident),+;) => (
permutation_trait_impl!($($name $ty $item),+);
);
);
macro_rules! permutation_trait_impl(
($($name:ident $ty:ident $item:ident),+) => (
impl<
I: Stream, $($ty),+ , Error: ParserError<I>,
$($name: Parser<I, $ty, Error>),+
> Permutation<I, ( $($ty),+ ), Error> for ( $($name),+ ) {
fn permutation(&mut self, input: &mut I) -> Result<( $($ty),+ ), Error> {
let mut res = ($(Option::<$ty>::None),+);
loop {
let mut err: Option<Error> = None;
let start = input.checkpoint();
permutation_trait_inner!(0, self, input, start, res, err, $($name)+);
// If we reach here, every iterator has either been applied before,
// or errored on the remaining input
if let Some(err) = err {
// There are remaining parsers, and all errored on the remaining input
input.reset(&start);
return Err(err.append(input, &start));
}
// All parsers were applied
match res {
($(Some($item)),+) => return Ok(($($item),+)),
_ => unreachable!(),
}
}
}
}
);
);
macro_rules! permutation_trait_inner(
($it:tt, $self:expr, $input:ident, $start:ident, $res:expr, $err:expr, $head:ident $($id:ident)*) => (
if $res.$it.is_none() {
$input.reset(&$start);
match $self.$it.parse_next($input) {
Ok(o) => {
$res.$it = Some(o);
continue;
}
Err(e) if e.is_backtrack() => {
$err = Some(match $err {
Some(err) => err.or(e),
None => e,
});
}
Err(e) => return Err(e),
};
}
succ!($it, permutation_trait_inner!($self, $input, $start, $res, $err, $($id)*));
);
($it:tt, $self:expr, $input:ident, $start:ident, $res:expr, $err:expr,) => ();
);
permutation_trait!(
P1 O1 o1
P2 O2 o2
P3 O3 o3
P4 O4 o4
P5 O5 o5
P6 O6 o6
P7 O7 o7
P8 O8 o8
P9 O9 o9
P10 O10 o10
P11 O11 o11
P12 O12 o12
P13 O13 o13
P14 O14 o14
P15 O15 o15
P16 O16 o16
P17 O17 o17
P18 O18 o18
P19 O19 o19
P20 O20 o20
P21 O21 o21
);

506
vendor/winnow/src/combinator/core.rs vendored Normal file
View File

@@ -0,0 +1,506 @@
use crate::combinator::trace;
use crate::error::{ModalError, ParserError};
use crate::stream::Stream;
use crate::*;
/// Apply a [`Parser`], producing `None` on [`ErrMode::Backtrack`][crate::error::ErrMode::Backtrack].
///
/// To chain an error up, see [`cut_err`].
///
/// # Example
///
/// ```rust
/// # use winnow::prelude::*;
/// use winnow::combinator::opt;
/// use winnow::ascii::alpha1;
/// # fn main() {
///
/// fn parser<'i>(i: &mut &'i str) -> ModalResult<Option<&'i str>> {
/// opt(alpha1).parse_next(i)
/// }
///
/// assert_eq!(parser.parse_peek("abcd;"), Ok((";", Some("abcd"))));
/// assert_eq!(parser.parse_peek("123;"), Ok(("123;", None)));
/// # }
/// ```
pub fn opt<Input: Stream, Output, Error, ParseNext>(
mut parser: ParseNext,
) -> impl Parser<Input, Option<Output>, Error>
where
ParseNext: Parser<Input, Output, Error>,
Error: ParserError<Input>,
{
trace("opt", move |input: &mut Input| {
let start = input.checkpoint();
match parser.parse_next(input) {
Ok(o) => Ok(Some(o)),
Err(e) if e.is_backtrack() => {
input.reset(&start);
Ok(None)
}
Err(e) => Err(e),
}
})
}
/// Calls the parser if the condition is met.
///
/// # Example
///
/// ```rust
/// # use winnow::prelude::*;
/// # use winnow::combinator::opt;
/// use winnow::combinator::cond;
/// use winnow::ascii::alpha1;
/// # fn main() {
///
/// fn parser<'i>(i: &mut &'i str) -> ModalResult<Option<&'i str>> {
/// let prefix = opt("-").parse_next(i)?;
/// let condition = prefix.is_some();
/// cond(condition, alpha1).parse_next(i)
/// }
///
/// assert_eq!(parser.parse_peek("-abcd;"), Ok((";", Some("abcd"))));
/// assert_eq!(parser.parse_peek("abcd;"), Ok(("abcd;", None)));
/// assert!(parser.parse_peek("-123;").is_err());
/// assert_eq!(parser.parse_peek("123;"), Ok(("123;", None)));
/// # }
/// ```
pub fn cond<Input, Output, Error, ParseNext>(
cond: bool,
mut parser: ParseNext,
) -> impl Parser<Input, Option<Output>, Error>
where
Input: Stream,
ParseNext: Parser<Input, Output, Error>,
Error: ParserError<Input>,
{
trace("cond", move |input: &mut Input| {
if cond {
parser.parse_next(input).map(Some)
} else {
Ok(None)
}
})
}
/// Apply the parser without advancing the input.
///
/// To lookahead and only advance on success, see [`opt`].
///
/// # Example
///
/// ```rust
/// # use winnow::prelude::*;
/// use winnow::combinator::peek;
/// use winnow::ascii::alpha1;
/// # fn main() {
///
/// fn parser<'i>(input: &mut &'i str) -> ModalResult<&'i str> {
/// peek(alpha1).parse_next(input)
/// }
///
/// assert_eq!(parser.parse_peek("abcd;"), Ok(("abcd;", "abcd")));
/// assert!(parser.parse_peek("123;").is_err());
/// # }
/// ```
#[doc(alias = "look_ahead")]
#[doc(alias = "rewind")]
pub fn peek<Input, Output, Error, ParseNext>(
mut parser: ParseNext,
) -> impl Parser<Input, Output, Error>
where
Input: Stream,
Error: ParserError<Input>,
ParseNext: Parser<Input, Output, Error>,
{
trace("peek", move |input: &mut Input| {
let start = input.checkpoint();
let res = parser.parse_next(input);
input.reset(&start);
res
})
}
/// Match the end of the [`Stream`]
///
/// Otherwise, it will error.
///
/// # Effective Signature
///
/// Assuming you are parsing a `&str` [Stream]:
/// ```rust
/// # use winnow::prelude::*;;
/// pub fn eof<'i>(input: &mut &'i str) -> ModalResult<&'i str>
/// # {
/// # winnow::combinator::eof.parse_next(input)
/// # }
/// ```
///
/// # Example
///
/// ```rust
/// # use std::str;
/// # use winnow::combinator::eof;
/// # use winnow::prelude::*;
///
/// fn parser<'i>(input: &mut &'i str) -> ModalResult<&'i str> {
/// eof.parse_next(input)
/// }
/// assert!(parser.parse_peek("abc").is_err());
/// assert_eq!(parser.parse_peek(""), Ok(("", "")));
/// ```
#[doc(alias = "end")]
#[doc(alias = "eoi")]
pub fn eof<Input, Error>(input: &mut Input) -> Result<<Input as Stream>::Slice, Error>
where
Input: Stream,
Error: ParserError<Input>,
{
trace("eof", move |input: &mut Input| {
if input.eof_offset() == 0 {
Ok(input.next_slice(0))
} else {
Err(ParserError::from_input(input))
}
})
.parse_next(input)
}
/// Succeeds if the child parser returns an error.
///
/// <div class="warning">
///
/// **Note:** This does not advance the [`Stream`]
///
/// </div>
///
/// # Example
///
/// ```rust
/// # use winnow::prelude::*;
/// use winnow::combinator::not;
/// use winnow::ascii::alpha1;
/// # fn main() {
///
/// fn parser<'i>(input: &mut &'i str) -> ModalResult<()> {
/// not(alpha1).parse_next(input)
/// }
///
/// assert_eq!(parser.parse_peek("123"), Ok(("123", ())));
/// assert!(parser.parse_peek("abcd").is_err());
/// # }
/// ```
pub fn not<Input, Output, Error, ParseNext>(mut parser: ParseNext) -> impl Parser<Input, (), Error>
where
Input: Stream,
Error: ParserError<Input>,
ParseNext: Parser<Input, Output, Error>,
{
trace("not", move |input: &mut Input| {
let start = input.checkpoint();
let res = parser.parse_next(input);
input.reset(&start);
match res {
Ok(_) => Err(ParserError::from_input(input)),
Err(e) if e.is_backtrack() => Ok(()),
Err(e) => Err(e),
}
})
}
/// Transforms an [`ErrMode::Backtrack`][crate::error::ErrMode::Backtrack] (recoverable) to [`ErrMode::Cut`][crate::error::ErrMode::Cut] (unrecoverable)
///
/// This commits the parse result, preventing alternative branch paths like with
/// [`winnow::combinator::alt`][crate::combinator::alt].
///
/// See the [tutorial][crate::_tutorial::chapter_7] for more details.
///
/// # Example
///
/// Without `cut_err`:
/// ```rust
/// # use winnow::token::one_of;
/// # use winnow::token::rest;
/// # use winnow::ascii::digit1;
/// # use winnow::combinator::alt;
/// # use winnow::combinator::preceded;
/// # use winnow::prelude::*;
/// # fn main() {
///
/// fn parser<'i>(input: &mut &'i str) -> ModalResult<&'i str> {
/// alt((
/// preceded(one_of(['+', '-']), digit1),
/// rest
/// )).parse_next(input)
/// }
///
/// assert_eq!(parser.parse_peek("+10 ab"), Ok((" ab", "10")));
/// assert_eq!(parser.parse_peek("ab"), Ok(("", "ab")));
/// assert_eq!(parser.parse_peek("+"), Ok(("", "+")));
/// # }
/// ```
///
/// With `cut_err`:
/// ```rust
/// # use winnow::{error::ErrMode, error::ContextError};
/// # use winnow::prelude::*;
/// # use winnow::token::one_of;
/// # use winnow::token::rest;
/// # use winnow::ascii::digit1;
/// # use winnow::combinator::alt;
/// # use winnow::combinator::preceded;
/// use winnow::combinator::cut_err;
/// # fn main() {
///
/// fn parser<'i>(input: &mut &'i str) -> ModalResult<&'i str> {
/// alt((
/// preceded(one_of(['+', '-']), cut_err(digit1)),
/// rest
/// )).parse_next(input)
/// }
///
/// assert_eq!(parser.parse_peek("+10 ab"), Ok((" ab", "10")));
/// assert_eq!(parser.parse_peek("ab"), Ok(("", "ab")));
/// assert_eq!(parser.parse_peek("+"), Err(ErrMode::Cut(ContextError::new())));
/// # }
/// ```
pub fn cut_err<Input, Output, Error, ParseNext>(
mut parser: ParseNext,
) -> impl Parser<Input, Output, Error>
where
Input: Stream,
Error: ParserError<Input> + ModalError,
ParseNext: Parser<Input, Output, Error>,
{
trace("cut_err", move |input: &mut Input| {
parser.parse_next(input).map_err(|e| e.cut())
})
}
/// Transforms an [`ErrMode::Cut`][crate::error::ErrMode::Cut] (unrecoverable) to [`ErrMode::Backtrack`][crate::error::ErrMode::Backtrack] (recoverable)
///
/// This attempts the parse, allowing other parsers to be tried on failure, like with
/// [`winnow::combinator::alt`][crate::combinator::alt].
pub fn backtrack_err<Input, Output, Error, ParseNext>(
mut parser: ParseNext,
) -> impl Parser<Input, Output, Error>
where
Input: Stream,
Error: ParserError<Input> + ModalError,
ParseNext: Parser<Input, Output, Error>,
{
trace("backtrack_err", move |input: &mut Input| {
parser.parse_next(input).map_err(|e| e.backtrack())
})
}
/// A placeholder for a not-yet-implemented [`Parser`]
///
/// This is analogous to the [`todo!`] macro and helps with prototyping.
///
/// # Panic
///
/// This will panic when parsing
///
/// # Example
///
/// ```rust
/// # use winnow::prelude::*;
/// # use winnow::combinator::todo;
///
/// fn parser(input: &mut &str) -> ModalResult<u64> {
/// todo(input)
/// }
/// ```
#[track_caller]
pub fn todo<Input, Output, Error>(input: &mut Input) -> Result<Output, Error>
where
Input: Stream,
Error: ParserError<Input>,
{
#![allow(clippy::todo)]
trace("todo", move |_input: &mut Input| {
todo!("unimplemented parse")
})
.parse_next(input)
}
/// Repeats the embedded parser, lazily returning the results
///
/// Call the iterator's [`ParserIterator::finish`] method to get the remaining input if successful,
/// or the error value if we encountered an error.
///
/// On [`ErrMode::Backtrack`][crate::error::ErrMode::Backtrack], iteration will stop. To instead chain an error up, see [`cut_err`].
///
/// # Example
///
/// ```rust
/// # use winnow::prelude::*;
/// use winnow::{combinator::iterator, ascii::alpha1, combinator::terminated};
/// use std::collections::HashMap;
///
/// let data = "abc|defg|hijkl|mnopqr|123";
/// let mut it = iterator(data, terminated(alpha1, "|"));
///
/// let parsed = it.map(|v| (v, v.len())).collect::<HashMap<_,_>>();
/// let res: ModalResult<_> = it.finish();
///
/// assert_eq!(parsed, [("abc", 3usize), ("defg", 4), ("hijkl", 5), ("mnopqr", 6)].iter().cloned().collect());
/// assert_eq!(res, Ok(("123", ())));
/// ```
pub fn iterator<Input, Output, Error, ParseNext>(
input: Input,
parser: ParseNext,
) -> ParserIterator<ParseNext, Input, Output, Error>
where
ParseNext: Parser<Input, Output, Error>,
Input: Stream,
Error: ParserError<Input>,
{
ParserIterator {
parser,
input,
state: State::Running,
o: Default::default(),
}
}
/// Main structure associated to [`iterator`].
pub struct ParserIterator<F, I, O, E>
where
F: Parser<I, O, E>,
I: Stream,
{
parser: F,
input: I,
state: State<E>,
o: core::marker::PhantomData<O>,
}
impl<F, I, O, E> ParserIterator<F, I, O, E>
where
F: Parser<I, O, E>,
I: Stream,
E: ParserError<I>,
{
/// Returns the remaining input if parsing was successful, or the error if we encountered an error.
pub fn finish(self) -> Result<(I, ()), E> {
match self.state {
State::Running | State::Done => Ok((self.input, ())),
State::Cut(e) => Err(e),
}
}
}
impl<F, I, O, E> core::iter::Iterator for &mut ParserIterator<F, I, O, E>
where
F: Parser<I, O, E>,
I: Stream,
E: ParserError<I>,
{
type Item = O;
fn next(&mut self) -> Option<Self::Item> {
if matches!(self.state, State::Running) {
let start = self.input.checkpoint();
match self.parser.parse_next(&mut self.input) {
Ok(o) => {
self.state = State::Running;
Some(o)
}
Err(e) if e.is_backtrack() => {
self.input.reset(&start);
self.state = State::Done;
None
}
Err(e) => {
self.state = State::Cut(e);
None
}
}
} else {
None
}
}
}
enum State<E> {
Running,
Done,
Cut(E),
}
/// Succeed, consuming no input
///
/// For example, it can be used as the last alternative in `alt` to
/// specify the default case.
///
/// Useful with:
/// - [`Parser::value`]
/// - [`Parser::default_value`]
/// - [`Parser::map`]
///
/// <div class="warning">
///
/// **Note:** This never advances the [`Stream`]
///
/// </div>
///
/// # Example
///
/// ```rust
/// # use winnow::prelude::*;
/// use winnow::combinator::alt;
/// use winnow::combinator::empty;
///
/// fn sign(input: &mut &str) -> ModalResult<isize> {
/// alt((
/// '-'.value(-1),
/// '+'.value(1),
/// empty.value(1)
/// )).parse_next(input)
/// }
/// assert_eq!(sign.parse_peek("+10"), Ok(("10", 1)));
/// assert_eq!(sign.parse_peek("-10"), Ok(("10", -1)));
/// assert_eq!(sign.parse_peek("10"), Ok(("10", 1)));
/// ```
#[doc(alias = "value")]
#[doc(alias = "success")]
#[inline]
pub fn empty<Input, Error>(_input: &mut Input) -> Result<(), Error>
where
Input: Stream,
Error: ParserError<Input>,
{
Ok(())
}
/// A parser which always fails.
///
/// For example, it can be used as the last alternative in `alt` to
/// control the error message given.
///
/// # Example
///
/// ```rust
/// # use winnow::{error::ErrMode, error::InputError};
/// # use winnow::prelude::*;
/// use winnow::combinator::fail;
///
/// fn parser<'i>(input: &mut &'i str) -> ModalResult<(), InputError<&'i str>> {
/// fail.parse_next(input)
/// }
///
/// assert_eq!(parser.parse_peek("string"), Err(ErrMode::Backtrack(InputError::at("string"))));
/// ```
#[doc(alias = "unexpected")]
#[inline]
pub fn fail<Input, Output, Error>(i: &mut Input) -> Result<Output, Error>
where
Input: Stream,
Error: ParserError<Input>,
{
trace("fail", |i: &mut Input| Err(ParserError::from_input(i))).parse_next(i)
}

View File

@@ -0,0 +1,304 @@
#![cfg(feature = "std")]
use std::io::Write;
use crate::error::ParserError;
use crate::stream::Stream;
use crate::*;
pub(crate) struct Trace<P, D, I, O, E>
where
P: Parser<I, O, E>,
I: Stream,
D: std::fmt::Display,
E: ParserError<I>,
{
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,
E: ParserError<I>,
{
#[inline(always)]
pub(crate) 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,
E: ParserError<I>,
{
#[inline]
fn parse_next(&mut self, i: &mut I) -> Result<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(crate) struct Depth {
depth: usize,
inc: bool,
}
impl Depth {
pub(crate) fn new() -> Self {
let depth = DEPTH.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
let inc = true;
Self { depth, inc }
}
pub(crate) fn existing() -> Self {
let depth = DEPTH.load(std::sync::atomic::Ordering::SeqCst);
let inc = false;
Self { depth, inc }
}
}
impl Drop for Depth {
fn drop(&mut self) {
if self.inc {
let _ = DEPTH.fetch_sub(1, std::sync::atomic::Ordering::SeqCst);
}
}
}
impl AsRef<usize> for Depth {
#[inline(always)]
fn as_ref(&self) -> &usize {
&self.depth
}
}
impl crate::lib::std::ops::Deref for Depth {
type Target = usize;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.depth
}
}
static DEPTH: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
pub(crate) enum Severity {
Success,
Backtrack,
Cut,
Incomplete,
}
impl Severity {
pub(crate) fn with_result<T, I: Stream, E: ParserError<I>>(result: &Result<T, E>) -> Self {
match result {
Ok(_) => Self::Success,
Err(e) if e.is_backtrack() => Self::Backtrack,
Err(e) if e.is_incomplete() => Self::Incomplete,
_ => Self::Cut,
}
}
}
pub(crate) fn start<I: Stream>(
depth: usize,
name: &dyn crate::lib::std::fmt::Display,
count: usize,
input: &I,
) {
let gutter_style = anstyle::Style::new().bold();
let input_style = anstyle::Style::new().underline();
let eof_style = anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Cyan.into()));
let (call_width, input_width) = column_widths();
let count = if 0 < count {
format!(":{count}")
} else {
"".to_owned()
};
let call_column = format!("{:depth$}> {name}{count}", "");
// The debug version of `slice` might be wider, either due to rendering one byte as two nibbles or
// escaping in strings.
let mut debug_slice = format!("{:?}", crate::util::from_fn(|f| input.trace(f)));
let (debug_slice, eof) = if let Some(debug_offset) = debug_slice
.char_indices()
.enumerate()
.find_map(|(pos, (offset, _))| (input_width <= pos).then_some(offset))
{
debug_slice.truncate(debug_offset);
let eof = "";
(debug_slice, eof)
} else {
let eof = if debug_slice.chars().count() < input_width {
""
} else {
""
};
(debug_slice, eof)
};
let writer = anstream::stderr();
let mut writer = writer.lock();
let _ = writeln!(
writer,
"{call_column:call_width$} {gutter_style}|{gutter_reset} {input_style}{debug_slice}{input_reset}{eof_style}{eof}{eof_reset}",
gutter_style=gutter_style.render(),
gutter_reset=gutter_style.render_reset(),
input_style=input_style.render(),
input_reset=input_style.render_reset(),
eof_style=eof_style.render(),
eof_reset=eof_style.render_reset(),
);
}
pub(crate) fn end(
depth: usize,
name: &dyn crate::lib::std::fmt::Display,
count: usize,
consumed: usize,
severity: Severity,
) {
let gutter_style = anstyle::Style::new().bold();
let (call_width, _) = column_widths();
let count = if 0 < count {
format!(":{count}")
} else {
"".to_owned()
};
let call_column = format!("{:depth$}< {name}{count}", "");
let (status_style, status) = match severity {
Severity::Success => {
let style = anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Green.into()));
let status = format!("+{consumed}");
(style, status)
}
Severity::Backtrack => (
anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Yellow.into())),
"backtrack".to_owned(),
),
Severity::Cut => (
anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Red.into())),
"cut".to_owned(),
),
Severity::Incomplete => (
anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Red.into())),
"incomplete".to_owned(),
),
};
let writer = anstream::stderr();
let mut writer = writer.lock();
let _ = writeln!(
writer,
"{status_style}{call_column:call_width$}{status_reset} {gutter_style}|{gutter_reset} {status_style}{status}{status_reset}",
gutter_style=gutter_style.render(),
gutter_reset=gutter_style.render_reset(),
status_style=status_style.render(),
status_reset=status_style.render_reset(),
);
}
pub(crate) fn result(depth: usize, name: &dyn crate::lib::std::fmt::Display, severity: Severity) {
let gutter_style = anstyle::Style::new().bold();
let (call_width, _) = column_widths();
let call_column = format!("{:depth$}| {name}", "");
let (status_style, status) = match severity {
Severity::Success => (
anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Green.into())),
"",
),
Severity::Backtrack => (
anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Yellow.into())),
"backtrack",
),
Severity::Cut => (
anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Red.into())),
"cut",
),
Severity::Incomplete => (
anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Red.into())),
"incomplete",
),
};
let writer = anstream::stderr();
let mut writer = writer.lock();
let _ = writeln!(
writer,
"{status_style}{call_column:call_width$}{status_reset} {gutter_style}|{gutter_reset} {status_style}{status}{status_reset}",
gutter_style=gutter_style.render(),
gutter_reset=gutter_style.render_reset(),
status_style=status_style.render(),
status_reset=status_style.render_reset(),
);
}
fn column_widths() -> (usize, usize) {
let term_width = term_width();
let min_call_width = 40;
let min_input_width = 20;
let decor_width = 3;
let extra_width = term_width
.checked_sub(min_call_width + min_input_width + decor_width)
.unwrap_or_default();
let call_width = min_call_width + 2 * extra_width / 3;
let input_width = min_input_width + extra_width / 3;
(call_width, input_width)
}
fn term_width() -> usize {
columns_env().or_else(query_width).unwrap_or(80)
}
fn query_width() -> Option<usize> {
use is_terminal_polyfill::IsTerminal;
if std::io::stderr().is_terminal() {
terminal_size::terminal_size().map(|(w, _h)| w.0.into())
} else {
None
}
}
fn columns_env() -> Option<usize> {
std::env::var("COLUMNS")
.ok()
.and_then(|c| c.parse::<usize>().ok())
}

View File

@@ -0,0 +1,96 @@
#![cfg_attr(feature = "debug", allow(clippy::std_instead_of_core))]
#[cfg(feature = "debug")]
mod internals;
use crate::error::ParserError;
use crate::stream::Stream;
use crate::Parser;
/// Trace the execution of the parser
///
/// Note that [`Parser::context`] also provides high level trace information.
///
/// See [tutorial][crate::_tutorial::chapter_8] for more details.
///
/// # Example
///
/// ```rust
/// # use winnow::{error::ErrMode, error::Needed};
/// # use winnow::token::take_while;
/// # use winnow::stream::AsChar;
/// # use winnow::prelude::*;
/// use winnow::combinator::trace;
///
/// fn short_alpha<'s>(s: &mut &'s [u8]) -> ModalResult<&'s [u8]> {
/// trace("short_alpha",
/// take_while(3..=6, AsChar::is_alpha)
/// ).parse_next(s)
/// }
///
/// assert_eq!(short_alpha.parse_peek(b"latin123"), Ok((&b"123"[..], &b"latin"[..])));
/// assert_eq!(short_alpha.parse_peek(b"lengthy"), Ok((&b"y"[..], &b"length"[..])));
/// assert_eq!(short_alpha.parse_peek(b"latin"), Ok((&b""[..], &b"latin"[..])));
/// assert!(short_alpha.parse_peek(b"ed").is_err());
/// assert!(short_alpha.parse_peek(b"12345").is_err());
/// ```
#[cfg_attr(not(feature = "debug"), allow(unused_variables))]
#[cfg_attr(not(feature = "debug"), allow(unused_mut))]
#[cfg_attr(not(feature = "debug"), inline(always))]
pub fn trace<I: Stream, O, E: ParserError<I>>(
name: impl crate::lib::std::fmt::Display,
parser: impl Parser<I, O, E>,
) -> impl Parser<I, O, E> {
#[cfg(feature = "debug")]
{
internals::Trace::new(parser, name)
}
#[cfg(not(feature = "debug"))]
{
parser
}
}
#[cfg_attr(not(feature = "debug"), allow(unused_variables))]
pub(crate) fn trace_result<T, I: Stream, E: ParserError<I>>(
name: impl crate::lib::std::fmt::Display,
res: &Result<T, E>,
) {
#[cfg(feature = "debug")]
{
let depth = internals::Depth::existing();
let severity = internals::Severity::with_result(res);
internals::result(*depth, &name, severity);
}
}
pub(crate) struct DisplayDebug<D>(pub(crate) D);
impl<D: crate::lib::std::fmt::Debug> crate::lib::std::fmt::Display for DisplayDebug<D> {
fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
#[test]
#[cfg(feature = "std")]
#[cfg_attr(miri, ignore)]
#[cfg(unix)]
#[cfg(feature = "debug")]
fn example() {
use term_transcript::{test::TestConfig, ShellOptions};
let path = snapbox::cmd::compile_example("string", ["--features=debug"]).unwrap();
let current_dir = path.parent().unwrap();
let cmd = path.file_name().unwrap();
// HACK: term_transcript doesn't allow non-UTF8 paths
let cmd = format!("./{}", cmd.to_string_lossy());
TestConfig::new(
ShellOptions::default()
.with_current_dir(current_dir)
.with_env("CLICOLOR_FORCE", "1"),
)
.test("assets/trace.svg", [format!(r#"{cmd} '"abc"'"#).as_str()]);
}

800
vendor/winnow/src/combinator/impls.rs vendored Normal file
View File

@@ -0,0 +1,800 @@
//! Opaque implementations of [`Parser`]
use crate::combinator::trace;
use crate::combinator::trace_result;
use crate::combinator::DisplayDebug;
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
use crate::error::FromRecoverableError;
use crate::error::{AddContext, FromExternalError, ParserError};
use crate::lib::std::borrow::Borrow;
use crate::lib::std::ops::Range;
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
use crate::stream::Recover;
use crate::stream::StreamIsPartial;
use crate::stream::{Location, Stream};
use crate::*;
/// [`Parser`] implementation for [`Parser::by_ref`]
pub struct ByRef<'p, P, I, O, E> {
pub(crate) p: &'p mut P,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<I, O, E, P> Parser<I, O, E> for ByRef<'_, P, I, O, E>
where
P: Parser<I, O, E>,
{
#[inline(always)]
fn parse_next(&mut self, i: &mut I) -> Result<O, E> {
self.p.parse_next(i)
}
}
/// [`Parser`] implementation for [`Parser::map`]
pub struct Map<F, G, I, O, O2, E>
where
F: Parser<I, O, E>,
G: FnMut(O) -> O2,
{
pub(crate) parser: F,
pub(crate) map: G,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) o2: core::marker::PhantomData<O2>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<F, G, I, O, O2, E> Parser<I, O2, E> for Map<F, G, I, O, O2, E>
where
F: Parser<I, O, E>,
G: FnMut(O) -> O2,
{
#[inline]
fn parse_next(&mut self, i: &mut I) -> Result<O2, E> {
match self.parser.parse_next(i) {
Err(e) => Err(e),
Ok(o) => Ok((self.map)(o)),
}
}
}
/// [`Parser`] implementation for [`Parser::try_map`]
pub struct TryMap<F, G, I, O, O2, E, E2>
where
F: Parser<I, O, E>,
G: FnMut(O) -> Result<O2, E2>,
I: Stream,
E: FromExternalError<I, E2>,
E: ParserError<I>,
{
pub(crate) parser: F,
pub(crate) map: G,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) o2: core::marker::PhantomData<O2>,
pub(crate) e: core::marker::PhantomData<E>,
pub(crate) e2: core::marker::PhantomData<E2>,
}
impl<F, G, I, O, O2, E, E2> Parser<I, O2, E> for TryMap<F, G, I, O, O2, E, E2>
where
F: Parser<I, O, E>,
G: FnMut(O) -> Result<O2, E2>,
I: Stream,
E: FromExternalError<I, E2>,
E: ParserError<I>,
{
#[inline]
fn parse_next(&mut self, input: &mut I) -> Result<O2, E> {
let start = input.checkpoint();
let o = self.parser.parse_next(input)?;
let res = (self.map)(o).map_err(|err| {
input.reset(&start);
E::from_external_error(input, err)
});
trace_result("verify", &res);
res
}
}
/// [`Parser`] implementation for [`Parser::verify_map`]
pub struct VerifyMap<F, G, I, O, O2, E>
where
F: Parser<I, O, E>,
G: FnMut(O) -> Option<O2>,
I: Stream,
E: ParserError<I>,
{
pub(crate) parser: F,
pub(crate) map: G,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) o2: core::marker::PhantomData<O2>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<F, G, I, O, O2, E> Parser<I, O2, E> for VerifyMap<F, G, I, O, O2, E>
where
F: Parser<I, O, E>,
G: FnMut(O) -> Option<O2>,
I: Stream,
E: ParserError<I>,
{
#[inline]
fn parse_next(&mut self, input: &mut I) -> Result<O2, E> {
let start = input.checkpoint();
let o = self.parser.parse_next(input)?;
let res = (self.map)(o).ok_or_else(|| {
input.reset(&start);
ParserError::from_input(input)
});
trace_result("verify", &res);
res
}
}
/// [`Parser`] implementation for [`Parser::and_then`]
pub struct AndThen<F, G, I, O, O2, E>
where
F: Parser<I, O, E>,
G: Parser<O, O2, E>,
O: StreamIsPartial,
I: Stream,
{
pub(crate) outer: F,
pub(crate) inner: G,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) o2: core::marker::PhantomData<O2>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<F, G, I, O, O2, E> Parser<I, O2, E> for AndThen<F, G, I, O, O2, E>
where
F: Parser<I, O, E>,
G: Parser<O, O2, E>,
O: StreamIsPartial,
I: Stream,
{
#[inline(always)]
fn parse_next(&mut self, i: &mut I) -> Result<O2, E> {
let start = i.checkpoint();
let mut o = self.outer.parse_next(i)?;
let _ = o.complete();
let o2 = self.inner.parse_next(&mut o).map_err(|err| {
i.reset(&start);
err
})?;
Ok(o2)
}
}
/// [`Parser`] implementation for [`Parser::parse_to`]
pub struct ParseTo<P, I, O, O2, E>
where
P: Parser<I, O, E>,
I: Stream,
O: crate::stream::ParseSlice<O2>,
E: ParserError<I>,
{
pub(crate) p: P,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) o2: core::marker::PhantomData<O2>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<P, I, O, O2, E> Parser<I, O2, E> for ParseTo<P, I, O, O2, E>
where
P: Parser<I, O, E>,
I: Stream,
O: crate::stream::ParseSlice<O2>,
E: ParserError<I>,
{
#[inline]
fn parse_next(&mut self, i: &mut I) -> Result<O2, E> {
let start = i.checkpoint();
let o = self.p.parse_next(i)?;
let res = o.parse_slice().ok_or_else(|| {
i.reset(&start);
ParserError::from_input(i)
});
trace_result("verify", &res);
res
}
}
/// [`Parser`] implementation for [`Parser::flat_map`]
pub struct FlatMap<F, G, H, I, O, O2, E>
where
F: Parser<I, O, E>,
G: FnMut(O) -> H,
H: Parser<I, O2, E>,
{
pub(crate) f: F,
pub(crate) g: G,
pub(crate) h: core::marker::PhantomData<H>,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) o2: core::marker::PhantomData<O2>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<F, G, H, I, O, O2, E> Parser<I, O2, E> for FlatMap<F, G, H, I, O, O2, E>
where
F: Parser<I, O, E>,
G: FnMut(O) -> H,
H: Parser<I, O2, E>,
{
#[inline(always)]
fn parse_next(&mut self, i: &mut I) -> Result<O2, E> {
let o = self.f.parse_next(i)?;
(self.g)(o).parse_next(i)
}
}
/// [`Parser`] implementation for [`Parser::complete_err`]
pub struct CompleteErr<P, I, O, E> {
pub(crate) p: P,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<P, I, O, E> Parser<I, O, E> for CompleteErr<P, I, O, E>
where
P: Parser<I, O, E>,
I: Stream,
E: ParserError<I>,
{
#[inline]
fn parse_next(&mut self, input: &mut I) -> Result<O, E> {
trace("complete_err", |input: &mut I| {
match (self.p).parse_next(input) {
Err(err) => match err.needed() {
Some(_) => Err(ParserError::from_input(input)),
None => Err(err),
},
rest => rest,
}
})
.parse_next(input)
}
}
/// [`Parser`] implementation for [`Parser::verify`]
pub struct Verify<F, G, I, O, O2, E>
where
F: Parser<I, O, E>,
G: FnMut(&O2) -> bool,
I: Stream,
O: Borrow<O2>,
O2: ?Sized,
E: ParserError<I>,
{
pub(crate) parser: F,
pub(crate) filter: G,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) o2: core::marker::PhantomData<O2>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<F, G, I, O, O2, E> Parser<I, O, E> for Verify<F, G, I, O, O2, E>
where
F: Parser<I, O, E>,
G: FnMut(&O2) -> bool,
I: Stream,
O: Borrow<O2>,
O2: ?Sized,
E: ParserError<I>,
{
#[inline]
fn parse_next(&mut self, input: &mut I) -> Result<O, E> {
let start = input.checkpoint();
let o = self.parser.parse_next(input)?;
let res = (self.filter)(o.borrow()).then_some(o).ok_or_else(|| {
input.reset(&start);
ParserError::from_input(input)
});
trace_result("verify", &res);
res
}
}
/// [`Parser`] implementation for [`Parser::value`]
pub struct Value<F, I, O, O2, E>
where
F: Parser<I, O, E>,
O2: Clone,
{
pub(crate) parser: F,
pub(crate) val: O2,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<F, I, O, O2, E> Parser<I, O2, E> for Value<F, I, O, O2, E>
where
F: Parser<I, O, E>,
O2: Clone,
{
#[inline]
fn parse_next(&mut self, input: &mut I) -> Result<O2, E> {
(self.parser).parse_next(input).map(|_| self.val.clone())
}
}
/// [`Parser`] implementation for [`Parser::default_value`]
pub struct DefaultValue<F, I, O, O2, E>
where
F: Parser<I, O, E>,
O2: core::default::Default,
{
pub(crate) parser: F,
pub(crate) o2: core::marker::PhantomData<O2>,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<F, I, O, O2, E> Parser<I, O2, E> for DefaultValue<F, I, O, O2, E>
where
F: Parser<I, O, E>,
O2: core::default::Default,
{
#[inline]
fn parse_next(&mut self, input: &mut I) -> Result<O2, E> {
(self.parser).parse_next(input).map(|_| O2::default())
}
}
/// [`Parser`] implementation for [`Parser::void`]
pub struct Void<F, I, O, E>
where
F: Parser<I, O, E>,
{
pub(crate) parser: F,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<F, I, O, E> Parser<I, (), E> for Void<F, I, O, E>
where
F: Parser<I, O, E>,
{
#[inline(always)]
fn parse_next(&mut self, input: &mut I) -> Result<(), E> {
(self.parser).parse_next(input).map(|_| ())
}
}
/// [`Parser`] implementation for [`Parser::take`]
pub struct Take<F, I, O, E>
where
F: Parser<I, O, E>,
I: Stream,
{
pub(crate) parser: F,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<I, O, E, F> Parser<I, <I as Stream>::Slice, E> for Take<F, I, O, E>
where
F: Parser<I, O, E>,
I: Stream,
{
#[inline]
fn parse_next(&mut self, input: &mut I) -> Result<<I as Stream>::Slice, E> {
let checkpoint = input.checkpoint();
match (self.parser).parse_next(input) {
Ok(_) => {
let offset = input.offset_from(&checkpoint);
input.reset(&checkpoint);
let taken = input.next_slice(offset);
Ok(taken)
}
Err(e) => Err(e),
}
}
}
/// [`Parser`] implementation for [`Parser::with_taken`]
pub struct WithTaken<F, I, O, E>
where
F: Parser<I, O, E>,
I: Stream,
{
pub(crate) parser: F,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<F, I, O, E> Parser<I, (O, <I as Stream>::Slice), E> for WithTaken<F, I, O, E>
where
F: Parser<I, O, E>,
I: Stream,
{
#[inline]
fn parse_next(&mut self, input: &mut I) -> Result<(O, <I as Stream>::Slice), E> {
let checkpoint = input.checkpoint();
match (self.parser).parse_next(input) {
Ok(result) => {
let offset = input.offset_from(&checkpoint);
input.reset(&checkpoint);
let taken = input.next_slice(offset);
Ok((result, taken))
}
Err(e) => Err(e),
}
}
}
/// [`Parser`] implementation for [`Parser::span`]
pub struct Span<F, I, O, E>
where
F: Parser<I, O, E>,
I: Stream + Location,
{
pub(crate) parser: F,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<I, O, E, F> Parser<I, Range<usize>, E> for Span<F, I, O, E>
where
F: Parser<I, O, E>,
I: Stream + Location,
{
#[inline]
fn parse_next(&mut self, input: &mut I) -> Result<Range<usize>, E> {
let start = input.current_token_start();
self.parser.parse_next(input).map(move |_| {
let end = input.previous_token_end();
start..end
})
}
}
/// [`Parser`] implementation for [`Parser::with_span`]
pub struct WithSpan<F, I, O, E>
where
F: Parser<I, O, E>,
I: Stream + Location,
{
pub(crate) parser: F,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<F, I, O, E> Parser<I, (O, Range<usize>), E> for WithSpan<F, I, O, E>
where
F: Parser<I, O, E>,
I: Stream + Location,
{
#[inline]
fn parse_next(&mut self, input: &mut I) -> Result<(O, Range<usize>), E> {
let start = input.current_token_start();
self.parser.parse_next(input).map(move |output| {
let end = input.previous_token_end();
(output, (start..end))
})
}
}
/// [`Parser`] implementation for [`Parser::output_into`]
pub struct OutputInto<F, I, O, O2, E>
where
F: Parser<I, O, E>,
O: Into<O2>,
{
pub(crate) parser: F,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) o2: core::marker::PhantomData<O2>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<F, I, O, O2, E> Parser<I, O2, E> for OutputInto<F, I, O, O2, E>
where
F: Parser<I, O, E>,
O: Into<O2>,
{
#[inline]
fn parse_next(&mut self, i: &mut I) -> Result<O2, E> {
self.parser.parse_next(i).map(|o| o.into())
}
}
/// [`Parser`] implementation for [`Parser::err_into`]
pub struct ErrInto<F, I, O, E, E2>
where
F: Parser<I, O, E>,
E: Into<E2>,
{
pub(crate) parser: F,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) e: core::marker::PhantomData<E>,
pub(crate) e2: core::marker::PhantomData<E2>,
}
impl<F, I, O, E, E2> Parser<I, O, E2> for ErrInto<F, I, O, E, E2>
where
F: Parser<I, O, E>,
E: Into<E2>,
{
#[inline]
fn parse_next(&mut self, i: &mut I) -> Result<O, E2> {
self.parser.parse_next(i).map_err(|err| err.into())
}
}
/// [`Parser`] implementation for [`Parser::context`]
pub struct Context<F, I, O, E, C>
where
F: Parser<I, O, E>,
I: Stream,
E: AddContext<I, C>,
E: ParserError<I>,
C: Clone + crate::lib::std::fmt::Debug,
{
pub(crate) parser: F,
pub(crate) context: C,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) e: core::marker::PhantomData<E>,
}
impl<F, I, O, E, C> Parser<I, O, E> for Context<F, I, O, E, C>
where
F: Parser<I, O, E>,
I: Stream,
E: AddContext<I, C>,
E: ParserError<I>,
C: Clone + crate::lib::std::fmt::Debug,
{
#[inline]
fn parse_next(&mut self, i: &mut I) -> Result<O, E> {
let context = self.context.clone();
trace(DisplayDebug(self.context.clone()), move |i: &mut I| {
let start = i.checkpoint();
(self.parser)
.parse_next(i)
.map_err(|err| err.add_context(i, &start, context.clone()))
})
.parse_next(i)
}
}
/// [`Parser`] implementation for [`Parser::context`]
pub struct ContextWith<P, I, O, E, F, C, FI>
where
P: Parser<I, O, E>,
I: Stream,
E: AddContext<I, C>,
E: ParserError<I>,
F: Fn() -> FI + Clone,
C: crate::lib::std::fmt::Debug,
FI: Iterator<Item = C>,
{
pub(crate) parser: P,
pub(crate) context: F,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) e: core::marker::PhantomData<E>,
pub(crate) c: core::marker::PhantomData<C>,
pub(crate) fi: core::marker::PhantomData<FI>,
}
impl<P, I, O, E, F, C, FI> Parser<I, O, E> for ContextWith<P, I, O, E, F, C, FI>
where
P: Parser<I, O, E>,
I: Stream,
E: AddContext<I, C>,
E: ParserError<I>,
F: Fn() -> FI + Clone,
C: crate::lib::std::fmt::Debug,
FI: Iterator<Item = C>,
{
#[inline]
fn parse_next(&mut self, i: &mut I) -> Result<O, E> {
let context = self.context.clone();
let start = i.checkpoint();
(self.parser).parse_next(i).map_err(|mut err| {
for context in context() {
err = err.add_context(i, &start, context);
}
err
})
}
}
/// [`Parser`] implementation for [`Parser::map_err`]
pub struct MapErr<F, G, I, O, E, E2>
where
F: Parser<I, O, E>,
G: FnMut(E) -> E2,
{
pub(crate) parser: F,
pub(crate) map: G,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) e: core::marker::PhantomData<E>,
pub(crate) e2: core::marker::PhantomData<E2>,
}
impl<F, G, I, O, E, E2> Parser<I, O, E2> for MapErr<F, G, I, O, E, E2>
where
F: Parser<I, O, E>,
G: FnMut(E) -> E2,
{
#[inline]
fn parse_next(&mut self, i: &mut I) -> Result<O, E2> {
match self.parser.parse_next(i) {
Err(e) => Err((self.map)(e)),
Ok(o) => Ok(o),
}
}
}
/// [`Parser`] implementation for [`Parser::retry_after`]
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
pub struct RetryAfter<P, R, I, O, E>
where
P: Parser<I, O, E>,
R: Parser<I, (), E>,
I: Stream,
I: Recover<E>,
E: ParserError<I> + FromRecoverableError<I, E>,
{
pub(crate) parser: P,
pub(crate) recover: R,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) e: core::marker::PhantomData<E>,
}
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
impl<P, R, I, O, E> Parser<I, O, E> for RetryAfter<P, R, I, O, E>
where
P: Parser<I, O, E>,
R: Parser<I, (), E>,
I: Stream,
I: Recover<E>,
E: ParserError<I> + FromRecoverableError<I, E>,
{
#[inline(always)]
fn parse_next(&mut self, i: &mut I) -> Result<O, E> {
if I::is_recovery_supported() {
retry_after_inner(&mut self.parser, &mut self.recover, i)
} else {
self.parser.parse_next(i)
}
}
}
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
fn retry_after_inner<P, R, I, O, E>(parser: &mut P, recover: &mut R, i: &mut I) -> Result<O, E>
where
P: Parser<I, O, E>,
R: Parser<I, (), E>,
I: Stream,
I: Recover<E>,
E: ParserError<I> + FromRecoverableError<I, E>,
{
loop {
let token_start = i.checkpoint();
let mut err = match parser.parse_next(i) {
Ok(o) => {
return Ok(o);
}
Err(e) if e.is_incomplete() => return Err(e),
Err(err) => err,
};
let err_start = i.checkpoint();
let err_start_eof_offset = i.eof_offset();
if recover.parse_next(i).is_ok() {
let i_eof_offset = i.eof_offset();
if err_start_eof_offset == i_eof_offset {
// Didn't advance so bubble the error up
} else if let Err(err_) = i.record_err(&token_start, &err_start, err) {
err = err_;
} else {
continue;
}
}
i.reset(&err_start);
err = E::from_recoverable_error(&token_start, &err_start, i, err);
return Err(err);
}
}
/// [`Parser`] implementation for [`Parser::resume_after`]
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
pub struct ResumeAfter<P, R, I, O, E>
where
P: Parser<I, O, E>,
R: Parser<I, (), E>,
I: Stream,
I: Recover<E>,
E: ParserError<I> + FromRecoverableError<I, E>,
{
pub(crate) parser: P,
pub(crate) recover: R,
pub(crate) i: core::marker::PhantomData<I>,
pub(crate) o: core::marker::PhantomData<O>,
pub(crate) e: core::marker::PhantomData<E>,
}
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
impl<P, R, I, O, E> Parser<I, Option<O>, E> for ResumeAfter<P, R, I, O, E>
where
P: Parser<I, O, E>,
R: Parser<I, (), E>,
I: Stream,
I: Recover<E>,
E: ParserError<I> + FromRecoverableError<I, E>,
{
#[inline(always)]
fn parse_next(&mut self, i: &mut I) -> Result<Option<O>, E> {
if I::is_recovery_supported() {
resume_after_inner(&mut self.parser, &mut self.recover, i)
} else {
self.parser.parse_next(i).map(Some)
}
}
}
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
fn resume_after_inner<P, R, I, O, E>(
parser: &mut P,
recover: &mut R,
i: &mut I,
) -> Result<Option<O>, E>
where
P: Parser<I, O, E>,
R: Parser<I, (), E>,
I: Stream,
I: Recover<E>,
E: ParserError<I> + FromRecoverableError<I, E>,
{
let token_start = i.checkpoint();
let mut err = match parser.parse_next(i) {
Ok(o) => {
return Ok(Some(o));
}
Err(e) if e.is_incomplete() => return Err(e),
Err(err) => err,
};
let err_start = i.checkpoint();
if recover.parse_next(i).is_ok() {
if let Err(err_) = i.record_err(&token_start, &err_start, err) {
err = err_;
} else {
return Ok(None);
}
}
i.reset(&err_start);
err = FromRecoverableError::from_recoverable_error(&token_start, &err_start, i, err);
Err(err)
}

180
vendor/winnow/src/combinator/mod.rs vendored Normal file
View File

@@ -0,0 +1,180 @@
//! # List of parsers and combinators
//!
//! <div class="warning">
//!
//! **Note**: this list is meant to provide a nicer way to find a parser than reading through the documentation on docs.rs. Function combinators are organized in module so they are a bit easier to find.
//!
//! </div>
//!
//! ## Basic elements
//!
//! Those are used to take a series of tokens for the lowest level elements of your grammar, like, "here is a dot", or "here is an big endian integer".
//!
//! | combinator | usage | input | new input | output | comment |
//! |---|---|---|---|---|---|
//! | [`one_of`][crate::token::one_of] | `one_of(['a', 'b', 'c'])` | `"abc"` | `"bc"` | `Ok('a')` |Matches one of the provided [set of tokens][crate::stream::ContainsToken] (works with non ASCII characters too)|
//! | [`none_of`][crate::token::none_of] | `none_of(['a', 'b', 'c'])` | `"xyab"` | `"yab"` | `Ok('x')` |Matches anything but one of the provided [set of tokens][crate::stream::ContainsToken]|
//! | [`literal`][crate::token::literal] | `"hello"` | `"hello world"` | `" world"` | `Ok("hello")` |Recognizes a specific suite of characters or bytes (see also [`Caseless`][crate::ascii::Caseless])|
//! | [`take`][crate::token::take] | `take(4)` | `"hello"` | `"o"` | `Ok("hell")` |Takes a specific number of bytes or characters|
//! | [`take_while`][crate::token::take_while] | `take_while(0.., is_alphabetic)` | `"abc123"` | `"123"` | `Ok("abc")` |Returns the longest slice of bytes or characters for which the provided [set of tokens][crate::stream::ContainsToken] matches.|
//! | [`take_till`][crate::token::take_till] | `take_till(0.., is_alphabetic)` | `"123abc"` | `"abc"` | `Ok("123")` |Returns a slice of bytes or characters until the provided [set of tokens][crate::stream::ContainsToken] matches. This is the reverse behaviour from `take_while`: `take_till(f)` is equivalent to `take_while(0.., \|c\| !f(c))`|
//! | [`take_until`][crate::token::take_until] | `take_until(0.., "world")` | `"Hello world"` | `"world"` | `Ok("Hello ")` |Returns a slice of bytes or characters until the provided [literal][crate::token::literal] is found.|
//!
//! ## Choice combinators
//!
//! | combinator | usage | input | new input | output | comment |
//! |---|---|---|---|---|---|
//! | [`alt`] | `alt(("ab", "cd"))` | `"cdef"` | `"ef"` | `Ok("cd")` |Try a list of parsers and return the result of the first successful one|
//! | [`dispatch`] | \- | \- | \- | \- | `match` for parsers |
//! | [`permutation`] | `permutation(("ab", "cd", "12"))` | `"cd12abc"` | `"c"` | `Ok(("ab", "cd", "12"))` |Succeeds when all its child parser have succeeded, whatever the order|
//!
//! ## Sequence combinators
//!
//! | combinator | usage | input | new input | output | comment |
//! |---|---|---|---|---|---|
//! | [`(...)` (tuples)][crate::Parser] | `("ab", "XY", take(1))` | `"abXYZ!"` | `"!"` | `Ok(("ab", "XY", "Z"))` |Parse a series of values|
//! | [`seq!`] | `seq!(_: '(', take(2), _: ')')` | `"(ab)cd"` | `"cd"` | `Ok("ab")` |Parse a series of values, discarding those you specify|
//! | [`delimited`] | `delimited('(', take(2), ')')` | `"(ab)cd"` | `"cd"` | `Ok("ab")` |Parse three values, discarding the first and third value|
//! | [`preceded`] | `preceded("ab", "XY")` | `"abXYZ"` | `"Z"` | `Ok("XY")` |Parse two values, discarding the first value|
//! | [`terminated`] | `terminated("ab", "XY")` | `"abXYZ"` | `"Z"` | `Ok("ab")` |Parse two values, discarding the second value|
//! | [`separated_pair`] | `separated_pair("hello", ',', "world")` | `"hello,world!"` | `"!"` | `Ok(("hello", "world"))` | Parse three values, discarding the middle value|
//!
//! ## Applying a parser multiple times
//!
//! | combinator | usage | input | new input | output | comment |
//! |---|---|---|---|---|---|
//! | [`repeat`] | `repeat(1..=3, "ab")` | `"ababc"` | `"c"` | `Ok(vec!["ab", "ab"])` |Applies the parser between m and n times (n included) and returns the list of results in a Vec|
//! | [`repeat_till`] | `repeat_till(0.., "ab", "ef")` | `"ababefg"` | `"g"` | `Ok((vec!["ab", "ab"], "ef"))` |Applies the first parser until the second applies. Returns a tuple containing the list of results from the first in a Vec and the result of the second|
//! | [`separated`] | `separated(1..=3, "ab", ",")` | `"ab,ab,ab."` | `"."` | `Ok(vec!["ab", "ab", "ab"])` |Applies the parser and separator between m and n times (n included) and returns the list of results in a Vec|
//! | [`Repeat::fold`] | <code>repeat(1..=2, `be_u8`).fold(\|\| 0, \|acc, item\| acc + item)</code> | `[1, 2, 3]` | `[3]` | `Ok(3)` |Applies the parser between m and n times (n included) and folds the list of return value|
//!
//! ## Partial related
//!
//! - [`eof`]: Returns its input if it is at the end of input data
//! - [`Parser::complete_err`]: Replaces an `Incomplete` returned by the child parser with an `Backtrack`
//!
//! ## Modifiers
//!
//! - [`cond`]: Conditional combinator. Wraps another parser and calls it if the condition is met
//! - [`Parser::flat_map`]: method to map a new parser from the output of the first parser, then apply that parser over the rest of the input
//! - [`Parser::value`]: method to replace the result of a parser
//! - [`Parser::default_value`]: method to replace the result of a parser
//! - [`Parser::void`]: method to discard the result of a parser
//! - [`Parser::map`]: method to map a function on the result of a parser
//! - [`Parser::and_then`]: Applies a second parser over the output of the first one
//! - [`Parser::verify_map`]: Maps a function returning an `Option` on the output of a parser
//! - [`Parser::try_map`]: Maps a function returning a `Result` on the output of a parser
//! - [`Parser::parse_to`]: Apply [`std::str::FromStr`] to the output of the parser
//! - [`not`]: Returns a result only if the embedded parser returns `Backtrack` or `Incomplete`. Does not consume the input
//! - [`opt`]: Make the underlying parser optional
//! - [`peek`]: Returns a result without consuming the input
//! - [`Parser::take`]: If the child parser was successful, return the consumed input as the produced value
//! - [`Parser::with_taken`]: If the child parser was successful, return a tuple of the consumed input and the produced output.
//! - [`Parser::span`]: If the child parser was successful, return the location of the consumed input as the produced value
//! - [`Parser::with_span`]: If the child parser was successful, return a tuple of the location of the consumed input and the produced output.
//! - [`Parser::verify`]: Returns the result of the child parser if it satisfies a verification function
//!
//! ## Error management and debugging
//!
//! - [`cut_err`]: Commit the parse result, disallowing alternative parsers from being attempted
//! - [`backtrack_err`]: Attempts a parse, allowing alternative parsers to be attempted despite
//! use of `cut_err`
//! - [`Parser::context`]: Add context to the error if the parser fails
//! - [`trace`]: Print the parse state with the `debug` feature flag
//! - [`todo()`]: Placeholder parser
//!
//! ## Remaining combinators
//!
//! - [`empty`]: Succeed, consuming no input
//! - [`fail`]: Inversion of [`empty`]. Always fails.
//! - [`Parser::by_ref`]: Allow moving `&mut impl Parser` into other parsers
//!
//! ## Text parsing
//!
//! - [`any`][crate::token::any]: Matches one token
//! - [`tab`][crate::ascii::tab]: Matches a tab character `\t`
//! - [`crlf`][crate::ascii::crlf]: Recognizes the string `\r\n`
//! - [`line_ending`][crate::ascii::line_ending]: Recognizes an end of line (both `\n` and `\r\n`)
//! - [`newline`][crate::ascii::newline]: Matches a newline character `\n`
//! - [`till_line_ending`][crate::ascii::till_line_ending]: Recognizes a string of any char except `\r` or `\n`
//! - [`rest`][crate::token::rest]: Return the remaining input
//!
//! - [`alpha0`][crate::ascii::alpha0]: Recognizes zero or more lowercase and uppercase alphabetic characters: `[a-zA-Z]`. [`alpha1`][crate::ascii::alpha1] does the same but returns at least one character
//! - [`alphanumeric0`][crate::ascii::alphanumeric0]: Recognizes zero or more numerical and alphabetic characters: `[0-9a-zA-Z]`. [`alphanumeric1`][crate::ascii::alphanumeric1] does the same but returns at least one character
//! - [`space0`][crate::ascii::space0]: Recognizes zero or more spaces and tabs. [`space1`][crate::ascii::space1] does the same but returns at least one character
//! - [`multispace0`][crate::ascii::multispace0]: Recognizes zero or more spaces, tabs, carriage returns and line feeds. [`multispace1`][crate::ascii::multispace1] does the same but returns at least one character
//! - [`digit0`][crate::ascii::digit0]: Recognizes zero or more numerical characters: `[0-9]`. [`digit1`][crate::ascii::digit1] does the same but returns at least one character
//! - [`hex_digit0`][crate::ascii::hex_digit0]: Recognizes zero or more hexadecimal numerical characters: `[0-9A-Fa-f]`. [`hex_digit1`][crate::ascii::hex_digit1] does the same but returns at least one character
//! - [`oct_digit0`][crate::ascii::oct_digit0]: Recognizes zero or more octal characters: `[0-7]`. [`oct_digit1`][crate::ascii::oct_digit1] does the same but returns at least one character
//!
//! - [`float`][crate::ascii::float]: Parse a floating point number in a byte string
//! - [`dec_int`][crate::ascii::dec_int]: Decode a variable-width, decimal signed integer
//! - [`dec_uint`][crate::ascii::dec_uint]: Decode a variable-width, decimal unsigned integer
//! - [`hex_uint`][crate::ascii::hex_uint]: Decode a variable-width, hexadecimal integer
//!
//! - [`take_escaped`][crate::ascii::take_escaped]: Recognize the input slice with escaped characters
//! - [`escaped_transform`][crate::ascii::escaped_transform]: Parse escaped characters, unescaping them
//!
//! ### Character test functions
//!
//! Use these functions with a combinator like `take_while`:
//!
//! - [`AsChar::is_alpha`][crate::stream::AsChar::is_alpha]: Tests if byte is ASCII alphabetic: `[A-Za-z]`
//! - [`AsChar::is_alphanum`][crate::stream::AsChar::is_alphanum]: Tests if byte is ASCII alphanumeric: `[A-Za-z0-9]`
//! - [`AsChar::is_dec_digit`][crate::stream::AsChar::is_dec_digit]: Tests if byte is ASCII digit: `[0-9]`
//! - [`AsChar::is_hex_digit`][crate::stream::AsChar::is_hex_digit]: Tests if byte is ASCII hex digit: `[0-9A-Fa-f]`
//! - [`AsChar::is_oct_digit`][crate::stream::AsChar::is_oct_digit]: Tests if byte is ASCII octal digit: `[0-7]`
//! - [`AsChar::is_space`][crate::stream::AsChar::is_space]: Tests if byte is ASCII space or tab: `[ \t]`
//! - [`AsChar::is_newline`][crate::stream::AsChar::is_newline]: Tests if byte is ASCII newline: `[\n]`
//!
//! ## Binary format parsing
//!
//! - [`length_repeat`][crate::binary::length_repeat] Gets a number from the first parser, then applies the second parser that many times
//! - [`length_take`][crate::binary::length_take]: Gets a number from the first parser, then takes a subslice of the input of that size, and returns that subslice
//! - [`length_and_then`][crate::binary::length_and_then]: Gets a number from the first parser, takes a subslice of the input of that size, then applies the second parser on that subslice. If the second parser returns `Incomplete`, `length_value` will return an error
//!
//! ### Integers
//!
//! Parsing integers from binary formats can be done in two ways: With parser functions, or combinators with configurable endianness.
//!
//! - **configurable endianness:** [`i16`][crate::binary::i16], [`i32`][crate::binary::i32],
//! [`i64`][crate::binary::i64], [`u16`][crate::binary::u16], [`u32`][crate::binary::u32],
//! [`u64`][crate::binary::u64] are combinators that take as argument a
//! [`winnow::binary::Endianness`][crate::binary::Endianness], like this: `i16(endianness)`. If the
//! parameter is `winnow::binary::Endianness::Big`, parse a big endian `i16` integer, otherwise a
//! little endian `i16` integer.
//! - **fixed endianness**: The functions are prefixed by `be_` for big endian numbers, and by `le_` for little endian numbers, and the suffix is the type they parse to. As an example, `be_u32` parses a big endian unsigned integer stored in 32 bits.
//! - [`be_f32`][crate::binary::be_f32], [`be_f64`][crate::binary::be_f64]: Big endian floating point numbers
//! - [`le_f32`][crate::binary::le_f32], [`le_f64`][crate::binary::le_f64]: Little endian floating point numbers
//! - [`be_i8`][crate::binary::be_i8], [`be_i16`][crate::binary::be_i16], [`be_i24`][crate::binary::be_i24], [`be_i32`][crate::binary::be_i32], [`be_i64`][crate::binary::be_i64], [`be_i128`][crate::binary::be_i128]: Big endian signed integers
//! - [`be_u8`][crate::binary::be_u8], [`be_u16`][crate::binary::be_u16], [`be_u24`][crate::binary::be_u24], [`be_u32`][crate::binary::be_u32], [`be_u64`][crate::binary::be_u64], [`be_u128`][crate::binary::be_u128]: Big endian unsigned integers
//! - [`le_i8`][crate::binary::le_i8], [`le_i16`][crate::binary::le_i16], [`le_i24`][crate::binary::le_i24], [`le_i32`][crate::binary::le_i32], [`le_i64`][crate::binary::le_i64], [`le_i128`][crate::binary::le_i128]: Little endian signed integers
//! - [`le_u8`][crate::binary::le_u8], [`le_u16`][crate::binary::le_u16], [`le_u24`][crate::binary::le_u24], [`le_u32`][crate::binary::le_u32], [`le_u64`][crate::binary::le_u64], [`le_u128`][crate::binary::le_u128]: Little endian unsigned integers
//!
//! ### Bit stream parsing
//!
//! - [`bits`][crate::binary::bits::bits]: Transforms the current input type (byte slice `&[u8]`) to a bit stream on which bit specific parsers and more general combinators can be applied
//! - [`bytes`][crate::binary::bits::bytes]: Transforms its bits stream input back into a byte slice for the underlying parser
//! - [`take`][crate::binary::bits::take]: Take a set number of bits
//! - [`pattern`][crate::binary::bits::pattern]: Check if a set number of bits matches a pattern
//! - [`bool`][crate::binary::bits::bool]: Match any one bit
mod branch;
mod core;
mod debug;
mod multi;
mod sequence;
#[cfg(test)]
mod tests;
pub mod impls;
pub use self::branch::*;
pub use self::core::*;
pub use self::debug::*;
pub use self::multi::*;
pub use self::sequence::*;
#[allow(unused_imports)]
use crate::Parser;

1534
vendor/winnow/src/combinator/multi.rs vendored Normal file

File diff suppressed because it is too large Load Diff

174
vendor/winnow/src/combinator/sequence.rs vendored Normal file
View File

@@ -0,0 +1,174 @@
use crate::combinator::trace;
use crate::error::ParserError;
use crate::stream::Stream;
use crate::*;
#[doc(inline)]
pub use crate::seq;
/// Sequence two parsers, only returning the output from the second.
///
/// See also [`seq`] to generalize this across any number of fields.
///
/// # Example
///
/// ```rust
/// # use winnow::{error::ErrMode, error::Needed};
/// # use winnow::prelude::*;
/// # use winnow::error::Needed::Size;
/// use winnow::combinator::preceded;
///
/// fn parser<'i>(input: &mut &'i str) -> ModalResult<&'i str> {
/// preceded("abc", "efg").parse_next(input)
/// }
///
/// assert_eq!(parser.parse_peek("abcefg"), Ok(("", "efg")));
/// assert_eq!(parser.parse_peek("abcefghij"), Ok(("hij", "efg")));
/// assert!(parser.parse_peek("").is_err());
/// assert!(parser.parse_peek("123").is_err());
/// ```
#[doc(alias = "ignore_then")]
pub fn preceded<Input, Ignored, Output, Error, IgnoredParser, ParseNext>(
mut ignored: IgnoredParser,
mut parser: ParseNext,
) -> impl Parser<Input, Output, Error>
where
Input: Stream,
Error: ParserError<Input>,
IgnoredParser: Parser<Input, Ignored, Error>,
ParseNext: Parser<Input, Output, Error>,
{
trace("preceded", move |input: &mut Input| {
let _ = ignored.parse_next(input)?;
parser.parse_next(input)
})
}
/// Sequence two parsers, only returning the output of the first.
///
/// See also [`seq`] to generalize this across any number of fields.
///
/// # Example
///
/// ```rust
/// # use winnow::{error::ErrMode, error::Needed};
/// # use winnow::prelude::*;
/// # use winnow::error::Needed::Size;
/// use winnow::combinator::terminated;
///
/// fn parser<'i>(input: &mut &'i str) -> ModalResult<&'i str> {
/// terminated("abc", "efg").parse_next(input)
/// }
///
/// assert_eq!(parser.parse_peek("abcefg"), Ok(("", "abc")));
/// assert_eq!(parser.parse_peek("abcefghij"), Ok(("hij", "abc")));
/// assert!(parser.parse_peek("").is_err());
/// assert!(parser.parse_peek("123").is_err());
/// ```
#[doc(alias = "then_ignore")]
pub fn terminated<Input, Output, Ignored, Error, ParseNext, IgnoredParser>(
mut parser: ParseNext,
mut ignored: IgnoredParser,
) -> impl Parser<Input, Output, Error>
where
Input: Stream,
Error: ParserError<Input>,
ParseNext: Parser<Input, Output, Error>,
IgnoredParser: Parser<Input, Ignored, Error>,
{
trace("terminated", move |input: &mut Input| {
let o = parser.parse_next(input)?;
ignored.parse_next(input).map(|_| o)
})
}
/// Sequence three parsers, only returning the values of the first and third.
///
/// See also [`seq`] to generalize this across any number of fields.
///
/// # Example
///
/// ```rust
/// # use winnow::{error::ErrMode, error::Needed};
/// # use winnow::error::Needed::Size;
/// # use winnow::prelude::*;
/// use winnow::combinator::separated_pair;
///
/// fn parser<'i>(input: &mut &'i str) -> ModalResult<(&'i str, &'i str)> {
/// separated_pair("abc", "|", "efg").parse_next(input)
/// }
///
/// assert_eq!(parser.parse_peek("abc|efg"), Ok(("", ("abc", "efg"))));
/// assert_eq!(parser.parse_peek("abc|efghij"), Ok(("hij", ("abc", "efg"))));
/// assert!(parser.parse_peek("").is_err());
/// assert!(parser.parse_peek("123").is_err());
/// ```
pub fn separated_pair<Input, O1, Sep, O2, Error, P1, SepParser, P2>(
mut first: P1,
mut sep: SepParser,
mut second: P2,
) -> impl Parser<Input, (O1, O2), Error>
where
Input: Stream,
Error: ParserError<Input>,
P1: Parser<Input, O1, Error>,
SepParser: Parser<Input, Sep, Error>,
P2: Parser<Input, O2, Error>,
{
trace("separated_pair", move |input: &mut Input| {
let o1 = first.parse_next(input)?;
let _ = sep.parse_next(input)?;
second.parse_next(input).map(|o2| (o1, o2))
})
}
/// Sequence three parsers, only returning the output of the second.
///
/// See also [`seq`] to generalize this across any number of fields.
///
/// # Example
///
/// ```rust
/// # use winnow::{error::ErrMode, error::Needed};
/// # use winnow::error::Needed::Size;
/// # use winnow::prelude::*;
/// use winnow::combinator::delimited;
///
/// fn parser<'i>(input: &mut &'i str) -> ModalResult<&'i str> {
/// delimited("(", "abc", ")").parse_next(input)
/// }
///
/// assert_eq!(parser.parse_peek("(abc)"), Ok(("", "abc")));
/// assert_eq!(parser.parse_peek("(abc)def"), Ok(("def", "abc")));
/// assert!(parser.parse_peek("").is_err());
/// assert!(parser.parse_peek("123").is_err());
/// ```
#[doc(alias = "between")]
#[doc(alias = "padded")]
pub fn delimited<
Input,
Ignored1,
Output,
Ignored2,
Error,
IgnoredParser1,
ParseNext,
IgnoredParser2,
>(
mut ignored1: IgnoredParser1,
mut parser: ParseNext,
mut ignored2: IgnoredParser2,
) -> impl Parser<Input, Output, Error>
where
Input: Stream,
Error: ParserError<Input>,
IgnoredParser1: Parser<Input, Ignored1, Error>,
ParseNext: Parser<Input, Output, Error>,
IgnoredParser2: Parser<Input, Ignored2, Error>,
{
trace("delimited", move |input: &mut Input| {
let _ = ignored1.parse_next(input)?;
let o2 = parser.parse_next(input)?;
ignored2.parse_next(input).map(|_| o2)
})
}

4034
vendor/winnow/src/combinator/tests.rs vendored Normal file

File diff suppressed because it is too large Load Diff

1582
vendor/winnow/src/error.rs vendored Normal file

File diff suppressed because it is too large Load Diff

207
vendor/winnow/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,207 @@
//! > winnow, making parsing a breeze
//!
//! `winnow` is a parser combinator library
//!
//! Quick links:
//! - [List of combinators][crate::combinator]
//! - [Tutorial][_tutorial::chapter_0]
//! - [Special Topics][_topic]
//! - [Discussions](https://github.com/winnow-rs/winnow/discussions)
//! - [CHANGELOG](https://github.com/winnow-rs/winnow/blob/v0.7.13/CHANGELOG.md) (includes major version migration
//! guides)
//!
//! ## Aspirations
//!
//! `winnow` aims to be your "do everything" parser, much like people treat regular expressions.
//!
//! In roughly priority order:
//! 1. Support writing parser declaratively while not getting in the way of imperative-style
//! parsing when needed, working as an open-ended toolbox rather than a close-ended framework.
//! 2. Flexible enough to be used for any application, including parsing strings, binary data,
//! or separate [lexing and parsing phases][_topic::lexing]
//! 3. Zero-cost abstractions, making it easy to write high performance parsers
//! 4. Easy to use, making it trivial for one-off uses
//!
//! In addition:
//! - Resilient maintainership, including
//! - Willing to break compatibility rather than batching up breaking changes in large releases
//! - Leverage feature flags to keep one active branch
//! - We will support the last 6 months of rust releases (MSRV, currently 1.64.0)
//!
//! See also [Special Topic: Why winnow?][crate::_topic::why]
//!
//! ## Example
//!
//! Run
//! ```console
//! $ cargo add winnow
//! ```
//!
//! Then use it to parse:
//! ```rust
//! # #[cfg(feature = "alloc")] {
#![doc = include_str!("../examples/css/parser.rs")]
//! # }
//! ```
//!
//! See also the [Tutorial][_tutorial::chapter_0] and [Special Topics][_topic]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, feature(extended_key_value_attributes))]
#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
#![warn(missing_docs)]
#![warn(clippy::std_instead_of_core)]
#![warn(clippy::std_instead_of_alloc)]
#![warn(clippy::print_stderr)]
#![warn(clippy::print_stdout)]
#[cfg(feature = "alloc")]
#[cfg_attr(test, macro_use)]
#[allow(unused_extern_crates)]
extern crate alloc;
#[doc = include_str!("../README.md")]
#[cfg(doctest)]
pub struct ReadmeDoctests;
/// Lib module to re-export everything needed from `std` or `core`/`alloc`. This is how `serde` does
/// it, albeit there it is not public.
#[doc(hidden)]
pub(crate) mod lib {
#![allow(unused_imports)]
/// `std` facade allowing `std`/`core` to be interchangeable. Reexports `alloc` crate optionally,
/// as well as `core` or `std`
#[cfg(not(feature = "std"))]
/// internal std exports for no_std compatibility
pub(crate) mod std {
#[doc(hidden)]
#[cfg(not(feature = "alloc"))]
pub(crate) use core::borrow;
#[cfg(feature = "alloc")]
#[doc(hidden)]
pub(crate) use alloc::{borrow, boxed, collections, string, vec};
#[doc(hidden)]
pub(crate) use core::{
cmp, convert, fmt, hash, iter, mem, ops, option, result, slice, str,
};
}
#[cfg(feature = "std")]
/// internal std exports for `no_std` compatibility
pub(crate) mod std {
#![allow(clippy::std_instead_of_core)]
#![allow(clippy::std_instead_of_alloc)]
#[doc(hidden)]
pub(crate) use std::{
borrow, boxed, cmp, collections, convert, fmt, hash, iter, mem, ops, result, slice,
str, string, vec,
};
}
}
pub(crate) mod util {
#[allow(dead_code)]
pub(crate) fn from_fn<F: Fn(&mut core::fmt::Formatter<'_>) -> core::fmt::Result>(
f: F,
) -> FromFn<F> {
FromFn(f)
}
pub(crate) struct FromFn<F>(F)
where
F: Fn(&mut core::fmt::Formatter<'_>) -> core::fmt::Result;
impl<F> core::fmt::Debug for FromFn<F>
where
F: Fn(&mut core::fmt::Formatter<'_>) -> core::fmt::Result,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
(self.0)(f)
}
}
impl<F> core::fmt::Display for FromFn<F>
where
F: Fn(&mut core::fmt::Formatter<'_>) -> core::fmt::Result,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
(self.0)(f)
}
}
}
#[macro_use]
mod macros;
#[macro_use]
pub mod error;
mod parser;
pub mod stream;
pub mod ascii;
pub mod binary;
pub mod combinator;
pub mod token;
#[cfg(feature = "unstable-doc")]
pub mod _topic;
#[cfg(feature = "unstable-doc")]
pub mod _tutorial;
/// Core concepts available for glob import
///
/// Including
/// - [`StreamIsPartial`][crate::stream::StreamIsPartial]
/// - [`Parser`]
///
/// ## Example
///
/// ```rust
/// use winnow::prelude::*;
///
/// fn parse_data(input: &mut &str) -> ModalResult<u64> {
/// // ...
/// # winnow::ascii::dec_uint(input)
/// }
///
/// fn main() {
/// let result = parse_data.parse("100");
/// assert_eq!(result, Ok(100));
/// }
/// ```
pub mod prelude {
pub use crate::error::ModalError as _;
pub use crate::error::ParserError as _;
pub use crate::stream::AsChar as _;
pub use crate::stream::ContainsToken as _;
pub use crate::stream::Stream as _;
pub use crate::stream::StreamIsPartial as _;
pub use crate::ModalParser;
pub use crate::ModalResult;
pub use crate::Parser;
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
pub use crate::RecoverableParser as _;
#[cfg(test)]
pub(crate) use crate::TestResult;
}
pub use error::ModalResult;
pub use error::Result;
pub use parser::*;
pub use stream::BStr;
pub use stream::Bytes;
pub use stream::LocatingSlice;
pub use stream::Partial;
pub use stream::Stateful;
pub use stream::Str;
#[cfg(test)]
pub(crate) use error::TestResult;

92
vendor/winnow/src/macros/dispatch.rs vendored Normal file
View File

@@ -0,0 +1,92 @@
/// `match` for parsers
///
/// While `match` works by accepting a value and returning values:
/// ```rust,ignore
/// let result_value = match scrutinee_value {
/// ArmPattern => arm_value,
/// };
/// ```
/// `dispatch!` composes parsers:
/// ```rust,ignore
/// let result_parser = dispatch!{scrutinee_parser;
/// ArmPattern => arm_parser,
/// };
/// ```
///
/// This is useful when parsers have unique prefixes to test for.
/// This offers better performance over
/// [`alt`][crate::combinator::alt] though it might be at the cost of duplicating parts of your grammar
/// if you needed to [`peek(input_parser)`][crate::combinator::peek] the scrutinee.
///
/// For tight control over the error in a catch-all case, use [`fail`][crate::combinator::fail].
///
/// # Example
///
/// ```rust
/// use winnow::prelude::*;
/// use winnow::combinator::dispatch;
/// # use winnow::token::take;
/// # use winnow::token::take_while;
/// # use winnow::combinator::fail;
///
/// fn integer(input: &mut &str) -> ModalResult<u64> {
/// dispatch! {take(2usize);
/// "0b" => take_while(1.., '0'..='1').try_map(|s| u64::from_str_radix(s, 2)),
/// "0o" => take_while(1.., '0'..='7').try_map(|s| u64::from_str_radix(s, 8)),
/// "0d" => take_while(1.., '0'..='9').try_map(|s| u64::from_str_radix(s, 10)),
/// "0x" => take_while(1.., ('0'..='9', 'a'..='f', 'A'..='F')).try_map(|s| u64::from_str_radix(s, 16)),
/// _ => fail::<_, u64, _>,
/// }
/// .parse_next(input)
/// }
///
/// assert_eq!(integer.parse_peek("0x100 Hello"), Ok((" Hello", 0x100)));
/// ```
///
/// ```rust
/// use winnow::prelude::*;
/// use winnow::combinator::dispatch;
/// # use winnow::token::any;
/// # use winnow::combinator::preceded;
/// # use winnow::combinator::empty;
/// # use winnow::combinator::fail;
///
/// fn escaped(input: &mut &str) -> ModalResult<char> {
/// preceded('\\', escape_seq_char).parse_next(input)
/// }
///
/// fn escape_seq_char(input: &mut &str) -> ModalResult<char> {
/// dispatch! {any;
/// 'b' => empty.value('\u{8}'),
/// 'f' => empty.value('\u{c}'),
/// 'n' => empty.value('\n'),
/// 'r' => empty.value('\r'),
/// 't' => empty.value('\t'),
/// '\\' => empty.value('\\'),
/// '"' => empty.value('"'),
/// _ => fail::<_, char, _>,
/// }
/// .parse_next(input)
/// }
///
/// assert_eq!(escaped.parse_peek("\\nHello"), Ok(("Hello", '\n')));
/// ```
#[macro_export]
#[doc(hidden)] // forced to be visible in intended location
macro_rules! dispatch {
(
$scrutinee_parser:expr;
$( $arm_pat:pat $(if $arm_pred:expr)? => $arm_parser: expr ),+ $(,)?
) => {
$crate::combinator::trace("dispatch", move |i: &mut _|
{
use $crate::Parser;
let initial = $scrutinee_parser.parse_next(i)?;
match initial {
$(
$arm_pat $(if $arm_pred)? => $arm_parser.parse_next(i),
)*
}
})
}
}

57
vendor/winnow/src/macros/mod.rs vendored Normal file
View File

@@ -0,0 +1,57 @@
mod dispatch;
mod seq;
#[cfg(test)]
macro_rules! assert_parse(
($left: expr, $right: expr) => {
let res: $crate::error::ModalResult<_, $crate::error::InputError<_>> = $left;
snapbox::assert_data_eq!(snapbox::data::ToDebug::to_debug(&res), $right);
};
);
macro_rules! impl_partial_eq {
($lhs:ty, $rhs:ty) => {
#[allow(unused_lifetimes)]
impl<'a> PartialEq<$rhs> for $lhs {
#[inline]
fn eq(&self, other: &$rhs) -> bool {
let l = self;
let r: &Self = other.as_ref();
PartialEq::eq(l, r)
}
}
#[allow(unused_lifetimes)]
impl<'a> PartialEq<$lhs> for $rhs {
#[inline]
fn eq(&self, other: &$lhs) -> bool {
PartialEq::eq(other, self)
}
}
};
}
macro_rules! impl_partial_ord {
($lhs:ty, $rhs:ty) => {
#[allow(unused_lifetimes)]
impl<'a> PartialOrd<$rhs> for $lhs {
#[inline]
fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
let l = self;
let r: &Self = other.as_ref();
PartialOrd::partial_cmp(l, r)
}
}
#[allow(unused_lifetimes)]
impl<'a> PartialOrd<$lhs> for $rhs {
#[inline]
fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
PartialOrd::partial_cmp(other, self)
}
}
};
}
#[cfg(test)]
mod tests;

334
vendor/winnow/src/macros/seq.rs vendored Normal file
View File

@@ -0,0 +1,334 @@
/// Initialize a struct or tuple out of a sequences of parsers
///
/// Unlike normal struct initialization syntax:
/// - `_` fields can exist to run a parser but ignore the result
/// - Parse results for a field can later be referenced using the field name
///
/// Unlike normal tuple initialization syntax:
/// - Struct-style initialization (`{ 0: _, 1: _}`) is not supported
/// - `_: <parser>` fields can exist to run a parser but ignore the result
///
///# Example
///
/// ```
/// # use winnow::prelude::*;
/// # use winnow::ascii::{alphanumeric1, dec_uint, space0};
/// # use winnow::combinator::delimited;
/// # use winnow::combinator::empty;
/// # use winnow::error::ContextError;
/// # use winnow::error::ErrMode;
/// use winnow::combinator::seq;
///
/// #[derive(Default, Debug, PartialEq)]
/// struct Field {
/// namespace: u32,
/// name: Vec<u8>,
/// value: Vec<u8>,
/// point: (u32, u32),
/// metadata: Vec<u8>,
/// }
///
/// // Parse into structs / tuple-structs
/// fn field(input: &mut &[u8]) -> ModalResult<Field> {
/// seq!{Field {
/// namespace: empty.value(5),
/// name: alphanumeric1.map(|s: &[u8]| s.to_owned()),
/// // `_` fields are ignored when building the struct
/// _: (space0, b':', space0),
/// value: alphanumeric1.map(|s: &[u8]| s.to_owned()),
/// _: (space0, b':', space0),
/// point: point,
/// // default initialization also works
/// ..Default::default()
/// }}.parse_next(input)
/// }
///
/// // Or parse into tuples
/// fn point(input: &mut &[u8]) -> ModalResult<(u32, u32)> {
/// let mut num = dec_uint::<_, u32, ErrMode<ContextError>>;
/// seq!(num, _: (space0, b',', space0), num).parse_next(input)
/// }
///
/// assert_eq!(
/// field.parse_peek(&b"test: data: 123 , 4"[..]),
/// Ok((
/// &b""[..],
/// Field {
/// namespace: 5,
/// name: b"test"[..].to_owned(),
/// value: b"data"[..].to_owned(),
/// point: (123, 4),
/// metadata: Default::default(),
/// },
/// )),
/// );
/// ```
#[macro_export]
#[doc(alias = "tuple")]
#[doc(alias = "preceded")]
#[doc(alias = "terminated")]
#[doc(alias = "delimited")]
#[doc(alias = "pair")]
#[doc(alias = "separated_pair")]
#[doc(alias = "struct_parser")]
#[doc(hidden)] // forced to be visible in intended location
macro_rules! seq {
($($name: ident)::* { $($fields: tt)* }) => {
$crate::combinator::trace(stringify!($($name)::*), move |input: &mut _| {
$crate::seq_parse_struct_fields!(
( $($fields)* );
( _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20 );
input ;
);
Ok($crate::seq_init_struct_fields!(
( $($fields)* );
$($name)::* ;
))
})
};
($($name: ident)::* ( $($fields: tt)* )) => {
$crate::combinator::trace(stringify!($($name)::*), move |input: &mut _| {
$crate::seq_parse_tuple_fields!(
( $($fields)* );
( _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20 );
input;
);
Ok($crate::seq_init_tuple_fields!(
( $($fields)* );
( _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20 );
$($name)::*;
))
})
};
(( $($fields: tt)* )) => {
$crate::combinator::trace("tuple", move |input: &mut _| {
$crate::seq_parse_tuple_fields!(
( $($fields)* );
( _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20 );
input;
);
Ok($crate::seq_init_tuple_fields!(
( $($fields)* );
( _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20 );
;
))
})
};
($($fields: tt)*) => {
$crate::seq!((
$($fields)*
))
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! seq_parse_struct_fields {
(
( _ : $head_parser: expr, $($fields: tt)* );
( $unnamed1: ident, $($unnamed: ident),* );
$input: ident ;
) => {
let $unnamed1 = $crate::Parser::parse_next(&mut $head_parser, $input)?;
$crate::seq_parse_struct_fields!(
( $($fields)* );
( $($unnamed),* );
$input ;
)
};
(
( _ : $head_parser: expr );
( $unnamed1: ident, $($unnamed: ident),* );
$input: ident ;
) => {
let $unnamed1 = $crate::Parser::parse_next(&mut $head_parser, $input)?;
};
(
( $head_field: ident : $head_parser: expr, $($fields: tt)* );
( $unnamed1: ident, $($unnamed: ident),* );
$input: ident ;
) => {
let $head_field = $crate::Parser::parse_next(&mut $head_parser, $input)?;
$crate::seq_parse_struct_fields!(
( $($fields)* );
( $($unnamed),* );
$input ;
)
};
(
( $head_field: ident : $head_parser: expr );
( $unnamed1: ident, $($unnamed: ident),* );
$input: ident ;
) => {
let $head_field = $crate::Parser::parse_next(&mut $head_parser, $input)?;
};
(
( .. $update: expr );
( $($unnamed: ident),* );
$input: expr ;
) => {};
(
( $(,)? );
( $($unnamed: ident),* );
$input: expr ;
) => {};
}
#[macro_export]
#[doc(hidden)]
macro_rules! seq_parse_tuple_fields {
(
( $(_ :)? $head_parser: expr, $($fields: tt)* );
( $unnamed1: ident, $($unnamed: ident),* );
$input: ident;
) => {
let $unnamed1 = $crate::Parser::parse_next(&mut $head_parser, $input)?;
$crate::seq_parse_tuple_fields!(
( $($fields)* );
( $($unnamed),* );
$input ;
)
};
(
( $(_ :)? $head_parser: expr );
( $unnamed1: ident, $($unnamed: ident),* );
$input: ident;
) => {
let $unnamed1 = $crate::Parser::parse_next(&mut $head_parser, $input)?;
};
(
( $(,)? );
( $($unnamed: ident),* );
$input: expr;
) => {};
}
#[macro_export]
#[doc(hidden)]
macro_rules! seq_init_struct_fields {
(
( _ : $head_parser: expr, $($fields: tt)* );
$($name: ident)::* ;
$($inits: tt)*
) => {
$crate::seq_init_struct_fields!(
( $($fields)* );
$($name)::* ;
$($inits)*
)
};
(
( _ : $head_parser: expr );
$($name: ident)::* ;
$($inits: tt)*
) => {
$crate::seq_init_struct_fields!(
();
$($name)::* ;
$($inits)*
)
};
(
( $head_field: ident : $head_parser: expr, $($fields: tt)* );
$($name: ident)::* ;
$($inits: tt)*
) =>
{
$crate::seq_init_struct_fields!(
( $($fields)* );
$($name)::* ;
$($inits)* $head_field,
)
};
(
( $head_field: ident : $head_parser: expr );
$($name: ident)::* ;
$($inits: tt)*
) => {
$crate::seq_init_struct_fields!(
();
$($name)::* ;
$($inits)* $head_field,
)
};
(
( .. $update: expr );
$($name: ident)::* ;
$($inits: tt)*
) => {
$($name)::* { $($inits)* ..$update }
};
(
( $(,)? );
$($name: ident)::* ;
$($inits: tt)*
) => {
$($name)::* { $($inits)* }
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! seq_init_tuple_fields {
(
( _ : $head_parser: expr, $($fields: tt)* );
( $unnamed1: ident, $($unnamed: ident),* );
$($name: ident)::*;
$($inits: tt)*
) => {
$crate::seq_init_tuple_fields!(
( $($fields)* );
( $($unnamed),* );
$($name)::* ;
$($inits)*
)
};
(
( _ : $head_parser: expr );
( $unnamed1: ident, $($unnamed: ident),* );
$($name: ident)::*;
$($inits: tt)*
) => {
$crate::seq_init_tuple_fields!(
();
( $($unnamed),* );
$($name)::* ;
$($inits)*
)
};
(
( $head_parser: expr, $($fields: tt)* );
( $unnamed1: ident, $($unnamed: ident),* );
$($name: ident)::*;
$($inits: tt)*
) =>
{
$crate::seq_init_tuple_fields!(
( $($fields)* );
( $($unnamed),* );
$($name)::* ;
$($inits)* $unnamed1,
)
};
(
( $head_parser: expr );
( $unnamed1: ident, $($unnamed: ident),* );
$($name: ident)::*;
$($inits: tt)*
) => {
$crate::seq_init_tuple_fields!(
();
( $($unnamed),* );
$($name)::* ;
$($inits)* $unnamed1,
)
};
(
( $(,)? );
( $unnamed1: ident, $($unnamed: ident),* );
$($name: ident)::*;
$($inits: tt)*
) => {
$($name)::* ( $($inits)* )
};
}

616
vendor/winnow/src/macros/tests.rs vendored Normal file
View File

@@ -0,0 +1,616 @@
use snapbox::prelude::*;
use snapbox::str;
use crate::ascii::dec_uint;
use crate::ascii::digit0;
use crate::combinator::dispatch;
use crate::combinator::empty;
use crate::combinator::fail;
use crate::combinator::seq;
use crate::prelude::*;
use crate::token::any;
#[test]
fn dispatch_basics() {
fn escape_seq_char<'i>(input: &mut &'i str) -> TestResult<&'i str, char> {
dispatch! {any;
'b' => empty.value('\u{8}'),
'f' => empty.value('\u{c}'),
'n' => empty.value('\n'),
'r' => empty.value('\r'),
't' => empty.value('\t'),
'\\' => empty.value('\\'),
'"' => empty.value('"'),
_ => fail::<_, char, _>,
}
.parse_next(input)
}
assert_parse!(
escape_seq_char.parse_peek("b123"),
str![[r#"
Ok(
(
"123",
'\u{8}',
),
)
"#]]
.raw()
);
assert_parse!(
escape_seq_char.parse_peek("error"),
str![[r#"
Err(
Backtrack(
InputError {
input: "rror",
},
),
)
"#]]
.raw()
);
assert_parse!(
escape_seq_char.parse_peek(""),
str![[r#"
Err(
Backtrack(
InputError {
input: "",
},
),
)
"#]]
.raw()
);
}
#[test]
fn seq_struct_basics() {
#[derive(Debug, PartialEq)]
struct Point {
x: u32,
y: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint,
}
}
.parse_next(input)
}
assert_parse!(
parser.parse_peek("123,4 remaining"),
str![[r#"
Ok(
(
" remaining",
Point {
x: 123,
y: 4,
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek("123, remaining"),
str![[r#"
Err(
Backtrack(
InputError {
input: " remaining",
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek(""),
str![[r#"
Err(
Backtrack(
InputError {
input: "",
},
),
)
"#]]
.raw()
);
}
#[test]
fn seq_struct_default_init() {
#[derive(Debug, PartialEq, Default)]
struct Point {
x: u32,
y: u32,
z: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint,
..Default::default()
}
}
.parse_next(input)
}
assert_parse!(
parser.parse_peek("123,4 remaining"),
str![[r#"
Ok(
(
" remaining",
Point {
x: 123,
y: 4,
z: 0,
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek("123, remaining"),
str![[r#"
Err(
Backtrack(
InputError {
input: " remaining",
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek(""),
str![[r#"
Err(
Backtrack(
InputError {
input: "",
},
),
)
"#]]
.raw()
);
}
#[test]
fn seq_struct_trailing_comma_elided() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point {
x: u32,
y: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint,
_: empty,
}
}
.parse_next(input)
}
}
#[test]
fn seq_struct_no_trailing_comma() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point {
x: u32,
y: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint
}
}
.parse_next(input)
}
}
#[test]
fn seq_struct_no_trailing_comma_elided() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point {
x: u32,
y: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint,
_: empty
}
}
.parse_next(input)
}
}
#[test]
fn seq_enum_struct_variant() {
#[derive(Debug, PartialEq, Eq)]
enum Expr {
Add { lhs: u32, rhs: u32 },
Mul(u32, u32),
}
fn add<'i>(input: &mut &'i [u8]) -> TestResult<&'i [u8], Expr> {
seq! {Expr::Add {
lhs: dec_uint::<_, u32, _>,
_: b" + ",
rhs: dec_uint::<_, u32, _>,
}}
.parse_next(input)
}
fn mul<'i>(input: &mut &'i [u8]) -> TestResult<&'i [u8], Expr> {
seq!(Expr::Mul(
dec_uint::<_, u32, _>,
_: b" * ",
dec_uint::<_, u32, _>,
))
.parse_next(input)
}
assert_parse!(
add.parse_peek(&b"1 + 2"[..]),
str![[r#"
Ok(
(
[],
Add {
lhs: 1,
rhs: 2,
},
),
)
"#]]
.raw()
);
assert_parse!(
mul.parse_peek(&b"3 * 4"[..]),
str![[r#"
Ok(
(
[],
Mul(
3,
4,
),
),
)
"#]]
.raw()
);
}
#[test]
fn seq_struct_borrow() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point {
x: u32,
y: u32,
}
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
let mut dec_uint = digit0.parse_to();
seq! {
Point {
x: dec_uint,
_: ',',
y: dec_uint,
_: empty
}
}
.parse_next(input)
}
}
#[test]
fn seq_tuple_struct_basics() {
#[derive(Debug, PartialEq)]
struct Point(u32, u32);
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point(
dec_uint,
_: ',',
dec_uint,
)
}
.parse_next(input)
}
assert_parse!(
parser.parse_peek("123,4 remaining"),
str![[r#"
Ok(
(
" remaining",
Point(
123,
4,
),
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek("123, remaining"),
str![[r#"
Err(
Backtrack(
InputError {
input: " remaining",
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek(""),
str![[r#"
Err(
Backtrack(
InputError {
input: "",
},
),
)
"#]]
.raw()
);
}
#[test]
fn seq_tuple_struct_trailing_comma_elided() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point(u32, u32);
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point(
dec_uint,
_: ',',
dec_uint,
_: empty,
)
}
.parse_next(input)
}
}
#[test]
fn seq_tuple_struct_no_trailing_comma() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point(u32, u32);
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point(
dec_uint,
_: ',',
dec_uint
)
}
.parse_next(input)
}
}
#[test]
fn seq_tuple_struct_no_trailing_comma_elided() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point(u32, u32);
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
seq! {
Point(
dec_uint,
_: ',',
dec_uint,
_: empty
)
}
.parse_next(input)
}
}
#[test]
fn seq_tuple_basics() {
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
seq! {
(
dec_uint,
_: ',',
dec_uint,
)
}
.parse_next(input)
}
assert_parse!(
parser.parse_peek("123,4 remaining"),
str![[r#"
Ok(
(
" remaining",
(
123,
4,
),
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek("123, remaining"),
str![[r#"
Err(
Backtrack(
InputError {
input: " remaining",
},
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek(""),
str![[r#"
Err(
Backtrack(
InputError {
input: "",
},
),
)
"#]]
.raw()
);
}
#[test]
fn seq_tuple_trailing_comma_elided() {
#![allow(dead_code)]
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
seq! {
(
dec_uint,
_: ',',
dec_uint,
_: empty,
)
}
.parse_next(input)
}
}
#[test]
fn seq_tuple_no_trailing_comma() {
#![allow(dead_code)]
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
seq! {
(
dec_uint,
_: ',',
dec_uint
)
}
.parse_next(input)
}
}
#[test]
fn seq_tuple_no_trailing_comma_elided() {
#![allow(dead_code)]
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
seq! {
(
dec_uint,
_: ',',
dec_uint,
_: empty
)
}
.parse_next(input)
}
}
#[test]
fn seq_tuple_no_parens() {
#![allow(dead_code)]
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, (u32, u32)> {
seq! (
dec_uint,
_: ',',
dec_uint,
)
.parse_next(input)
}
}
#[test]
fn seq_tuple_borrow() {
#![allow(dead_code)]
#[derive(Debug, PartialEq)]
struct Point(u32, u32);
fn parser<'i>(input: &mut &'i str) -> TestResult<&'i str, Point> {
let mut dec_uint = digit0.parse_to();
seq! {
Point(
dec_uint,
_: ',',
dec_uint,
_: empty
)
}
.parse_next(input)
}
}

1592
vendor/winnow/src/parser.rs vendored Normal file

File diff suppressed because it is too large Load Diff

541
vendor/winnow/src/stream/bstr.rs vendored Normal file
View File

@@ -0,0 +1,541 @@
use core::num::NonZeroUsize;
use crate::error::Needed;
use crate::lib::std::iter::{Cloned, Enumerate};
use crate::lib::std::slice::Iter;
use crate::lib::std::{cmp::Ordering, fmt, ops};
use crate::stream::AsBStr;
use crate::stream::Checkpoint;
use crate::stream::Compare;
use crate::stream::CompareResult;
use crate::stream::FindSlice;
use crate::stream::Offset;
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
use crate::stream::Recover;
use crate::stream::SliceLen;
use crate::stream::Stream;
use crate::stream::StreamIsPartial;
use crate::stream::UpdateSlice;
/// Improved `Debug` experience for `&[u8]` UTF-8-ish streams
#[allow(clippy::derived_hash_with_manual_eq)]
#[derive(Hash)]
#[repr(transparent)]
pub struct BStr([u8]);
impl BStr {
/// Make a stream out of a byte slice-like.
#[inline]
pub fn new<B: ?Sized + AsRef<[u8]>>(bytes: &B) -> &Self {
Self::from_bytes(bytes.as_ref())
}
#[inline]
fn from_bytes(slice: &[u8]) -> &Self {
unsafe { crate::lib::std::mem::transmute(slice) }
}
#[inline]
fn as_bytes(&self) -> &[u8] {
&self.0
}
}
impl SliceLen for &BStr {
#[inline(always)]
fn slice_len(&self) -> usize {
self.len()
}
}
impl<'i> Stream for &'i BStr {
type Token = u8;
type Slice = &'i [u8];
type IterOffsets = Enumerate<Cloned<Iter<'i, u8>>>;
type Checkpoint = Checkpoint<Self, Self>;
#[inline(always)]
fn iter_offsets(&self) -> Self::IterOffsets {
self.iter().cloned().enumerate()
}
#[inline(always)]
fn eof_offset(&self) -> usize {
self.len()
}
#[inline(always)]
fn next_token(&mut self) -> Option<Self::Token> {
if self.is_empty() {
None
} else {
let token = self[0];
*self = &self[1..];
Some(token)
}
}
#[inline(always)]
fn peek_token(&self) -> Option<Self::Token> {
if self.is_empty() {
None
} else {
Some(self[0])
}
}
#[inline(always)]
fn offset_for<P>(&self, predicate: P) -> Option<usize>
where
P: Fn(Self::Token) -> bool,
{
self.iter().position(|b| predicate(*b))
}
#[inline(always)]
fn offset_at(&self, tokens: usize) -> Result<usize, Needed> {
if let Some(needed) = tokens.checked_sub(self.len()).and_then(NonZeroUsize::new) {
Err(Needed::Size(needed))
} else {
Ok(tokens)
}
}
#[inline(always)]
fn next_slice(&mut self, offset: usize) -> Self::Slice {
let (slice, next) = self.0.split_at(offset);
*self = BStr::from_bytes(next);
slice
}
#[inline(always)]
unsafe fn next_slice_unchecked(&mut self, offset: usize) -> Self::Slice {
#[cfg(debug_assertions)]
self.peek_slice(offset);
// SAFETY: `Stream::next_slice_unchecked` requires `offset` to be in bounds
let slice = unsafe { self.0.get_unchecked(..offset) };
// SAFETY: `Stream::next_slice_unchecked` requires `offset` to be in bounds
let next = unsafe { self.0.get_unchecked(offset..) };
*self = BStr::from_bytes(next);
slice
}
#[inline(always)]
fn peek_slice(&self, offset: usize) -> Self::Slice {
&self[..offset]
}
#[inline(always)]
unsafe fn peek_slice_unchecked(&self, offset: usize) -> Self::Slice {
#[cfg(debug_assertions)]
self.peek_slice(offset);
// SAFETY: `Stream::next_slice_unchecked` requires `offset` to be in bounds
let slice = unsafe { self.0.get_unchecked(..offset) };
slice
}
#[inline(always)]
fn checkpoint(&self) -> Self::Checkpoint {
Checkpoint::<_, Self>::new(*self)
}
#[inline(always)]
fn reset(&mut self, checkpoint: &Self::Checkpoint) {
*self = checkpoint.inner;
}
#[inline(always)]
fn raw(&self) -> &dyn crate::lib::std::fmt::Debug {
self
}
}
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
impl<E> Recover<E> for &BStr {
#[inline(always)]
fn record_err(
&mut self,
_token_start: &Self::Checkpoint,
_err_start: &Self::Checkpoint,
err: E,
) -> Result<(), E> {
Err(err)
}
/// Report whether the [`Stream`] can save off errors for recovery
#[inline(always)]
fn is_recovery_supported() -> bool {
false
}
}
impl StreamIsPartial for &BStr {
type PartialState = ();
#[inline]
fn complete(&mut self) -> Self::PartialState {
// Already complete
}
#[inline]
fn restore_partial(&mut self, _state: Self::PartialState) {}
#[inline(always)]
fn is_partial_supported() -> bool {
false
}
}
impl Offset for &BStr {
#[inline(always)]
fn offset_from(&self, start: &Self) -> usize {
self.as_bytes().offset_from(&start.as_bytes())
}
}
impl<'a> Offset<<&'a BStr as Stream>::Checkpoint> for &'a BStr {
#[inline(always)]
fn offset_from(&self, other: &<&'a BStr as Stream>::Checkpoint) -> usize {
self.checkpoint().offset_from(other)
}
}
impl AsBStr for &BStr {
#[inline(always)]
fn as_bstr(&self) -> &[u8] {
(*self).as_bytes()
}
}
impl<'a, T> Compare<T> for &'a BStr
where
&'a [u8]: Compare<T>,
{
#[inline(always)]
fn compare(&self, t: T) -> CompareResult {
let bytes = (*self).as_bytes();
bytes.compare(t)
}
}
impl<'i, S> FindSlice<S> for &'i BStr
where
&'i [u8]: FindSlice<S>,
{
#[inline(always)]
fn find_slice(&self, substr: S) -> Option<crate::lib::std::ops::Range<usize>> {
let bytes = (*self).as_bytes();
let offset = bytes.find_slice(substr);
offset
}
}
impl UpdateSlice for &BStr {
#[inline(always)]
fn update_slice(self, inner: Self::Slice) -> Self {
BStr::new(inner)
}
}
#[cfg(feature = "alloc")]
impl fmt::Display for BStr {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
crate::lib::std::string::String::from_utf8_lossy(self.as_bytes()).fmt(f)
}
}
impl fmt::Debug for BStr {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !f.alternate() {
write!(f, "\"")?;
}
for byte in self.as_bytes() {
let c = *byte as char;
write!(f, "{}", c.escape_debug())?;
}
if !f.alternate() {
write!(f, "\"")?;
}
Ok(())
}
}
impl ops::Deref for BStr {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
self.as_bytes()
}
}
impl ops::Index<usize> for BStr {
type Output = u8;
#[inline]
fn index(&self, idx: usize) -> &u8 {
&self.as_bytes()[idx]
}
}
impl ops::Index<ops::RangeFull> for BStr {
type Output = BStr;
#[inline]
fn index(&self, _: ops::RangeFull) -> &BStr {
self
}
}
impl ops::Index<ops::Range<usize>> for BStr {
type Output = BStr;
#[inline]
fn index(&self, r: ops::Range<usize>) -> &BStr {
BStr::new(&self.as_bytes()[r.start..r.end])
}
}
impl ops::Index<ops::RangeInclusive<usize>> for BStr {
type Output = BStr;
#[inline]
fn index(&self, r: ops::RangeInclusive<usize>) -> &BStr {
BStr::new(&self.as_bytes()[*r.start()..=*r.end()])
}
}
impl ops::Index<ops::RangeFrom<usize>> for BStr {
type Output = BStr;
#[inline]
fn index(&self, r: ops::RangeFrom<usize>) -> &BStr {
BStr::new(&self.as_bytes()[r.start..])
}
}
impl ops::Index<ops::RangeTo<usize>> for BStr {
type Output = BStr;
#[inline]
fn index(&self, r: ops::RangeTo<usize>) -> &BStr {
BStr::new(&self.as_bytes()[..r.end])
}
}
impl ops::Index<ops::RangeToInclusive<usize>> for BStr {
type Output = BStr;
#[inline]
fn index(&self, r: ops::RangeToInclusive<usize>) -> &BStr {
BStr::new(&self.as_bytes()[..=r.end])
}
}
impl AsRef<[u8]> for BStr {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl AsRef<BStr> for [u8] {
#[inline]
fn as_ref(&self) -> &BStr {
BStr::new(self)
}
}
impl AsRef<BStr> for str {
#[inline]
fn as_ref(&self) -> &BStr {
BStr::new(self)
}
}
#[cfg(feature = "alloc")]
impl crate::lib::std::borrow::ToOwned for BStr {
type Owned = crate::lib::std::vec::Vec<u8>;
#[inline]
fn to_owned(&self) -> Self::Owned {
crate::lib::std::vec::Vec::from(self.as_bytes())
}
}
#[cfg(feature = "alloc")]
impl crate::lib::std::borrow::Borrow<BStr> for crate::lib::std::vec::Vec<u8> {
#[inline]
fn borrow(&self) -> &BStr {
BStr::from_bytes(self.as_slice())
}
}
impl<'a> Default for &'a BStr {
fn default() -> &'a BStr {
BStr::new(b"")
}
}
impl<'a> From<&'a [u8]> for &'a BStr {
#[inline]
fn from(s: &'a [u8]) -> &'a BStr {
BStr::new(s)
}
}
impl<'a> From<&'a BStr> for &'a [u8] {
#[inline]
fn from(s: &'a BStr) -> &'a [u8] {
BStr::as_bytes(s)
}
}
impl<'a> From<&'a str> for &'a BStr {
#[inline]
fn from(s: &'a str) -> &'a BStr {
BStr::new(s.as_bytes())
}
}
impl Eq for BStr {}
impl PartialEq<BStr> for BStr {
#[inline]
fn eq(&self, other: &BStr) -> bool {
self.as_bytes() == other.as_bytes()
}
}
impl_partial_eq!(BStr, [u8]);
impl_partial_eq!(BStr, &'a [u8]);
impl_partial_eq!(BStr, str);
impl_partial_eq!(BStr, &'a str);
impl PartialOrd for BStr {
#[inline]
fn partial_cmp(&self, other: &BStr) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for BStr {
#[inline]
fn cmp(&self, other: &BStr) -> Ordering {
Ord::cmp(self.as_bytes(), other.as_bytes())
}
}
impl_partial_ord!(BStr, [u8]);
impl_partial_ord!(BStr, &'a [u8]);
impl_partial_ord!(BStr, str);
impl_partial_ord!(BStr, &'a str);
#[cfg(test)]
mod test {
use crate::stream::BStr;
#[test]
fn partial_eq_bstr_byte_slice() {
let input = b"foo".as_slice();
let actual = BStr::new(input);
assert!(actual == input);
}
#[test]
fn partial_eq_byte_slice_bstr() {
let input = b"foo".as_slice();
let actual = BStr::new(input);
assert!(input == actual);
}
#[test]
fn partial_eq_bstr_str() {
let input = "foo";
let actual = BStr::new(input);
assert!(actual == input);
}
#[test]
fn partial_eq_str_bstr() {
let input = "foo";
let actual = BStr::new(input);
assert!(input == actual);
}
#[test]
fn partial_ord_bstr_byte_slice() {
let input = b"foo".as_slice();
let actual = BStr::new(input);
assert!(actual.partial_cmp(input) == Some(core::cmp::Ordering::Equal));
}
#[test]
fn partial_ord_byte_slice_bstr() {
let input = b"foo".as_slice();
let actual = BStr::new(input);
assert!(input.partial_cmp(actual) == Some(core::cmp::Ordering::Equal));
}
#[test]
fn partial_ord_bstr_str() {
let input = "foo";
let actual = BStr::new(input);
assert!(actual.partial_cmp(input) == Some(core::cmp::Ordering::Equal));
}
#[test]
fn partial_ord_str_bstr() {
let input = "foo";
let actual = BStr::new(input);
assert!(input.partial_cmp(actual) == Some(core::cmp::Ordering::Equal));
}
}
#[cfg(all(test, feature = "std"))]
mod display {
use crate::stream::BStr;
#[test]
fn clean() {
assert_eq!(&format!("{}", BStr::new(b"abc")), "abc");
assert_eq!(&format!("{}", BStr::new(b"\xf0\x28\x8c\xbc")), "<EFBFBD>(<28><>");
}
}
#[cfg(all(test, feature = "std"))]
mod debug {
use crate::stream::BStr;
use crate::stream::Stream as _;
use snapbox::assert_data_eq;
use snapbox::str;
#[test]
fn test_debug() {
let input = BStr::new(b"abc");
let expected = str![[r#""abc""#]];
assert_data_eq!(&format!("{input:?}"), expected);
let input = BStr::new(b"\0\0\0 ftypisom\0\0\x02\0isomiso2avc1mp");
let expected = str![[r#""/0/0/0 ftypisom/0/0/u{2}/0isomiso2avc1mp""#]];
assert_data_eq!(&format!("{input:?}"), expected);
}
#[test]
fn test_pretty_debug() {
let input = BStr::new(b"abc");
let expected = str!["abc"];
assert_data_eq!(&format!("{input:#?}"), expected);
}
#[test]
fn test_trace() {
let input = BStr::new(b"abc");
let expected = str!["abc"];
assert_data_eq!(
crate::util::from_fn(|f| input.trace(f)).to_string(),
expected
);
}
}

563
vendor/winnow/src/stream/bytes.rs vendored Normal file
View File

@@ -0,0 +1,563 @@
use core::num::NonZeroUsize;
use crate::error::Needed;
use crate::lib::std::iter::{Cloned, Enumerate};
use crate::lib::std::slice::Iter;
use crate::lib::std::{cmp::Ordering, fmt, ops};
use crate::stream::AsBytes;
use crate::stream::Checkpoint;
use crate::stream::Compare;
use crate::stream::CompareResult;
use crate::stream::FindSlice;
use crate::stream::Offset;
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
use crate::stream::Recover;
use crate::stream::SliceLen;
use crate::stream::Stream;
use crate::stream::StreamIsPartial;
use crate::stream::UpdateSlice;
/// Improved `Debug` experience for `&[u8]` byte streams
#[allow(clippy::derived_hash_with_manual_eq)]
#[derive(Hash)]
#[repr(transparent)]
pub struct Bytes([u8]);
impl Bytes {
/// Make a stream out of a byte slice-like.
#[inline]
pub fn new<B: ?Sized + AsRef<[u8]>>(bytes: &B) -> &Self {
Self::from_bytes(bytes.as_ref())
}
#[inline]
fn from_bytes(slice: &[u8]) -> &Self {
unsafe { crate::lib::std::mem::transmute(slice) }
}
#[inline]
fn as_bytes(&self) -> &[u8] {
&self.0
}
}
impl SliceLen for &Bytes {
#[inline(always)]
fn slice_len(&self) -> usize {
self.len()
}
}
impl<'i> Stream for &'i Bytes {
type Token = u8;
type Slice = &'i [u8];
type IterOffsets = Enumerate<Cloned<Iter<'i, u8>>>;
type Checkpoint = Checkpoint<Self, Self>;
#[inline(always)]
fn iter_offsets(&self) -> Self::IterOffsets {
self.iter().cloned().enumerate()
}
#[inline(always)]
fn eof_offset(&self) -> usize {
self.len()
}
#[inline(always)]
fn next_token(&mut self) -> Option<Self::Token> {
if self.is_empty() {
None
} else {
let token = self[0];
*self = &self[1..];
Some(token)
}
}
#[inline(always)]
fn peek_token(&self) -> Option<Self::Token> {
if self.is_empty() {
None
} else {
Some(self[0])
}
}
#[inline(always)]
fn offset_for<P>(&self, predicate: P) -> Option<usize>
where
P: Fn(Self::Token) -> bool,
{
self.iter().position(|b| predicate(*b))
}
#[inline(always)]
fn offset_at(&self, tokens: usize) -> Result<usize, Needed> {
if let Some(needed) = tokens.checked_sub(self.len()).and_then(NonZeroUsize::new) {
Err(Needed::Size(needed))
} else {
Ok(tokens)
}
}
#[inline(always)]
fn next_slice(&mut self, offset: usize) -> Self::Slice {
let (slice, next) = self.0.split_at(offset);
*self = Bytes::from_bytes(next);
slice
}
#[inline(always)]
unsafe fn next_slice_unchecked(&mut self, offset: usize) -> Self::Slice {
#[cfg(debug_assertions)]
self.peek_slice(offset);
// SAFETY: `Stream::next_slice_unchecked` requires `offset` to be in bounds
let slice = unsafe { self.0.get_unchecked(..offset) };
// SAFETY: `Stream::next_slice_unchecked` requires `offset` to be in bounds
let next = unsafe { self.0.get_unchecked(offset..) };
*self = Bytes::from_bytes(next);
slice
}
#[inline(always)]
fn peek_slice(&self, offset: usize) -> Self::Slice {
&self[..offset]
}
#[inline(always)]
unsafe fn peek_slice_unchecked(&self, offset: usize) -> Self::Slice {
#[cfg(debug_assertions)]
self.peek_slice(offset);
// SAFETY: `Stream::next_slice_unchecked` requires `offset` to be in bounds
let slice = unsafe { self.0.get_unchecked(..offset) };
slice
}
#[inline(always)]
fn checkpoint(&self) -> Self::Checkpoint {
Checkpoint::<_, Self>::new(*self)
}
#[inline(always)]
fn reset(&mut self, checkpoint: &Self::Checkpoint) {
*self = checkpoint.inner;
}
#[inline(always)]
fn raw(&self) -> &dyn crate::lib::std::fmt::Debug {
self
}
}
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
impl<E> Recover<E> for &Bytes {
#[inline(always)]
fn record_err(
&mut self,
_token_start: &Self::Checkpoint,
_err_start: &Self::Checkpoint,
err: E,
) -> Result<(), E> {
Err(err)
}
/// Report whether the [`Stream`] can save off errors for recovery
#[inline(always)]
fn is_recovery_supported() -> bool {
false
}
}
impl StreamIsPartial for &Bytes {
type PartialState = ();
#[inline]
fn complete(&mut self) -> Self::PartialState {
// Already complete
}
#[inline]
fn restore_partial(&mut self, _state: Self::PartialState) {}
#[inline(always)]
fn is_partial_supported() -> bool {
false
}
}
impl Offset for &Bytes {
#[inline(always)]
fn offset_from(&self, start: &Self) -> usize {
self.as_bytes().offset_from(&start.as_bytes())
}
}
impl<'a> Offset<<&'a Bytes as Stream>::Checkpoint> for &'a Bytes {
#[inline(always)]
fn offset_from(&self, other: &<&'a Bytes as Stream>::Checkpoint) -> usize {
self.checkpoint().offset_from(other)
}
}
impl AsBytes for &Bytes {
#[inline(always)]
fn as_bytes(&self) -> &[u8] {
(*self).as_bytes()
}
}
impl<'a, T> Compare<T> for &'a Bytes
where
&'a [u8]: Compare<T>,
{
#[inline(always)]
fn compare(&self, t: T) -> CompareResult {
let bytes = (*self).as_bytes();
bytes.compare(t)
}
}
impl<'i, S> FindSlice<S> for &'i Bytes
where
&'i [u8]: FindSlice<S>,
{
#[inline(always)]
fn find_slice(&self, substr: S) -> Option<crate::lib::std::ops::Range<usize>> {
let bytes = (*self).as_bytes();
let offset = bytes.find_slice(substr);
offset
}
}
impl UpdateSlice for &Bytes {
#[inline(always)]
fn update_slice(self, inner: Self::Slice) -> Self {
Bytes::new(inner)
}
}
impl fmt::Display for Bytes {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Self as fmt::UpperHex>::fmt(self, f)
}
}
impl fmt::Debug for Bytes {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Self as fmt::UpperHex>::fmt(self, f)
}
}
impl fmt::LowerHex for Bytes {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for byte in self.as_bytes() {
write!(f, "{byte:0>2x}")?;
}
Ok(())
}
}
impl fmt::UpperHex for Bytes {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, byte) in self.as_bytes().iter().enumerate() {
if 0 < i {
let absolute = (self.as_bytes().as_ptr() as usize) + i;
if f.alternate() && absolute != 0 && absolute % 4 == 0 {
write!(f, "_")?;
}
}
write!(f, "{byte:0>2X}")?;
}
Ok(())
}
}
impl ops::Deref for Bytes {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
self.as_bytes()
}
}
impl ops::Index<usize> for Bytes {
type Output = u8;
#[inline]
fn index(&self, idx: usize) -> &u8 {
&self.as_bytes()[idx]
}
}
impl ops::Index<ops::RangeFull> for Bytes {
type Output = Bytes;
#[inline]
fn index(&self, _: ops::RangeFull) -> &Bytes {
self
}
}
impl ops::Index<ops::Range<usize>> for Bytes {
type Output = Bytes;
#[inline]
fn index(&self, r: ops::Range<usize>) -> &Bytes {
Bytes::new(&self.as_bytes()[r.start..r.end])
}
}
impl ops::Index<ops::RangeInclusive<usize>> for Bytes {
type Output = Bytes;
#[inline]
fn index(&self, r: ops::RangeInclusive<usize>) -> &Bytes {
Bytes::new(&self.as_bytes()[*r.start()..=*r.end()])
}
}
impl ops::Index<ops::RangeFrom<usize>> for Bytes {
type Output = Bytes;
#[inline]
fn index(&self, r: ops::RangeFrom<usize>) -> &Bytes {
Bytes::new(&self.as_bytes()[r.start..])
}
}
impl ops::Index<ops::RangeTo<usize>> for Bytes {
type Output = Bytes;
#[inline]
fn index(&self, r: ops::RangeTo<usize>) -> &Bytes {
Bytes::new(&self.as_bytes()[..r.end])
}
}
impl ops::Index<ops::RangeToInclusive<usize>> for Bytes {
type Output = Bytes;
#[inline]
fn index(&self, r: ops::RangeToInclusive<usize>) -> &Bytes {
Bytes::new(&self.as_bytes()[..=r.end])
}
}
impl AsRef<[u8]> for Bytes {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl AsRef<Bytes> for [u8] {
#[inline]
fn as_ref(&self) -> &Bytes {
Bytes::new(self)
}
}
impl AsRef<Bytes> for str {
#[inline]
fn as_ref(&self) -> &Bytes {
Bytes::new(self)
}
}
#[cfg(feature = "alloc")]
impl crate::lib::std::borrow::ToOwned for Bytes {
type Owned = crate::lib::std::vec::Vec<u8>;
#[inline]
fn to_owned(&self) -> Self::Owned {
crate::lib::std::vec::Vec::from(self.as_bytes())
}
}
#[cfg(feature = "alloc")]
impl crate::lib::std::borrow::Borrow<Bytes> for crate::lib::std::vec::Vec<u8> {
#[inline]
fn borrow(&self) -> &Bytes {
Bytes::from_bytes(self.as_slice())
}
}
impl<'a> Default for &'a Bytes {
fn default() -> &'a Bytes {
Bytes::new(b"")
}
}
impl<'a> From<&'a [u8]> for &'a Bytes {
#[inline]
fn from(s: &'a [u8]) -> &'a Bytes {
Bytes::new(s)
}
}
impl<'a> From<&'a Bytes> for &'a [u8] {
#[inline]
fn from(s: &'a Bytes) -> &'a [u8] {
Bytes::as_bytes(s)
}
}
impl<'a> From<&'a str> for &'a Bytes {
#[inline]
fn from(s: &'a str) -> &'a Bytes {
Bytes::new(s.as_bytes())
}
}
impl Eq for Bytes {}
impl PartialEq<Bytes> for Bytes {
#[inline]
fn eq(&self, other: &Bytes) -> bool {
self.as_bytes() == other.as_bytes()
}
}
impl_partial_eq!(Bytes, [u8]);
impl_partial_eq!(Bytes, &'a [u8]);
impl_partial_eq!(Bytes, str);
impl_partial_eq!(Bytes, &'a str);
impl PartialOrd for Bytes {
#[inline]
fn partial_cmp(&self, other: &Bytes) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Bytes {
#[inline]
fn cmp(&self, other: &Bytes) -> Ordering {
Ord::cmp(self.as_bytes(), other.as_bytes())
}
}
impl_partial_ord!(Bytes, [u8]);
impl_partial_ord!(Bytes, &'a [u8]);
impl_partial_ord!(Bytes, str);
impl_partial_ord!(Bytes, &'a str);
#[cfg(test)]
mod test {
use crate::stream::Bytes;
#[test]
fn partial_eq_bytes_byte_slice() {
let input = b"foo".as_slice();
let actual = Bytes::new(input);
assert!(actual == input);
}
#[test]
fn partial_eq_byte_slice_bytes() {
let input = b"foo".as_slice();
let actual = Bytes::new(input);
assert!(input == actual);
}
#[test]
fn partial_eq_bytes_str() {
let input = "foo";
let actual = Bytes::new(input);
assert!(actual == input);
}
#[test]
fn partial_eq_str_bytes() {
let input = "foo";
let actual = Bytes::new(input);
assert!(input == actual);
}
#[test]
fn partial_ord_bytes_byte_slice() {
let input = b"foo".as_slice();
let actual = Bytes::new(input);
assert!(actual.partial_cmp(input) == Some(core::cmp::Ordering::Equal));
}
#[test]
fn partial_ord_byte_slice_bytes() {
let input = b"foo".as_slice();
let actual = Bytes::new(input);
assert!(input.partial_cmp(actual) == Some(core::cmp::Ordering::Equal));
}
#[test]
fn partial_ord_bytes_str() {
let input = "foo";
let actual = Bytes::new(input);
assert!(actual.partial_cmp(input) == Some(core::cmp::Ordering::Equal));
}
#[test]
fn partial_ord_str_bytes() {
let input = "foo";
let actual = Bytes::new(input);
assert!(input.partial_cmp(actual) == Some(core::cmp::Ordering::Equal));
}
}
#[cfg(all(test, feature = "std"))]
mod display {
use crate::stream::Bytes;
#[test]
fn clean() {
assert_eq!(&format!("{}", Bytes::new(b"abc")), "616263");
assert_eq!(&format!("{}", Bytes::new(b"\xf0\x28\x8c\xbc")), "F0288CBC");
}
}
#[cfg(all(test, feature = "std"))]
mod debug {
use crate::stream::Bytes;
use crate::stream::Stream as _;
use snapbox::assert_data_eq;
use snapbox::str;
#[test]
fn test_debug() {
let input = Bytes::new(b"\0\0\0 ftypisom\0\0\x02\0isomiso2avc1mp");
let expected = str!["000000206674797069736F6D0000020069736F6D69736F32617663316D70"];
assert_data_eq!(&format!("{input:?}"), expected);
}
#[test]
fn test_pretty_debug() {
let input = Bytes::new(b"\0\0\0 ftypisom\0\0\x02\0isomiso2avc1mp");
let expected = str!["000000206674797069736F6D0000020069736F6D69736F32617663316D70"];
assert_data_eq!(&format!("{input:#?}").replace('_', ""), expected);
}
#[test]
fn test_trace() {
let input = Bytes::new(b"\0\0\0 ftypisom\0\0\x02\0isomiso2avc1mp");
let expected = str!["000000206674797069736F6D0000020069736F6D69736F32617663316D70"];
assert_data_eq!(
crate::util::from_fn(|f| input.trace(f))
.to_string()
.replace('_', ""),
expected
);
}
#[test]
fn test_sliced() {
// Output can change from run-to-run
let total = Bytes::new(b"12345678901234567890");
let _ = format!("{total:#?}");
let _ = format!("{:#?}", &total[1..]);
let _ = format!("{:#?}", &total[10..]);
}
}

326
vendor/winnow/src/stream/locating.rs vendored Normal file
View File

@@ -0,0 +1,326 @@
use crate::error::Needed;
use crate::stream::AsBStr;
use crate::stream::AsBytes;
use crate::stream::Checkpoint;
use crate::stream::Compare;
use crate::stream::CompareResult;
use crate::stream::FindSlice;
use crate::stream::Location;
use crate::stream::Offset;
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
use crate::stream::Recover;
use crate::stream::SliceLen;
use crate::stream::Stream;
use crate::stream::StreamIsPartial;
use crate::stream::UpdateSlice;
/// Allow collecting the span of a parsed token within a slice
///
/// Converting byte offsets to line or column numbers is left up to the user, as computing column
/// numbers requires domain knowledge (are columns byte-based, codepoint-based, or grapheme-based?)
/// and O(n) iteration over the input to determine codepoint and line boundaries.
///
/// [The `line-span` crate](https://docs.rs/line-span/latest/line_span/) can help with converting
/// byte offsets to line numbers.
///
/// See [`Parser::span`][crate::Parser::span] and [`Parser::with_span`][crate::Parser::with_span] for more details
#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
#[doc(alias = "LocatingSliceSpan")]
#[doc(alias = "Located")]
pub struct LocatingSlice<I> {
initial: I,
input: I,
}
impl<I> LocatingSlice<I>
where
I: Clone + Offset,
{
/// Wrap another Stream with span tracking
pub fn new(input: I) -> Self {
let initial = input.clone();
Self { initial, input }
}
#[inline]
fn previous_token_end(&self) -> usize {
// Assumptions:
// - Index offsets is sufficient
// - Tokens are continuous
self.input.offset_from(&self.initial)
}
#[inline]
fn current_token_start(&self) -> usize {
// Assumptions:
// - Index offsets is sufficient
self.input.offset_from(&self.initial)
}
}
impl<I> LocatingSlice<I>
where
I: Clone + Stream + Offset,
{
/// Reset the stream to the start
///
/// This is useful for formats that encode a graph with addresses relative to the start of the
/// input.
#[doc(alias = "fseek")]
#[inline]
pub fn reset_to_start(&mut self) {
let start = self.initial.checkpoint();
self.input.reset(&start);
}
}
impl<I> AsRef<I> for LocatingSlice<I> {
#[inline(always)]
fn as_ref(&self) -> &I {
&self.input
}
}
impl<I: core::fmt::Debug> core::fmt::Debug for LocatingSlice<I> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.input.fmt(f)
}
}
impl<I> crate::lib::std::ops::Deref for LocatingSlice<I> {
type Target = I;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.input
}
}
impl<I: crate::lib::std::fmt::Display> crate::lib::std::fmt::Display for LocatingSlice<I> {
fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result {
self.input.fmt(f)
}
}
impl<I> SliceLen for LocatingSlice<I>
where
I: SliceLen,
{
#[inline(always)]
fn slice_len(&self) -> usize {
self.input.slice_len()
}
}
impl<I: Stream> Stream for LocatingSlice<I> {
type Token = <I as Stream>::Token;
type Slice = <I as Stream>::Slice;
type IterOffsets = <I as Stream>::IterOffsets;
type Checkpoint = Checkpoint<I::Checkpoint, Self>;
#[inline(always)]
fn iter_offsets(&self) -> Self::IterOffsets {
self.input.iter_offsets()
}
#[inline(always)]
fn eof_offset(&self) -> usize {
self.input.eof_offset()
}
#[inline(always)]
fn next_token(&mut self) -> Option<Self::Token> {
self.input.next_token()
}
#[inline(always)]
fn peek_token(&self) -> Option<Self::Token> {
self.input.peek_token()
}
#[inline(always)]
fn offset_for<P>(&self, predicate: P) -> Option<usize>
where
P: Fn(Self::Token) -> bool,
{
self.input.offset_for(predicate)
}
#[inline(always)]
fn offset_at(&self, tokens: usize) -> Result<usize, Needed> {
self.input.offset_at(tokens)
}
#[inline(always)]
fn next_slice(&mut self, offset: usize) -> Self::Slice {
self.input.next_slice(offset)
}
#[inline(always)]
unsafe fn next_slice_unchecked(&mut self, offset: usize) -> Self::Slice {
// SAFETY: Passing up invariants
unsafe { self.input.next_slice_unchecked(offset) }
}
#[inline(always)]
fn peek_slice(&self, offset: usize) -> Self::Slice {
self.input.peek_slice(offset)
}
#[inline(always)]
unsafe fn peek_slice_unchecked(&self, offset: usize) -> Self::Slice {
// SAFETY: Passing up invariants
unsafe { self.input.peek_slice_unchecked(offset) }
}
#[inline(always)]
fn checkpoint(&self) -> Self::Checkpoint {
Checkpoint::<_, Self>::new(self.input.checkpoint())
}
#[inline(always)]
fn reset(&mut self, checkpoint: &Self::Checkpoint) {
self.input.reset(&checkpoint.inner);
}
#[inline(always)]
fn raw(&self) -> &dyn crate::lib::std::fmt::Debug {
#![allow(deprecated)]
self.input.raw()
}
fn trace(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.input.trace(f)
}
}
impl<I> Location for LocatingSlice<I>
where
I: Clone + Offset,
{
#[inline(always)]
fn previous_token_end(&self) -> usize {
self.previous_token_end()
}
#[inline(always)]
fn current_token_start(&self) -> usize {
self.current_token_start()
}
}
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
impl<I, E> Recover<E> for LocatingSlice<I>
where
I: Recover<E>,
I: Stream,
{
#[inline(always)]
fn record_err(
&mut self,
_token_start: &Self::Checkpoint,
_err_start: &Self::Checkpoint,
err: E,
) -> Result<(), E> {
Err(err)
}
/// Report whether the [`Stream`] can save off errors for recovery
#[inline(always)]
fn is_recovery_supported() -> bool {
false
}
}
impl<I> StreamIsPartial for LocatingSlice<I>
where
I: StreamIsPartial,
{
type PartialState = I::PartialState;
#[inline]
fn complete(&mut self) -> Self::PartialState {
self.input.complete()
}
#[inline]
fn restore_partial(&mut self, state: Self::PartialState) {
self.input.restore_partial(state);
}
#[inline(always)]
fn is_partial_supported() -> bool {
I::is_partial_supported()
}
#[inline(always)]
fn is_partial(&self) -> bool {
self.input.is_partial()
}
}
impl<I> Offset for LocatingSlice<I>
where
I: Stream,
{
#[inline(always)]
fn offset_from(&self, other: &Self) -> usize {
self.offset_from(&other.checkpoint())
}
}
impl<I> Offset<<LocatingSlice<I> as Stream>::Checkpoint> for LocatingSlice<I>
where
I: Stream,
{
#[inline(always)]
fn offset_from(&self, other: &<LocatingSlice<I> as Stream>::Checkpoint) -> usize {
self.checkpoint().offset_from(other)
}
}
impl<I> AsBytes for LocatingSlice<I>
where
I: AsBytes,
{
#[inline(always)]
fn as_bytes(&self) -> &[u8] {
self.input.as_bytes()
}
}
impl<I> AsBStr for LocatingSlice<I>
where
I: AsBStr,
{
#[inline(always)]
fn as_bstr(&self) -> &[u8] {
self.input.as_bstr()
}
}
impl<I, U> Compare<U> for LocatingSlice<I>
where
I: Compare<U>,
{
#[inline(always)]
fn compare(&self, other: U) -> CompareResult {
self.input.compare(other)
}
}
impl<I, T> FindSlice<T> for LocatingSlice<I>
where
I: FindSlice<T>,
{
#[inline(always)]
fn find_slice(&self, substr: T) -> Option<crate::lib::std::ops::Range<usize>> {
self.input.find_slice(substr)
}
}
impl<I> UpdateSlice for LocatingSlice<I>
where
I: UpdateSlice,
{
#[inline(always)]
fn update_slice(mut self, inner: Self::Slice) -> Self {
self.input = I::update_slice(self.input, inner);
self
}
}

2263
vendor/winnow/src/stream/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

354
vendor/winnow/src/stream/partial.rs vendored Normal file
View File

@@ -0,0 +1,354 @@
use crate::error::Needed;
use crate::stream::AsBStr;
use crate::stream::AsBytes;
use crate::stream::Checkpoint;
use crate::stream::Compare;
use crate::stream::CompareResult;
use crate::stream::FindSlice;
use crate::stream::Location;
use crate::stream::Offset;
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
use crate::stream::Recover;
use crate::stream::SliceLen;
use crate::stream::Stream;
use crate::stream::StreamIsPartial;
use crate::stream::UpdateSlice;
/// Mark the input as a partial buffer for streaming input.
///
/// Complete input means that we already have all of the data. This will be the common case with
/// small files that can be read entirely to memory.
///
/// In contrast, streaming input assumes that we might not have all of the data.
/// This can happen with some network protocol or large file parsers, where the
/// input buffer can be full and need to be resized or refilled.
/// - [`ErrMode::Incomplete`][crate::error::ErrMode::Incomplete] will report how much more data is needed.
/// - [`Parser::complete_err`][crate::Parser::complete_err] transform
/// [`ErrMode::Incomplete`][crate::error::ErrMode::Incomplete] to
/// [`ErrMode::Backtrack`][crate::error::ErrMode::Backtrack]
///
/// See also [`StreamIsPartial`] to tell whether the input supports complete or partial parsing.
///
/// See also [Special Topics: Parsing Partial Input][crate::_topic::partial].
///
/// # Example
///
/// Here is how it works in practice:
///
/// ```rust
/// # use winnow::{Result, error::ErrMode, error::Needed, error::ContextError, token, ascii, stream::Partial};
/// # use winnow::prelude::*;
///
/// fn take_partial<'s>(i: &mut Partial<&'s [u8]>) -> ModalResult<&'s [u8], ContextError> {
/// token::take(4u8).parse_next(i)
/// }
///
/// fn take_complete<'s>(i: &mut &'s [u8]) -> ModalResult<&'s [u8], ContextError> {
/// token::take(4u8).parse_next(i)
/// }
///
/// // both parsers will take 4 bytes as expected
/// assert_eq!(take_partial.parse_peek(Partial::new(&b"abcde"[..])), Ok((Partial::new(&b"e"[..]), &b"abcd"[..])));
/// assert_eq!(take_complete.parse_peek(&b"abcde"[..]), Ok((&b"e"[..], &b"abcd"[..])));
///
/// // if the input is smaller than 4 bytes, the partial parser
/// // will return `Incomplete` to indicate that we need more data
/// assert_eq!(take_partial.parse_peek(Partial::new(&b"abc"[..])), Err(ErrMode::Incomplete(Needed::new(1))));
///
/// // but the complete parser will return an error
/// assert!(take_complete.parse_peek(&b"abc"[..]).is_err());
///
/// // the alpha0 function takes 0 or more alphabetic characters
/// fn alpha0_partial<'s>(i: &mut Partial<&'s str>) -> ModalResult<&'s str, ContextError> {
/// ascii::alpha0.parse_next(i)
/// }
///
/// fn alpha0_complete<'s>(i: &mut &'s str) -> ModalResult<&'s str, ContextError> {
/// ascii::alpha0.parse_next(i)
/// }
///
/// // if there's a clear limit to the taken characters, both parsers work the same way
/// assert_eq!(alpha0_partial.parse_peek(Partial::new("abcd;")), Ok((Partial::new(";"), "abcd")));
/// assert_eq!(alpha0_complete.parse_peek("abcd;"), Ok((";", "abcd")));
///
/// // but when there's no limit, the partial version returns `Incomplete`, because it cannot
/// // know if more input data should be taken. The whole input could be "abcd;", or
/// // "abcde;"
/// assert_eq!(alpha0_partial.parse_peek(Partial::new("abcd")), Err(ErrMode::Incomplete(Needed::new(1))));
///
/// // while the complete version knows that all of the data is there
/// assert_eq!(alpha0_complete.parse_peek("abcd"), Ok(("", "abcd")));
/// ```
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Partial<I> {
input: I,
partial: bool,
}
impl<I> Partial<I>
where
I: StreamIsPartial,
{
/// Create a partial input
#[inline]
pub fn new(input: I) -> Self {
debug_assert!(
!I::is_partial_supported(),
"`Partial` can only wrap complete sources"
);
let partial = true;
Self { input, partial }
}
/// Extract the original [`Stream`]
#[inline(always)]
pub fn into_inner(self) -> I {
self.input
}
}
impl<I> Default for Partial<I>
where
I: Default + StreamIsPartial,
{
#[inline]
fn default() -> Self {
Self::new(I::default())
}
}
impl<I> crate::lib::std::ops::Deref for Partial<I> {
type Target = I;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.input
}
}
impl<I: crate::lib::std::fmt::Display> crate::lib::std::fmt::Display for Partial<I> {
fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result {
self.input.fmt(f)
}
}
impl<I> SliceLen for Partial<I>
where
I: SliceLen,
{
#[inline(always)]
fn slice_len(&self) -> usize {
self.input.slice_len()
}
}
impl<I: Stream> Stream for Partial<I> {
type Token = <I as Stream>::Token;
type Slice = <I as Stream>::Slice;
type IterOffsets = <I as Stream>::IterOffsets;
type Checkpoint = Checkpoint<I::Checkpoint, Self>;
#[inline(always)]
fn iter_offsets(&self) -> Self::IterOffsets {
self.input.iter_offsets()
}
#[inline(always)]
fn eof_offset(&self) -> usize {
self.input.eof_offset()
}
#[inline(always)]
fn next_token(&mut self) -> Option<Self::Token> {
self.input.next_token()
}
#[inline(always)]
fn peek_token(&self) -> Option<Self::Token> {
self.input.peek_token()
}
#[inline(always)]
fn offset_for<P>(&self, predicate: P) -> Option<usize>
where
P: Fn(Self::Token) -> bool,
{
self.input.offset_for(predicate)
}
#[inline(always)]
fn offset_at(&self, tokens: usize) -> Result<usize, Needed> {
self.input.offset_at(tokens)
}
#[inline(always)]
fn next_slice(&mut self, offset: usize) -> Self::Slice {
self.input.next_slice(offset)
}
#[inline(always)]
unsafe fn next_slice_unchecked(&mut self, offset: usize) -> Self::Slice {
// SAFETY: Passing up invariants
unsafe { self.input.next_slice_unchecked(offset) }
}
#[inline(always)]
fn peek_slice(&self, offset: usize) -> Self::Slice {
self.input.peek_slice(offset)
}
#[inline(always)]
unsafe fn peek_slice_unchecked(&self, offset: usize) -> Self::Slice {
// SAFETY: Passing up invariants
unsafe { self.input.peek_slice_unchecked(offset) }
}
#[inline(always)]
fn checkpoint(&self) -> Self::Checkpoint {
Checkpoint::<_, Self>::new(self.input.checkpoint())
}
#[inline(always)]
fn reset(&mut self, checkpoint: &Self::Checkpoint) {
self.input.reset(&checkpoint.inner);
}
#[inline(always)]
fn raw(&self) -> &dyn crate::lib::std::fmt::Debug {
&self.input
}
}
impl<I> Location for Partial<I>
where
I: Location,
{
#[inline(always)]
fn previous_token_end(&self) -> usize {
self.input.previous_token_end()
}
#[inline(always)]
fn current_token_start(&self) -> usize {
self.input.current_token_start()
}
}
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
impl<I, E> Recover<E> for Partial<I>
where
I: Recover<E>,
I: Stream,
{
#[inline(always)]
fn record_err(
&mut self,
_token_start: &Self::Checkpoint,
_err_start: &Self::Checkpoint,
err: E,
) -> Result<(), E> {
Err(err)
}
/// Report whether the [`Stream`] can save off errors for recovery
#[inline(always)]
fn is_recovery_supported() -> bool {
false
}
}
impl<I> StreamIsPartial for Partial<I>
where
I: StreamIsPartial,
{
type PartialState = bool;
#[inline]
fn complete(&mut self) -> Self::PartialState {
core::mem::replace(&mut self.partial, false)
}
#[inline]
fn restore_partial(&mut self, state: Self::PartialState) {
self.partial = state;
}
#[inline(always)]
fn is_partial_supported() -> bool {
true
}
#[inline(always)]
fn is_partial(&self) -> bool {
self.partial
}
}
impl<I> Offset for Partial<I>
where
I: Stream,
{
#[inline(always)]
fn offset_from(&self, start: &Self) -> usize {
self.offset_from(&start.checkpoint())
}
}
impl<I> Offset<<Partial<I> as Stream>::Checkpoint> for Partial<I>
where
I: Stream,
{
#[inline(always)]
fn offset_from(&self, other: &<Partial<I> as Stream>::Checkpoint) -> usize {
self.checkpoint().offset_from(other)
}
}
impl<I> AsBytes for Partial<I>
where
I: AsBytes,
{
#[inline(always)]
fn as_bytes(&self) -> &[u8] {
self.input.as_bytes()
}
}
impl<I> AsBStr for Partial<I>
where
I: AsBStr,
{
#[inline(always)]
fn as_bstr(&self) -> &[u8] {
self.input.as_bstr()
}
}
impl<I, T> Compare<T> for Partial<I>
where
I: Compare<T>,
{
#[inline(always)]
fn compare(&self, t: T) -> CompareResult {
self.input.compare(t)
}
}
impl<I, T> FindSlice<T> for Partial<I>
where
I: FindSlice<T>,
{
#[inline(always)]
fn find_slice(&self, substr: T) -> Option<crate::lib::std::ops::Range<usize>> {
self.input.find_slice(substr)
}
}
impl<I> UpdateSlice for Partial<I>
where
I: UpdateSlice,
{
#[inline(always)]
fn update_slice(self, inner: Self::Slice) -> Self {
Partial {
input: I::update_slice(self.input, inner),
partial: self.partial,
}
}
}

143
vendor/winnow/src/stream/range.rs vendored Normal file
View File

@@ -0,0 +1,143 @@
/// A range bounded inclusively for counting parses performed
///
/// This is flexible in what can be converted to a [Range]:
/// ```rust
/// # #[cfg(feature = "std")] {
/// # use winnow::prelude::*;
/// # use winnow::token::any;
/// # use winnow::combinator::repeat;
/// # fn inner(input: &mut &str) -> ModalResult<char> {
/// # any.parse_next(input)
/// # }
/// # let mut input = "0123456789012345678901234567890123456789";
/// # let input = &mut input;
/// let parser: Vec<_> = repeat(5, inner).parse_next(input).unwrap();
/// # let mut input = "0123456789012345678901234567890123456789";
/// # let input = &mut input;
/// let parser: Vec<_> = repeat(.., inner).parse_next(input).unwrap();
/// # let mut input = "0123456789012345678901234567890123456789";
/// # let input = &mut input;
/// let parser: Vec<_> = repeat(1.., inner).parse_next(input).unwrap();
/// # let mut input = "0123456789012345678901234567890123456789";
/// # let input = &mut input;
/// let parser: Vec<_> = repeat(5..8, inner).parse_next(input).unwrap();
/// # let mut input = "0123456789012345678901234567890123456789";
/// # let input = &mut input;
/// let parser: Vec<_> = repeat(5..=8, inner).parse_next(input).unwrap();
/// # }
/// ```
#[derive(PartialEq, Eq, Copy, Clone)]
pub struct Range {
pub(crate) start_inclusive: usize,
pub(crate) end_inclusive: Option<usize>,
}
impl Range {
#[inline(always)]
fn raw(start_inclusive: usize, end_inclusive: Option<usize>) -> Self {
Self {
start_inclusive,
end_inclusive,
}
}
}
impl crate::lib::std::ops::RangeBounds<usize> for Range {
#[inline(always)]
fn start_bound(&self) -> crate::lib::std::ops::Bound<&usize> {
crate::lib::std::ops::Bound::Included(&self.start_inclusive)
}
#[inline(always)]
fn end_bound(&self) -> crate::lib::std::ops::Bound<&usize> {
if let Some(end_inclusive) = &self.end_inclusive {
crate::lib::std::ops::Bound::Included(end_inclusive)
} else {
crate::lib::std::ops::Bound::Unbounded
}
}
}
impl From<usize> for Range {
#[inline(always)]
fn from(fixed: usize) -> Self {
(fixed..=fixed).into()
}
}
impl From<crate::lib::std::ops::Range<usize>> for Range {
#[inline(always)]
fn from(range: crate::lib::std::ops::Range<usize>) -> Self {
let start_inclusive = range.start;
let end_inclusive = Some(range.end.saturating_sub(1));
Self::raw(start_inclusive, end_inclusive)
}
}
impl From<crate::lib::std::ops::RangeFull> for Range {
#[inline(always)]
fn from(_: crate::lib::std::ops::RangeFull) -> Self {
let start_inclusive = 0;
let end_inclusive = None;
Self::raw(start_inclusive, end_inclusive)
}
}
impl From<crate::lib::std::ops::RangeFrom<usize>> for Range {
#[inline(always)]
fn from(range: crate::lib::std::ops::RangeFrom<usize>) -> Self {
let start_inclusive = range.start;
let end_inclusive = None;
Self::raw(start_inclusive, end_inclusive)
}
}
impl From<crate::lib::std::ops::RangeTo<usize>> for Range {
#[inline(always)]
fn from(range: crate::lib::std::ops::RangeTo<usize>) -> Self {
let start_inclusive = 0;
let end_inclusive = Some(range.end.saturating_sub(1));
Self::raw(start_inclusive, end_inclusive)
}
}
impl From<crate::lib::std::ops::RangeInclusive<usize>> for Range {
#[inline(always)]
fn from(range: crate::lib::std::ops::RangeInclusive<usize>) -> Self {
let start_inclusive = *range.start();
let end_inclusive = Some(*range.end());
Self::raw(start_inclusive, end_inclusive)
}
}
impl From<crate::lib::std::ops::RangeToInclusive<usize>> for Range {
#[inline(always)]
fn from(range: crate::lib::std::ops::RangeToInclusive<usize>) -> Self {
let start_inclusive = 0;
let end_inclusive = Some(range.end);
Self::raw(start_inclusive, end_inclusive)
}
}
impl crate::lib::std::fmt::Display for Range {
fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result {
self.start_inclusive.fmt(f)?;
match self.end_inclusive {
Some(e) if e == self.start_inclusive => {}
Some(e) => {
"..=".fmt(f)?;
e.fmt(f)?;
}
None => {
"..".fmt(f)?;
}
}
Ok(())
}
}
impl crate::lib::std::fmt::Debug for Range {
fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result {
write!(f, "{self}")
}
}

344
vendor/winnow/src/stream/recoverable.rs vendored Normal file
View File

@@ -0,0 +1,344 @@
use crate::error::FromRecoverableError;
use crate::error::Needed;
use crate::stream::AsBStr;
use crate::stream::AsBytes;
use crate::stream::Checkpoint;
use crate::stream::Compare;
use crate::stream::CompareResult;
use crate::stream::FindSlice;
use crate::stream::Location;
use crate::stream::Offset;
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
use crate::stream::Recover;
use crate::stream::SliceLen;
use crate::stream::Stream;
use crate::stream::StreamIsPartial;
use crate::stream::UpdateSlice;
/// Allow recovering from parse errors, capturing them as the parser continues
///
/// Generally, this will be used indirectly via
/// [`RecoverableParser::recoverable_parse`][crate::RecoverableParser::recoverable_parse].
#[derive(Clone, Debug)]
pub struct Recoverable<I, E>
where
I: Stream,
{
input: I,
errors: Vec<E>,
is_recoverable: bool,
}
impl<I, E> Default for Recoverable<I, E>
where
I: Default + Stream,
{
#[inline]
fn default() -> Self {
Self::new(I::default())
}
}
impl<I, E> Recoverable<I, E>
where
I: Stream,
{
/// Track recoverable errors with the stream
#[inline]
pub fn new(input: I) -> Self {
Self {
input,
errors: Default::default(),
is_recoverable: true,
}
}
/// Act as a normal stream
#[inline]
pub fn unrecoverable(input: I) -> Self {
Self {
input,
errors: Default::default(),
is_recoverable: false,
}
}
/// Access the current input and errors
#[inline]
pub fn into_parts(self) -> (I, Vec<E>) {
(self.input, self.errors)
}
}
impl<I, E> AsRef<I> for Recoverable<I, E>
where
I: Stream,
{
#[inline(always)]
fn as_ref(&self) -> &I {
&self.input
}
}
impl<I, E> crate::lib::std::ops::Deref for Recoverable<I, E>
where
I: Stream,
{
type Target = I;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.input
}
}
impl<I: crate::lib::std::fmt::Display, E> crate::lib::std::fmt::Display for Recoverable<I, E>
where
I: Stream,
{
fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result {
crate::lib::std::fmt::Display::fmt(&self.input, f)
}
}
impl<I, E> SliceLen for Recoverable<I, E>
where
I: SliceLen,
I: Stream,
{
#[inline(always)]
fn slice_len(&self) -> usize {
self.input.slice_len()
}
}
impl<I, E: crate::lib::std::fmt::Debug> Stream for Recoverable<I, E>
where
I: Stream,
{
type Token = <I as Stream>::Token;
type Slice = <I as Stream>::Slice;
type IterOffsets = <I as Stream>::IterOffsets;
type Checkpoint = Checkpoint<I::Checkpoint, Self>;
#[inline(always)]
fn iter_offsets(&self) -> Self::IterOffsets {
self.input.iter_offsets()
}
#[inline(always)]
fn eof_offset(&self) -> usize {
self.input.eof_offset()
}
#[inline(always)]
fn next_token(&mut self) -> Option<Self::Token> {
self.input.next_token()
}
#[inline(always)]
fn peek_token(&self) -> Option<Self::Token> {
self.input.peek_token()
}
#[inline(always)]
fn offset_for<P>(&self, predicate: P) -> Option<usize>
where
P: Fn(Self::Token) -> bool,
{
self.input.offset_for(predicate)
}
#[inline(always)]
fn offset_at(&self, tokens: usize) -> Result<usize, Needed> {
self.input.offset_at(tokens)
}
#[inline(always)]
fn next_slice(&mut self, offset: usize) -> Self::Slice {
self.input.next_slice(offset)
}
#[inline(always)]
unsafe fn next_slice_unchecked(&mut self, offset: usize) -> Self::Slice {
// SAFETY: Passing up invariants
unsafe { self.input.next_slice_unchecked(offset) }
}
#[inline(always)]
fn peek_slice(&self, offset: usize) -> Self::Slice {
self.input.peek_slice(offset)
}
#[inline(always)]
unsafe fn peek_slice_unchecked(&self, offset: usize) -> Self::Slice {
// SAFETY: Passing up invariants
unsafe { self.input.peek_slice_unchecked(offset) }
}
#[inline(always)]
fn checkpoint(&self) -> Self::Checkpoint {
Checkpoint::<_, Self>::new(self.input.checkpoint())
}
#[inline(always)]
fn reset(&mut self, checkpoint: &Self::Checkpoint) {
self.input.reset(&checkpoint.inner);
}
#[inline(always)]
fn raw(&self) -> &dyn crate::lib::std::fmt::Debug {
&self.input
}
}
impl<I, E> Location for Recoverable<I, E>
where
I: Location,
I: Stream,
{
#[inline(always)]
fn previous_token_end(&self) -> usize {
self.input.previous_token_end()
}
#[inline(always)]
fn current_token_start(&self) -> usize {
self.input.current_token_start()
}
}
impl<I, E, R> Recover<E> for Recoverable<I, R>
where
I: Stream,
R: FromRecoverableError<Self, E>,
R: crate::lib::std::fmt::Debug,
E: crate::error::ParserError<Self>,
{
fn record_err(
&mut self,
token_start: &Self::Checkpoint,
err_start: &Self::Checkpoint,
err: E,
) -> Result<(), E> {
if self.is_recoverable {
if err.is_incomplete() {
Err(err)
} else {
self.errors
.push(R::from_recoverable_error(token_start, err_start, self, err));
Ok(())
}
} else {
Err(err)
}
}
/// Report whether the [`Stream`] can save off errors for recovery
#[inline(always)]
fn is_recovery_supported() -> bool {
true
}
}
impl<I, E> StreamIsPartial for Recoverable<I, E>
where
I: StreamIsPartial,
I: Stream,
{
type PartialState = I::PartialState;
#[inline]
fn complete(&mut self) -> Self::PartialState {
self.input.complete()
}
#[inline]
fn restore_partial(&mut self, state: Self::PartialState) {
self.input.restore_partial(state);
}
#[inline(always)]
fn is_partial_supported() -> bool {
I::is_partial_supported()
}
#[inline(always)]
fn is_partial(&self) -> bool {
self.input.is_partial()
}
}
impl<I, E> Offset for Recoverable<I, E>
where
I: Stream,
E: crate::lib::std::fmt::Debug,
{
#[inline(always)]
fn offset_from(&self, other: &Self) -> usize {
self.offset_from(&other.checkpoint())
}
}
impl<I, E> Offset<<Recoverable<I, E> as Stream>::Checkpoint> for Recoverable<I, E>
where
I: Stream,
E: crate::lib::std::fmt::Debug,
{
#[inline(always)]
fn offset_from(&self, other: &<Recoverable<I, E> as Stream>::Checkpoint) -> usize {
self.checkpoint().offset_from(other)
}
}
impl<I, E> AsBytes for Recoverable<I, E>
where
I: Stream,
I: AsBytes,
{
#[inline(always)]
fn as_bytes(&self) -> &[u8] {
self.input.as_bytes()
}
}
impl<I, E> AsBStr for Recoverable<I, E>
where
I: Stream,
I: AsBStr,
{
#[inline(always)]
fn as_bstr(&self) -> &[u8] {
self.input.as_bstr()
}
}
impl<I, E, U> Compare<U> for Recoverable<I, E>
where
I: Stream,
I: Compare<U>,
{
#[inline(always)]
fn compare(&self, other: U) -> CompareResult {
self.input.compare(other)
}
}
impl<I, E, T> FindSlice<T> for Recoverable<I, E>
where
I: Stream,
I: FindSlice<T>,
{
#[inline(always)]
fn find_slice(&self, substr: T) -> Option<crate::lib::std::ops::Range<usize>> {
self.input.find_slice(substr)
}
}
impl<I, E> UpdateSlice for Recoverable<I, E>
where
I: Stream,
I: UpdateSlice,
E: crate::lib::std::fmt::Debug,
{
#[inline(always)]
fn update_slice(mut self, inner: Self::Slice) -> Self {
self.input = I::update_slice(self.input, inner);
self
}
}

312
vendor/winnow/src/stream/stateful.rs vendored Normal file
View File

@@ -0,0 +1,312 @@
use crate::error::Needed;
use crate::stream::AsBStr;
use crate::stream::AsBytes;
use crate::stream::Checkpoint;
use crate::stream::Compare;
use crate::stream::CompareResult;
use crate::stream::FindSlice;
use crate::stream::Location;
use crate::stream::Offset;
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
use crate::stream::Recover;
use crate::stream::SliceLen;
use crate::stream::Stream;
use crate::stream::StreamIsPartial;
use crate::stream::UpdateSlice;
/// Thread global state through your parsers
///
/// Use cases
/// - Recursion checks
/// - Error recovery
/// - Debugging
///
/// # Example
///
/// ```
/// # use std::cell::Cell;
/// # use winnow::prelude::*;
/// # use winnow::stream::Stateful;
/// # use winnow::ascii::alpha1;
/// # type Error = ();
///
/// #[derive(Debug)]
/// struct State<'s>(&'s mut u32);
///
/// impl<'s> State<'s> {
/// fn count(&mut self) {
/// *self.0 += 1;
/// }
/// }
///
/// type Stream<'is> = Stateful<&'is str, State<'is>>;
///
/// fn word<'s>(i: &mut Stream<'s>) -> ModalResult<&'s str> {
/// i.state.count();
/// alpha1.parse_next(i)
/// }
///
/// let data = "Hello";
/// let mut state = 0;
/// let input = Stream { input: data, state: State(&mut state) };
/// let output = word.parse(input).unwrap();
/// assert_eq!(state, 1);
/// ```
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
#[doc(alias = "LocatingSliceSpan")]
pub struct Stateful<I, S> {
/// Inner input being wrapped in state
pub input: I,
/// User-provided state
pub state: S,
}
impl<I, S> AsRef<I> for Stateful<I, S> {
#[inline(always)]
fn as_ref(&self) -> &I {
&self.input
}
}
impl<I, S> crate::lib::std::ops::Deref for Stateful<I, S> {
type Target = I;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
impl<I: crate::lib::std::fmt::Display, S> crate::lib::std::fmt::Display for Stateful<I, S> {
fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result {
self.input.fmt(f)
}
}
impl<I, S> SliceLen for Stateful<I, S>
where
I: SliceLen,
{
#[inline(always)]
fn slice_len(&self) -> usize {
self.input.slice_len()
}
}
impl<I: Stream, S: crate::lib::std::fmt::Debug> Stream for Stateful<I, S> {
type Token = <I as Stream>::Token;
type Slice = <I as Stream>::Slice;
type IterOffsets = <I as Stream>::IterOffsets;
type Checkpoint = Checkpoint<I::Checkpoint, Self>;
#[inline(always)]
fn iter_offsets(&self) -> Self::IterOffsets {
self.input.iter_offsets()
}
#[inline(always)]
fn eof_offset(&self) -> usize {
self.input.eof_offset()
}
#[inline(always)]
fn next_token(&mut self) -> Option<Self::Token> {
self.input.next_token()
}
#[inline(always)]
fn peek_token(&self) -> Option<Self::Token> {
self.input.peek_token()
}
#[inline(always)]
fn offset_for<P>(&self, predicate: P) -> Option<usize>
where
P: Fn(Self::Token) -> bool,
{
self.input.offset_for(predicate)
}
#[inline(always)]
fn offset_at(&self, tokens: usize) -> Result<usize, Needed> {
self.input.offset_at(tokens)
}
#[inline(always)]
fn next_slice(&mut self, offset: usize) -> Self::Slice {
self.input.next_slice(offset)
}
#[inline(always)]
unsafe fn next_slice_unchecked(&mut self, offset: usize) -> Self::Slice {
// SAFETY: Passing up invariants
unsafe { self.input.next_slice_unchecked(offset) }
}
#[inline(always)]
fn peek_slice(&self, offset: usize) -> Self::Slice {
self.input.peek_slice(offset)
}
#[inline(always)]
unsafe fn peek_slice_unchecked(&self, offset: usize) -> Self::Slice {
// SAFETY: Passing up invariants
unsafe { self.input.peek_slice_unchecked(offset) }
}
#[inline(always)]
fn checkpoint(&self) -> Self::Checkpoint {
Checkpoint::<_, Self>::new(self.input.checkpoint())
}
#[inline(always)]
fn reset(&mut self, checkpoint: &Self::Checkpoint) {
self.input.reset(&checkpoint.inner);
}
#[inline(always)]
fn raw(&self) -> &dyn crate::lib::std::fmt::Debug {
#![allow(deprecated)]
self.input.raw()
}
fn trace(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.input.trace(f)
}
}
impl<I, S> Location for Stateful<I, S>
where
I: Location,
{
#[inline(always)]
fn previous_token_end(&self) -> usize {
self.input.previous_token_end()
}
#[inline(always)]
fn current_token_start(&self) -> usize {
self.input.current_token_start()
}
}
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
impl<I, E, S> Recover<E> for Stateful<I, S>
where
I: Recover<E>,
I: Stream,
S: Clone + crate::lib::std::fmt::Debug,
{
#[inline(always)]
fn record_err(
&mut self,
_token_start: &Self::Checkpoint,
_err_start: &Self::Checkpoint,
err: E,
) -> Result<(), E> {
Err(err)
}
/// Report whether the [`Stream`] can save off errors for recovery
#[inline(always)]
fn is_recovery_supported() -> bool {
false
}
}
impl<I, S> StreamIsPartial for Stateful<I, S>
where
I: StreamIsPartial,
{
type PartialState = I::PartialState;
#[inline]
fn complete(&mut self) -> Self::PartialState {
self.input.complete()
}
#[inline]
fn restore_partial(&mut self, state: Self::PartialState) {
self.input.restore_partial(state);
}
#[inline(always)]
fn is_partial_supported() -> bool {
I::is_partial_supported()
}
#[inline(always)]
fn is_partial(&self) -> bool {
self.input.is_partial()
}
}
impl<I, S> Offset for Stateful<I, S>
where
I: Stream,
S: Clone + crate::lib::std::fmt::Debug,
{
#[inline(always)]
fn offset_from(&self, start: &Self) -> usize {
self.offset_from(&start.checkpoint())
}
}
impl<I, S> Offset<<Stateful<I, S> as Stream>::Checkpoint> for Stateful<I, S>
where
I: Stream,
S: crate::lib::std::fmt::Debug,
{
#[inline(always)]
fn offset_from(&self, other: &<Stateful<I, S> as Stream>::Checkpoint) -> usize {
self.checkpoint().offset_from(other)
}
}
impl<I, S> AsBytes for Stateful<I, S>
where
I: AsBytes,
{
#[inline(always)]
fn as_bytes(&self) -> &[u8] {
self.input.as_bytes()
}
}
impl<I, S> AsBStr for Stateful<I, S>
where
I: AsBStr,
{
#[inline(always)]
fn as_bstr(&self) -> &[u8] {
self.input.as_bstr()
}
}
impl<I, S, U> Compare<U> for Stateful<I, S>
where
I: Compare<U>,
{
#[inline(always)]
fn compare(&self, other: U) -> CompareResult {
self.input.compare(other)
}
}
impl<I, S, T> FindSlice<T> for Stateful<I, S>
where
I: FindSlice<T>,
{
#[inline(always)]
fn find_slice(&self, substr: T) -> Option<crate::lib::std::ops::Range<usize>> {
self.input.find_slice(substr)
}
}
impl<I, S> UpdateSlice for Stateful<I, S>
where
I: UpdateSlice,
S: Clone + crate::lib::std::fmt::Debug,
{
#[inline(always)]
fn update_slice(mut self, inner: Self::Slice) -> Self {
self.input = I::update_slice(self.input, inner);
self
}
}

275
vendor/winnow/src/stream/tests.rs vendored Normal file
View File

@@ -0,0 +1,275 @@
#[cfg(feature = "std")]
use proptest::prelude::*;
use crate::error::ErrMode;
use crate::error::ErrMode::Backtrack;
use crate::error::InputError;
use crate::token::literal;
use crate::{
combinator::{separated, separated_pair},
ModalResult, Parser,
};
use super::*;
#[cfg(feature = "std")]
#[test]
fn test_fxhashmap_compiles() {
let input = "a=b";
fn pair(i: &mut &str) -> ModalResult<(char, char)> {
let out = separated_pair('a', '=', 'b').parse_next(i)?;
Ok(out)
}
let _: rustc_hash::FxHashMap<char, char> = separated(0.., pair, ',').parse(input).unwrap();
}
#[test]
fn test_offset_u8() {
let s = b"abcd123";
let a = &s[..];
let b = &a[2..];
let c = &a[..4];
let d = &a[3..5];
assert_eq!(b.offset_from(&a), 2);
assert_eq!(c.offset_from(&a), 0);
assert_eq!(d.offset_from(&a), 3);
}
#[test]
fn test_offset_str() {
let a = "abcřèÂßÇd123";
let b = &a[7..];
let c = &a[..5];
let d = &a[5..9];
assert_eq!(b.offset_from(&a), 7);
assert_eq!(c.offset_from(&a), 0);
assert_eq!(d.offset_from(&a), 5);
}
#[test]
#[cfg(feature = "alloc")]
fn test_bit_stream_empty() {
let i = (&b""[..], 0);
let actual = i.iter_offsets().collect::<crate::lib::std::vec::Vec<_>>();
assert_eq!(actual, vec![]);
let actual = i.eof_offset();
assert_eq!(actual, 0);
let actual = i.peek_token();
assert_eq!(actual, None);
let actual = i.offset_for(|b| b);
assert_eq!(actual, None);
let actual = i.offset_at(1);
assert_eq!(actual, Err(Needed::new(1)));
let actual_slice = i.peek_slice(0);
assert_eq!(actual_slice, (&b""[..], 0, 0));
}
#[test]
#[cfg(feature = "alloc")]
fn test_bit_offset_empty() {
let i = (&b""[..], 0);
let actual = i.offset_from(&i);
assert_eq!(actual, 0);
}
#[cfg(feature = "std")]
proptest! {
#[test]
#[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253
fn bit_stream(byte_len in 0..20usize, start in 0..160usize) {
bit_stream_inner(byte_len, start);
}
}
#[cfg(feature = "std")]
fn bit_stream_inner(byte_len: usize, start: usize) {
let start = start.min(byte_len * 8);
let start_byte = start / 8;
let start_bit = start % 8;
let bytes = vec![0b1010_1010; byte_len];
let i = (&bytes[start_byte..], start_bit);
let mut curr_i = i;
let mut curr_offset = 0;
while let Some(_token) = curr_i.peek_token() {
let to_offset = curr_i.offset_from(&i);
assert_eq!(curr_offset, to_offset);
let actual_slice = i.peek_slice(curr_offset);
let expected_slice = i.clone().peek_slice(curr_offset);
assert_eq!(actual_slice, expected_slice);
let at_offset = i.offset_at(curr_offset).unwrap();
assert_eq!(curr_offset, at_offset);
let eof_offset = curr_i.eof_offset();
let eof_slice = curr_i.peek_slice(eof_offset);
let eof_slice_i = (eof_slice.0, eof_slice.1);
assert_eq!(eof_slice_i, curr_i);
curr_offset += 1;
let _ = curr_i.next_token();
}
assert_eq!(i.eof_offset(), curr_offset);
}
#[test]
fn test_partial_complete() {
let mut i = Partial::new(&b""[..]);
assert!(Partial::<&[u8]>::is_partial_supported());
assert!(i.is_partial(), "incomplete by default");
let incomplete_state = i.complete();
assert!(!i.is_partial(), "the stream should be marked as complete");
i.restore_partial(incomplete_state);
assert!(i.is_partial(), "incomplete stream state should be restored");
}
#[test]
fn test_custom_slice() {
type Token = usize;
type TokenSlice<'i> = &'i [Token];
let mut tokens: TokenSlice<'_> = &[1, 2, 3, 4];
let input = &mut tokens;
let start = input.checkpoint();
let _ = input.next_token();
let _ = input.next_token();
let offset = input.offset_from(&start);
assert_eq!(offset, 2);
}
#[test]
fn test_literal_support_char() {
assert_eq!(
literal::<_, _, ErrMode<InputError<_>>>('π').parse_peek("π"),
Ok(("", "π"))
);
assert_eq!(
literal::<_, _, ErrMode<InputError<_>>>('π').parse_peek("π3.14"),
Ok(("3.14", "π"))
);
assert_eq!(
literal::<_, _, ErrMode<InputError<_>>>("π").parse_peek("π3.14"),
Ok(("3.14", "π"))
);
assert_eq!(
literal::<_, _, ErrMode<InputError<_>>>('-').parse_peek("π"),
Err(Backtrack(InputError::at("π")))
);
assert_eq!(
literal::<_, Partial<&[u8]>, ErrMode<InputError<_>>>('π')
.parse_peek(Partial::new(b"\xCF\x80")),
Ok((Partial::new(Default::default()), "π".as_bytes()))
);
assert_eq!(
literal::<_, &[u8], ErrMode<InputError<_>>>('π').parse_peek(b"\xCF\x80"),
Ok((Default::default(), "π".as_bytes()))
);
assert_eq!(
literal::<_, Partial<&[u8]>, ErrMode<InputError<_>>>('π')
.parse_peek(Partial::new(b"\xCF\x803.14")),
Ok((Partial::new(&b"3.14"[..]), "π".as_bytes()))
);
assert_eq!(
literal::<_, &[u8], ErrMode<InputError<_>>>('π').parse_peek(b"\xCF\x80"),
Ok((Default::default(), "π".as_bytes()))
);
assert_eq!(
literal::<_, &[u8], ErrMode<InputError<_>>>('π').parse_peek(b"\xCF\x803.14"),
Ok((&b"3.14"[..], "π".as_bytes()))
);
assert_eq!(
literal::<_, &[u8], ErrMode<InputError<_>>>(AsciiCaseless('a')).parse_peek(b"ABCxyz"),
Ok((&b"BCxyz"[..], &b"A"[..]))
);
assert_eq!(
literal::<_, &[u8], ErrMode<InputError<_>>>('a').parse_peek(b"ABCxyz"),
Err(Backtrack(InputError::at(&b"ABCxyz"[..],)))
);
assert_eq!(
literal::<_, &[u8], ErrMode<InputError<_>>>(AsciiCaseless('π')).parse_peek(b"\xCF\x803.14"),
Ok((&b"3.14"[..], "π".as_bytes()))
);
assert_eq!(
literal::<_, _, ErrMode<InputError<_>>>(AsciiCaseless('🧑')).parse_peek("🧑你好"),
Ok(("你好", "🧑"))
);
let mut buffer = [0; 4];
let input = '\u{241b}'.encode_utf8(&mut buffer);
assert_eq!(
literal::<_, &[u8], ErrMode<InputError<_>>>(AsciiCaseless('␛'))
.parse_peek(input.as_bytes()),
Ok((&b""[..], [226, 144, 155].as_slice()))
);
assert_eq!(
literal::<_, &[u8], ErrMode<InputError<_>>>('-').parse_peek(b"\xCF\x80"),
Err(Backtrack(InputError::at(&b"\xCF\x80"[..],)))
);
}
#[test]
fn tokenslice_location() {
#[derive(Clone, Debug)]
struct Token {
span: crate::lib::std::ops::Range<usize>,
}
impl Location for Token {
#[inline(always)]
fn previous_token_end(&self) -> usize {
self.span.end
}
#[inline(always)]
fn current_token_start(&self) -> usize {
self.span.start
}
}
let input = [
Token { span: 1..9 },
Token { span: 11..19 },
Token { span: 21..29 },
];
let mut input = TokenSlice::new(&input);
assert_eq!(input.previous_token_end(), 1);
// Parse operation
assert_eq!(input.current_token_start(), 1);
let _ = input.next_token();
assert_eq!(input.previous_token_end(), 9);
// Parse operation
assert_eq!(input.current_token_start(), 11);
let _ = input.next_token();
assert_eq!(input.previous_token_end(), 19);
// Parse operation
assert_eq!(input.current_token_start(), 21);
let _ = input.next_token();
assert_eq!(input.previous_token_end(), 29);
assert_eq!(input.current_token_start(), 29);
}

314
vendor/winnow/src/stream/token.rs vendored Normal file
View File

@@ -0,0 +1,314 @@
use crate::error::Needed;
use crate::lib::std::iter::Enumerate;
use crate::lib::std::slice::Iter;
use crate::stream::Checkpoint;
use crate::stream::Compare;
use crate::stream::CompareResult;
use crate::stream::Location;
use crate::stream::Offset;
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
use crate::stream::Recover;
use crate::stream::SliceLen;
use crate::stream::Stream;
use crate::stream::StreamIsPartial;
use crate::stream::UpdateSlice;
/// Specialized input for parsing lexed tokens
///
/// Helpful impls
/// - Any `PartialEq` type (e.g. a `TokenKind` or `&str`) can be used with
/// [`literal`][crate::token::literal]
/// - A `PartialEq` for `&str` allows for using `&str` as a parser for tokens
/// - [`ContainsToken`][crate::stream::ContainsToken] for `T` to for parsing with token sets
/// - [`Location`] for `T` to extract spans from tokens
///
/// See also [Lexing and Parsing][crate::_topic::lexing].
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct TokenSlice<'t, T> {
initial: &'t [T],
input: &'t [T],
}
impl<'t, T> TokenSlice<'t, T>
where
T: crate::lib::std::fmt::Debug + Clone,
{
/// Make a stream to parse tokens
#[inline]
pub fn new(input: &'t [T]) -> Self {
Self {
initial: input,
input,
}
}
/// Reset the stream to the start
///
/// This is useful for formats that encode a graph with addresses relative to the start of the
/// input.
#[doc(alias = "fseek")]
#[inline]
pub fn reset_to_start(&mut self) {
let start = self.initial.checkpoint();
self.input.reset(&start);
}
/// Iterate over consumed tokens starting with the last emitted
///
/// This is intended to help build up appropriate context when reporting errors.
#[inline]
pub fn previous_tokens(&self) -> impl Iterator<Item = &'t T> {
let offset = self.input.offset_from(&self.initial);
self.initial[0..offset].iter().rev()
}
}
/// Track locations by implementing [`Location`] on the Token.
impl<T> TokenSlice<'_, T>
where
T: Location,
{
#[inline(always)]
fn previous_token_end(&self) -> Option<usize> {
let index = self.input.offset_from(&self.initial);
index
.checked_sub(1)
.map(|i| self.initial[i].previous_token_end())
}
#[inline(always)]
fn current_token_start(&self) -> Option<usize> {
self.input.first().map(|t| t.current_token_start())
}
}
impl<T> Default for TokenSlice<'_, T>
where
T: crate::lib::std::fmt::Debug + Clone,
{
fn default() -> Self {
Self::new(&[])
}
}
impl<T> crate::lib::std::ops::Deref for TokenSlice<'_, T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.input
}
}
impl<T: core::fmt::Debug> core::fmt::Debug for TokenSlice<'_, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.input.fmt(f)
}
}
impl<T> SliceLen for TokenSlice<'_, T> {
#[inline(always)]
fn slice_len(&self) -> usize {
self.input.slice_len()
}
}
impl<'t, T> Stream for TokenSlice<'t, T>
where
T: crate::lib::std::fmt::Debug + Clone,
{
type Token = &'t T;
type Slice = &'t [T];
type IterOffsets = Enumerate<Iter<'t, T>>;
type Checkpoint = Checkpoint<&'t [T], Self>;
#[inline(always)]
fn iter_offsets(&self) -> Self::IterOffsets {
self.input.iter().enumerate()
}
#[inline(always)]
fn eof_offset(&self) -> usize {
self.input.eof_offset()
}
#[inline(always)]
fn next_token(&mut self) -> Option<Self::Token> {
let (token, next) = self.input.split_first()?;
self.input = next;
Some(token)
}
#[inline(always)]
fn peek_token(&self) -> Option<Self::Token> {
self.input.first()
}
#[inline(always)]
fn offset_for<P>(&self, predicate: P) -> Option<usize>
where
P: Fn(Self::Token) -> bool,
{
self.input.iter().position(predicate)
}
#[inline(always)]
fn offset_at(&self, tokens: usize) -> Result<usize, Needed> {
self.input.offset_at(tokens)
}
#[inline(always)]
fn next_slice(&mut self, offset: usize) -> Self::Slice {
self.input.next_slice(offset)
}
#[inline(always)]
unsafe fn next_slice_unchecked(&mut self, offset: usize) -> Self::Slice {
// SAFETY: Passing up invariants
unsafe { self.input.next_slice_unchecked(offset) }
}
#[inline(always)]
fn peek_slice(&self, offset: usize) -> Self::Slice {
self.input.peek_slice(offset)
}
#[inline(always)]
unsafe fn peek_slice_unchecked(&self, offset: usize) -> Self::Slice {
// SAFETY: Passing up invariants
unsafe { self.input.peek_slice_unchecked(offset) }
}
#[inline(always)]
fn checkpoint(&self) -> Self::Checkpoint {
Checkpoint::<_, Self>::new(self.input)
}
#[inline(always)]
fn reset(&mut self, checkpoint: &Self::Checkpoint) {
self.input = checkpoint.inner;
}
#[inline(always)]
fn raw(&self) -> &dyn crate::lib::std::fmt::Debug {
#![allow(deprecated)]
self.input.raw()
}
fn trace(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.input.trace(f)
}
}
impl<T> Location for TokenSlice<'_, T>
where
T: Location,
{
#[inline(always)]
fn previous_token_end(&self) -> usize {
self.previous_token_end()
.or_else(|| self.current_token_start())
.unwrap_or(0)
}
#[inline(always)]
fn current_token_start(&self) -> usize {
self.current_token_start()
.or_else(|| self.previous_token_end())
.unwrap_or(0)
}
}
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
impl<T, E> Recover<E> for TokenSlice<'_, T>
where
T: crate::lib::std::fmt::Debug + Clone,
{
#[inline(always)]
fn record_err(
&mut self,
_token_start: &Self::Checkpoint,
_err_start: &Self::Checkpoint,
err: E,
) -> Result<(), E> {
Err(err)
}
/// Report whether the [`Stream`] can save off errors for recovery
#[inline(always)]
fn is_recovery_supported() -> bool {
false
}
}
impl<'t, T> StreamIsPartial for TokenSlice<'t, T>
where
T: crate::lib::std::fmt::Debug + Clone,
{
type PartialState = <&'t [T] as StreamIsPartial>::PartialState;
#[inline]
fn complete(&mut self) -> Self::PartialState {
#![allow(clippy::semicolon_if_nothing_returned)]
self.input.complete()
}
#[inline]
fn restore_partial(&mut self, state: Self::PartialState) {
self.input.restore_partial(state);
}
#[inline(always)]
fn is_partial_supported() -> bool {
<&[T] as StreamIsPartial>::is_partial_supported()
}
#[inline(always)]
fn is_partial(&self) -> bool {
self.input.is_partial()
}
}
impl<T> Offset for TokenSlice<'_, T>
where
T: crate::lib::std::fmt::Debug + Clone,
{
#[inline(always)]
fn offset_from(&self, other: &Self) -> usize {
self.offset_from(&other.checkpoint())
}
}
impl<T> Offset<<TokenSlice<'_, T> as Stream>::Checkpoint> for TokenSlice<'_, T>
where
T: crate::lib::std::fmt::Debug + Clone,
{
#[inline(always)]
fn offset_from(&self, other: &<TokenSlice<'_, T> as Stream>::Checkpoint) -> usize {
self.checkpoint().offset_from(other)
}
}
impl<T, O> Compare<O> for TokenSlice<'_, T>
where
T: PartialEq<O> + Eq,
{
#[inline]
fn compare(&self, t: O) -> CompareResult {
if let Some(token) = self.first() {
if *token == t {
CompareResult::Ok(1)
} else {
CompareResult::Error
}
} else {
CompareResult::Incomplete
}
}
}
impl<T> UpdateSlice for TokenSlice<'_, T>
where
T: crate::lib::std::fmt::Debug + Clone,
{
#[inline(always)]
fn update_slice(mut self, inner: Self::Slice) -> Self {
self.input = <&[T] as UpdateSlice>::update_slice(self.input, inner);
self
}
}

1094
vendor/winnow/src/token/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

2895
vendor/winnow/src/token/tests.rs vendored Normal file

File diff suppressed because it is too large Load Diff