Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
1
third-party/vendor/winnow/.cargo-checksum.json
vendored
Normal file
1
third-party/vendor/winnow/.cargo-checksum.json
vendored
Normal file
File diff suppressed because one or more lines are too long
1422
third-party/vendor/winnow/Cargo.lock
generated
vendored
Normal file
1422
third-party/vendor/winnow/Cargo.lock
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
260
third-party/vendor/winnow/Cargo.toml
vendored
Normal file
260
third-party/vendor/winnow/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
# 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.64.0"
|
||||
name = "winnow"
|
||||
version = "0.5.40"
|
||||
include = [
|
||||
"build.rs",
|
||||
"src/**/*",
|
||||
"Cargo.toml",
|
||||
"Cargo.lock",
|
||||
"LICENSE*",
|
||||
"README.md",
|
||||
"benches/**/*",
|
||||
"examples/**/*",
|
||||
]
|
||||
autoexamples = 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]
|
||||
cargo-args = [
|
||||
"-Zunstable-options",
|
||||
"-Zrustdoc-scrape-examples",
|
||||
]
|
||||
features = ["unstable-doc"]
|
||||
rustdoc-args = [
|
||||
"--cfg",
|
||||
"docsrs",
|
||||
]
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "CHANGELOG.md"
|
||||
min = 1
|
||||
replace = "{{version}}"
|
||||
search = "Unreleased"
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
exactly = 1
|
||||
file = "CHANGELOG.md"
|
||||
replace = "...{{tag_name}}"
|
||||
search = '\.\.\.HEAD'
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "CHANGELOG.md"
|
||||
min = 1
|
||||
replace = "{{date}}"
|
||||
search = "ReleaseDate"
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
exactly = 1
|
||||
file = "CHANGELOG.md"
|
||||
replace = """
|
||||
<!-- next-header -->
|
||||
## [Unreleased] - ReleaseDate
|
||||
"""
|
||||
search = "<!-- next-header -->"
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
exactly = 1
|
||||
file = "CHANGELOG.md"
|
||||
replace = """
|
||||
<!-- next-url -->
|
||||
[Unreleased]: https://github.com/winnow-rs/winnow/compare/{{tag_name}}...HEAD"""
|
||||
search = "<!-- next-url -->"
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
exactly = 1
|
||||
file = "src/lib.rs"
|
||||
replace = "blob/v{{version}}/CHANGELOG.md"
|
||||
search = 'blob/v.+\..+\..+/CHANGELOG.md'
|
||||
|
||||
[profile.bench]
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
|
||||
[[example]]
|
||||
name = "arithmetic"
|
||||
test = true
|
||||
required-features = ["alloc"]
|
||||
|
||||
[[example]]
|
||||
name = "css"
|
||||
test = true
|
||||
required-features = ["alloc"]
|
||||
|
||||
[[example]]
|
||||
name = "custom_error"
|
||||
test = true
|
||||
required-features = ["alloc"]
|
||||
|
||||
[[example]]
|
||||
name = "http"
|
||||
required-features = ["alloc"]
|
||||
|
||||
[[example]]
|
||||
name = "ini"
|
||||
test = true
|
||||
required-features = ["std"]
|
||||
|
||||
[[example]]
|
||||
name = "json"
|
||||
test = true
|
||||
required-features = ["std"]
|
||||
|
||||
[[example]]
|
||||
name = "ndjson"
|
||||
test = true
|
||||
required-features = ["std"]
|
||||
|
||||
[[example]]
|
||||
name = "json_iterator"
|
||||
required-features = ["std"]
|
||||
|
||||
[[example]]
|
||||
name = "iterator"
|
||||
|
||||
[[example]]
|
||||
name = "s_expression"
|
||||
required-features = ["alloc"]
|
||||
|
||||
[[example]]
|
||||
name = "string"
|
||||
required-features = ["alloc"]
|
||||
|
||||
[[bench]]
|
||||
name = "arithmetic"
|
||||
path = "examples/arithmetic/bench.rs"
|
||||
harness = false
|
||||
required-features = ["alloc"]
|
||||
|
||||
[[bench]]
|
||||
name = "contains_token"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "find_slice"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "iter"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "next_slice"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "number"
|
||||
harness = false
|
||||
|
||||
[[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]
|
||||
version = "0.4.9"
|
||||
optional = true
|
||||
|
||||
[dependencies.memchr]
|
||||
version = "2.5"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.terminal_size]
|
||||
version = "0.2.6"
|
||||
optional = true
|
||||
|
||||
[dev-dependencies.circular]
|
||||
version = "0.3.0"
|
||||
|
||||
[dev-dependencies.criterion]
|
||||
version = "0.5.1"
|
||||
|
||||
[dev-dependencies.doc-comment]
|
||||
version = "0.3"
|
||||
|
||||
[dev-dependencies.escargot]
|
||||
version = "0.5.7"
|
||||
|
||||
[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.4.11"
|
||||
features = ["examples"]
|
||||
|
||||
[dev-dependencies.term-transcript]
|
||||
version = "0.2.0"
|
||||
|
||||
[features]
|
||||
alloc = []
|
||||
debug = [
|
||||
"dep:anstream",
|
||||
"dep:anstyle",
|
||||
"dep:is-terminal",
|
||||
"dep:terminal_size",
|
||||
]
|
||||
default = ["std"]
|
||||
simd = ["dep:memchr"]
|
||||
std = [
|
||||
"alloc",
|
||||
"memchr?/std",
|
||||
]
|
||||
unstable-doc = [
|
||||
"alloc",
|
||||
"std",
|
||||
"simd",
|
||||
"unstable-recover",
|
||||
]
|
||||
unstable-recover = []
|
||||
18
third-party/vendor/winnow/LICENSE-MIT
vendored
Normal file
18
third-party/vendor/winnow/LICENSE-MIT
vendored
Normal 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
third-party/vendor/winnow/README.md
vendored
Normal file
27
third-party/vendor/winnow/README.md
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# winnow, making parsing a breeze
|
||||
|
||||
[](LICENSE)
|
||||
[](https://github.com/winnow-rs/winnow/actions/workflows/ci.yml)
|
||||
[](https://coveralls.io/github/winnow-rs/winnow?branch=main)
|
||||
[](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>
|
||||
114
third-party/vendor/winnow/benches/contains_token.rs
vendored
Normal file
114
third-party/vendor/winnow/benches/contains_token.rs
vendored
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
use criterion::black_box;
|
||||
|
||||
use winnow::combinator::alt;
|
||||
use winnow::combinator::repeat;
|
||||
use winnow::prelude::*;
|
||||
use winnow::token::take_till;
|
||||
use winnow::token::take_while;
|
||||
|
||||
fn contains_token(c: &mut criterion::Criterion) {
|
||||
let data = [
|
||||
("contiguous", CONTIGUOUS),
|
||||
("interleaved", INTERLEAVED),
|
||||
("canada", CANADA),
|
||||
];
|
||||
let mut group = c.benchmark_group("contains_token");
|
||||
for (name, sample) in data {
|
||||
let len = sample.len();
|
||||
group.throughput(criterion::Throughput::Bytes(len as u64));
|
||||
|
||||
group.bench_with_input(criterion::BenchmarkId::new("slice", name), &len, |b, _| {
|
||||
b.iter(|| black_box(parser_slice.parse_peek(black_box(sample)).unwrap()));
|
||||
});
|
||||
group.bench_with_input(criterion::BenchmarkId::new("array", name), &len, |b, _| {
|
||||
b.iter(|| black_box(parser_array.parse_peek(black_box(sample)).unwrap()));
|
||||
});
|
||||
group.bench_with_input(criterion::BenchmarkId::new("tuple", name), &len, |b, _| {
|
||||
b.iter(|| black_box(parser_tuple.parse_peek(black_box(sample)).unwrap()));
|
||||
});
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("closure-or", name),
|
||||
&len,
|
||||
|b, _| {
|
||||
b.iter(|| black_box(parser_closure_or.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("closure-matches", name),
|
||||
&len,
|
||||
|b, _| {
|
||||
b.iter(|| {
|
||||
black_box(
|
||||
parser_closure_matches
|
||||
.parse_peek(black_box(sample))
|
||||
.unwrap(),
|
||||
)
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
fn parser_slice(input: &mut &str) -> PResult<usize> {
|
||||
let contains = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'][..];
|
||||
repeat(
|
||||
0..,
|
||||
alt((take_while(1.., contains), take_till(1.., contains))),
|
||||
)
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn parser_array(input: &mut &str) -> PResult<usize> {
|
||||
let contains = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||
repeat(
|
||||
0..,
|
||||
alt((take_while(1.., contains), take_till(1.., contains))),
|
||||
)
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn parser_tuple(input: &mut &str) -> PResult<usize> {
|
||||
let contains = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
|
||||
repeat(
|
||||
0..,
|
||||
alt((take_while(1.., contains), take_till(1.., contains))),
|
||||
)
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn parser_closure_or(input: &mut &str) -> PResult<usize> {
|
||||
let contains = |c: char| {
|
||||
c == '0'
|
||||
|| c == '1'
|
||||
|| c == '2'
|
||||
|| c == '3'
|
||||
|| c == '4'
|
||||
|| c == '5'
|
||||
|| c == '6'
|
||||
|| c == '7'
|
||||
|| c == '8'
|
||||
|| c == '9'
|
||||
};
|
||||
repeat(
|
||||
0..,
|
||||
alt((take_while(1.., contains), take_till(1.., contains))),
|
||||
)
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn parser_closure_matches(input: &mut &str) -> PResult<usize> {
|
||||
let contains = |c: char| matches!(c, '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9');
|
||||
repeat(
|
||||
0..,
|
||||
alt((take_while(1.., contains), take_till(1.., contains))),
|
||||
)
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
const CONTIGUOUS: &str = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
|
||||
const INTERLEAVED: &str = "0123456789abc0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab";
|
||||
const CANADA: &str = include_str!("../third_party/nativejson-benchmark/data/canada.json");
|
||||
|
||||
criterion::criterion_group!(benches, contains_token);
|
||||
criterion::criterion_main!(benches);
|
||||
50
third-party/vendor/winnow/benches/find_slice.rs
vendored
Normal file
50
third-party/vendor/winnow/benches/find_slice.rs
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
use criterion::black_box;
|
||||
|
||||
use winnow::combinator::repeat;
|
||||
use winnow::prelude::*;
|
||||
use winnow::token::take_until;
|
||||
|
||||
fn find_slice(c: &mut criterion::Criterion) {
|
||||
let empty = "";
|
||||
let start_byte = "\r".repeat(100);
|
||||
let start_slice = "\r\n".repeat(100);
|
||||
let small = format!("{:>10}\r\n", "").repeat(100);
|
||||
let large = format!("{:>10000}\r\n", "").repeat(100);
|
||||
|
||||
let data = [
|
||||
("empty", (empty, empty)),
|
||||
("start", (&start_byte, &start_slice)),
|
||||
("medium", (&small, &small)),
|
||||
("large", (&large, &large)),
|
||||
];
|
||||
let mut group = c.benchmark_group("find_slice");
|
||||
for (name, samples) in data {
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("byte", name),
|
||||
samples.0,
|
||||
|b, sample| {
|
||||
b.iter(|| black_box(parser_byte.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("slice", name),
|
||||
samples.1,
|
||||
|b, sample| {
|
||||
b.iter(|| black_box(parser_slice.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
fn parser_byte(input: &mut &str) -> PResult<usize> {
|
||||
repeat(0.., (take_until(0.., "\r"), "\r")).parse_next(input)
|
||||
}
|
||||
|
||||
fn parser_slice(input: &mut &str) -> PResult<usize> {
|
||||
repeat(0.., (take_until(0.., "\r\n"), "\r\n")).parse_next(input)
|
||||
}
|
||||
|
||||
criterion::criterion_group!(benches, find_slice);
|
||||
criterion::criterion_main!(benches);
|
||||
120
third-party/vendor/winnow/benches/iter.rs
vendored
Normal file
120
third-party/vendor/winnow/benches/iter.rs
vendored
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
use criterion::black_box;
|
||||
|
||||
use winnow::combinator::opt;
|
||||
use winnow::prelude::*;
|
||||
use winnow::stream::AsChar;
|
||||
use winnow::stream::Stream as _;
|
||||
use winnow::token::one_of;
|
||||
|
||||
fn iter(c: &mut criterion::Criterion) {
|
||||
let data = [
|
||||
("contiguous", CONTIGUOUS.as_bytes()),
|
||||
("interleaved", INTERLEAVED.as_bytes()),
|
||||
("canada", CANADA.as_bytes()),
|
||||
];
|
||||
let mut group = c.benchmark_group("iter");
|
||||
for (name, sample) in data {
|
||||
let len = sample.len();
|
||||
group.throughput(criterion::Throughput::Bytes(len as u64));
|
||||
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("iterate", name),
|
||||
&len,
|
||||
|b, _| {
|
||||
b.iter(|| black_box(iterate.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("next_token", name),
|
||||
&len,
|
||||
|b, _| {
|
||||
b.iter(|| black_box(next_token.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("opt(one_of)", name),
|
||||
&len,
|
||||
|b, _| {
|
||||
b.iter(|| black_box(opt_one_of.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("take_while", name),
|
||||
&len,
|
||||
|b, _| {
|
||||
b.iter(|| black_box(take_while.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
group.bench_with_input(criterion::BenchmarkId::new("repeat", name), &len, |b, _| {
|
||||
b.iter(|| black_box(repeat.parse_peek(black_box(sample)).unwrap()));
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
fn iterate(input: &mut &[u8]) -> PResult<usize> {
|
||||
let mut count = 0;
|
||||
for byte in input.iter() {
|
||||
if byte.is_dec_digit() {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
input.finish();
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
fn next_token(input: &mut &[u8]) -> PResult<usize> {
|
||||
let mut count = 0;
|
||||
while let Some(byte) = input.next_token() {
|
||||
if byte.is_dec_digit() {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
fn opt_one_of(input: &mut &[u8]) -> PResult<usize> {
|
||||
let mut count = 0;
|
||||
while !input.is_empty() {
|
||||
while opt(one_of(AsChar::is_dec_digit))
|
||||
.parse_next(input)?
|
||||
.is_some()
|
||||
{
|
||||
count += 1;
|
||||
}
|
||||
while opt(one_of(|b: u8| !b.is_dec_digit()))
|
||||
.parse_next(input)?
|
||||
.is_some()
|
||||
{}
|
||||
}
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
fn take_while(input: &mut &[u8]) -> PResult<usize> {
|
||||
let mut count = 0;
|
||||
while !input.is_empty() {
|
||||
count += winnow::token::take_while(0.., AsChar::is_dec_digit)
|
||||
.parse_next(input)?
|
||||
.len();
|
||||
let _ = winnow::token::take_while(0.., |b: u8| !b.is_dec_digit()).parse_next(input)?;
|
||||
}
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
fn repeat(input: &mut &[u8]) -> PResult<usize> {
|
||||
let mut count = 0;
|
||||
while !input.is_empty() {
|
||||
count += winnow::combinator::repeat(0.., one_of(AsChar::is_dec_digit))
|
||||
.map(|count: usize| count)
|
||||
.parse_next(input)?;
|
||||
winnow::combinator::repeat(0.., one_of(|b: u8| !b.is_dec_digit())).parse_next(input)?;
|
||||
}
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
const CONTIGUOUS: &str = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
|
||||
const INTERLEAVED: &str = "0123456789abc0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab";
|
||||
const CANADA: &str = include_str!("../third_party/nativejson-benchmark/data/canada.json");
|
||||
|
||||
criterion::criterion_group!(benches, iter);
|
||||
criterion::criterion_main!(benches);
|
||||
133
third-party/vendor/winnow/benches/next_slice.rs
vendored
Normal file
133
third-party/vendor/winnow/benches/next_slice.rs
vendored
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
use criterion::black_box;
|
||||
|
||||
use winnow::combinator::repeat;
|
||||
use winnow::prelude::*;
|
||||
use winnow::token::one_of;
|
||||
use winnow::token::tag;
|
||||
|
||||
fn next_slice(c: &mut criterion::Criterion) {
|
||||
let mut group = c.benchmark_group("next_slice");
|
||||
|
||||
let name = "ascii";
|
||||
let sample = "h".repeat(100);
|
||||
let sample = sample.as_str();
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("char", name),
|
||||
sample,
|
||||
|b, sample| {
|
||||
b.iter(|| black_box(parser_ascii_char.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("str", name),
|
||||
sample,
|
||||
|b, sample| {
|
||||
b.iter(|| black_box(parser_ascii_str.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("one_of", name),
|
||||
sample,
|
||||
|b, sample| {
|
||||
b.iter(|| black_box(parser_ascii_one_of.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("tag_char", name),
|
||||
sample,
|
||||
|b, sample| {
|
||||
b.iter(|| black_box(parser_ascii_tag_char.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("tag_str", name),
|
||||
sample,
|
||||
|b, sample| {
|
||||
b.iter(|| black_box(parser_ascii_tag_str.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
|
||||
let name = "utf8";
|
||||
let sample = "🧑".repeat(100);
|
||||
let sample = sample.as_str();
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("char", name),
|
||||
sample,
|
||||
|b, sample| {
|
||||
b.iter(|| black_box(parser_utf8_char.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("str", name),
|
||||
sample,
|
||||
|b, sample| {
|
||||
b.iter(|| black_box(parser_utf8_str.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("one_of", name),
|
||||
sample,
|
||||
|b, sample| {
|
||||
b.iter(|| black_box(parser_utf8_one_of.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("tag_char", name),
|
||||
sample,
|
||||
|b, sample| {
|
||||
b.iter(|| black_box(parser_utf8_tag_char.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("tag_str", name),
|
||||
sample,
|
||||
|b, sample| {
|
||||
b.iter(|| black_box(parser_utf8_tag_str.parse_peek(black_box(sample)).unwrap()));
|
||||
},
|
||||
);
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
fn parser_ascii_char(input: &mut &str) -> PResult<usize> {
|
||||
repeat(0.., 'h').parse_next(input)
|
||||
}
|
||||
|
||||
fn parser_ascii_str(input: &mut &str) -> PResult<usize> {
|
||||
repeat(0.., "h").parse_next(input)
|
||||
}
|
||||
|
||||
fn parser_ascii_one_of(input: &mut &str) -> PResult<usize> {
|
||||
repeat(0.., one_of('h')).parse_next(input)
|
||||
}
|
||||
|
||||
fn parser_ascii_tag_char(input: &mut &str) -> PResult<usize> {
|
||||
repeat(0.., tag('h')).parse_next(input)
|
||||
}
|
||||
|
||||
fn parser_ascii_tag_str(input: &mut &str) -> PResult<usize> {
|
||||
repeat(0.., tag("h")).parse_next(input)
|
||||
}
|
||||
|
||||
fn parser_utf8_char(input: &mut &str) -> PResult<usize> {
|
||||
repeat(0.., '🧑').parse_next(input)
|
||||
}
|
||||
|
||||
fn parser_utf8_str(input: &mut &str) -> PResult<usize> {
|
||||
repeat(0.., "🧑").parse_next(input)
|
||||
}
|
||||
|
||||
fn parser_utf8_one_of(input: &mut &str) -> PResult<usize> {
|
||||
repeat(0.., one_of('🧑')).parse_next(input)
|
||||
}
|
||||
|
||||
fn parser_utf8_tag_char(input: &mut &str) -> PResult<usize> {
|
||||
repeat(0.., tag('🧑')).parse_next(input)
|
||||
}
|
||||
|
||||
fn parser_utf8_tag_str(input: &mut &str) -> PResult<usize> {
|
||||
repeat(0.., tag("🧑")).parse_next(input)
|
||||
}
|
||||
|
||||
criterion::criterion_group!(benches, next_slice);
|
||||
criterion::criterion_main!(benches);
|
||||
70
third-party/vendor/winnow/benches/number.rs
vendored
Normal file
70
third-party/vendor/winnow/benches/number.rs
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#[macro_use]
|
||||
extern crate criterion;
|
||||
|
||||
use criterion::Criterion;
|
||||
|
||||
use winnow::ascii::float;
|
||||
use winnow::binary::be_u64;
|
||||
use winnow::error::ErrMode;
|
||||
use winnow::error::ErrorKind;
|
||||
use winnow::error::InputError;
|
||||
use winnow::error::ParserError;
|
||||
use winnow::prelude::*;
|
||||
use winnow::stream::ParseSlice;
|
||||
|
||||
type Stream<'i> = &'i [u8];
|
||||
|
||||
fn parser(i: &mut Stream<'_>) -> PResult<u64> {
|
||||
be_u64.parse_next(i)
|
||||
}
|
||||
|
||||
fn number(c: &mut Criterion) {
|
||||
let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
|
||||
|
||||
parser
|
||||
.parse_peek(&data[..])
|
||||
.expect("should parse correctly");
|
||||
c.bench_function("number", move |b| {
|
||||
b.iter(|| parser.parse_peek(&data[..]).unwrap());
|
||||
});
|
||||
}
|
||||
|
||||
fn float_bytes(c: &mut Criterion) {
|
||||
println!(
|
||||
"float_bytes result: {:?}",
|
||||
float::<_, f64, InputError<_>>.parse_peek(&b"-1.234E-12"[..])
|
||||
);
|
||||
c.bench_function("float bytes", |b| {
|
||||
b.iter(|| float::<_, f64, InputError<_>>.parse_peek(&b"-1.234E-12"[..]));
|
||||
});
|
||||
}
|
||||
|
||||
fn float_str(c: &mut Criterion) {
|
||||
println!(
|
||||
"float_str result: {:?}",
|
||||
float::<_, f64, InputError<_>>.parse_peek("-1.234E-12")
|
||||
);
|
||||
c.bench_function("float str", |b| {
|
||||
b.iter(|| float::<_, f64, InputError<_>>.parse_peek("-1.234E-12"));
|
||||
});
|
||||
}
|
||||
|
||||
fn std_float(input: &mut &[u8]) -> PResult<f64> {
|
||||
match input.parse_slice() {
|
||||
Some(n) => Ok(n),
|
||||
None => Err(ErrMode::from_error_kind(input, ErrorKind::Slice)),
|
||||
}
|
||||
}
|
||||
|
||||
fn std_float_bytes(c: &mut Criterion) {
|
||||
println!(
|
||||
"std_float_bytes result: {:?}",
|
||||
std_float.parse_peek(&b"-1.234E-12"[..])
|
||||
);
|
||||
c.bench_function("std_float bytes", |b| {
|
||||
b.iter(|| std_float.parse_peek(&b"-1.234E-12"[..]));
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, number, float_bytes, std_float_bytes, float_str);
|
||||
criterion_main!(benches);
|
||||
33
third-party/vendor/winnow/examples/arithmetic/bench.rs
vendored
Normal file
33
third-party/vendor/winnow/examples/arithmetic/bench.rs
vendored
Normal 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);
|
||||
86
third-party/vendor/winnow/examples/arithmetic/main.rs
vendored
Normal file
86
third-party/vendor/winnow/examples/arithmetic/main.rs
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
use winnow::prelude::*;
|
||||
|
||||
mod parser;
|
||||
mod parser_ast;
|
||||
mod 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::lex.parse(input)?;
|
||||
println!(" {:#?}", tokens);
|
||||
let result = parser_lexer::expr.parse(tokens.as_slice()).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)
|
||||
}
|
||||
}
|
||||
135
third-party/vendor/winnow/examples/arithmetic/parser.rs
vendored
Normal file
135
third-party/vendor/winnow/examples/arithmetic/parser.rs
vendored
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use winnow::prelude::*;
|
||||
use winnow::{
|
||||
ascii::{digit1 as digits, multispace0 as multispaces},
|
||||
combinator::alt,
|
||||
combinator::delimited,
|
||||
combinator::repeat,
|
||||
token::one_of,
|
||||
};
|
||||
|
||||
// Parser definition
|
||||
|
||||
pub fn expr(i: &mut &str) -> PResult<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
|
||||
fn term(i: &mut &str) -> PResult<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
|
||||
fn factor(i: &mut &str) -> PResult<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) -> PResult<i64> {
|
||||
delimited('(', expr, ')').parse_next(i)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn factor_test() {
|
||||
let input = "3";
|
||||
let expected = Ok(("", 3));
|
||||
assert_eq!(factor.parse_peek(input), expected);
|
||||
|
||||
let input = " 12";
|
||||
let expected = Ok(("", 12));
|
||||
assert_eq!(factor.parse_peek(input), expected);
|
||||
|
||||
let input = "537 ";
|
||||
let expected = Ok(("", 537));
|
||||
assert_eq!(factor.parse_peek(input), expected);
|
||||
|
||||
let input = " 24 ";
|
||||
let expected = Ok(("", 24));
|
||||
assert_eq!(factor.parse_peek(input), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn term_test() {
|
||||
let input = " 12 *2 / 3";
|
||||
let expected = Ok(("", 8));
|
||||
assert_eq!(term.parse_peek(input), expected);
|
||||
|
||||
let input = " 12 *2 / 3";
|
||||
let expected = Ok(("", 8));
|
||||
assert_eq!(term.parse_peek(input), expected);
|
||||
|
||||
let input = " 2* 3 *2 *2 / 3";
|
||||
let expected = Ok(("", 8));
|
||||
assert_eq!(term.parse_peek(input), expected);
|
||||
|
||||
let input = " 48 / 3/2";
|
||||
let expected = Ok(("", 8));
|
||||
assert_eq!(term.parse_peek(input), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expr_test() {
|
||||
let input = " 1 + 2 ";
|
||||
let expected = Ok(("", 3));
|
||||
assert_eq!(expr.parse_peek(input), expected);
|
||||
|
||||
let input = " 12 + 6 - 4+ 3";
|
||||
let expected = Ok(("", 17));
|
||||
assert_eq!(expr.parse_peek(input), expected);
|
||||
|
||||
let input = " 1 + 2*3 + 4";
|
||||
let expected = Ok(("", 11));
|
||||
assert_eq!(expr.parse_peek(input), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parens_test() {
|
||||
let input = " ( 2 )";
|
||||
let expected = Ok(("", 2));
|
||||
assert_eq!(expr.parse_peek(input), expected);
|
||||
|
||||
let input = " 2* ( 3 + 4 ) ";
|
||||
let expected = Ok(("", 14));
|
||||
assert_eq!(expr.parse_peek(input), expected);
|
||||
|
||||
let input = " 2*2 / ( 5 - 1) + 3";
|
||||
let expected = Ok(("", 4));
|
||||
assert_eq!(expr.parse_peek(input), expected);
|
||||
}
|
||||
182
third-party/vendor/winnow/examples/arithmetic/parser_ast.rs
vendored
Normal file
182
third-party/vendor/winnow/examples/arithmetic/parser_ast.rs
vendored
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
use std::fmt;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
use winnow::prelude::*;
|
||||
use winnow::{
|
||||
ascii::{digit1 as digits, multispace0 as multispaces},
|
||||
combinator::alt,
|
||||
combinator::delimited,
|
||||
combinator::repeat,
|
||||
token::one_of,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub 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 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 fn expr(i: &mut &str) -> PResult<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)
|
||||
}
|
||||
|
||||
fn term(i: &mut &str) -> PResult<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)
|
||||
}
|
||||
|
||||
fn factor(i: &mut &str) -> PResult<Expr> {
|
||||
delimited(
|
||||
multispaces,
|
||||
alt((digits.try_map(FromStr::from_str).map(Expr::Value), parens)),
|
||||
multispaces,
|
||||
)
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
fn parens(i: &mut &str) -> PResult<Expr> {
|
||||
delimited("(", expr, ")")
|
||||
.map(|e| Expr::Paren(Box::new(e)))
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn factor_test() {
|
||||
let input = "3";
|
||||
let expected = Ok(("", String::from("Value(3)")));
|
||||
assert_eq!(factor.map(|e| format!("{e:?}")).parse_peek(input), expected);
|
||||
|
||||
let input = " 12";
|
||||
let expected = Ok(("", String::from("Value(12)")));
|
||||
assert_eq!(factor.map(|e| format!("{e:?}")).parse_peek(input), expected);
|
||||
|
||||
let input = "537 ";
|
||||
let expected = Ok(("", String::from("Value(537)")));
|
||||
assert_eq!(factor.map(|e| format!("{e:?}")).parse_peek(input), expected);
|
||||
|
||||
let input = " 24 ";
|
||||
let expected = Ok(("", String::from("Value(24)")));
|
||||
assert_eq!(factor.map(|e| format!("{e:?}")).parse_peek(input), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn term_test() {
|
||||
let input = " 12 *2 / 3";
|
||||
let expected = Ok(("", String::from("Div(Mul(Value(12), Value(2)), Value(3))")));
|
||||
assert_eq!(term.map(|e| format!("{e:?}")).parse_peek(input), expected);
|
||||
|
||||
let input = " 12 *2 / 3";
|
||||
let expected = Ok(("", String::from("Div(Mul(Value(12), Value(2)), Value(3))")));
|
||||
assert_eq!(term.map(|e| format!("{e:?}")).parse_peek(input), expected);
|
||||
|
||||
let input = " 2* 3 *2 *2 / 3";
|
||||
let expected = Ok((
|
||||
"",
|
||||
String::from("Div(Mul(Mul(Mul(Value(2), Value(3)), Value(2)), Value(2)), Value(3))"),
|
||||
));
|
||||
assert_eq!(term.map(|e| format!("{e:?}")).parse_peek(input), expected);
|
||||
|
||||
let input = " 48 / 3/2";
|
||||
let expected = Ok(("", String::from("Div(Div(Value(48), Value(3)), Value(2))")));
|
||||
assert_eq!(term.map(|e| format!("{e:?}")).parse_peek(input), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expr_test() {
|
||||
let input = " 1 + 2 ";
|
||||
let expected = Ok(("", String::from("Add(Value(1), Value(2))")));
|
||||
assert_eq!(expr.map(|e| format!("{e:?}")).parse_peek(input), expected);
|
||||
|
||||
let input = " 12 + 6 - 4+ 3";
|
||||
let expected = Ok((
|
||||
"",
|
||||
String::from("Add(Sub(Add(Value(12), Value(6)), Value(4)), Value(3))"),
|
||||
));
|
||||
assert_eq!(expr.map(|e| format!("{e:?}")).parse_peek(input), expected);
|
||||
|
||||
let input = " 1 + 2*3 + 4";
|
||||
let expected = Ok((
|
||||
"",
|
||||
String::from("Add(Add(Value(1), Mul(Value(2), Value(3))), Value(4))"),
|
||||
));
|
||||
assert_eq!(expr.map(|e| format!("{e:?}")).parse_peek(input), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parens_test() {
|
||||
let input = " ( 2 )";
|
||||
let expected = Ok(("", String::from("Paren(Value(2))")));
|
||||
assert_eq!(expr.map(|e| format!("{e:?}")).parse_peek(input), expected);
|
||||
|
||||
let input = " 2* ( 3 + 4 ) ";
|
||||
let expected = Ok((
|
||||
"",
|
||||
String::from("Mul(Value(2), Paren(Add(Value(3), Value(4))))"),
|
||||
));
|
||||
assert_eq!(expr.map(|e| format!("{e:?}")).parse_peek(input), expected);
|
||||
|
||||
let input = " 2*2 / ( 5 - 1) + 3";
|
||||
let expected = Ok((
|
||||
"",
|
||||
String::from("Add(Div(Mul(Value(2), Value(2)), Paren(Sub(Value(5), Value(1)))), Value(3))"),
|
||||
));
|
||||
assert_eq!(expr.map(|e| format!("{e:?}")).parse_peek(input), expected);
|
||||
}
|
||||
300
third-party/vendor/winnow/examples/arithmetic/parser_lexer.rs
vendored
Normal file
300
third-party/vendor/winnow/examples/arithmetic/parser_lexer.rs
vendored
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
use std::fmt;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
use winnow::prelude::*;
|
||||
use winnow::{
|
||||
ascii::{digit1 as digits, multispace0 as multispaces},
|
||||
combinator::alt,
|
||||
combinator::dispatch,
|
||||
combinator::fail,
|
||||
combinator::peek,
|
||||
combinator::repeat,
|
||||
combinator::{delimited, preceded, terminated},
|
||||
token::any,
|
||||
token::one_of,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub 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 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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Token {
|
||||
Value(i64),
|
||||
Oper(Oper),
|
||||
OpenParen,
|
||||
CloseParen,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Oper {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
}
|
||||
|
||||
impl winnow::stream::ContainsToken<Token> for Token {
|
||||
#[inline(always)]
|
||||
fn contains_token(&self, token: Token) -> bool {
|
||||
*self == token
|
||||
}
|
||||
}
|
||||
|
||||
impl winnow::stream::ContainsToken<Token> for &'_ [Token] {
|
||||
#[inline]
|
||||
fn contains_token(&self, token: Token) -> bool {
|
||||
self.iter().any(|t| *t == token)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const LEN: usize> winnow::stream::ContainsToken<Token> for &'_ [Token; LEN] {
|
||||
#[inline]
|
||||
fn contains_token(&self, token: Token) -> bool {
|
||||
self.iter().any(|t| *t == token)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const LEN: usize> winnow::stream::ContainsToken<Token> for [Token; LEN] {
|
||||
#[inline]
|
||||
fn contains_token(&self, token: Token) -> bool {
|
||||
self.iter().any(|t| *t == token)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn expr2(i: &mut &str) -> PResult<Expr> {
|
||||
let tokens = lex.parse_next(i)?;
|
||||
expr.parse_next(&mut tokens.as_slice())
|
||||
}
|
||||
|
||||
pub fn lex(i: &mut &str) -> PResult<Vec<Token>> {
|
||||
preceded(multispaces, repeat(1.., terminated(token, multispaces))).parse_next(i)
|
||||
}
|
||||
|
||||
fn token(i: &mut &str) -> PResult<Token> {
|
||||
dispatch! {peek(any);
|
||||
'0'..='9' => digits.try_map(FromStr::from_str).map(Token::Value),
|
||||
'(' => '('.value(Token::OpenParen),
|
||||
')' => ')'.value(Token::CloseParen),
|
||||
'+' => '+'.value(Token::Oper(Oper::Add)),
|
||||
'-' => '-'.value(Token::Oper(Oper::Sub)),
|
||||
'*' => '*'.value(Token::Oper(Oper::Mul)),
|
||||
'/' => '/'.value(Token::Oper(Oper::Div)),
|
||||
_ => fail,
|
||||
}
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
pub fn expr(i: &mut &[Token]) -> PResult<Expr> {
|
||||
let init = term.parse_next(i)?;
|
||||
|
||||
repeat(
|
||||
0..,
|
||||
(
|
||||
one_of([Token::Oper(Oper::Add), Token::Oper(Oper::Sub)]),
|
||||
term,
|
||||
),
|
||||
)
|
||||
.fold(
|
||||
move || init.clone(),
|
||||
|acc, (op, val): (Token, Expr)| {
|
||||
if op == Token::Oper(Oper::Add) {
|
||||
Expr::Add(Box::new(acc), Box::new(val))
|
||||
} else {
|
||||
Expr::Sub(Box::new(acc), Box::new(val))
|
||||
}
|
||||
},
|
||||
)
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
fn term(i: &mut &[Token]) -> PResult<Expr> {
|
||||
let init = factor.parse_next(i)?;
|
||||
|
||||
repeat(
|
||||
0..,
|
||||
(
|
||||
one_of([Token::Oper(Oper::Mul), Token::Oper(Oper::Div)]),
|
||||
factor,
|
||||
),
|
||||
)
|
||||
.fold(
|
||||
move || init.clone(),
|
||||
|acc, (op, val): (Token, Expr)| {
|
||||
if op == Token::Oper(Oper::Mul) {
|
||||
Expr::Mul(Box::new(acc), Box::new(val))
|
||||
} else {
|
||||
Expr::Div(Box::new(acc), Box::new(val))
|
||||
}
|
||||
},
|
||||
)
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
fn factor(i: &mut &[Token]) -> PResult<Expr> {
|
||||
alt((
|
||||
one_of(|t| matches!(t, Token::Value(_))).map(|t| match t {
|
||||
Token::Value(v) => Expr::Value(v),
|
||||
_ => unreachable!(),
|
||||
}),
|
||||
parens,
|
||||
))
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
fn parens(i: &mut &[Token]) -> PResult<Expr> {
|
||||
delimited(one_of(Token::OpenParen), expr, one_of(Token::CloseParen))
|
||||
.map(|e| Expr::Paren(Box::new(e)))
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lex_test() {
|
||||
let input = "3";
|
||||
let expected = Ok(String::from(r#"("", [Value(3)])"#));
|
||||
assert_eq!(lex.parse_peek(input).map(|e| format!("{e:?}")), expected);
|
||||
|
||||
let input = " 24 ";
|
||||
let expected = Ok(String::from(r#"("", [Value(24)])"#));
|
||||
assert_eq!(lex.parse_peek(input).map(|e| format!("{e:?}")), expected);
|
||||
|
||||
let input = " 12 *2 / 3";
|
||||
let expected = Ok(String::from(
|
||||
r#"("", [Value(12), Oper(Mul), Value(2), Oper(Div), Value(3)])"#,
|
||||
));
|
||||
assert_eq!(lex.parse_peek(input).map(|e| format!("{e:?}")), expected);
|
||||
|
||||
let input = " 2*2 / ( 5 - 1) + 3";
|
||||
let expected = Ok(String::from(
|
||||
r#"("", [Value(2), Oper(Mul), Value(2), Oper(Div), OpenParen, Value(5), Oper(Sub), Value(1), CloseParen, Oper(Add), Value(3)])"#,
|
||||
));
|
||||
assert_eq!(lex.parse_peek(input).map(|e| format!("{e:?}")), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn factor_test() {
|
||||
let input = "3";
|
||||
let expected = Ok(String::from("Value(3)"));
|
||||
let input = lex.parse(input).unwrap();
|
||||
assert_eq!(factor.map(|e| format!("{e:?}")).parse(&input), expected);
|
||||
|
||||
let input = " 12";
|
||||
let expected = Ok(String::from("Value(12)"));
|
||||
let input = lex.parse(input).unwrap();
|
||||
assert_eq!(factor.map(|e| format!("{e:?}")).parse(&input), expected);
|
||||
|
||||
let input = "537 ";
|
||||
let expected = Ok(String::from("Value(537)"));
|
||||
let input = lex.parse(input).unwrap();
|
||||
assert_eq!(factor.map(|e| format!("{e:?}")).parse(&input), expected);
|
||||
|
||||
let input = " 24 ";
|
||||
let expected = Ok(String::from("Value(24)"));
|
||||
let input = lex.parse(input).unwrap();
|
||||
assert_eq!(factor.map(|e| format!("{e:?}")).parse(&input), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn term_test() {
|
||||
let input = " 12 *2 / 3";
|
||||
let expected = Ok(String::from("Div(Mul(Value(12), Value(2)), Value(3))"));
|
||||
let input = lex.parse(input).unwrap();
|
||||
assert_eq!(term.map(|e| format!("{e:?}")).parse(&input), expected);
|
||||
|
||||
let input = " 12 *2 / 3";
|
||||
let expected = Ok(String::from("Div(Mul(Value(12), Value(2)), Value(3))"));
|
||||
let input = lex.parse(input).unwrap();
|
||||
assert_eq!(term.map(|e| format!("{e:?}")).parse(&input), expected);
|
||||
|
||||
let input = " 2* 3 *2 *2 / 3";
|
||||
let expected = Ok(String::from(
|
||||
"Div(Mul(Mul(Mul(Value(2), Value(3)), Value(2)), Value(2)), Value(3))",
|
||||
));
|
||||
let input = lex.parse(input).unwrap();
|
||||
assert_eq!(term.map(|e| format!("{e:?}")).parse(&input), expected);
|
||||
|
||||
let input = " 48 / 3/2";
|
||||
let expected = Ok(String::from("Div(Div(Value(48), Value(3)), Value(2))"));
|
||||
let input = lex.parse(input).unwrap();
|
||||
assert_eq!(term.map(|e| format!("{e:?}")).parse(&input), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expr_test() {
|
||||
let input = " 1 + 2 ";
|
||||
let expected = Ok(String::from("Add(Value(1), Value(2))"));
|
||||
let input = lex.parse(input).unwrap();
|
||||
assert_eq!(expr.map(|e| format!("{e:?}")).parse(&input), expected);
|
||||
|
||||
let input = " 12 + 6 - 4+ 3";
|
||||
let expected = Ok(String::from(
|
||||
"Add(Sub(Add(Value(12), Value(6)), Value(4)), Value(3))",
|
||||
));
|
||||
let input = lex.parse(input).unwrap();
|
||||
assert_eq!(expr.map(|e| format!("{e:?}")).parse(&input), expected);
|
||||
|
||||
let input = " 1 + 2*3 + 4";
|
||||
let expected = Ok(String::from(
|
||||
"Add(Add(Value(1), Mul(Value(2), Value(3))), Value(4))",
|
||||
));
|
||||
let input = lex.parse(input).unwrap();
|
||||
assert_eq!(expr.map(|e| format!("{e:?}")).parse(&input), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parens_test() {
|
||||
let input = " ( 2 )";
|
||||
let expected = Ok(String::from("Paren(Value(2))"));
|
||||
let input = lex.parse(input).unwrap();
|
||||
assert_eq!(expr.map(|e| format!("{e:?}")).parse(&input), expected);
|
||||
|
||||
let input = " 2* ( 3 + 4 ) ";
|
||||
let expected = Ok(String::from(
|
||||
"Mul(Value(2), Paren(Add(Value(3), Value(4))))",
|
||||
));
|
||||
let input = lex.parse(input).unwrap();
|
||||
assert_eq!(expr.map(|e| format!("{e:?}")).parse(&input), expected);
|
||||
|
||||
let input = " 2*2 / ( 5 - 1) + 3";
|
||||
let expected = Ok(String::from(
|
||||
"Add(Div(Mul(Value(2), Value(2)), Paren(Sub(Value(5), Value(1)))), Value(3))",
|
||||
));
|
||||
let input = lex.parse(input).unwrap();
|
||||
assert_eq!(expr.map(|e| format!("{e:?}")).parse(&input), expected);
|
||||
}
|
||||
62
third-party/vendor/winnow/examples/css/main.rs
vendored
Normal file
62
third-party/vendor/winnow/examples/css/main.rs
vendored
Normal 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,
|
||||
}
|
||||
))
|
||||
);
|
||||
}
|
||||
35
third-party/vendor/winnow/examples/css/parser.rs
vendored
Normal file
35
third-party/vendor/winnow/examples/css/parser.rs
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
use winnow::combinator::seq;
|
||||
use winnow::prelude::*;
|
||||
use winnow::token::take_while;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct Color {
|
||||
pub red: u8,
|
||||
pub green: u8,
|
||||
pub 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 fn hex_color(input: &mut &str) -> PResult<Color> {
|
||||
seq!(Color {
|
||||
_: '#',
|
||||
red: hex_primary,
|
||||
green: hex_primary,
|
||||
blue: hex_primary
|
||||
})
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn hex_primary(input: &mut &str) -> PResult<u8> {
|
||||
take_while(2, |c: char| c.is_ascii_hexdigit())
|
||||
.try_map(|input| u8::from_str_radix(input, 16))
|
||||
.parse_next(input)
|
||||
}
|
||||
40
third-party/vendor/winnow/examples/custom_error.rs
vendored
Normal file
40
third-party/vendor/winnow/examples/custom_error.rs
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use winnow::error::ErrMode;
|
||||
use winnow::error::ErrorKind;
|
||||
use winnow::error::ParserError;
|
||||
use winnow::prelude::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum CustomError<I> {
|
||||
MyError,
|
||||
Nom(I, ErrorKind),
|
||||
}
|
||||
|
||||
impl<I: Clone> ParserError<I> for CustomError<I> {
|
||||
fn from_error_kind(input: &I, kind: ErrorKind) -> Self {
|
||||
CustomError::Nom(input.clone(), kind)
|
||||
}
|
||||
|
||||
fn append(self, _: &I, _: ErrorKind) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse<'s>(_input: &mut &'s str) -> PResult<&'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();
|
||||
match err {
|
||||
ErrMode::Backtrack(e) => assert_eq!(e, CustomError::MyError),
|
||||
_ => panic!("Unexpected error: {:?}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
36
third-party/vendor/winnow/examples/http/bench.rs
vendored
Normal file
36
third-party/vendor/winnow/examples/http/bench.rs
vendored
Normal 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
third-party/vendor/winnow/examples/http/main.rs
vendored
Normal file
47
third-party/vendor/winnow/examples/http/main.rs
vendored
Normal 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
third-party/vendor/winnow/examples/http/parser.rs
vendored
Normal file
137
third-party/vendor/winnow/examples/http/parser.rs
vendored
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
use winnow::combinator::seq;
|
||||
use winnow::prelude::*;
|
||||
use winnow::{ascii::line_ending, combinator::repeat, token::take_while};
|
||||
|
||||
pub type Stream<'i> = &'i [u8];
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct Request<'a> {
|
||||
method: &'a [u8],
|
||||
uri: &'a [u8],
|
||||
version: &'a [u8],
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct Header<'a> {
|
||||
name: &'a [u8],
|
||||
value: Vec<&'a [u8]>,
|
||||
}
|
||||
|
||||
pub 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>) -> PResult<(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>) -> PResult<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>) -> PResult<&'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>) -> PResult<&'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>) -> PResult<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'
|
||||
}
|
||||
138
third-party/vendor/winnow/examples/http/parser_streaming.rs
vendored
Normal file
138
third-party/vendor/winnow/examples/http/parser_streaming.rs
vendored
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
use winnow::combinator::seq;
|
||||
use winnow::{
|
||||
ascii::line_ending, combinator::repeat, prelude::*, stream::Partial, token::take_while,
|
||||
};
|
||||
|
||||
pub type Stream<'i> = Partial<&'i [u8]>;
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct Request<'a> {
|
||||
method: &'a [u8],
|
||||
uri: &'a [u8],
|
||||
version: &'a [u8],
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct Header<'a> {
|
||||
name: &'a [u8],
|
||||
value: Vec<&'a [u8]>,
|
||||
}
|
||||
|
||||
pub 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>) -> PResult<(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>) -> PResult<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>) -> PResult<&'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>) -> PResult<&'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>) -> PResult<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'
|
||||
}
|
||||
61
third-party/vendor/winnow/examples/ini/bench.rs
vendored
Normal file
61
third-party/vendor/winnow/examples/ini/bench.rs
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
use winnow::combinator::repeat;
|
||||
use winnow::prelude::*;
|
||||
|
||||
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>) -> PResult<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
third-party/vendor/winnow/examples/ini/main.rs
vendored
Normal file
60
third-party/vendor/winnow/examples/ini/main.rs
vendored
Normal 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)
|
||||
}
|
||||
}
|
||||
146
third-party/vendor/winnow/examples/ini/parser.rs
vendored
Normal file
146
third-party/vendor/winnow/examples/ini/parser.rs
vendored
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
use std::collections::HashMap;
|
||||
use std::str;
|
||||
|
||||
use winnow::prelude::*;
|
||||
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 type Stream<'i> = &'i [u8];
|
||||
|
||||
pub fn categories<'s>(i: &mut Stream<'s>) -> PResult<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>) -> PResult<&'s str> {
|
||||
delimited('[', take_while(0.., |c| c != b']'), ']')
|
||||
.try_map(str::from_utf8)
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
pub fn key_value<'s>(i: &mut Stream<'s>) -> PResult<(&'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)));
|
||||
}
|
||||
208
third-party/vendor/winnow/examples/ini/parser_str.rs
vendored
Normal file
208
third-party/vendor/winnow/examples/ini/parser_str.rs
vendored
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use winnow::prelude::*;
|
||||
use winnow::{
|
||||
ascii::{alphanumeric1 as alphanumeric, space0 as space},
|
||||
combinator::opt,
|
||||
combinator::repeat,
|
||||
combinator::{delimited, terminated},
|
||||
token::{take_till, take_while},
|
||||
};
|
||||
|
||||
pub type Stream<'i> = &'i str;
|
||||
|
||||
pub fn categories<'s>(
|
||||
input: &mut Stream<'s>,
|
||||
) -> PResult<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>) -> PResult<(&'s str, HashMap<&'s str, &'s str>)> {
|
||||
(category, keys_and_values).parse_next(i)
|
||||
}
|
||||
|
||||
fn category<'s>(i: &mut Stream<'s>) -> PResult<&'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>) -> PResult<HashMap<&'s str, &'s str>> {
|
||||
repeat(0.., key_value).parse_next(input)
|
||||
}
|
||||
|
||||
fn key_value<'s>(i: &mut Stream<'s>) -> PResult<(&'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>) -> PResult<&'s str> {
|
||||
take_while(0.., |c| c != '\r' && c != '\n').parse_next(i)
|
||||
}
|
||||
|
||||
fn space_or_line_ending<'s>(i: &mut Stream<'s>) -> PResult<&'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: {} | o: {:?}", i, 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: {} | o: ({:?},{:?})", 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 = "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: {} | o: ({:?},{:?})", 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 = "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: {} | o: ({:?},{:?})", i, 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: {} | o: {:?}", i, 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: {} | o: {:?}", i, 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: {} | o: {:?}", 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(("", expected_h)));
|
||||
}
|
||||
77
third-party/vendor/winnow/examples/iterator.rs
vendored
Normal file
77
third-party/vendor/winnow/examples/iterator.rs
vendored
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
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) -> PResult<&'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 || {
|
||||
match parser.parse_next(&mut data) {
|
||||
// when successful, a parser returns a tuple of
|
||||
// the remaining input and the output value.
|
||||
// So we replace the captured input data with the
|
||||
// remaining input, to be parsed on the next call
|
||||
Ok(o) => Some(o),
|
||||
_ => None,
|
||||
}
|
||||
});
|
||||
|
||||
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: PResult<(_, _), ()> = 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 {:?}, remaining input is '{}'",
|
||||
res, remaining_input
|
||||
);
|
||||
}
|
||||
70
third-party/vendor/winnow/examples/json/bench.rs
vendored
Normal file
70
third-party/vendor/winnow/examples/json/bench.rs
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
use winnow::prelude::*;
|
||||
use winnow::Partial;
|
||||
|
||||
mod json;
|
||||
mod parser;
|
||||
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("basic", name), &len, |b, _| {
|
||||
type Error<'i> = winnow::error::InputError<parser::Stream<'i>>;
|
||||
|
||||
b.iter(|| parser::json::<Error>.parse_peek(sample).unwrap());
|
||||
});
|
||||
group.bench_with_input(criterion::BenchmarkId::new("unit", name), &len, |b, _| {
|
||||
type Error<'i> = ();
|
||||
|
||||
b.iter(|| parser::json::<Error>.parse_peek(sample).unwrap());
|
||||
});
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("context", name),
|
||||
&len,
|
||||
|b, _| {
|
||||
type Error<'i> = winnow::error::ContextError<parser::Stream<'i>>;
|
||||
|
||||
b.iter(|| parser::json::<Error>.parse_peek(sample).unwrap());
|
||||
},
|
||||
);
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("dispatch", name),
|
||||
&len,
|
||||
|b, _| {
|
||||
type Error<'i> = winnow::error::InputError<parser_dispatch::Stream<'i>>;
|
||||
|
||||
b.iter(|| parser_dispatch::json::<Error>.parse_peek(sample).unwrap());
|
||||
},
|
||||
);
|
||||
group.bench_with_input(
|
||||
criterion::BenchmarkId::new("streaming", name),
|
||||
&len,
|
||||
|b, _| {
|
||||
type Error<'i> = winnow::error::InputError<parser_partial::Stream<'i>>;
|
||||
|
||||
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
third-party/vendor/winnow/examples/json/json.rs
vendored
Normal file
11
third-party/vendor/winnow/examples/json/json.rs
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum JsonValue {
|
||||
Null,
|
||||
Boolean(bool),
|
||||
Str(String),
|
||||
Num(f64),
|
||||
Array(Vec<JsonValue>),
|
||||
Object(HashMap<String, JsonValue>),
|
||||
}
|
||||
98
third-party/vendor/winnow/examples/json/main.rs
vendored
Normal file
98
third-party/vendor/winnow/examples/json/main.rs
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
mod json;
|
||||
mod parser;
|
||||
mod parser_dispatch;
|
||||
#[allow(dead_code)]
|
||||
mod parser_partial;
|
||||
|
||||
use winnow::error::ErrorKind;
|
||||
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::json::<ErrorKind>.parse(data),
|
||||
Impl::Dispatch => parser_dispatch::json::<ErrorKind>.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)
|
||||
}
|
||||
}
|
||||
328
third-party/vendor/winnow/examples/json/parser.rs
vendored
Normal file
328
third-party/vendor/winnow/examples/json/parser.rs
vendored
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
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},
|
||||
token::{any, none_of, take, take_while},
|
||||
};
|
||||
|
||||
use crate::json::JsonValue;
|
||||
|
||||
pub type Stream<'i> = &'i str;
|
||||
|
||||
/// The root element of a JSON parser is any value
|
||||
///
|
||||
/// A parser has the following signature:
|
||||
/// `&mut Stream -> PResult<Output, InputError>`, with `PResult` defined as:
|
||||
/// `type PResult<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 fn json<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<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>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<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)
|
||||
}
|
||||
|
||||
/// `tag(string)` generates a parser that recognizes the argument string.
|
||||
///
|
||||
/// This also shows returning a sub-slice of the original input
|
||||
fn null<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<&'i str, E> {
|
||||
// This is a parser that returns `"null"` if it sees the string "null", and
|
||||
// an error otherwise
|
||||
"null".parse_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>) -> PResult<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 recognize 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>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<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("string")
|
||||
.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>) -> PResult<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>) -> PResult<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>) -> PResult<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>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<Vec<JsonValue>, E> {
|
||||
preceded(
|
||||
('[', ws),
|
||||
cut_err(terminated(
|
||||
separated(0.., json_value, (ws, ',', ws)),
|
||||
(ws, ']'),
|
||||
)),
|
||||
)
|
||||
.context("array")
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn object<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<HashMap<String, JsonValue>, E> {
|
||||
preceded(
|
||||
('{', ws),
|
||||
cut_err(terminated(
|
||||
separated(0.., key_value, (ws, ',', ws)),
|
||||
(ws, '}'),
|
||||
)),
|
||||
)
|
||||
.context("object")
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn key_value<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<(String, JsonValue), E> {
|
||||
separated_pair(string, cut_err((ws, ':', ws)), json_value).parse_next(input)
|
||||
}
|
||||
|
||||
/// Parser combinators are constructed from the bottom up:
|
||||
/// first we write parsers for the smallest elements (here a space character),
|
||||
/// then we'll combine them in larger parsers
|
||||
fn ws<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<&'i str, E> {
|
||||
// Combinators like `take_while` return a function. That function is the
|
||||
// parser,to which we can pass the input
|
||||
take_while(0.., WS).parse_next(input)
|
||||
}
|
||||
|
||||
const WS: &[char] = &[' ', '\t', '\r', '\n'];
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[allow(clippy::useless_attribute)]
|
||||
#[allow(dead_code)] // its dead for benches
|
||||
use super::*;
|
||||
|
||||
#[allow(clippy::useless_attribute)]
|
||||
#[allow(dead_code)] // its dead for benches
|
||||
type Error<'i> = winnow::error::InputError<&'i str>;
|
||||
|
||||
#[test]
|
||||
fn json_string() {
|
||||
assert_eq!(
|
||||
string::<Error<'_>>.parse_peek("\"\""),
|
||||
Ok(("", "".to_string()))
|
||||
);
|
||||
assert_eq!(
|
||||
string::<Error<'_>>.parse_peek("\"abc\""),
|
||||
Ok(("", "abc".to_string()))
|
||||
);
|
||||
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_string())),
|
||||
);
|
||||
assert_eq!(
|
||||
string::<Error<'_>>.parse_peek("\"\\uD83D\\uDE10\""),
|
||||
Ok(("", "😐".to_string()))
|
||||
);
|
||||
|
||||
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_string(), Num(42.0)),
|
||||
("b".to_string(), Str("x".to_string())),
|
||||
]
|
||||
.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_string())]);
|
||||
|
||||
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_string(), Null),
|
||||
("true".to_string(), Boolean(true)),
|
||||
("false".to_string(), Boolean(false)),
|
||||
("number".to_string(), Num(123e4)),
|
||||
("string".to_string(), Str(" abc 123 ".to_string())),
|
||||
(
|
||||
"array".to_string(),
|
||||
Array(vec![Boolean(false), Num(1.0), Str("two".to_string())])
|
||||
),
|
||||
(
|
||||
"object".to_string(),
|
||||
Object(
|
||||
vec![
|
||||
("a".to_string(), Num(1.0)),
|
||||
("b".to_string(), Str("c".to_string())),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
)
|
||||
),
|
||||
("empty_array".to_string(), Array(vec![]),),
|
||||
("empty_object".to_string(), Object(HashMap::new()),),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
)
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
335
third-party/vendor/winnow/examples/json/parser_dispatch.rs
vendored
Normal file
335
third-party/vendor/winnow/examples/json/parser_dispatch.rs
vendored
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
use std::collections::HashMap;
|
||||
use std::str;
|
||||
|
||||
use winnow::prelude::*;
|
||||
use winnow::{
|
||||
ascii::float,
|
||||
combinator::cut_err,
|
||||
combinator::empty,
|
||||
combinator::fail,
|
||||
combinator::peek,
|
||||
combinator::{alt, dispatch},
|
||||
combinator::{delimited, preceded, separated_pair, terminated},
|
||||
combinator::{repeat, separated},
|
||||
error::{AddContext, ParserError},
|
||||
token::{any, none_of, take, take_while},
|
||||
};
|
||||
|
||||
use crate::json::JsonValue;
|
||||
|
||||
pub type Stream<'i> = &'i str;
|
||||
|
||||
/// The root element of a JSON parser is any value
|
||||
///
|
||||
/// A parser has the following signature:
|
||||
/// `&mut Stream -> PResult<Output, InputError>`, with `PResult` defined as:
|
||||
/// `type PResult<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 fn json<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<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>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<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)
|
||||
}
|
||||
|
||||
/// `tag(string)` generates a parser that recognizes the argument string.
|
||||
///
|
||||
/// This also shows returning a sub-slice of the original input
|
||||
fn null<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<&'i str, E> {
|
||||
// This is a parser that returns `"null"` if it sees the string "null", and
|
||||
// an error otherwise
|
||||
"null".parse_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>) -> PResult<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>) -> PResult<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 recognize 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>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<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("string")
|
||||
.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>) -> PResult<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>) -> PResult<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>) -> PResult<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>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<Vec<JsonValue>, E> {
|
||||
preceded(
|
||||
('[', ws),
|
||||
cut_err(terminated(
|
||||
separated(0.., json_value, (ws, ',', ws)),
|
||||
(ws, ']'),
|
||||
)),
|
||||
)
|
||||
.context("array")
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn object<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<HashMap<String, JsonValue>, E> {
|
||||
preceded(
|
||||
('{', ws),
|
||||
cut_err(terminated(
|
||||
separated(0.., key_value, (ws, ',', ws)),
|
||||
(ws, '}'),
|
||||
)),
|
||||
)
|
||||
.context("object")
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn key_value<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<(String, JsonValue), E> {
|
||||
separated_pair(string, cut_err((ws, ':', ws)), json_value).parse_next(input)
|
||||
}
|
||||
|
||||
/// Parser combinators are constructed from the bottom up:
|
||||
/// first we write parsers for the smallest elements (here a space character),
|
||||
/// then we'll combine them in larger parsers
|
||||
fn ws<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<&'i str, E> {
|
||||
// Combinators like `take_while` return a function. That function is the
|
||||
// parser,to which we can pass the input
|
||||
take_while(0.., WS).parse_next(input)
|
||||
}
|
||||
|
||||
const WS: &[char] = &[' ', '\t', '\r', '\n'];
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[allow(clippy::useless_attribute)]
|
||||
#[allow(dead_code)] // its dead for benches
|
||||
use super::*;
|
||||
|
||||
#[allow(clippy::useless_attribute)]
|
||||
#[allow(dead_code)] // its dead for benches
|
||||
type Error<'i> = winnow::error::InputError<&'i str>;
|
||||
|
||||
#[test]
|
||||
fn json_string() {
|
||||
assert_eq!(
|
||||
string::<Error<'_>>.parse_peek("\"\""),
|
||||
Ok(("", "".to_string()))
|
||||
);
|
||||
assert_eq!(
|
||||
string::<Error<'_>>.parse_peek("\"abc\""),
|
||||
Ok(("", "abc".to_string()))
|
||||
);
|
||||
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_string())),
|
||||
);
|
||||
assert_eq!(
|
||||
string::<Error<'_>>.parse_peek("\"\\uD83D\\uDE10\""),
|
||||
Ok(("", "😐".to_string()))
|
||||
);
|
||||
|
||||
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_string(), Num(42.0)),
|
||||
("b".to_string(), Str("x".to_string())),
|
||||
]
|
||||
.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_string())]);
|
||||
|
||||
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_string(), Null),
|
||||
("true".to_string(), Boolean(true)),
|
||||
("false".to_string(), Boolean(false)),
|
||||
("number".to_string(), Num(123e4)),
|
||||
("string".to_string(), Str(" abc 123 ".to_string())),
|
||||
(
|
||||
"array".to_string(),
|
||||
Array(vec![Boolean(false), Num(1.0), Str("two".to_string())])
|
||||
),
|
||||
(
|
||||
"object".to_string(),
|
||||
Object(
|
||||
vec![
|
||||
("a".to_string(), Num(1.0)),
|
||||
("b".to_string(), Str("c".to_string())),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
)
|
||||
),
|
||||
("empty_array".to_string(), Array(vec![]),),
|
||||
("empty_object".to_string(), Object(HashMap::new()),),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
)
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
354
third-party/vendor/winnow/examples/json/parser_partial.rs
vendored
Normal file
354
third-party/vendor/winnow/examples/json/parser_partial.rs
vendored
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
use std::collections::HashMap;
|
||||
use std::str;
|
||||
|
||||
use winnow::prelude::*;
|
||||
use winnow::{
|
||||
ascii::float,
|
||||
combinator::alt,
|
||||
combinator::{cut_err, rest},
|
||||
combinator::{delimited, preceded, separated_pair, terminated},
|
||||
combinator::{repeat, separated},
|
||||
error::{AddContext, ParserError},
|
||||
stream::Partial,
|
||||
token::{any, none_of, take, take_while},
|
||||
};
|
||||
|
||||
use crate::json::JsonValue;
|
||||
|
||||
pub type Stream<'i> = Partial<&'i str>;
|
||||
|
||||
/// The root element of a JSON parser is any value
|
||||
///
|
||||
/// A parser has the following signature:
|
||||
/// `&mut Stream -> PResult<Output, InputError>`, with `PResult` defined as:
|
||||
/// `type PResult<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 fn json<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<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>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<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)
|
||||
}
|
||||
|
||||
/// `tag(string)` generates a parser that recognizes the argument string.
|
||||
///
|
||||
/// This also shows returning a sub-slice of the original input
|
||||
fn null<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<&'i str, E> {
|
||||
// This is a parser that returns `"null"` if it sees the string "null", and
|
||||
// an error otherwise
|
||||
"null".parse_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>) -> PResult<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 recognize 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>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<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("string")
|
||||
.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>) -> PResult<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>) -> PResult<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>) -> PResult<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>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<Vec<JsonValue>, E> {
|
||||
preceded(
|
||||
('[', ws),
|
||||
cut_err(terminated(
|
||||
separated(0.., json_value, (ws, ',', ws)),
|
||||
(ws, ']'),
|
||||
)),
|
||||
)
|
||||
.context("array")
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn object<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<HashMap<String, JsonValue>, E> {
|
||||
preceded(
|
||||
('{', ws),
|
||||
cut_err(terminated(
|
||||
separated(0.., key_value, (ws, ',', ws)),
|
||||
(ws, '}'),
|
||||
)),
|
||||
)
|
||||
.context("object")
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn key_value<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<(String, JsonValue), E> {
|
||||
separated_pair(string, cut_err((ws, ':', ws)), json_value).parse_next(input)
|
||||
}
|
||||
|
||||
/// Parser combinators are constructed from the bottom up:
|
||||
/// first we write parsers for the smallest elements (here a space character),
|
||||
/// then we'll combine them in larger parsers
|
||||
fn ws<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<&'i str, E> {
|
||||
// Combinators like `take_while` return a function. That function is the
|
||||
// parser,to which we can pass the input
|
||||
take_while(0.., WS).parse_next(input)
|
||||
}
|
||||
|
||||
fn ws_or_eof<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<&'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(dead_code)] // its dead for benches
|
||||
use super::*;
|
||||
|
||||
#[allow(clippy::useless_attribute)]
|
||||
#[allow(dead_code)] // its dead for benches
|
||||
type Error<'i> = winnow::error::InputError<Partial<&'i str>>;
|
||||
|
||||
#[test]
|
||||
fn json_string() {
|
||||
assert_eq!(
|
||||
string::<Error<'_>>.parse_peek(Partial::new("\"\"")),
|
||||
Ok((Partial::new(""), "".to_string()))
|
||||
);
|
||||
assert_eq!(
|
||||
string::<Error<'_>>.parse_peek(Partial::new("\"abc\"")),
|
||||
Ok((Partial::new(""), "abc".to_string()))
|
||||
);
|
||||
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_string()
|
||||
)),
|
||||
);
|
||||
assert_eq!(
|
||||
string::<Error<'_>>.parse_peek(Partial::new("\"\\uD83D\\uDE10\"")),
|
||||
Ok((Partial::new(""), "😐".to_string()))
|
||||
);
|
||||
|
||||
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_string(), Num(42.0)),
|
||||
("b".to_string(), Str("x".to_string())),
|
||||
]
|
||||
.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_string())]);
|
||||
|
||||
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_string(), Null),
|
||||
("true".to_string(), Boolean(true)),
|
||||
("false".to_string(), Boolean(false)),
|
||||
("number".to_string(), Num(123e4)),
|
||||
("string".to_string(), Str(" abc 123 ".to_string())),
|
||||
(
|
||||
"array".to_string(),
|
||||
Array(vec![Boolean(false), Num(1.0), Str("two".to_string())])
|
||||
),
|
||||
(
|
||||
"object".to_string(),
|
||||
Object(
|
||||
vec![
|
||||
("a".to_string(), Num(1.0)),
|
||||
("b".to_string(), Str("c".to_string())),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
)
|
||||
),
|
||||
("empty_array".to_string(), Array(vec![]),),
|
||||
("empty_object".to_string(), Object(HashMap::new()),),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
)
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
311
third-party/vendor/winnow/examples/json_iterator.rs
vendored
Normal file
311
third-party/vendor/winnow/examples/json_iterator.rs
vendored
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use winnow::prelude::*;
|
||||
use winnow::{
|
||||
ascii::{alphanumeric1 as alphanumeric, escaped, float},
|
||||
combinator::alt,
|
||||
combinator::cut_err,
|
||||
combinator::separated,
|
||||
combinator::{preceded, separated_pair, terminated},
|
||||
error::ParserError,
|
||||
error::StrContext,
|
||||
stream::Offset,
|
||||
token::one_of,
|
||||
token::{tag, 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 tag::<_, _, ()>("[").parse_next(&mut data) {
|
||||
Err(_) => None,
|
||||
Ok(_) => {
|
||||
println!("[");
|
||||
self.offset(data);
|
||||
let mut first = true;
|
||||
let mut done = false;
|
||||
let mut previous = std::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 tag::<_, _, ()>("]").parse_next(&mut data).is_ok() {
|
||||
println!("]");
|
||||
v.offset(data);
|
||||
done = true;
|
||||
return None;
|
||||
}
|
||||
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
match tag::<_, _, ()>(",").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 tag::<_, _, ()>("{").parse_next(&mut data) {
|
||||
Err(_) => None,
|
||||
Ok(_) => {
|
||||
self.offset(data);
|
||||
|
||||
println!("{{");
|
||||
|
||||
let mut first = true;
|
||||
let mut done = false;
|
||||
let mut previous = std::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 tag::<_, _, ()>("}").parse_next(&mut data).is_ok() {
|
||||
println!("}}");
|
||||
v.offset(data);
|
||||
done = true;
|
||||
return None;
|
||||
}
|
||||
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
match tag::<_, _, ()>(",").parse_next(&mut data) {
|
||||
Ok(_) => {
|
||||
println!(",");
|
||||
v.offset(data);
|
||||
}
|
||||
Err(_) => {
|
||||
done = true;
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match string(&mut data) {
|
||||
Ok(key) => {
|
||||
v.offset(data);
|
||||
|
||||
match tag::<_, _, ()>(":").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) -> PResult<&'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) -> PResult<&'a str, E> {
|
||||
escaped(alphanumeric, '\\', one_of(['"', 'n', '\\'])).parse_next(i)
|
||||
}
|
||||
|
||||
fn string<'s>(i: &mut &'s str) -> PResult<&'s str> {
|
||||
preceded('\"', cut_err(terminated(parse_str, '\"')))
|
||||
.context(StrContext::Label("string"))
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
fn boolean(input: &mut &str) -> PResult<bool> {
|
||||
alt(("false".map(|_| false), "true".map(|_| true))).parse_next(input)
|
||||
}
|
||||
|
||||
fn array(i: &mut &str) -> PResult<()> {
|
||||
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) -> PResult<(&'s str, ())> {
|
||||
separated_pair(preceded(sp, string), cut_err(preceded(sp, ':')), value).parse_next(i)
|
||||
}
|
||||
|
||||
fn hash(i: &mut &str) -> PResult<()> {
|
||||
preceded(
|
||||
'{',
|
||||
cut_err(terminated(
|
||||
separated(0.., key_value, preceded(sp, ',')),
|
||||
preceded(sp, '}'),
|
||||
)),
|
||||
)
|
||||
.context(StrContext::Label("map"))
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
fn value(i: &mut &str) -> PResult<()> {
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
158
third-party/vendor/winnow/examples/ndjson/example.ndjson
vendored
Normal file
158
third-party/vendor/winnow/examples/ndjson/example.ndjson
vendored
Normal 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}
|
||||
|
||||
114
third-party/vendor/winnow/examples/ndjson/main.rs
vendored
Normal file
114
third-party/vendor/winnow/examples/ndjson/main.rs
vendored
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
mod parser;
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use winnow::error::ErrMode;
|
||||
use winnow::error::InputError;
|
||||
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 input = parser::Stream::new(std::str::from_utf8(buffer.data()).map_err(to_lexopt)?);
|
||||
match parser::ndjson::<InputError<parser::Stream>>.parse_peek(input) {
|
||||
Ok((remainder, value)) => {
|
||||
println!("{:?}", value);
|
||||
println!();
|
||||
// Tell the buffer how much we read
|
||||
let consumed = remainder.offset_from(&input);
|
||||
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())
|
||||
}
|
||||
344
third-party/vendor/winnow/examples/ndjson/parser.rs
vendored
Normal file
344
third-party/vendor/winnow/examples/ndjson/parser.rs
vendored
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
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},
|
||||
stream::Partial,
|
||||
token::{any, none_of, take, take_while},
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub 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 type Stream<'i> = Partial<&'i str>;
|
||||
|
||||
pub fn ndjson<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<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>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<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)
|
||||
}
|
||||
|
||||
/// `tag(string)` generates a parser that recognizes the argument string.
|
||||
///
|
||||
/// This also shows returning a sub-slice of the original input
|
||||
fn null<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<&'i str, E> {
|
||||
// This is a parser that returns `"null"` if it sees the string "null", and
|
||||
// an error otherwise
|
||||
"null".parse_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>) -> PResult<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 recognize 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>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<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("string")
|
||||
.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>) -> PResult<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>) -> PResult<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>) -> PResult<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>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<Vec<JsonValue>, E> {
|
||||
preceded(
|
||||
('[', ws),
|
||||
cut_err(terminated(
|
||||
separated(0.., json_value, (ws, ',', ws)),
|
||||
(ws, ']'),
|
||||
)),
|
||||
)
|
||||
.context("array")
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn object<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<HashMap<String, JsonValue>, E> {
|
||||
preceded(
|
||||
('{', ws),
|
||||
cut_err(terminated(
|
||||
separated(0.., key_value, (ws, ',', ws)),
|
||||
(ws, '}'),
|
||||
)),
|
||||
)
|
||||
.context("object")
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn key_value<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>(
|
||||
input: &mut Stream<'i>,
|
||||
) -> PResult<(String, JsonValue), E> {
|
||||
separated_pair(string, cut_err((ws, ':', ws)), json_value).parse_next(input)
|
||||
}
|
||||
|
||||
/// Parser combinators are constructed from the bottom up:
|
||||
/// first we write parsers for the smallest elements (here a space character),
|
||||
/// then we'll combine them in larger parsers
|
||||
fn ws<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<&'i str, E> {
|
||||
// Combinators like `take_while` return a function. That function is the
|
||||
// parser,to which we can pass the input
|
||||
take_while(0.., WS).parse_next(input)
|
||||
}
|
||||
|
||||
const WS: &[char] = &[' ', '\t'];
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[allow(clippy::useless_attribute)]
|
||||
#[allow(dead_code)] // its dead for benches
|
||||
use super::*;
|
||||
|
||||
#[allow(clippy::useless_attribute)]
|
||||
#[allow(dead_code)] // its dead for benches
|
||||
type Error<'i> = winnow::error::InputError<Partial<&'i str>>;
|
||||
|
||||
#[test]
|
||||
fn json_string() {
|
||||
assert_eq!(
|
||||
string::<Error<'_>>.parse_peek(Partial::new("\"\"")),
|
||||
Ok((Partial::new(""), "".to_string()))
|
||||
);
|
||||
assert_eq!(
|
||||
string::<Error<'_>>.parse_peek(Partial::new("\"abc\"")),
|
||||
Ok((Partial::new(""), "abc".to_string()))
|
||||
);
|
||||
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_string()
|
||||
)),
|
||||
);
|
||||
assert_eq!(
|
||||
string::<Error<'_>>.parse_peek(Partial::new("\"\\uD83D\\uDE10\"")),
|
||||
Ok((Partial::new(""), "😐".to_string()))
|
||||
);
|
||||
|
||||
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_string(), Num(42.0)),
|
||||
("b".to_string(), Str("x".to_string())),
|
||||
]
|
||||
.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_string())]);
|
||||
|
||||
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_string(), Null),
|
||||
("true".to_string(), Boolean(true)),
|
||||
("false".to_string(), Boolean(false)),
|
||||
("number".to_string(), Num(123e4)),
|
||||
("string".to_string(), Str(" abc 123 ".to_string())),
|
||||
(
|
||||
"array".to_string(),
|
||||
Array(vec![Boolean(false), Num(1.0), Str("two".to_string())])
|
||||
),
|
||||
(
|
||||
"object".to_string(),
|
||||
Object(
|
||||
vec![
|
||||
("a".to_string(), Num(1.0)),
|
||||
("b".to_string(), Str("c".to_string())),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
)
|
||||
),
|
||||
("empty_array".to_string(), Array(vec![]),),
|
||||
("empty_object".to_string(), Object(HashMap::new()),),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
))
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
20
third-party/vendor/winnow/examples/s_expression/main.rs
vendored
Normal file
20
third-party/vendor/winnow/examples/s_expression/main.rs
vendored
Normal 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)
|
||||
);
|
||||
}
|
||||
361
third-party/vendor/winnow/examples/s_expression/parser.rs
vendored
Normal file
361
third-party/vendor/winnow/examples/s_expression/parser.rs
vendored
Normal 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 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_string()))
|
||||
}
|
||||
|
||||
/// 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 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 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 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) -> PResult<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) -> PResult<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) -> PResult<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) -> PResult<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) -> PResult<Atom> {
|
||||
alt((
|
||||
"#t".map(|_| Atom::Boolean(true)),
|
||||
"#f".map(|_| Atom::Boolean(false)),
|
||||
))
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
fn parse_builtin(i: &mut &'_ str) -> PResult<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) -> PResult<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) -> PResult<Atom> {
|
||||
preceded(":", cut_err(alpha1))
|
||||
.context(StrContext::Label("keyword"))
|
||||
.map(|sym_str: &str| Atom::Keyword(sym_str.to_string()))
|
||||
.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) -> PResult<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) -> PResult<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) -> PResult<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 Parser<&'a str, O1, ContextError>
|
||||
where
|
||||
F: Parser<&'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
third-party/vendor/winnow/examples/string/main.rs
vendored
Normal file
70
third-party/vendor/winnow/examples/string/main.rs
vendored
Normal 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"))
|
||||
);
|
||||
}
|
||||
167
third-party/vendor/winnow/examples/string/parser.rs
vendored
Normal file
167
third-party/vendor/winnow/examples/string/parser.rs
vendored
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
//! 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};
|
||||
|
||||
/// Parse a string. Use a loop of `parse_fragment` and push all of the fragments
|
||||
/// into an output string.
|
||||
pub fn parse_string<'a, E>(input: &mut &'a str) -> PResult<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) -> PResult<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) -> PResult<&'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) -> PResult<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) -> PResult<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,
|
||||
) -> PResult<&'a str, E> {
|
||||
preceded('\\', multispace1).parse_next(input)
|
||||
}
|
||||
19
third-party/vendor/winnow/src/_topic/arithmetic.rs
vendored
Normal file
19
third-party/vendor/winnow/src/_topic/arithmetic.rs
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
//! # Arithmetic
|
||||
//!
|
||||
//! ## Direct evaluation
|
||||
//!
|
||||
//! ```rust
|
||||
#![doc = include_str!("../../examples/arithmetic/parser.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! ## Parse to AST
|
||||
//!
|
||||
//! ```rust
|
||||
#![doc = include_str!("../../examples/arithmetic/parser_ast.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! ## Parse to Tokens then AST
|
||||
//!
|
||||
//! ```rust
|
||||
#![doc = include_str!("../../examples/arithmetic/parser_lexer.rs")]
|
||||
//! ```
|
||||
27
third-party/vendor/winnow/src/_topic/error.rs
vendored
Normal file
27
third-party/vendor/winnow/src/_topic/error.rs
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
//! # Custom Errors
|
||||
//!
|
||||
//! Between [`ContextError`], [`Parser::context`], and [`cut_err`],
|
||||
//! most error needs will likely be met
|
||||
//! (see [tutorial][chapter_6]).
|
||||
//! When that isn't the case, you can implement your own error type.
|
||||
//!
|
||||
//! The most basic error trait is [`ParserError`].
|
||||
//!
|
||||
//! Optional traits include:
|
||||
//! - [`AddContext`]
|
||||
//! - [`FromExternalError`]
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//!```rust
|
||||
#![doc = include_str!("../../examples/custom_error.rs")]
|
||||
//!```
|
||||
|
||||
#![allow(unused_imports)]
|
||||
use crate::combinator::cut_err;
|
||||
use crate::error::ContextError;
|
||||
use crate::Parser;
|
||||
use crate::_tutorial::chapter_6;
|
||||
use crate::error::AddContext;
|
||||
use crate::error::FromExternalError;
|
||||
use crate::error::ParserError;
|
||||
8
third-party/vendor/winnow/src/_topic/fromstr.rs
vendored
Normal file
8
third-party/vendor/winnow/src/_topic/fromstr.rs
vendored
Normal 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
third-party/vendor/winnow/src/_topic/http.rs
vendored
Normal file
5
third-party/vendor/winnow/src/_topic/http.rs
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
//! # HTTP
|
||||
//!
|
||||
//! ```rust
|
||||
#![doc = include_str!("../../examples/http/parser.rs")]
|
||||
//! ```
|
||||
5
third-party/vendor/winnow/src/_topic/ini.rs
vendored
Normal file
5
third-party/vendor/winnow/src/_topic/ini.rs
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
//! # INI
|
||||
//!
|
||||
//! ```rust
|
||||
#![doc = include_str!("../../examples/ini/parser.rs")]
|
||||
//! ```
|
||||
5
third-party/vendor/winnow/src/_topic/json.rs
vendored
Normal file
5
third-party/vendor/winnow/src/_topic/json.rs
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
//! # json
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../examples/json/parser.rs")]
|
||||
//! ```
|
||||
330
third-party/vendor/winnow/src/_topic/language.rs
vendored
Normal file
330
third-party/vendor/winnow/src/_topic/language.rs
vendored
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
//! # 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_till1,
|
||||
//! };
|
||||
//!
|
||||
//! pub fn peol_comment<'a, E: ParserError<&'a str>>(i: &mut &'a str) -> PResult<(), E>
|
||||
//! {
|
||||
//! ('%', take_till1(['\n', '\r']))
|
||||
//! .void() // Output is thrown away.
|
||||
//! .parse_next(i)
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ### `/* C-style comments */`
|
||||
//!
|
||||
//! Inline comments surrounded with sentinel tags `(*` and `*)`. This version returns an output of `()`
|
||||
//! and does not handle nested comments.
|
||||
//!
|
||||
//! ```rust
|
||||
//! use winnow::prelude::*;
|
||||
//! use winnow::{
|
||||
//! error::ParserError,
|
||||
//! token::{tag, take_until},
|
||||
//! };
|
||||
//!
|
||||
//! pub fn pinline_comment<'a, E: ParserError<&'a str>>(i: &mut &'a str) -> PResult<(), 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) -> PResult<&'s str> {
|
||||
//! (
|
||||
//! one_of(|c: char| c.is_alpha() || c == '_'),
|
||||
//! take_while(0.., |c: char| c.is_alphanum() || c == '_')
|
||||
//! )
|
||||
//! .recognize()
|
||||
//! .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 recognize `h`. The tuple ensures that
|
||||
//! `ello_world123abc` will be piped to the next [`take_while`][crate::token::take_while] parser,
|
||||
//! which recognizes every remaining character. However, the tuple returns a tuple of the results
|
||||
//! of its sub-parsers. The [`recognize`][crate::Parser::recognize] 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 [`escaped`] and [`escaped_transform`].
|
||||
//!
|
||||
//! ### 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,
|
||||
//! token::tag,
|
||||
//! };
|
||||
//!
|
||||
//! fn hexadecimal<'s>(input: &mut &'s str) -> PResult<&'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(|()| ()).recognize()
|
||||
//! ).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,
|
||||
//! token::tag,
|
||||
//! };
|
||||
//!
|
||||
//! fn hexadecimal_value(input: &mut &str) -> PResult<i64> {
|
||||
//! preceded(
|
||||
//! alt(("0x", "0X")),
|
||||
//! repeat(1..,
|
||||
//! terminated(one_of(('0'..='9', 'a'..='f', 'A'..='F')), repeat(0.., '_').map(|()| ()))
|
||||
//! ).map(|()| ()).recognize()
|
||||
//! ).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,
|
||||
//! token::tag,
|
||||
//! };
|
||||
//!
|
||||
//! fn octal<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! preceded(
|
||||
//! alt(("0o", "0O")),
|
||||
//! repeat(1..,
|
||||
//! terminated(one_of('0'..='7'), repeat(0.., '_').map(|()| ()))
|
||||
//! ).map(|()| ()).recognize()
|
||||
//! ).parse_next(input)
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! #### Binary
|
||||
//!
|
||||
//! ```rust
|
||||
//! use winnow::prelude::*;
|
||||
//! use winnow::{
|
||||
//! combinator::alt,
|
||||
//! combinator::{repeat},
|
||||
//! combinator::{preceded, terminated},
|
||||
//! token::one_of,
|
||||
//! token::tag,
|
||||
//! };
|
||||
//!
|
||||
//! fn binary<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! preceded(
|
||||
//! alt(("0b", "0B")),
|
||||
//! repeat(1..,
|
||||
//! terminated(one_of('0'..='1'), repeat(0.., '_').map(|()| ()))
|
||||
//! ).map(|()| ()).recognize()
|
||||
//! ).parse_next(input)
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! #### Decimal
|
||||
//!
|
||||
//! ```rust
|
||||
//! use winnow::prelude::*;
|
||||
//! use winnow::{
|
||||
//! combinator::{repeat},
|
||||
//! combinator::terminated,
|
||||
//! token::one_of,
|
||||
//! };
|
||||
//!
|
||||
//! fn decimal<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! repeat(1..,
|
||||
//! terminated(one_of('0'..='9'), repeat(0.., '_').map(|()| ()))
|
||||
//! ).map(|()| ())
|
||||
//! .recognize()
|
||||
//! .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) -> PResult<&'s str> {
|
||||
//! alt((
|
||||
//! // Case one: .42
|
||||
//! (
|
||||
//! '.',
|
||||
//! decimal,
|
||||
//! opt((
|
||||
//! one_of(['e', 'E']),
|
||||
//! opt(one_of(['+', '-'])),
|
||||
//! decimal
|
||||
//! ))
|
||||
//! ).recognize()
|
||||
//! , // Case two: 42e42 and 42.42e42
|
||||
//! (
|
||||
//! decimal,
|
||||
//! opt(preceded(
|
||||
//! '.',
|
||||
//! decimal,
|
||||
//! )),
|
||||
//! one_of(['e', 'E']),
|
||||
//! opt(one_of(['+', '-'])),
|
||||
//! decimal
|
||||
//! ).recognize()
|
||||
//! , // Case three: 42. and 42.42
|
||||
//! (
|
||||
//! decimal,
|
||||
//! '.',
|
||||
//! opt(decimal)
|
||||
//! ).recognize()
|
||||
//! )).parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! fn decimal<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! repeat(1..,
|
||||
//! terminated(one_of('0'..='9'), repeat(0.., '_').map(|()| ()))
|
||||
//! ).
|
||||
//! map(|()| ())
|
||||
//! .recognize()
|
||||
//! .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::escaped_transform;
|
||||
use crate::ascii::float;
|
||||
use crate::ascii::hex_uint;
|
||||
40
third-party/vendor/winnow/src/_topic/mod.rs
vendored
Normal file
40
third-party/vendor/winnow/src/_topic/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
//! # Special Topics
|
||||
//!
|
||||
//! These are short recipes for accomplishing common tasks.
|
||||
//!
|
||||
//! - [Why `winnow`?][why]
|
||||
//! - [Migrating from `nom`][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]
|
||||
//! - [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 nom;
|
||||
pub mod partial;
|
||||
pub mod performance;
|
||||
pub mod s_expression;
|
||||
pub mod stream;
|
||||
pub mod why;
|
||||
49
third-party/vendor/winnow/src/_topic/nom.rs
vendored
Normal file
49
third-party/vendor/winnow/src/_topic/nom.rs
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
//! # 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].
|
||||
//!
|
||||
//! 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/v0.3-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/v0.4-main/CHANGELOG.md#compatibility-2) 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/v0.5.0/CHANGELOG.md))
|
||||
//! 1. Commit
|
||||
//! 1. Resolve deprecation messagess
|
||||
//! 1. Commit
|
||||
//!
|
||||
//! 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)
|
||||
46
third-party/vendor/winnow/src/_topic/partial.rs
vendored
Normal file
46
third-party/vendor/winnow/src/_topic/partial.rs
vendored
Normal 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](http://ndjson.org/)
|
||||
//! - 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
third-party/vendor/winnow/src/_topic/performance.rs
vendored
Normal file
55
third-party/vendor/winnow/src/_topic/performance.rs
vendored
Normal 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;
|
||||
5
third-party/vendor/winnow/src/_topic/s_expression.rs
vendored
Normal file
5
third-party/vendor/winnow/src/_topic/s_expression.rs
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
//! # s-expression
|
||||
//!
|
||||
//! ```rust
|
||||
#![doc = include_str!("../../examples/s_expression/parser.rs")]
|
||||
//! ```
|
||||
66
third-party/vendor/winnow/src/_topic/stream.rs
vendored
Normal file
66
third-party/vendor/winnow/src/_topic/stream.rs
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
//! # 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
|
||||
//! - [`Located`] for looking up the absolute position of a token
|
||||
//!
|
||||
//! But that won't always cut it for your parser. For example, you might lex `&str` into
|
||||
//! a series of tokens and then want to parse a `TokenStream`.
|
||||
//!
|
||||
//! ## Implementing a custom stream
|
||||
//!
|
||||
//! Let's assume we have an input type we'll call `MyStream`.
|
||||
//! `MyStream` is a sequence of `MyItem` type.
|
||||
//!
|
||||
//! The goal is to define parsers with this signature: `&mut MyStream -> PResult<Output>`.
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::tag;
|
||||
//! # type MyStream<'i> = &'i str;
|
||||
//! # type Output<'i> = &'i str;
|
||||
//! fn parser<'s>(i: &mut MyStream<'s>) -> PResult<Output<'s>> {
|
||||
//! "test".parse_next(i)
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Here are the traits you may have to implement for `MyStream`:
|
||||
//!
|
||||
//! | 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`:
|
||||
//!
|
||||
//! | trait | usage |
|
||||
//! |---|---|
|
||||
//! | [`AsChar`] |Transforms common types to a char for basic token parsing|
|
||||
//! | [`ContainsToken`] |Look for the token in the given set|
|
||||
//!
|
||||
//! And traits for `&[MyItem]`:
|
||||
//!
|
||||
//! | trait | usage |
|
||||
//! |---|---|
|
||||
//! | [`SliceLen`] |Calculate the input length|
|
||||
//! | [`ParseSlice`] |Used to integrate `&str`'s `parse()` method|
|
||||
//!
|
||||
//! ## Implementing a custom token
|
||||
//!
|
||||
//! If you are parsing `&[Myitem]`, leaving just the `MyItem` traits.
|
||||
//!
|
||||
//! For example:
|
||||
//! ```rust
|
||||
#![doc = include_str!("../../examples/arithmetic/parser_lexer.rs")]
|
||||
//! ```
|
||||
|
||||
#[allow(unused_imports)] // Here for intra-dock links
|
||||
use crate::stream::*;
|
||||
101
third-party/vendor/winnow/src/_topic/why.rs
vendored
Normal file
101
third-party/vendor/winnow/src/_topic/why.rs
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
//! # Why `winnow`?
|
||||
//!
|
||||
//! To answer this question, it will be useful to contrast this with other approaches to parsing.
|
||||
//!
|
||||
//! **Note:** This will focus on principles and priorities. For a deeper and wider wider
|
||||
//! comparison with other Rust parser libraries, see
|
||||
//! [parse-rosetta-rs](https://github.com/rosetta-rs/parse-rosetta-rs).
|
||||
//!
|
||||
//! ## 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
|
||||
//! ["I’ve 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][crate::trace] for easier debugging
|
||||
//! - [Streaming parsing][crate::Partial] for network communication or large file
|
||||
//! - [Stateful][crate::Stateful] parsers
|
||||
//!
|
||||
//! For binary formats, `winnow` includes:
|
||||
//! - [A hexadecimal view][crate::Bytes] in [traces][crate::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::Located]
|
||||
//! - [A textual view when parsing as bytes][crate::BStr] in [traces][crate::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.
|
||||
//!
|
||||
//! See also our [nom migration guide][super::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::stream::Accumulate;
|
||||
39
third-party/vendor/winnow/src/_tutorial/chapter_0.rs
vendored
Normal file
39
third-party/vendor/winnow/src/_tutorial/chapter_0.rs
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
//! # 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:
|
||||
//!
|
||||
//! - The parsers are small and easy to write
|
||||
//! - The parsers components are easy to reuse (if they're general enough, please add them to winnow!)
|
||||
//! - The parsers components are easy to test separately (unit tests and property-based tests)
|
||||
//! - The parser combination code looks close to the grammar you would have written
|
||||
//! - You can build partial parsers, specific to the data you need at the moment, and ignore the rest
|
||||
|
||||
#![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;
|
||||
86
third-party/vendor/winnow/src/_tutorial/chapter_1.rs
vendored
Normal file
86
third-party/vendor/winnow/src/_tutorial/chapter_1.rs
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
//! # 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 build simple parsers, and
|
||||
//! then combine them (using "combinators").
|
||||
//!
|
||||
//! Let's discuss what a "parser" actually does. A parser takes an input and 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 left pointing to
|
||||
//! data that still needs processing
|
||||
//!
|
||||
//! If the parser failed, then there are multiple errors that could be returned.
|
||||
//! For simplicity, however, in the next chapters we will leave these unexplored.
|
||||
//!
|
||||
//! ```text
|
||||
//! ┌─► Ok(what matched the parser)
|
||||
//! ┌─────────┐ │
|
||||
//! my input───►│my parser├──►either──┤
|
||||
//! └─────────┘ └─► Err(...)
|
||||
//! ```
|
||||
//!
|
||||
//!
|
||||
//! To represent this model of the world, winnow uses the [`PResult<O>`] type.
|
||||
//! The `Ok` variant has `output: O`;
|
||||
//! whereas the `Err` variant stores an error.
|
||||
//!
|
||||
//! You can import that from:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use winnow::PResult;
|
||||
//! ```
|
||||
//!
|
||||
//! 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.
|
||||
//!
|
||||
//! 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; 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) -> PResult<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 remaining input is the same as the input.
|
||||
//! - Since it doesn't parse anything, it also should just return an empty string.
|
||||
//!
|
||||
//! ```rust
|
||||
//! use winnow::PResult;
|
||||
//! use winnow::Parser;
|
||||
//!
|
||||
//! pub fn do_nothing_parser<'s>(input: &mut &'s str) -> PResult<&'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 crate::PResult;
|
||||
use crate::Parser;
|
||||
|
||||
pub use super::chapter_0 as previous;
|
||||
pub use super::chapter_2 as next;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
248
third-party/vendor/winnow/src/_tutorial/chapter_2.rs
vendored
Normal file
248
third-party/vendor/winnow/src/_tutorial/chapter_2.rs
vendored
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
//! # Chapter 2: Tokens and Tags
|
||||
//!
|
||||
//! The simplest *useful* parser you can write is one which matches tokens.
|
||||
//!
|
||||
//! ## 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::PResult;
|
||||
//! use winnow::stream::Stream;
|
||||
//! use winnow::error::ParserError;
|
||||
//! use winnow::error::ErrorKind;
|
||||
//! use winnow::error::ErrMode;
|
||||
//!
|
||||
//! fn parse_prefix(input: &mut &str) -> PResult<char> {
|
||||
//! let c = input.next_token().ok_or_else(|| {
|
||||
//! ErrMode::from_error_kind(input, ErrorKind::Token)
|
||||
//! })?;
|
||||
//! if c != '0' {
|
||||
//! return Err(ErrMode::from_error_kind(input, ErrorKind::Verify));
|
||||
//! }
|
||||
//! 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());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! [`any`] and [`Parser::verify`] are [`Parser`] building blocks on top of [`Stream`]:
|
||||
//! ```rust
|
||||
//! # use winnow::PResult;
|
||||
//! use winnow::Parser;
|
||||
//! use winnow::token::any;
|
||||
//!
|
||||
//! fn parse_prefix(input: &mut &str) -> PResult<char> {
|
||||
//! any.verify(|c| *c == '0').parse_next(input)
|
||||
//! }
|
||||
//! #
|
||||
//! # 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
|
||||
//! `char`.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use winnow::PResult;
|
||||
//! use winnow::Parser;
|
||||
//!
|
||||
//! fn parse_prefix(input: &mut &str) -> PResult<char> {
|
||||
//! '0'.parse_next(input)
|
||||
//! }
|
||||
//! #
|
||||
//! # 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::PResult;
|
||||
//! use winnow::stream::Stream;
|
||||
//! use winnow::error::ParserError;
|
||||
//! use winnow::error::ErrorKind;
|
||||
//! use winnow::error::ErrMode;
|
||||
//!
|
||||
//! fn parse_prefix<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! let expected = "0x";
|
||||
//! if input.len() < expected.len() {
|
||||
//! return Err(ErrMode::from_error_kind(input, ErrorKind::Slice));
|
||||
//! }
|
||||
//! let actual = input.next_slice(expected.len());
|
||||
//! if actual != expected {
|
||||
//! return Err(ErrMode::from_error_kind(input, ErrorKind::Verify));
|
||||
//! }
|
||||
//! 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());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Again, matching a literal is common enough that [`Parser`] is implemented for `&str`:
|
||||
//! ```rust
|
||||
//! # use winnow::PResult;
|
||||
//! use winnow::Parser;
|
||||
//!
|
||||
//! fn parse_prefix<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! "0x".parse_next(input)
|
||||
//! }
|
||||
//! #
|
||||
//! # 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());
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! In `winnow`, we call this type of parser a [`tag`]. See [`token`] for additional individual
|
||||
//! and token-slice parsers.
|
||||
//!
|
||||
//! ## Character Classes
|
||||
//!
|
||||
//! Selecting a single `char` or a [`tag`] is fairly limited. Sometimes, you will want to select one of several
|
||||
//! `chars` of a specific class, like digits. For this, we use the [`one_of`] parser:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use winnow::Parser;
|
||||
//! # use winnow::PResult;
|
||||
//! use winnow::token::one_of;
|
||||
//!
|
||||
//! fn parse_digits(input: &mut &str) -> PResult<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::InputError;
|
||||
//! > pub fn one_of<'i>(
|
||||
//! > list: &'static [char]
|
||||
//! > ) -> impl Parser<&'i str, char, InputError<&'i str>> {
|
||||
//! > // ...
|
||||
//! > # 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 `PResult`. 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::PResult;
|
||||
//! use winnow::token::take_while;
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<&'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::PResult;
|
||||
//! use winnow::ascii::hex_digit1;
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<&'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::one_of;
|
||||
use crate::token::tag;
|
||||
use crate::token::take_while;
|
||||
use crate::Parser;
|
||||
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;
|
||||
376
third-party/vendor/winnow/src/_tutorial/chapter_3.rs
vendored
Normal file
376
third-party/vendor/winnow/src/_tutorial/chapter_3.rs
vendored
Normal file
|
|
@ -0,0 +1,376 @@
|
|||
//! # Chapter 3: Sequencing and Alternatives
|
||||
//!
|
||||
//! In the last chapter, we saw how to create simple parsers using prebuilt parsers.
|
||||
//!
|
||||
//! In this chapter, we explore two other widely used features:
|
||||
//! alternatives and composition.
|
||||
//!
|
||||
//! ## Sequencing
|
||||
//!
|
||||
//! Now that we can create more interesting parsers, we can sequence them together, like:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! #
|
||||
//! fn parse_prefix<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! "0x".parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<&'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::token::take_while;
|
||||
//! #
|
||||
//! # fn parse_prefix<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # "0x".parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_digits<'s>(input: &mut &'s str) -> PResult<&'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 tag and you can instead use one of the provided combinators,
|
||||
//! like [`preceded`]:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! use winnow::combinator::preceded;
|
||||
//!
|
||||
//! # fn parse_prefix<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # "0x".parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_digits<'s>(input: &mut &'s str) -> PResult<&'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.
|
||||
//!
|
||||
//! [`Stream::checkpoint`] helps us to retry parsing:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! use winnow::stream::Stream;
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<(&'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) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'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());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! > **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_6`#errmode]
|
||||
//!
|
||||
//! [`opt`] is a basic building block for correctly handling retrying parsing:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! use winnow::combinator::opt;
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<(&'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) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'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::token::take_while;
|
||||
//! use winnow::combinator::alt;
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<(&'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) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'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());
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! > **Note:** [`empty`] and [`fail`] are parsers that might be useful in the `else` case.
|
||||
//!
|
||||
//! Sometimes a giant if/else-if ladder can be slow and you'd rather have a `match` statement for
|
||||
//! branches of your parser that have unique prefixes. In this case, you can use the
|
||||
//! [`dispatch`] macro:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # 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) -> PResult<&'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) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'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());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! > **Note:** [`peek`] may be useful when [`dispatch`]ing from hints from each case's parser.
|
||||
//!
|
||||
//! See [`combinator`] for more alternative parsers.
|
||||
|
||||
#![allow(unused_imports)]
|
||||
use super::chapter_6;
|
||||
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;
|
||||
107
third-party/vendor/winnow/src/_tutorial/chapter_4.rs
vendored
Normal file
107
third-party/vendor/winnow/src/_tutorial/chapter_4.rs
vendored
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
//! # Chapter 4: Parsers With Custom Return Types
|
||||
//!
|
||||
//! So far, we have seen mostly functions that take an `&str`, and return a
|
||||
//! `PResult<&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 [`PResult`] to the desired return type.
|
||||
//! For example, to return a `usize`, return a `PResult<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::ascii::digit1;
|
||||
//! #
|
||||
//! fn parse_digits(input: &mut &str) -> PResult<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::token::take_while;
|
||||
//! use winnow::combinator::dispatch;
|
||||
//! use winnow::token::take;
|
||||
//! use winnow::combinator::fail;
|
||||
//!
|
||||
//! fn parse_digits(input: &mut &str) -> PResult<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) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'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::PResult;
|
||||
use crate::Parser;
|
||||
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;
|
||||
282
third-party/vendor/winnow/src/_tutorial/chapter_5.rs
vendored
Normal file
282
third-party/vendor/winnow/src/_tutorial/chapter_5.rs
vendored
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
//! # 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::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) -> PResult<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) -> PResult<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) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'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::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) -> PResult<Vec<usize>> {
|
||||
//! repeat(0..,
|
||||
//! terminated(parse_digits, opt(','))
|
||||
//! ).parse_next(input)
|
||||
//! }
|
||||
//! #
|
||||
//! # fn parse_digits(input: &mut &str) -> PResult<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) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'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 `,` when we intended to not support that. We can
|
||||
//! easily fix this by using [`separated`]:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! # use winnow::combinator::dispatch;
|
||||
//! # use winnow::token::take;
|
||||
//! # use winnow::combinator::fail;
|
||||
//! use winnow::combinator::separated;
|
||||
//!
|
||||
//! fn parse_list(input: &mut &str) -> PResult<Vec<usize>> {
|
||||
//! separated(0.., parse_digits, ",").parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! // ...
|
||||
//! # fn parse_digits(input: &mut &str) -> PResult<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) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'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 [`repeat`], it isn't collecting directly into a [`Vec`] but
|
||||
//! [`Accumulate`] to gather the results. This lets us make more complex parsers than we did in
|
||||
//! [`chapter_2`] by accumulating the results into a `()` and [`recognize`][Parser::recognize]-ing the captured input:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! # use winnow::combinator::dispatch;
|
||||
//! # use winnow::token::take;
|
||||
//! # use winnow::combinator::fail;
|
||||
//! # use winnow::combinator::separated;
|
||||
//! #
|
||||
//! fn recognize_list<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! parse_list.recognize().parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! fn parse_list(input: &mut &str) -> PResult<()> {
|
||||
//! separated(0.., parse_digits, ",").parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! # fn parse_digits(input: &mut &str) -> PResult<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) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'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 = recognize_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::Parser;
|
||||
use std::vec::Vec;
|
||||
|
||||
pub use super::chapter_4 as previous;
|
||||
pub use super::chapter_6 as next;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
156
third-party/vendor/winnow/src/_tutorial/chapter_6.rs
vendored
Normal file
156
third-party/vendor/winnow/src/_tutorial/chapter_6.rs
vendored
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
//! # Chapter 6: Error Reporting
|
||||
//!
|
||||
//! ## `Error`
|
||||
//!
|
||||
//! Back in [`chapter_1`], we glossed over the `Err` side of [`PResult`]. `PResult<O>` is
|
||||
//! actually short for `PResult<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 improve the error quality.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! # use winnow::combinator::alt;
|
||||
//! use winnow::error::StrContext;
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<(&'s str, &'s str)> {
|
||||
//! alt((
|
||||
//! ("0b", parse_bin_digits).context(StrContext::Label("binary")),
|
||||
//! ("0o", parse_oct_digits).context(StrContext::Label("octal")),
|
||||
//! ("0d", parse_dec_digits).context(StrContext::Label("decimal")),
|
||||
//! ("0x", parse_hex_digits).context(StrContext::Label("hexadecimal")),
|
||||
//! )).parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! // ...
|
||||
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'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");
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! At first glance, this looks correct but what `context` will be reported when parsing `"0b5"`?
|
||||
//! If you remember back to [`chapter_3`], [`alt`] will only report the last error by default which
|
||||
//! means when parsing `"0b5"`, the `context` will be `"hexadecimal"`.
|
||||
//!
|
||||
//! ## `ErrMode`
|
||||
//!
|
||||
//! Let's break down `PResult<O, E>` one step further:
|
||||
//! ```rust
|
||||
//! # use winnow::error::ErrorKind;
|
||||
//! # use winnow::error::ErrMode;
|
||||
//! pub type PResult<O, E = ErrorKind> = Result<O, ErrMode<E>>;
|
||||
//! ```
|
||||
//! [`PResult`] is just a fancy wrapper around `Result` that wraps our error in an [`ErrMode`]
|
||||
//! type.
|
||||
//!
|
||||
//! [`ErrMode`] is an enum with [`Backtrack`] and [`Cut`] variants (ignore [`Incomplete`] as its only
|
||||
//! relevant for [streaming][_topic::stream]). By default, errors are [`Backtrack`], meaning that
|
||||
//! other parsing branches will be attempted on failure, like the next case of an [`alt`]. [`Cut`]
|
||||
//! shortcircuits all other branches, immediately reporting the error.
|
||||
//!
|
||||
//! So we can get the correct `context` by modifying the above example with [`cut_err`]:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! # use winnow::combinator::alt;
|
||||
//! # use winnow::error::StrContext;
|
||||
//! use winnow::combinator::cut_err;
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<(&'s str, &'s str)> {
|
||||
//! alt((
|
||||
//! ("0b", cut_err(parse_bin_digits)).context(StrContext::Label("binary")),
|
||||
//! ("0o", cut_err(parse_oct_digits)).context(StrContext::Label("octal")),
|
||||
//! ("0d", cut_err(parse_dec_digits)).context(StrContext::Label("decimal")),
|
||||
//! ("0x", cut_err(parse_hex_digits)).context(StrContext::Label("hexadecimal")),
|
||||
//! )).parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! // ...
|
||||
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'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");
|
||||
//! }
|
||||
//! ```
|
||||
//! Now, when parsing `"0b5"`, the `context` will be `"binary"`.
|
||||
|
||||
#![allow(unused_imports)]
|
||||
use super::chapter_1;
|
||||
use super::chapter_3;
|
||||
use crate::combinator::alt;
|
||||
use crate::combinator::cut_err;
|
||||
use crate::error::ContextError;
|
||||
use crate::error::ErrMode;
|
||||
use crate::error::ErrMode::*;
|
||||
use crate::error::ErrorKind;
|
||||
use crate::PResult;
|
||||
use crate::Parser;
|
||||
use crate::_topic;
|
||||
|
||||
pub use super::chapter_5 as previous;
|
||||
pub use super::chapter_7 as next;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
119
third-party/vendor/winnow/src/_tutorial/chapter_7.rs
vendored
Normal file
119
third-party/vendor/winnow/src/_tutorial/chapter_7.rs
vendored
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
//! # Chapter 7: 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::error::ErrMode;
|
||||
//! # use winnow::Parser;
|
||||
//! #
|
||||
//! pub fn parser<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! // ...
|
||||
//! # Ok("")
|
||||
//! }
|
||||
//!
|
||||
//! type PResult<O> = Result<
|
||||
//! O,
|
||||
//! ErrMode<ContextError>
|
||||
//! >;
|
||||
//! ```
|
||||
//! 1. We have to decide what to do about the "remainder" of the `input`.
|
||||
//! 2. The [`ErrMode<ContextError>`] is not 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`]
|
||||
//! - Removes the [`ErrMode`] wrapper
|
||||
//! - Wraps the error in [`ParseError`]
|
||||
//! - Provides access to the original [`input`][ParseError::input] with the
|
||||
//! [`offset`][ParseError::offset] of where it failed
|
||||
//! - Provides a default renderer (via [`std::fmt::Display`])
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # 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 = String;
|
||||
//!
|
||||
//! fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||
//! parse_digits
|
||||
//! .map(Hex)
|
||||
//! .parse(input)
|
||||
//! .map_err(|e| e.to_string())
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! // ...
|
||||
//! # fn parse_digits<'s>(input: &mut &'s str) -> PResult<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) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'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 crate::combinator::eof;
|
||||
use crate::error::ErrMode;
|
||||
use crate::error::InputError;
|
||||
use crate::error::ParseError;
|
||||
use crate::PResult;
|
||||
use crate::Parser;
|
||||
|
||||
pub use super::chapter_6 as previous;
|
||||
pub use super::chapter_8 as next;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
34
third-party/vendor/winnow/src/_tutorial/chapter_8.rs
vendored
Normal file
34
third-party/vendor/winnow/src/_tutorial/chapter_8.rs
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
//! # Chapter 8: Debugging
|
||||
//!
|
||||
//! When things inevitably go wrong, you can introspect the parsing state by running your test case
|
||||
//! with `--features debug`:
|
||||
//! 
|
||||
//!
|
||||
//! 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::PResult;
|
||||
//! # use winnow::Parser;
|
||||
//! use winnow::combinator::trace;
|
||||
//!
|
||||
//! pub fn do_nothing_parser<'s>(input: &mut &'s str) -> PResult<&'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::_tutorial as table_of_contents;
|
||||
14
third-party/vendor/winnow/src/_tutorial/mod.rs
vendored
Normal file
14
third-party/vendor/winnow/src/_tutorial/mod.rs
vendored
Normal 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;
|
||||
1727
third-party/vendor/winnow/src/ascii/mod.rs
vendored
Normal file
1727
third-party/vendor/winnow/src/ascii/mod.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
1575
third-party/vendor/winnow/src/ascii/tests.rs
vendored
Normal file
1575
third-party/vendor/winnow/src/ascii/tests.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
377
third-party/vendor/winnow/src/binary/bits/mod.rs
vendored
Normal file
377
third-party/vendor/winnow/src/binary/bits/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,377 @@
|
|||
//! Bit level parsers
|
||||
//!
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use crate::combinator::trace;
|
||||
use crate::error::{ErrMode, ErrorConvert, ErrorKind, Needed, ParserError};
|
||||
use crate::lib::std::ops::{AddAssign, Div, Shl, Shr};
|
||||
use crate::stream::{AsBytes, Stream, StreamIsPartial, ToUsize};
|
||||
use crate::{unpeek, IResult, PResult, Parser};
|
||||
|
||||
/// Number of bits in a byte
|
||||
const BYTE: usize = u8::BITS as usize;
|
||||
|
||||
/// Converts a byte-level input to a bit-level input
|
||||
///
|
||||
/// See [`bytes`] to convert it back.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use winnow::prelude::*;
|
||||
/// use winnow::Bytes;
|
||||
/// use winnow::binary::bits::{bits, take};
|
||||
/// use winnow::error::InputError;
|
||||
///
|
||||
/// type Stream<'i> = &'i Bytes;
|
||||
///
|
||||
/// fn stream(b: &[u8]) -> Stream<'_> {
|
||||
/// Bytes::new(b)
|
||||
/// }
|
||||
///
|
||||
/// fn parse(input: Stream<'_>) -> IResult<Stream<'_>, (u8, u8)> {
|
||||
/// bits::<_, _, InputError<(_, usize)>, _, _>((take(4usize), take(8usize))).parse_peek(input)
|
||||
/// }
|
||||
///
|
||||
/// let input = stream(&[0x12, 0x34, 0xff, 0xff]);
|
||||
///
|
||||
/// let output = parse(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<I, O, E1, E2, P>(mut parser: P) -> impl Parser<I, O, E2>
|
||||
where
|
||||
E1: ParserError<(I, usize)> + ErrorConvert<E2>,
|
||||
E2: ParserError<I>,
|
||||
I: Stream + Clone,
|
||||
P: Parser<(I, usize), O, E1>,
|
||||
{
|
||||
trace(
|
||||
"bits",
|
||||
unpeek(move |input: I| {
|
||||
match parser.parse_peek((input, 0)) {
|
||||
Ok(((rest, offset), result)) => {
|
||||
// If the next byte has been partially read, it will be sliced away as well.
|
||||
// The parser functions might already slice away all fully read bytes.
|
||||
// That's why `offset / BYTE` isn't necessarily needed at all times.
|
||||
let remaining_bytes_index =
|
||||
offset / BYTE + if offset % BYTE == 0 { 0 } else { 1 };
|
||||
let (input, _) = rest.peek_slice(remaining_bytes_index);
|
||||
Ok((input, result))
|
||||
}
|
||||
Err(ErrMode::Incomplete(n)) => {
|
||||
Err(ErrMode::Incomplete(n.map(|u| u.get() / BYTE + 1)))
|
||||
}
|
||||
Err(e) => Err(e.convert()),
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/// Convert a [`bits`] stream back into a byte stream
|
||||
///
|
||||
/// **Warning:** A partial byte remaining in the input will be ignored and the given parser will
|
||||
/// start parsing at the next full byte.
|
||||
///
|
||||
/// ```
|
||||
/// use winnow::prelude::*;
|
||||
/// use winnow::Bytes;
|
||||
/// use winnow::binary::bits::{bits, bytes, take};
|
||||
/// use winnow::combinator::rest;
|
||||
/// use winnow::error::InputError;
|
||||
///
|
||||
/// type Stream<'i> = &'i Bytes;
|
||||
///
|
||||
/// fn stream(b: &[u8]) -> Stream<'_> {
|
||||
/// Bytes::new(b)
|
||||
/// }
|
||||
///
|
||||
/// fn parse(input: Stream<'_>) -> IResult<Stream<'_>, (u8, u8, &[u8])> {
|
||||
/// bits::<_, _, InputError<(_, usize)>, _, _>((
|
||||
/// take(4usize),
|
||||
/// take(8usize),
|
||||
/// bytes::<_, _, InputError<_>, _, _>(rest)
|
||||
/// )).parse_peek(input)
|
||||
/// }
|
||||
///
|
||||
/// let input = stream(&[0x12, 0x34, 0xff, 0xff]);
|
||||
///
|
||||
/// assert_eq!(parse(input), Ok(( stream(&[]), (0x01, 0x23, &[0xff, 0xff][..]) )));
|
||||
/// ```
|
||||
pub fn bytes<I, O, E1, E2, P>(mut parser: P) -> impl Parser<(I, usize), O, E2>
|
||||
where
|
||||
E1: ParserError<I> + ErrorConvert<E2>,
|
||||
E2: ParserError<(I, usize)>,
|
||||
I: Stream<Token = u8> + Clone,
|
||||
P: Parser<I, O, E1>,
|
||||
{
|
||||
trace(
|
||||
"bytes",
|
||||
unpeek(move |(input, offset): (I, usize)| {
|
||||
let (inner, _) = if offset % BYTE != 0 {
|
||||
input.peek_slice(1 + offset / BYTE)
|
||||
} else {
|
||||
input.peek_slice(offset / BYTE)
|
||||
};
|
||||
let i = (input, offset);
|
||||
match parser.parse_peek(inner) {
|
||||
Ok((rest, res)) => Ok(((rest, 0), res)),
|
||||
Err(ErrMode::Incomplete(Needed::Unknown)) => {
|
||||
Err(ErrMode::Incomplete(Needed::Unknown))
|
||||
}
|
||||
Err(ErrMode::Incomplete(Needed::Size(sz))) => {
|
||||
Err(match sz.get().checked_mul(BYTE) {
|
||||
Some(v) => ErrMode::Incomplete(Needed::new(v)),
|
||||
None => ErrMode::Cut(E2::assert(
|
||||
&i,
|
||||
"overflow in turning needed bytes into needed bits",
|
||||
)),
|
||||
})
|
||||
}
|
||||
Err(e) => Err(e.convert()),
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/// Parse taking `count` bits
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use winnow::prelude::*;
|
||||
/// # use winnow::Bytes;
|
||||
/// # use winnow::error::{InputError, ErrorKind};
|
||||
/// use winnow::binary::bits::take;
|
||||
///
|
||||
/// type Stream<'i> = &'i Bytes;
|
||||
///
|
||||
/// fn stream(b: &[u8]) -> Stream<'_> {
|
||||
/// Bytes::new(b)
|
||||
/// }
|
||||
///
|
||||
/// fn parser(input: (Stream<'_>, usize), count: usize)-> IResult<(Stream<'_>, usize), u8> {
|
||||
/// take(count).parse_peek(input)
|
||||
/// }
|
||||
///
|
||||
/// // Consumes 0 bits, returns 0
|
||||
/// assert_eq!(parser((stream(&[0b00010010]), 0), 0), Ok(((stream(&[0b00010010]), 0), 0)));
|
||||
///
|
||||
/// // Consumes 4 bits, returns their values and increase offset to 4
|
||||
/// assert_eq!(parser((stream(&[0b00010010]), 0), 4), Ok(((stream(&[0b00010010]), 4), 0b00000001)));
|
||||
///
|
||||
/// // Consumes 4 bits, offset is 4, returns their values and increase offset to 0 of next byte
|
||||
/// assert_eq!(parser((stream(&[0b00010010]), 4), 4), Ok(((stream(&[]), 0), 0b00000010)));
|
||||
///
|
||||
/// // Tries to consume 12 bits but only 8 are available
|
||||
/// assert_eq!(parser((stream(&[0b00010010]), 0), 12), Err(winnow::error::ErrMode::Backtrack(InputError::new((stream(&[0b00010010]), 0), ErrorKind::Eof))));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn take<I, O, C, E: ParserError<(I, usize)>>(count: C) -> impl Parser<(I, usize), O, E>
|
||||
where
|
||||
I: Stream<Token = u8> + AsBytes + StreamIsPartial + Clone,
|
||||
C: ToUsize,
|
||||
O: From<u8> + AddAssign + Shl<usize, Output = O> + Shr<usize, Output = O>,
|
||||
{
|
||||
let count = count.to_usize();
|
||||
trace(
|
||||
"take",
|
||||
unpeek(move |input: (I, usize)| {
|
||||
if <I 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>(
|
||||
(input, bit_offset): (I, usize),
|
||||
count: usize,
|
||||
) -> IResult<(I, usize), O, E>
|
||||
where
|
||||
I: StreamIsPartial,
|
||||
I: Stream<Token = u8> + AsBytes + Clone,
|
||||
O: From<u8> + AddAssign + Shl<usize, Output = O> + Shr<usize, Output = O>,
|
||||
{
|
||||
if count == 0 {
|
||||
Ok(((input, bit_offset), 0u8.into()))
|
||||
} else {
|
||||
if input.eof_offset() * BYTE < count + bit_offset {
|
||||
if PARTIAL && input.is_partial() {
|
||||
Err(ErrMode::Incomplete(Needed::new(count)))
|
||||
} else {
|
||||
Err(ErrMode::from_error_kind(
|
||||
&(input, bit_offset),
|
||||
ErrorKind::Eof,
|
||||
))
|
||||
}
|
||||
} 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.as_bytes().iter().copied().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, _) = input.peek_slice(cnt);
|
||||
Ok(((input, end_offset), acc))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse taking `count` bits and comparing them to `pattern`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use winnow::prelude::*;
|
||||
/// # use winnow::Bytes;
|
||||
/// # use winnow::error::{InputError, ErrorKind};
|
||||
/// use winnow::binary::bits::tag;
|
||||
///
|
||||
/// 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(pattern: u8, count: u8, input: (Stream<'_>, usize)) -> IResult<(Stream<'_>, usize), u8> {
|
||||
/// tag(pattern, count).parse_peek(input)
|
||||
/// }
|
||||
///
|
||||
/// // The lowest 4 bits of 0b00001111 match the lowest 4 bits of 0b11111111.
|
||||
/// assert_eq!(
|
||||
/// parser(0b0000_1111, 4, (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!(
|
||||
/// parser(0b00000001, 1, (stream(&[0b11111111]), 0)),
|
||||
/// Ok(((stream(&[0b11111111]), 1), 0b00000001))
|
||||
/// );
|
||||
///
|
||||
/// // The lowest 2 bits of 0b11111111 and 0b00000001 are different.
|
||||
/// assert_eq!(
|
||||
/// parser(0b000000_01, 2, (stream(&[0b111111_11]), 0)),
|
||||
/// Err(winnow::error::ErrMode::Backtrack(InputError::new(
|
||||
/// (stream(&[0b11111111]), 0),
|
||||
/// ErrorKind::Tag
|
||||
/// )))
|
||||
/// );
|
||||
///
|
||||
/// // The lowest 8 bits of 0b11111111 and 0b11111110 are different.
|
||||
/// assert_eq!(
|
||||
/// parser(0b11111110, 8, (stream(&[0b11111111]), 0)),
|
||||
/// Err(winnow::error::ErrMode::Backtrack(InputError::new(
|
||||
/// (stream(&[0b11111111]), 0),
|
||||
/// ErrorKind::Tag
|
||||
/// )))
|
||||
/// );
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
#[doc(alias = "literal")]
|
||||
#[doc(alias = "just")]
|
||||
#[doc(alias = "tag")]
|
||||
pub fn pattern<I, O, C, E: ParserError<(I, usize)>>(
|
||||
pattern: O,
|
||||
count: C,
|
||||
) -> impl Parser<(I, usize), O, E>
|
||||
where
|
||||
I: Stream<Token = u8> + AsBytes + StreamIsPartial + Clone,
|
||||
C: ToUsize,
|
||||
O: From<u8> + AddAssign + Shl<usize, Output = O> + Shr<usize, Output = O> + PartialEq,
|
||||
{
|
||||
let count = count.to_usize();
|
||||
trace("pattern", move |input: &mut (I, usize)| {
|
||||
let start = input.checkpoint();
|
||||
|
||||
take(count).parse_next(input).and_then(|o| {
|
||||
if pattern == o {
|
||||
Ok(o)
|
||||
} else {
|
||||
input.reset(start);
|
||||
Err(ErrMode::Backtrack(E::from_error_kind(
|
||||
input,
|
||||
ErrorKind::Tag,
|
||||
)))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Deprecated, replaced with [`pattern`]
|
||||
#[deprecated(since = "0.5.38", note = "Replaced with `pattern`")]
|
||||
pub fn tag<I, O, C, E: ParserError<(I, usize)>>(p: O, count: C) -> impl Parser<(I, usize), O, E>
|
||||
where
|
||||
I: Stream<Token = u8> + AsBytes + StreamIsPartial + Clone,
|
||||
C: ToUsize,
|
||||
O: From<u8> + AddAssign + Shl<usize, Output = O> + Shr<usize, Output = O> + PartialEq,
|
||||
{
|
||||
pattern(p, count)
|
||||
}
|
||||
|
||||
/// Parses one specific bit as a bool.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use winnow::prelude::*;
|
||||
/// # use winnow::Bytes;
|
||||
/// # use winnow::error::{InputError, ErrorKind};
|
||||
/// use winnow::binary::bits::bool;
|
||||
///
|
||||
/// type Stream<'i> = &'i Bytes;
|
||||
///
|
||||
/// fn stream(b: &[u8]) -> Stream<'_> {
|
||||
/// Bytes::new(b)
|
||||
/// }
|
||||
///
|
||||
/// fn parse(input: (Stream<'_>, usize)) -> IResult<(Stream<'_>, usize), bool> {
|
||||
/// bool.parse_peek(input)
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(parse((stream(&[0b10000000]), 0)), Ok(((stream(&[0b10000000]), 1), true)));
|
||||
/// assert_eq!(parse((stream(&[0b10000000]), 1)), Ok(((stream(&[0b10000000]), 2), false)));
|
||||
/// ```
|
||||
#[doc(alias = "any")]
|
||||
pub fn bool<I, E: ParserError<(I, usize)>>(input: &mut (I, usize)) -> PResult<bool, E>
|
||||
where
|
||||
I: Stream<Token = u8> + AsBytes + StreamIsPartial + Clone,
|
||||
{
|
||||
trace("bool", |input: &mut (I, usize)| {
|
||||
let bit: u32 = take(1usize).parse_next(input)?;
|
||||
Ok(bit != 0)
|
||||
})
|
||||
.parse_next(input)
|
||||
}
|
||||
191
third-party/vendor/winnow/src/binary/bits/tests.rs
vendored
Normal file
191
third-party/vendor/winnow/src/binary/bits/tests.rs
vendored
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
use super::*;
|
||||
use crate::error::InputError;
|
||||
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].
|
||||
let result: IResult<&[u8], (u8, u8, u8)> =
|
||||
bits::<_, _, 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: IResult<&[u8], (u8, u8)> =
|
||||
bits::<_, _, 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: IResult<_, (u8, u8)> =
|
||||
bits::<_, _, InputError<(_, usize)>, _, _>((take(4usize), take(8usize))).parse_peek(input);
|
||||
|
||||
assert!(result.is_err());
|
||||
let error = result.err().unwrap();
|
||||
assert_eq!("Parsing requires 2 bytes/chars", error.to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_take_complete_0() {
|
||||
let input = &[0b00010010][..];
|
||||
let count = 0usize;
|
||||
assert_eq!(count, 0usize);
|
||||
let offset = 0usize;
|
||||
|
||||
let result: crate::IResult<(&[u8], usize), usize> = take(count).parse_peek((input, offset));
|
||||
|
||||
assert_eq!(result, Ok(((input, offset), 0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_take_complete_eof() {
|
||||
let input = &[0b00010010][..];
|
||||
|
||||
let result: crate::IResult<(&[u8], usize), usize> = take(1usize).parse_peek((input, 8));
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(crate::error::ErrMode::Backtrack(InputError::new(
|
||||
(input, 8),
|
||||
ErrorKind::Eof
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_take_complete_span_over_multiple_bytes() {
|
||||
let input = &[0b00010010, 0b00110100, 0b11111111, 0b11111111][..];
|
||||
|
||||
let result: crate::IResult<(&[u8], usize), usize> = 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: crate::IResult<(_, usize), usize> = take(count).parse_peek((input, offset));
|
||||
|
||||
assert_eq!(result, Ok(((input, offset), 0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tag_partial_ok() {
|
||||
let input = Partial::new(&[0b00011111][..]);
|
||||
let offset = 0usize;
|
||||
let bits_to_take = 4usize;
|
||||
let value_to_tag = 0b0001;
|
||||
|
||||
let result: crate::IResult<(_, usize), usize> =
|
||||
tag(value_to_tag, bits_to_take).parse_peek((input, offset));
|
||||
|
||||
assert_eq!(result, Ok(((input, bits_to_take), value_to_tag)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tag_partial_err() {
|
||||
let input = Partial::new(&[0b00011111][..]);
|
||||
let offset = 0usize;
|
||||
let bits_to_take = 4usize;
|
||||
let value_to_tag = 0b1111;
|
||||
|
||||
let result: crate::IResult<(_, usize), usize> =
|
||||
tag(value_to_tag, bits_to_take).parse_peek((input, offset));
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(crate::error::ErrMode::Backtrack(InputError::new(
|
||||
(input, offset),
|
||||
ErrorKind::Tag
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bool_0_complete() {
|
||||
let input = [0b10000000].as_ref();
|
||||
|
||||
let result: crate::IResult<(&[u8], usize), bool> = 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: crate::IResult<(&[u8], usize), bool> = bool.parse_peek((input, 8));
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(crate::error::ErrMode::Backtrack(InputError::new(
|
||||
(input, 8),
|
||||
ErrorKind::Eof
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bool_0_partial() {
|
||||
let input = Partial::new([0b10000000].as_ref());
|
||||
|
||||
let result: crate::IResult<(Partial<&[u8]>, usize), bool> = 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());
|
||||
|
||||
let result: crate::IResult<(Partial<&[u8]>, usize), bool> = bool.parse_peek((input, 8));
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(crate::error::ErrMode::Incomplete(Needed::new(1)))
|
||||
);
|
||||
}
|
||||
2591
third-party/vendor/winnow/src/binary/mod.rs
vendored
Normal file
2591
third-party/vendor/winnow/src/binary/mod.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
1316
third-party/vendor/winnow/src/binary/tests.rs
vendored
Normal file
1316
third-party/vendor/winnow/src/binary/tests.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
329
third-party/vendor/winnow/src/combinator/branch.rs
vendored
Normal file
329
third-party/vendor/winnow/src/combinator/branch.rs
vendored
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
use crate::combinator::trace;
|
||||
use crate::error::{ErrMode, ErrorKind, 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) -> PResult<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_6]).
|
||||
///
|
||||
/// 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::InputError,error::ErrorKind, error::Needed};
|
||||
/// # use winnow::prelude::*;
|
||||
/// use winnow::ascii::{alpha1, digit1};
|
||||
/// use winnow::combinator::alt;
|
||||
/// # fn main() {
|
||||
/// fn parser(input: &str) -> IResult<&str, &str> {
|
||||
/// alt((alpha1, digit1)).parse_peek(input)
|
||||
/// };
|
||||
///
|
||||
/// // the first parser, alpha1, recognizes the input
|
||||
/// assert_eq!(parser("abc"), Ok(("", "abc")));
|
||||
///
|
||||
/// // the first parser returns an error, so alt tries the second one
|
||||
/// assert_eq!(parser("123456"), Ok(("", "123456")));
|
||||
///
|
||||
/// // both parsers failed, and with the default error type, alt will return the last error
|
||||
/// assert_eq!(parser(" "), Err(ErrMode::Backtrack(InputError::new(" ", ErrorKind::Slice))));
|
||||
/// # }
|
||||
/// ```
|
||||
#[doc(alias = "choice")]
|
||||
pub fn alt<I: Stream, O, E: ParserError<I>, List: Alt<I, O, E>>(
|
||||
mut l: List,
|
||||
) -> impl Parser<I, O, E> {
|
||||
trace("alt", move |i: &mut I| l.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) -> PResult<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_6]).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use winnow::{error::ErrMode,error::{InputError, ErrorKind}, error::Needed};
|
||||
/// # use winnow::prelude::*;
|
||||
/// use winnow::ascii::{alpha1, digit1};
|
||||
/// use winnow::combinator::permutation;
|
||||
/// # fn main() {
|
||||
/// fn parser(input: &str) -> IResult<&str, (&str, &str)> {
|
||||
/// permutation((alpha1, digit1)).parse_peek(input)
|
||||
/// }
|
||||
///
|
||||
/// // permutation recognizes alphabetic characters then digit
|
||||
/// assert_eq!(parser("abc123"), Ok(("", ("abc", "123"))));
|
||||
///
|
||||
/// // but also in inverse order
|
||||
/// assert_eq!(parser("123abc"), Ok(("", ("abc", "123"))));
|
||||
///
|
||||
/// // it will fail if one of the parsers failed
|
||||
/// assert_eq!(parser("abc;"), Err(ErrMode::Backtrack(InputError::new(";", ErrorKind::Slice))));
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// 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, error::{InputError, ErrorKind}};
|
||||
/// # use winnow::prelude::*;
|
||||
/// use winnow::combinator::permutation;
|
||||
/// use winnow::token::any;
|
||||
///
|
||||
/// fn parser(input: &str) -> IResult<&str, (char, char)> {
|
||||
/// permutation((any, 'a')).parse_peek(input)
|
||||
/// }
|
||||
///
|
||||
/// // any parses 'b', then char('a') parses 'a'
|
||||
/// assert_eq!(parser("ba"), Ok(("", ('b', 'a'))));
|
||||
///
|
||||
/// // any parses 'a', then char('a') fails on 'b',
|
||||
/// // even though char('a') followed by any would succeed
|
||||
/// assert_eq!(parser("ab"), Err(ErrMode::Backtrack(InputError::new("b", ErrorKind::Verify))));
|
||||
/// ```
|
||||
///
|
||||
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) -> PResult<O, E> {
|
||||
let mut error: Option<E> = None;
|
||||
|
||||
let start = input.checkpoint();
|
||||
for branch in self {
|
||||
input.reset(start.clone());
|
||||
match branch.parse_next(input) {
|
||||
Err(ErrMode::Backtrack(e)) => {
|
||||
error = match error {
|
||||
Some(error) => Some(error.or(e)),
|
||||
None => Some(e),
|
||||
};
|
||||
}
|
||||
res => return res,
|
||||
}
|
||||
}
|
||||
|
||||
match error {
|
||||
Some(e) => Err(ErrMode::Backtrack(e.append(input, ErrorKind::Alt))),
|
||||
None => Err(ErrMode::assert(input, "`alt` needs at least one parser")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! alt_trait(
|
||||
($first:ident $second:ident $($id: ident)+) => (
|
||||
alt_trait!(__impl $first $second; $($id)+);
|
||||
);
|
||||
(__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) -> PResult<Output, Error> {
|
||||
let start = input.checkpoint();
|
||||
match self.0.parse_next(input) {
|
||||
Err(ErrMode::Backtrack(e)) => 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.clone());
|
||||
match $self.$it.parse_next($input) {
|
||||
Err(ErrMode::Backtrack(e)) => {
|
||||
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(ErrMode::Backtrack($err.append($input, ErrorKind::Alt)))
|
||||
});
|
||||
);
|
||||
|
||||
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, O, E: ParserError<I>, A: Parser<I, O, E>> Alt<I, O, E> for (A,) {
|
||||
fn choice(&mut self, input: &mut I) -> PResult<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) -> PResult<( $($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.clone());
|
||||
return Err(ErrMode::Backtrack(err.append(input, ErrorKind::Alt)));
|
||||
}
|
||||
|
||||
// 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.clone());
|
||||
match $self.$it.parse_next($input) {
|
||||
Ok(o) => {
|
||||
$res.$it = Some(o);
|
||||
continue;
|
||||
}
|
||||
Err(ErrMode::Backtrack(e)) => {
|
||||
$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
|
||||
);
|
||||
501
third-party/vendor/winnow/src/combinator/core.rs
vendored
Normal file
501
third-party/vendor/winnow/src/combinator/core.rs
vendored
Normal file
|
|
@ -0,0 +1,501 @@
|
|||
use crate::combinator::trace;
|
||||
use crate::error::{ErrMode, ErrorKind, Needed, ParserError};
|
||||
use crate::stream::Stream;
|
||||
use crate::*;
|
||||
|
||||
/// Return the remaining input.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use winnow::prelude::*;
|
||||
/// # use winnow::error::ErrorKind;
|
||||
/// # use winnow::error::InputError;
|
||||
/// use winnow::combinator::rest;
|
||||
/// assert_eq!(rest::<_,InputError<_>>.parse_peek("abc"), Ok(("", "abc")));
|
||||
/// assert_eq!(rest::<_,InputError<_>>.parse_peek(""), Ok(("", "")));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn rest<I, E: ParserError<I>>(input: &mut I) -> PResult<<I as Stream>::Slice, E>
|
||||
where
|
||||
I: Stream,
|
||||
{
|
||||
trace("rest", move |input: &mut I| Ok(input.finish())).parse_next(input)
|
||||
}
|
||||
|
||||
/// Return the length of the remaining input.
|
||||
///
|
||||
/// Note: this does not advance the [`Stream`]
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use winnow::prelude::*;
|
||||
/// # use winnow::error::ErrorKind;
|
||||
/// # use winnow::error::InputError;
|
||||
/// use winnow::combinator::rest_len;
|
||||
/// assert_eq!(rest_len::<_,InputError<_>>.parse_peek("abc"), Ok(("abc", 3)));
|
||||
/// assert_eq!(rest_len::<_,InputError<_>>.parse_peek(""), Ok(("", 0)));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn rest_len<I, E: ParserError<I>>(input: &mut I) -> PResult<usize, E>
|
||||
where
|
||||
I: Stream,
|
||||
{
|
||||
trace("rest_len", move |input: &mut I| {
|
||||
let len = input.eof_offset();
|
||||
Ok(len)
|
||||
})
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
/// Apply a [`Parser`], producing `None` on [`ErrMode::Backtrack`].
|
||||
///
|
||||
/// To chain an error up, see [`cut_err`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError};
|
||||
/// # use winnow::prelude::*;
|
||||
/// use winnow::combinator::opt;
|
||||
/// use winnow::ascii::alpha1;
|
||||
/// # fn main() {
|
||||
///
|
||||
/// fn parser(i: &str) -> IResult<&str, Option<&str>> {
|
||||
/// opt(alpha1).parse_peek(i)
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(parser("abcd;"), Ok((";", Some("abcd"))));
|
||||
/// assert_eq!(parser("123;"), Ok(("123;", None)));
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn opt<I: Stream, O, E: ParserError<I>, F>(mut f: F) -> impl Parser<I, Option<O>, E>
|
||||
where
|
||||
F: Parser<I, O, E>,
|
||||
{
|
||||
trace("opt", move |input: &mut I| {
|
||||
let start = input.checkpoint();
|
||||
match f.parse_next(input) {
|
||||
Ok(o) => Ok(Some(o)),
|
||||
Err(ErrMode::Backtrack(_)) => {
|
||||
input.reset(start);
|
||||
Ok(None)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Calls the parser if the condition is met.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, IResult};
|
||||
/// # use winnow::prelude::*;
|
||||
/// use winnow::combinator::cond;
|
||||
/// use winnow::ascii::alpha1;
|
||||
/// # fn main() {
|
||||
///
|
||||
/// fn parser(b: bool, i: &str) -> IResult<&str, Option<&str>> {
|
||||
/// cond(b, alpha1).parse_peek(i)
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(parser(true, "abcd;"), Ok((";", Some("abcd"))));
|
||||
/// assert_eq!(parser(false, "abcd;"), Ok(("abcd;", None)));
|
||||
/// assert_eq!(parser(true, "123;"), Err(ErrMode::Backtrack(InputError::new("123;", ErrorKind::Slice))));
|
||||
/// assert_eq!(parser(false, "123;"), Ok(("123;", None)));
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn cond<I, O, E: ParserError<I>, F>(b: bool, mut f: F) -> impl Parser<I, Option<O>, E>
|
||||
where
|
||||
I: Stream,
|
||||
F: Parser<I, O, E>,
|
||||
{
|
||||
trace("cond", move |input: &mut I| {
|
||||
if b {
|
||||
f.parse_next(input).map(Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Tries to apply its parser without consuming the input.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, IResult};
|
||||
/// # use winnow::prelude::*;
|
||||
/// use winnow::combinator::peek;
|
||||
/// use winnow::ascii::alpha1;
|
||||
/// # fn main() {
|
||||
///
|
||||
/// let mut parser = peek(alpha1);
|
||||
///
|
||||
/// assert_eq!(parser.parse_peek("abcd;"), Ok(("abcd;", "abcd")));
|
||||
/// assert_eq!(parser.parse_peek("123;"), Err(ErrMode::Backtrack(InputError::new("123;", ErrorKind::Slice))));
|
||||
/// # }
|
||||
/// ```
|
||||
#[doc(alias = "look_ahead")]
|
||||
#[doc(alias = "rewind")]
|
||||
pub fn peek<I: Stream, O, E: ParserError<I>, F>(mut f: F) -> impl Parser<I, O, E>
|
||||
where
|
||||
F: Parser<I, O, E>,
|
||||
{
|
||||
trace("peek", move |input: &mut I| {
|
||||
let start = input.checkpoint();
|
||||
let res = f.parse_next(input);
|
||||
input.reset(start);
|
||||
res
|
||||
})
|
||||
}
|
||||
|
||||
/// Match the end of the [`Stream`]
|
||||
///
|
||||
/// Otherwise, it will error.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use std::str;
|
||||
/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError};
|
||||
/// # use winnow::combinator::eof;
|
||||
/// # use winnow::prelude::*;
|
||||
///
|
||||
/// let mut parser = eof;
|
||||
/// assert_eq!(parser.parse_peek("abc"), Err(ErrMode::Backtrack(InputError::new("abc", ErrorKind::Eof))));
|
||||
/// assert_eq!(parser.parse_peek(""), Ok(("", "")));
|
||||
/// ```
|
||||
#[doc(alias = "end")]
|
||||
#[doc(alias = "eoi")]
|
||||
pub fn eof<I, E: ParserError<I>>(input: &mut I) -> PResult<<I as Stream>::Slice, E>
|
||||
where
|
||||
I: Stream,
|
||||
{
|
||||
trace("eof", move |input: &mut I| {
|
||||
if input.eof_offset() == 0 {
|
||||
Ok(input.next_slice(0))
|
||||
} else {
|
||||
Err(ErrMode::from_error_kind(input, ErrorKind::Eof))
|
||||
}
|
||||
})
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
/// Succeeds if the child parser returns an error.
|
||||
///
|
||||
/// **Note:** This does not advance the [`Stream`]
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, IResult};
|
||||
/// # use winnow::prelude::*;
|
||||
/// use winnow::combinator::not;
|
||||
/// use winnow::ascii::alpha1;
|
||||
/// # fn main() {
|
||||
///
|
||||
/// let mut parser = not(alpha1);
|
||||
///
|
||||
/// assert_eq!(parser.parse_peek("123"), Ok(("123", ())));
|
||||
/// assert_eq!(parser.parse_peek("abcd"), Err(ErrMode::Backtrack(InputError::new("abcd", ErrorKind::Not))));
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn not<I: Stream, O, E: ParserError<I>, F>(mut parser: F) -> impl Parser<I, (), E>
|
||||
where
|
||||
F: Parser<I, O, E>,
|
||||
{
|
||||
trace("not", move |input: &mut I| {
|
||||
let start = input.checkpoint();
|
||||
let res = parser.parse_next(input);
|
||||
input.reset(start);
|
||||
match res {
|
||||
Ok(_) => Err(ErrMode::from_error_kind(input, ErrorKind::Not)),
|
||||
Err(ErrMode::Backtrack(_)) => Ok(()),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Transforms an [`ErrMode::Backtrack`] (recoverable) to [`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_6] for more details.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Without `cut_err`:
|
||||
/// ```rust
|
||||
/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError};
|
||||
/// # use winnow::token::one_of;
|
||||
/// # use winnow::ascii::digit1;
|
||||
/// # use winnow::combinator::rest;
|
||||
/// # use winnow::combinator::alt;
|
||||
/// # use winnow::combinator::preceded;
|
||||
/// # use winnow::prelude::*;
|
||||
/// # fn main() {
|
||||
///
|
||||
/// fn parser(input: &str) -> IResult<&str, &str> {
|
||||
/// alt((
|
||||
/// preceded(one_of(['+', '-']), digit1),
|
||||
/// rest
|
||||
/// )).parse_peek(input)
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(parser("+10 ab"), Ok((" ab", "10")));
|
||||
/// assert_eq!(parser("ab"), Ok(("", "ab")));
|
||||
/// assert_eq!(parser("+"), Ok(("", "+")));
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// With `cut_err`:
|
||||
/// ```rust
|
||||
/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError};
|
||||
/// # use winnow::prelude::*;
|
||||
/// # use winnow::token::one_of;
|
||||
/// # use winnow::ascii::digit1;
|
||||
/// # use winnow::combinator::rest;
|
||||
/// # use winnow::combinator::alt;
|
||||
/// # use winnow::combinator::preceded;
|
||||
/// use winnow::combinator::cut_err;
|
||||
/// # fn main() {
|
||||
///
|
||||
/// fn parser(input: &str) -> IResult<&str, &str> {
|
||||
/// alt((
|
||||
/// preceded(one_of(['+', '-']), cut_err(digit1)),
|
||||
/// rest
|
||||
/// )).parse_peek(input)
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(parser("+10 ab"), Ok((" ab", "10")));
|
||||
/// assert_eq!(parser("ab"), Ok(("", "ab")));
|
||||
/// assert_eq!(parser("+"), Err(ErrMode::Cut(InputError::new("", ErrorKind::Slice ))));
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn cut_err<I, O, E: ParserError<I>, F>(mut parser: F) -> impl Parser<I, O, E>
|
||||
where
|
||||
I: Stream,
|
||||
F: Parser<I, O, E>,
|
||||
{
|
||||
trace("cut_err", move |input: &mut I| {
|
||||
parser.parse_next(input).map_err(|e| e.cut())
|
||||
})
|
||||
}
|
||||
|
||||
/// Transforms an [`ErrMode::Cut`] (unrecoverable) to [`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<I, O, E: ParserError<I>, F>(mut parser: F) -> impl Parser<I, O, E>
|
||||
where
|
||||
I: Stream,
|
||||
F: Parser<I, O, E>,
|
||||
{
|
||||
trace("backtrack_err", move |input: &mut I| {
|
||||
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) -> PResult<u64> {
|
||||
/// todo(input)
|
||||
/// }
|
||||
/// ```
|
||||
#[track_caller]
|
||||
pub fn todo<I, O, E>(input: &mut I) -> PResult<O, E>
|
||||
where
|
||||
I: Stream,
|
||||
{
|
||||
#![allow(clippy::todo)]
|
||||
trace("todo", move |_input: &mut I| 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`], iteration will stop. To instead chain an error up, see [`cut_err`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use winnow::{combinator::iterator, IResult, token::tag, 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: IResult<_,_> = it.finish();
|
||||
///
|
||||
/// assert_eq!(parsed, [("abc", 3usize), ("defg", 4), ("hijkl", 5), ("mnopqr", 6)].iter().cloned().collect());
|
||||
/// assert_eq!(res, Ok(("123", ())));
|
||||
/// ```
|
||||
pub fn iterator<I, O, E, F>(input: I, parser: F) -> ParserIterator<F, I, O, E>
|
||||
where
|
||||
F: Parser<I, O, E>,
|
||||
I: Stream,
|
||||
E: ParserError<I>,
|
||||
{
|
||||
ParserIterator {
|
||||
parser,
|
||||
input,
|
||||
state: Some(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: Option<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,
|
||||
{
|
||||
/// Returns the remaining input if parsing was successful, or the error if we encountered an error.
|
||||
pub fn finish(mut self) -> PResult<(I, ()), E> {
|
||||
match self.state.take().unwrap() {
|
||||
State::Running | State::Done => Ok((self.input, ())),
|
||||
State::Failure(e) => Err(ErrMode::Cut(e)),
|
||||
State::Incomplete(i) => Err(ErrMode::Incomplete(i)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, F, I, O, E> core::iter::Iterator for &'a mut ParserIterator<F, I, O, E>
|
||||
where
|
||||
F: Parser<I, O, E>,
|
||||
I: Stream,
|
||||
{
|
||||
type Item = O;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let State::Running = self.state.take().unwrap() {
|
||||
let start = self.input.checkpoint();
|
||||
|
||||
match self.parser.parse_next(&mut self.input) {
|
||||
Ok(o) => {
|
||||
self.state = Some(State::Running);
|
||||
Some(o)
|
||||
}
|
||||
Err(ErrMode::Backtrack(_)) => {
|
||||
self.input.reset(start);
|
||||
self.state = Some(State::Done);
|
||||
None
|
||||
}
|
||||
Err(ErrMode::Cut(e)) => {
|
||||
self.state = Some(State::Failure(e));
|
||||
None
|
||||
}
|
||||
Err(ErrMode::Incomplete(i)) => {
|
||||
self.state = Some(State::Incomplete(i));
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum State<E> {
|
||||
Running,
|
||||
Done,
|
||||
Failure(E),
|
||||
Incomplete(Needed),
|
||||
}
|
||||
|
||||
/// 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`]
|
||||
///
|
||||
/// **Note:** This never advances the [`Stream`]
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError};
|
||||
/// # use winnow::prelude::*;
|
||||
/// use winnow::combinator::alt;
|
||||
/// use winnow::combinator::empty;
|
||||
///
|
||||
/// fn sign(input: &str) -> IResult<&str, isize> {
|
||||
/// alt((
|
||||
/// '-'.value(-1),
|
||||
/// '+'.value(1),
|
||||
/// empty.value(1)
|
||||
/// )).parse_peek(input)
|
||||
/// }
|
||||
/// assert_eq!(sign("+10"), Ok(("10", 1)));
|
||||
/// assert_eq!(sign("-10"), Ok(("10", -1)));
|
||||
/// assert_eq!(sign("10"), Ok(("10", 1)));
|
||||
/// ```
|
||||
#[doc(alias = "value")]
|
||||
#[doc(alias = "success")]
|
||||
pub fn empty<I: Stream, E: ParserError<I>>(_input: &mut I) -> PResult<(), E> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Deprecated, replaced with [`empty`] + [`Parser::value`]
|
||||
#[deprecated(since = "0.5.35", note = "Replaced with empty.value(...)`")]
|
||||
pub fn success<I: Stream, O: Clone, E: ParserError<I>>(val: O) -> impl Parser<I, O, E> {
|
||||
trace("success", move |_input: &mut I| Ok(val.clone()))
|
||||
}
|
||||
|
||||
/// 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::ErrorKind, error::InputError, IResult};
|
||||
/// # use winnow::prelude::*;
|
||||
/// use winnow::combinator::fail;
|
||||
///
|
||||
/// let s = "string";
|
||||
/// assert_eq!(fail::<_, &str, _>.parse_peek(s), Err(ErrMode::Backtrack(InputError::new(s, ErrorKind::Fail))));
|
||||
/// ```
|
||||
#[doc(alias = "unexpected")]
|
||||
pub fn fail<I: Stream, O, E: ParserError<I>>(i: &mut I) -> PResult<O, E> {
|
||||
trace("fail", |i: &mut I| {
|
||||
Err(ErrMode::from_error_kind(i, ErrorKind::Fail))
|
||||
})
|
||||
.parse_next(i)
|
||||
}
|
||||
301
third-party/vendor/winnow/src/combinator/debug/internals.rs
vendored
Normal file
301
third-party/vendor/winnow/src/combinator/debug/internals.rs
vendored
Normal file
|
|
@ -0,0 +1,301 @@
|
|||
#![cfg(feature = "std")]
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
use crate::error::ErrMode;
|
||||
use crate::stream::Stream;
|
||||
use crate::*;
|
||||
|
||||
pub struct Trace<P, D, I, O, E>
|
||||
where
|
||||
P: Parser<I, O, E>,
|
||||
I: Stream,
|
||||
D: std::fmt::Display,
|
||||
{
|
||||
parser: P,
|
||||
name: D,
|
||||
call_count: usize,
|
||||
i: core::marker::PhantomData<I>,
|
||||
o: core::marker::PhantomData<O>,
|
||||
e: core::marker::PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<P, D, I, O, E> Trace<P, D, I, O, E>
|
||||
where
|
||||
P: Parser<I, O, E>,
|
||||
I: Stream,
|
||||
D: std::fmt::Display,
|
||||
{
|
||||
#[inline(always)]
|
||||
pub fn new(parser: P, name: D) -> Self {
|
||||
Self {
|
||||
parser,
|
||||
name,
|
||||
call_count: 0,
|
||||
i: Default::default(),
|
||||
o: Default::default(),
|
||||
e: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P, D, I, O, E> Parser<I, O, E> for Trace<P, D, I, O, E>
|
||||
where
|
||||
P: Parser<I, O, E>,
|
||||
I: Stream,
|
||||
D: std::fmt::Display,
|
||||
{
|
||||
#[inline]
|
||||
fn parse_next(&mut self, i: &mut I) -> PResult<O, E> {
|
||||
let depth = Depth::new();
|
||||
let original = i.checkpoint();
|
||||
start(*depth, &self.name, self.call_count, i);
|
||||
|
||||
let res = self.parser.parse_next(i);
|
||||
|
||||
let consumed = i.offset_from(&original);
|
||||
let severity = Severity::with_result(&res);
|
||||
end(*depth, &self.name, self.call_count, consumed, severity);
|
||||
self.call_count += 1;
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Depth {
|
||||
depth: usize,
|
||||
inc: bool,
|
||||
}
|
||||
|
||||
impl Depth {
|
||||
pub fn new() -> Self {
|
||||
let depth = DEPTH.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
|
||||
let inc = true;
|
||||
Self { depth, inc }
|
||||
}
|
||||
|
||||
pub 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 enum Severity {
|
||||
Success,
|
||||
Backtrack,
|
||||
Cut,
|
||||
Incomplete,
|
||||
}
|
||||
|
||||
impl Severity {
|
||||
pub fn with_result<T, E>(result: &Result<T, ErrMode<E>>) -> Self {
|
||||
match result {
|
||||
Ok(_) => Self::Success,
|
||||
Err(ErrMode::Backtrack(_)) => Self::Backtrack,
|
||||
Err(ErrMode::Cut(_)) => Self::Cut,
|
||||
Err(ErrMode::Incomplete(_)) => Self::Incomplete,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub 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!("{:#?}", input.raw());
|
||||
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 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 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::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())
|
||||
}
|
||||
91
third-party/vendor/winnow/src/combinator/debug/mod.rs
vendored
Normal file
91
third-party/vendor/winnow/src/combinator/debug/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#![cfg_attr(feature = "debug", allow(clippy::std_instead_of_core))]
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
mod internals;
|
||||
|
||||
use crate::error::ErrMode;
|
||||
use crate::stream::Stream;
|
||||
use crate::Parser;
|
||||
|
||||
#[cfg(all(feature = "debug", not(feature = "std")))]
|
||||
compile_error!("`debug` requires `std`");
|
||||
|
||||
/// 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::{InputError, ErrorKind}, 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]) -> PResult<&'s [u8], InputError<&'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_eq!(short_alpha.parse_peek(b"ed"), Err(ErrMode::Backtrack(InputError::new(&b"ed"[..], ErrorKind::Slice))));
|
||||
/// assert_eq!(short_alpha.parse_peek(b"12345"), Err(ErrMode::Backtrack(InputError::new(&b"12345"[..], ErrorKind::Slice))));
|
||||
/// ```
|
||||
#[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>(
|
||||
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, E>(
|
||||
name: impl crate::lib::std::fmt::Display,
|
||||
res: &Result<T, ErrMode<E>>,
|
||||
) {
|
||||
#[cfg(feature = "debug")]
|
||||
{
|
||||
let depth = internals::Depth::existing();
|
||||
let severity = internals::Severity::with_result(res);
|
||||
internals::result(*depth, &name, severity);
|
||||
}
|
||||
}
|
||||
|
||||
#[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", [cmd.as_str()]);
|
||||
}
|
||||
176
third-party/vendor/winnow/src/combinator/mod.rs
vendored
Normal file
176
third-party/vendor/winnow/src/combinator/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
//! # List of parsers and combinators
|
||||
//!
|
||||
//! **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.
|
||||
//!
|
||||
//! ## Basic elements
|
||||
//!
|
||||
//! Those are used to recognize the lowest level elements of your grammar, like, "here is a dot", or "here is an big endian integer".
|
||||
//!
|
||||
//! | combinator | usage | input | new input | output | comment |
|
||||
//! |---|---|---|---|---|---|
|
||||
//! | [`one_of`][crate::token::one_of] | `one_of(['a', 'b', 'c'])` | `"abc"` | `"bc"` | `Ok('a')` |Matches one of the provided characters (works with non ASCII characters too)|
|
||||
//! | [`none_of`][crate::token::none_of] | `none_of(['a', 'b', 'c'])` | `"xyab"` | `"yab"` | `Ok('x')` |Matches anything but the provided characters|
|
||||
//! | [`tag`][crate::token::tag] | `"hello"` | `"hello world"` | `" world"` | `Ok("hello")` |Recognizes a specific suite of characters or bytes (see also [`Caseless`][crate::ascii::Caseless])|
|
||||
//! | [`take`][crate::token::take] | `take(4)` | `"hello"` | `"o"` | `Ok("hell")` |Takes a specific number of bytes or characters|
|
||||
//! | [`take_while`][crate::token::take_while] | `take_while(0.., is_alphabetic)` | `"abc123"` | `"123"` | `Ok("abc")` |Returns the longest list of bytes for which the provided pattern matches.|
|
||||
//! | [`take_till0`][crate::token::take_till0] | `take_till0(is_alphabetic)` | `"123abc"` | `"abc"` | `Ok("123")` |Returns the longest list of bytes or characters until the provided pattern matches. `take_till1` does the same, but must return at least one character. This is the reverse behaviour from `take_while`: `take_till(f)` is equivalent to `take_while(0.., \|c\| !f(c))`|
|
||||
//! | [`take_until`][crate::token::take_until] | `take_until(0.., "world")` | `"Hello world"` | `"world"` | `Ok("Hello ")` |Returns the longest list of bytes or characters until the provided tag 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"))` |Chains parsers and assemble the sub results in a tuple. You can use as many child parsers as you can put elements in a tuple|
|
||||
//! | [`seq!`] | `seq!(_: char('('), take(2), _: char(')'))` | `"(ab)cd"` | `"cd"` | `Ok("ab")` ||
|
||||
//! | [`delimited`] | `delimited(char('('), take(2), char(')'))` | `"(ab)cd"` | `"cd"` | `Ok("ab")` ||
|
||||
//! | [`preceded`] | `preceded("ab", "XY")` | `"abXYZ"` | `"Z"` | `Ok("XY")` ||
|
||||
//! | [`terminated`] | `terminated("ab", "XY")` | `"abXYZ"` | `"Z"` | `Ok("ab")` ||
|
||||
//! | [`separated_pair`] | `separated_pair("hello", char(','), "world")` | `"hello,world!"` | `"!"` | `Ok(("hello", "world"))` ||
|
||||
//!
|
||||
//! ## Applying a parser multiple times
|
||||
//!
|
||||
//! | combinator | usage | input | 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.., tag( "ab" ), tag( "ef" ))` | `"ababefg"` | `"g"` | `Ok((vec!["ab", "ab"], "ef"))` |Applies the first parser until the second applies. Returns a tuple containing the list of results from the first in a Vec and the result of the second|
|
||||
//! | [`separated`] | `separated(1..=3, "ab", ",")` | `"ab,ab,ab."` | `"."` | `Ok(vec!["ab", "ab", "ab"])` |Applies the parser and separator between m and n times (n included) and returns the list of results in a Vec|
|
||||
//! | [`fold_repeat`] | `fold_repeat(1..=2, be_u8, \|\| 0, \|acc, item\| acc + item)` | `[1, 2, 3]` | `[3]` | `Ok(3)` |Applies the parser between m and n times (n included) and folds the list of return value|
|
||||
//!
|
||||
//! ## Partial related
|
||||
//!
|
||||
//! - [`eof`]: 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::recognize`]: If the child parser was successful, return the consumed input as the produced value
|
||||
//! - [`Parser::with_recognized`]: If the child parser was successful, return a tuple of the consumed input and the produced output.
|
||||
//! - [`Parser::span`]: If the child parser was successful, return the location of the consumed input as the produced value
|
||||
//! - [`Parser::with_span`]: If the child parser was successful, return a tuple of the location of the consumed input and the produced output.
|
||||
//! - [`Parser::verify`]: Returns the result of the child parser if it satisfies a verification function
|
||||
//!
|
||||
//! ## Error management and debugging
|
||||
//!
|
||||
//! - [`cut_err`]: Commit the parse result, disallowing alternative parsers from being attempted
|
||||
//! - [`backtrack_err`]: 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
|
||||
//!
|
||||
//! - [`success`]: Returns a value without consuming any input, always succeeds
|
||||
//! - [`fail`]: Inversion of `success`. Always fails.
|
||||
//! - [`Parser::by_ref`]: Allow moving `&mut impl Parser` into other parsers
|
||||
//!
|
||||
//! ## Text parsing
|
||||
//!
|
||||
//! - [`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`]: 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
|
||||
//!
|
||||
//! - [`escaped`][crate::ascii::escaped]: Matches a byte string with escaped characters
|
||||
//! - [`escaped_transform`][crate::ascii::escaped_transform]: Matches a byte string with escaped characters, and returns a new string with the escaped characters replaced
|
||||
//!
|
||||
//! ### 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_count`][crate::binary::length_count] Gets a number from the first parser, then applies the second parser that many times
|
||||
//! - [`length_data`][crate::binary::length_data]: Gets a number from the first parser, then takes a subslice of the input of that size, and returns that subslice
|
||||
//! - [`length_value`][crate::binary::length_value]: 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
|
||||
//! - [`tag`][crate::binary::bits::tag]: 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 parser;
|
||||
mod sequence;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use self::branch::*;
|
||||
pub use self::core::*;
|
||||
pub use self::debug::*;
|
||||
pub use self::multi::*;
|
||||
pub use self::parser::*;
|
||||
pub use self::sequence::*;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use crate::Parser;
|
||||
1408
third-party/vendor/winnow/src/combinator/multi.rs
vendored
Normal file
1408
third-party/vendor/winnow/src/combinator/multi.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
1097
third-party/vendor/winnow/src/combinator/parser.rs
vendored
Normal file
1097
third-party/vendor/winnow/src/combinator/parser.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
175
third-party/vendor/winnow/src/combinator/sequence.rs
vendored
Normal file
175
third-party/vendor/winnow/src/combinator/sequence.rs
vendored
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
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.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `first` The opening parser.
|
||||
/// * `second` The second parser to get object.
|
||||
///
|
||||
/// See also [`seq`] to generalize this across any number of fields.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
|
||||
/// # use winnow::prelude::*;
|
||||
/// # use winnow::error::Needed::Size;
|
||||
/// use winnow::combinator::preceded;
|
||||
/// use winnow::token::tag;
|
||||
///
|
||||
/// let mut parser = preceded("abc", "efg");
|
||||
///
|
||||
/// assert_eq!(parser.parse_peek("abcefg"), Ok(("", "efg")));
|
||||
/// assert_eq!(parser.parse_peek("abcefghij"), Ok(("hij", "efg")));
|
||||
/// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag))));
|
||||
/// assert_eq!(parser.parse_peek("123"), Err(ErrMode::Backtrack(InputError::new("123", ErrorKind::Tag))));
|
||||
/// ```
|
||||
#[doc(alias = "ignore_then")]
|
||||
pub fn preceded<I, O1, O2, E: ParserError<I>, F, G>(
|
||||
mut first: F,
|
||||
mut second: G,
|
||||
) -> impl Parser<I, O2, E>
|
||||
where
|
||||
I: Stream,
|
||||
F: Parser<I, O1, E>,
|
||||
G: Parser<I, O2, E>,
|
||||
{
|
||||
trace("preceded", move |input: &mut I| {
|
||||
let _ = first.parse_next(input)?;
|
||||
second.parse_next(input)
|
||||
})
|
||||
}
|
||||
|
||||
/// Sequence two parsers, only returning the output of the first.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `first` The first parser to apply.
|
||||
/// * `second` The second parser to match an object.
|
||||
///
|
||||
/// See also [`seq`] to generalize this across any number of fields.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
|
||||
/// # use winnow::prelude::*;
|
||||
/// # use winnow::error::Needed::Size;
|
||||
/// use winnow::combinator::terminated;
|
||||
/// use winnow::token::tag;
|
||||
///
|
||||
/// let mut parser = terminated("abc", "efg");
|
||||
///
|
||||
/// assert_eq!(parser.parse_peek("abcefg"), Ok(("", "abc")));
|
||||
/// assert_eq!(parser.parse_peek("abcefghij"), Ok(("hij", "abc")));
|
||||
/// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag))));
|
||||
/// assert_eq!(parser.parse_peek("123"), Err(ErrMode::Backtrack(InputError::new("123", ErrorKind::Tag))));
|
||||
/// ```
|
||||
#[doc(alias = "then_ignore")]
|
||||
pub fn terminated<I, O1, O2, E: ParserError<I>, F, G>(
|
||||
mut first: F,
|
||||
mut second: G,
|
||||
) -> impl Parser<I, O1, E>
|
||||
where
|
||||
I: Stream,
|
||||
F: Parser<I, O1, E>,
|
||||
G: Parser<I, O2, E>,
|
||||
{
|
||||
trace("terminated", move |input: &mut I| {
|
||||
let o1 = first.parse_next(input)?;
|
||||
second.parse_next(input).map(|_| o1)
|
||||
})
|
||||
}
|
||||
|
||||
/// Sequence three parsers, only returning the values of the first and third.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `first` The first parser to apply.
|
||||
/// * `sep` The separator parser to apply.
|
||||
/// * `second` The second parser to apply.
|
||||
///
|
||||
/// See also [`seq`] to generalize this across any number of fields.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
|
||||
/// # use winnow::error::Needed::Size;
|
||||
/// # use winnow::prelude::*;
|
||||
/// use winnow::combinator::separated_pair;
|
||||
/// use winnow::token::tag;
|
||||
///
|
||||
/// let mut parser = separated_pair("abc", "|", "efg");
|
||||
///
|
||||
/// assert_eq!(parser.parse_peek("abc|efg"), Ok(("", ("abc", "efg"))));
|
||||
/// assert_eq!(parser.parse_peek("abc|efghij"), Ok(("hij", ("abc", "efg"))));
|
||||
/// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag))));
|
||||
/// assert_eq!(parser.parse_peek("123"), Err(ErrMode::Backtrack(InputError::new("123", ErrorKind::Tag))));
|
||||
/// ```
|
||||
pub fn separated_pair<I, O1, O2, O3, E: ParserError<I>, F, G, H>(
|
||||
mut first: F,
|
||||
mut sep: G,
|
||||
mut second: H,
|
||||
) -> impl Parser<I, (O1, O3), E>
|
||||
where
|
||||
I: Stream,
|
||||
F: Parser<I, O1, E>,
|
||||
G: Parser<I, O2, E>,
|
||||
H: Parser<I, O3, E>,
|
||||
{
|
||||
trace("separated_pair", move |input: &mut I| {
|
||||
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.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `first` The first parser to apply and discard.
|
||||
/// * `second` The second parser to apply.
|
||||
/// * `third` The third parser to apply and discard.
|
||||
///
|
||||
/// See also [`seq`] to generalize this across any number of fields.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed};
|
||||
/// # use winnow::error::Needed::Size;
|
||||
/// # use winnow::prelude::*;
|
||||
/// use winnow::combinator::delimited;
|
||||
/// use winnow::token::tag;
|
||||
///
|
||||
/// let mut parser = delimited("(", "abc", ")");
|
||||
///
|
||||
/// assert_eq!(parser.parse_peek("(abc)"), Ok(("", "abc")));
|
||||
/// assert_eq!(parser.parse_peek("(abc)def"), Ok(("def", "abc")));
|
||||
/// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag))));
|
||||
/// assert_eq!(parser.parse_peek("123"), Err(ErrMode::Backtrack(InputError::new("123", ErrorKind::Tag))));
|
||||
/// ```
|
||||
#[doc(alias = "between")]
|
||||
#[doc(alias = "padded")]
|
||||
pub fn delimited<I, O1, O2, O3, E: ParserError<I>, F, G, H>(
|
||||
mut first: F,
|
||||
mut second: G,
|
||||
mut third: H,
|
||||
) -> impl Parser<I, O2, E>
|
||||
where
|
||||
I: Stream,
|
||||
F: Parser<I, O1, E>,
|
||||
G: Parser<I, O2, E>,
|
||||
H: Parser<I, O3, E>,
|
||||
{
|
||||
trace("delimited", move |input: &mut I| {
|
||||
let _ = first.parse_next(input)?;
|
||||
let o2 = second.parse_next(input)?;
|
||||
third.parse_next(input).map(|_| o2)
|
||||
})
|
||||
}
|
||||
1379
third-party/vendor/winnow/src/combinator/tests.rs
vendored
Normal file
1379
third-party/vendor/winnow/src/combinator/tests.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
1467
third-party/vendor/winnow/src/error.rs
vendored
Normal file
1467
third-party/vendor/winnow/src/error.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
256
third-party/vendor/winnow/src/lib.rs
vendored
Normal file
256
third-party/vendor/winnow/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
//! > 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.5.40/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 binary data, strings, or
|
||||
//! separate lexing and parsing phases
|
||||
//! 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(not(feature = "std"), no_std)]
|
||||
#![warn(missing_docs)]
|
||||
#![warn(clippy::std_instead_of_core)]
|
||||
// BEGIN - Embark standard lints v6 for Rust 1.55+
|
||||
// do not change or add/remove here, but one can add exceptions after this section
|
||||
// for more info see: <https://github.com/EmbarkStudios/rust-ecosystem/issues/59>
|
||||
// "-Dunsafe_code",
|
||||
#![warn(clippy::all)]
|
||||
#![warn(clippy::await_holding_lock)]
|
||||
#![warn(clippy::char_lit_as_u8)]
|
||||
#![warn(clippy::checked_conversions)]
|
||||
#![warn(clippy::dbg_macro)]
|
||||
#![warn(clippy::debug_assert_with_mut_call)]
|
||||
#![warn(clippy::doc_markdown)]
|
||||
#![warn(clippy::empty_enum)]
|
||||
#![warn(clippy::enum_glob_use)]
|
||||
#![warn(clippy::exit)]
|
||||
#![warn(clippy::expl_impl_clone_on_copy)]
|
||||
#![warn(clippy::explicit_deref_methods)]
|
||||
#![warn(clippy::explicit_into_iter_loop)]
|
||||
#![warn(clippy::fallible_impl_from)]
|
||||
#![warn(clippy::filter_map_next)]
|
||||
#![warn(clippy::flat_map_option)]
|
||||
#![warn(clippy::float_cmp_const)]
|
||||
#![warn(clippy::fn_params_excessive_bools)]
|
||||
#![warn(clippy::from_iter_instead_of_collect)]
|
||||
#![warn(clippy::if_let_mutex)]
|
||||
#![warn(clippy::implicit_clone)]
|
||||
#![warn(clippy::imprecise_flops)]
|
||||
#![warn(clippy::inefficient_to_string)]
|
||||
#![warn(clippy::invalid_upcast_comparisons)]
|
||||
#![warn(clippy::large_digit_groups)]
|
||||
#![warn(clippy::large_stack_arrays)]
|
||||
#![warn(clippy::large_types_passed_by_value)]
|
||||
#![warn(clippy::let_unit_value)]
|
||||
#![warn(clippy::linkedlist)]
|
||||
#![warn(clippy::lossy_float_literal)]
|
||||
#![warn(clippy::macro_use_imports)]
|
||||
#![warn(clippy::manual_ok_or)]
|
||||
#![warn(clippy::map_err_ignore)]
|
||||
#![warn(clippy::map_flatten)]
|
||||
#![warn(clippy::map_unwrap_or)]
|
||||
#![warn(clippy::match_on_vec_items)]
|
||||
#![warn(clippy::match_same_arms)]
|
||||
#![warn(clippy::match_wild_err_arm)]
|
||||
#![warn(clippy::match_wildcard_for_single_variants)]
|
||||
#![warn(clippy::mem_forget)]
|
||||
#![warn(clippy::mismatched_target_os)]
|
||||
#![warn(clippy::missing_enforced_import_renames)]
|
||||
#![warn(clippy::mut_mut)]
|
||||
#![warn(clippy::mutex_integer)]
|
||||
#![warn(clippy::needless_borrow)]
|
||||
#![warn(clippy::needless_continue)]
|
||||
#![warn(clippy::needless_for_each)]
|
||||
#![warn(clippy::option_option)]
|
||||
#![warn(clippy::path_buf_push_overwrite)]
|
||||
#![warn(clippy::ptr_as_ptr)]
|
||||
#![warn(clippy::rc_mutex)]
|
||||
#![warn(clippy::ref_option_ref)]
|
||||
#![warn(clippy::rest_pat_in_fully_bound_structs)]
|
||||
#![warn(clippy::same_functions_in_if_condition)]
|
||||
#![warn(clippy::semicolon_if_nothing_returned)]
|
||||
#![warn(clippy::single_match_else)]
|
||||
#![warn(clippy::string_add_assign)]
|
||||
#![warn(clippy::string_add)]
|
||||
#![warn(clippy::string_lit_as_bytes)]
|
||||
#![warn(clippy::string_to_string)]
|
||||
#![warn(clippy::todo)]
|
||||
#![warn(clippy::trait_duplication_in_bounds)]
|
||||
#![warn(clippy::unimplemented)]
|
||||
#![warn(clippy::unnested_or_patterns)]
|
||||
#![warn(clippy::unused_self)]
|
||||
#![warn(clippy::useless_transmute)]
|
||||
#![warn(clippy::verbose_file_reads)]
|
||||
#![warn(clippy::zero_sized_map_values)]
|
||||
#![warn(future_incompatible)]
|
||||
#![warn(nonstandard_style)]
|
||||
#![warn(rust_2018_idioms)]
|
||||
// END - Embark standard lints v6 for Rust 1.55+
|
||||
#![allow(clippy::branches_sharing_code)]
|
||||
#![allow(clippy::collapsible_else_if)]
|
||||
#![allow(clippy::if_same_then_else)]
|
||||
#![allow(clippy::bool_assert_comparison)]
|
||||
#![allow(clippy::let_and_return)]
|
||||
#![allow(clippy::assertions_on_constants)]
|
||||
#![allow(clippy::map_unwrap_or)]
|
||||
#![allow(clippy::single_match_else)]
|
||||
#![allow(clippy::single_match)]
|
||||
#![allow(clippy::unnested_or_patterns)]
|
||||
#![allow(deprecated)]
|
||||
#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(test, macro_use)]
|
||||
extern crate alloc;
|
||||
#[cfg(doctest)]
|
||||
extern crate doc_comment;
|
||||
|
||||
#[cfg(doctest)]
|
||||
doc_comment::doctest!("../README.md");
|
||||
|
||||
/// 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 {
|
||||
/// `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 mod std {
|
||||
#[doc(hidden)]
|
||||
#[cfg(not(feature = "alloc"))]
|
||||
pub use core::borrow;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[doc(hidden)]
|
||||
pub use alloc::{borrow, boxed, collections, string, vec};
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use core::{cmp, convert, fmt, hash, iter, mem, ops, option, result, slice, str};
|
||||
|
||||
/// internal reproduction of std prelude
|
||||
#[doc(hidden)]
|
||||
pub mod prelude {
|
||||
pub use core::prelude as v1;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
/// internal std exports for `no_std` compatibility
|
||||
pub mod std {
|
||||
#![allow(clippy::std_instead_of_core)]
|
||||
#[doc(hidden)]
|
||||
pub use std::{
|
||||
alloc, borrow, boxed, cmp, collections, convert, fmt, hash, iter, mem, ops, option,
|
||||
result, slice, str, string, vec,
|
||||
};
|
||||
|
||||
/// internal reproduction of std prelude
|
||||
#[doc(hidden)]
|
||||
pub mod prelude {
|
||||
pub use std::prelude as v1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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;
|
||||
pub mod trace;
|
||||
|
||||
#[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) -> PResult<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::stream::StreamIsPartial as _;
|
||||
pub use crate::IResult;
|
||||
pub use crate::PResult;
|
||||
pub use crate::Parser;
|
||||
#[cfg(feature = "unstable-recover")]
|
||||
pub use crate::RecoverableParser as _;
|
||||
}
|
||||
|
||||
pub use error::IResult;
|
||||
pub use error::PResult;
|
||||
pub use parser::*;
|
||||
pub use stream::BStr;
|
||||
pub use stream::Bytes;
|
||||
pub use stream::Located;
|
||||
pub use stream::Partial;
|
||||
pub use stream::Stateful;
|
||||
pub use stream::Str;
|
||||
55
third-party/vendor/winnow/src/macros/dispatch.rs
vendored
Normal file
55
third-party/vendor/winnow/src/macros/dispatch.rs
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/// `match` for parsers
|
||||
///
|
||||
/// 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`][crate::combinator::peek].
|
||||
///
|
||||
/// 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::any;
|
||||
/// # use winnow::combinator::peek;
|
||||
/// # use winnow::combinator::preceded;
|
||||
/// # use winnow::combinator::empty;
|
||||
/// # use winnow::combinator::fail;
|
||||
///
|
||||
/// fn escaped(input: &mut &str) -> PResult<char> {
|
||||
/// preceded('\\', escape_seq_char).parse_next(input)
|
||||
/// }
|
||||
///
|
||||
/// fn escape_seq_char(input: &mut &str) -> PResult<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 {
|
||||
($match_parser: expr; $( $pat:pat $(if $pred:expr)? => $expr: expr ),+ $(,)? ) => {
|
||||
$crate::combinator::trace("dispatch", move |i: &mut _|
|
||||
{
|
||||
use $crate::Parser;
|
||||
let initial = $match_parser.parse_next(i)?;
|
||||
match initial {
|
||||
$(
|
||||
$pat $(if $pred)? => $expr.parse_next(i),
|
||||
)*
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
5
third-party/vendor/winnow/src/macros/mod.rs
vendored
Normal file
5
third-party/vendor/winnow/src/macros/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
mod dispatch;
|
||||
mod seq;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
268
third-party/vendor/winnow/src/macros/seq.rs
vendored
Normal file
268
third-party/vendor/winnow/src/macros/seq.rs
vendored
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
/// Initialize a struct or tuple out of a sequences of parsers
|
||||
///
|
||||
///# 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::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]) -> PResult<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]) -> PResult<(u32, u32)> {
|
||||
/// let num = dec_uint::<_, u32, 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")]
|
||||
macro_rules! seq {
|
||||
($name: ident { $($fields: tt)* }) => {
|
||||
$crate::combinator::trace(stringify!($name), move |input: &mut _| {
|
||||
use $crate::Parser;
|
||||
$crate::seq_parse_struct_fields!(input; $($fields)*);
|
||||
#[allow(clippy::redundant_field_names)]
|
||||
Ok($crate::seq_init_struct_fields!( ($($fields)*); $name;))
|
||||
})
|
||||
};
|
||||
($name: ident ( $($elements: tt)* )) => {
|
||||
$crate::combinator::trace(stringify!($name), move |input: &mut _| {
|
||||
use $crate::Parser;
|
||||
$crate::seq_parse_tuple_fields!( ($($elements)*) ; ).map(|t| {
|
||||
$crate::seq_init_tuple_fields!(
|
||||
($($elements)*);
|
||||
(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17, t.18, t.19, t.20);
|
||||
$name;
|
||||
)
|
||||
}).parse_next(input)
|
||||
})
|
||||
};
|
||||
(( $($elements: tt)* )) => {
|
||||
$crate::combinator::trace("tuple", move |input: &mut _| {
|
||||
use $crate::Parser;
|
||||
$crate::seq_parse_tuple_fields!( ($($elements)*) ; ).map(|t| {
|
||||
$crate::seq_init_tuple_fields!(
|
||||
($($elements)*);
|
||||
(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17, t.18, t.19, t.20);
|
||||
;
|
||||
)
|
||||
}).parse_next(input)
|
||||
})
|
||||
};
|
||||
($($elements: tt)*) => {
|
||||
$crate::seq!(($($elements)*))
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! seq_parse_struct_fields {
|
||||
(
|
||||
$input: ident;
|
||||
_ : $head_parser: expr, $($fields: tt)*
|
||||
) => {
|
||||
let _ = $head_parser.parse_next($input)?;
|
||||
$crate::seq_parse_struct_fields!($input; $($fields)*)
|
||||
};
|
||||
(
|
||||
$input: ident;
|
||||
_ : $head_parser: expr
|
||||
) => {
|
||||
let _ = $head_parser.parse_next($input)?;
|
||||
};
|
||||
(
|
||||
$input: ident;
|
||||
$head_field: ident : $head_parser: expr, $($fields: tt)*
|
||||
) => {
|
||||
let $head_field = $head_parser.parse_next($input)?;
|
||||
$crate::seq_parse_struct_fields!($input; $($fields)*)
|
||||
};
|
||||
(
|
||||
$input: ident;
|
||||
$head_field: ident : $head_parser: expr
|
||||
) => {
|
||||
let $head_field = $head_parser.parse_next($input)?;
|
||||
};
|
||||
(
|
||||
$input: expr;
|
||||
.. $update: expr
|
||||
) => {};
|
||||
(
|
||||
$input: expr;
|
||||
$(,)?
|
||||
) => {};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! seq_parse_tuple_fields {
|
||||
(
|
||||
(_ : $head_parser: expr, $($fields: tt)* );
|
||||
$($sequenced: tt)*
|
||||
) => {
|
||||
$crate::seq_parse_tuple_fields!( ( $($fields)* ) ; $($sequenced)* $head_parser.void(), )
|
||||
};
|
||||
(
|
||||
(_ : $head_parser: expr);
|
||||
$($sequenced: tt)*
|
||||
) => {
|
||||
$crate::seq_parse_tuple_fields!((); $($sequenced)* $head_parser.void(), )
|
||||
};
|
||||
(
|
||||
($head_parser: expr, $($fields: tt)*);
|
||||
$($sequenced: tt)*
|
||||
) => {
|
||||
$crate::seq_parse_tuple_fields!( ( $($fields)* ) ; $($sequenced)* $head_parser, )
|
||||
};
|
||||
(
|
||||
($head_parser: expr);
|
||||
$($sequenced: tt)*
|
||||
)=> {
|
||||
$crate::seq_parse_tuple_fields!((); $($sequenced)* $head_parser, )
|
||||
};
|
||||
(
|
||||
();
|
||||
$($sequenced: tt)*
|
||||
) => {
|
||||
($($sequenced)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[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, )
|
||||
};
|
||||
(
|
||||
($head_field: ident : $head_parser: expr);
|
||||
$name: ident;
|
||||
$($inits: tt)*
|
||||
) => {
|
||||
$crate::seq_init_struct_fields!( (); $name ; $($inits)* $head_field: $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)*);
|
||||
($head_arg: expr, $($args: expr),*);
|
||||
$($name: ident)?;
|
||||
$($inits: tt)*
|
||||
) => {
|
||||
$crate::seq_init_tuple_fields!( ( $($fields)* ); ( $($args),* ) ; $($name)? ; $($inits)* )
|
||||
};
|
||||
(
|
||||
(_ : $head_parser: expr);
|
||||
($head_arg: expr, $($args: expr),*);
|
||||
$($name: ident)?;
|
||||
$($inits: tt)*
|
||||
) => {
|
||||
$crate::seq_init_tuple_fields!((); ( $($args),* ); $($name)? ; $($inits)*)
|
||||
};
|
||||
(
|
||||
($head_parser: expr, $($fields: tt)*);
|
||||
($head_arg: expr, $($args: expr),*);
|
||||
$($name: ident)?;
|
||||
$($inits: tt)*
|
||||
) => {
|
||||
$crate::seq_init_tuple_fields!( ( $($fields)* ) ; ( $($args),* ) ; $($name)? ; $($inits)* $head_arg, )
|
||||
};
|
||||
(
|
||||
($head_parser: expr);
|
||||
($head_arg: expr, $($args: expr),*);
|
||||
$($name: ident)?;
|
||||
$($inits: tt)*
|
||||
) => {
|
||||
$crate::seq_init_tuple_fields!((); ( $($args),* ); $($name)? ; $($inits)* $head_arg)
|
||||
};
|
||||
(
|
||||
();
|
||||
($($args: expr),*);
|
||||
$($name: ident)?;
|
||||
$($inits: expr),* $(,)?
|
||||
) => {
|
||||
$($name)?( $($inits,)* )
|
||||
};
|
||||
}
|
||||
378
third-party/vendor/winnow/src/macros/test.rs
vendored
Normal file
378
third-party/vendor/winnow/src/macros/test.rs
vendored
Normal file
|
|
@ -0,0 +1,378 @@
|
|||
use crate::ascii::dec_uint;
|
||||
use crate::combinator::dispatch;
|
||||
use crate::combinator::empty;
|
||||
use crate::combinator::fail;
|
||||
use crate::combinator::seq;
|
||||
use crate::error::ErrMode;
|
||||
use crate::error::ErrorKind;
|
||||
use crate::error::ParserError;
|
||||
use crate::prelude::*;
|
||||
use crate::token::any;
|
||||
|
||||
#[test]
|
||||
fn dispatch_basics() {
|
||||
fn escape_seq_char(input: &mut &str) -> PResult<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!(escape_seq_char.parse_peek("b123"), Ok(("123", '\u{8}')));
|
||||
assert_eq!(
|
||||
escape_seq_char.parse_peek("error"),
|
||||
Err(ErrMode::Backtrack(ParserError::from_error_kind(
|
||||
&"rror",
|
||||
ErrorKind::Fail
|
||||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
escape_seq_char.parse_peek(""),
|
||||
Err(ErrMode::Backtrack(ParserError::from_error_kind(
|
||||
&"",
|
||||
ErrorKind::Fail
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seq_struct_basics() {
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct Point {
|
||||
x: u32,
|
||||
y: u32,
|
||||
}
|
||||
|
||||
fn parser(input: &mut &str) -> PResult<Point> {
|
||||
seq! {
|
||||
Point {
|
||||
x: dec_uint,
|
||||
_: ',',
|
||||
y: dec_uint,
|
||||
}
|
||||
}
|
||||
.parse_next(input)
|
||||
}
|
||||
assert_eq!(
|
||||
parser.parse_peek("123,4 remaining"),
|
||||
Ok((" remaining", Point { x: 123, y: 4 },)),
|
||||
);
|
||||
assert_eq!(
|
||||
parser.parse_peek("123, remaining"),
|
||||
Err(ErrMode::Backtrack(ParserError::from_error_kind(
|
||||
&" remaining",
|
||||
ErrorKind::Fail
|
||||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
parser.parse_peek(""),
|
||||
Err(ErrMode::Backtrack(ParserError::from_error_kind(
|
||||
&"",
|
||||
ErrorKind::Fail
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seq_struct_default_init() {
|
||||
#[derive(Debug, PartialEq, Default)]
|
||||
struct Point {
|
||||
x: u32,
|
||||
y: u32,
|
||||
z: u32,
|
||||
}
|
||||
|
||||
fn parser(input: &mut &str) -> PResult<Point> {
|
||||
seq! {
|
||||
Point {
|
||||
x: dec_uint,
|
||||
_: ',',
|
||||
y: dec_uint,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
.parse_next(input)
|
||||
}
|
||||
assert_eq!(
|
||||
parser.parse_peek("123,4 remaining"),
|
||||
Ok((" remaining", Point { x: 123, y: 4, z: 0 },)),
|
||||
);
|
||||
assert_eq!(
|
||||
parser.parse_peek("123, remaining"),
|
||||
Err(ErrMode::Backtrack(ParserError::from_error_kind(
|
||||
&" remaining",
|
||||
ErrorKind::Fail
|
||||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
parser.parse_peek(""),
|
||||
Err(ErrMode::Backtrack(ParserError::from_error_kind(
|
||||
&"",
|
||||
ErrorKind::Fail
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seq_struct_trailing_comma_elided() {
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct Point {
|
||||
x: u32,
|
||||
y: u32,
|
||||
}
|
||||
|
||||
fn parser(input: &mut &str) -> PResult<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(input: &mut &str) -> PResult<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(input: &mut &str) -> PResult<Point> {
|
||||
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(input: &mut &str) -> PResult<Point> {
|
||||
seq! {
|
||||
Point(
|
||||
dec_uint,
|
||||
_: ',',
|
||||
dec_uint,
|
||||
)
|
||||
}
|
||||
.parse_next(input)
|
||||
}
|
||||
assert_eq!(
|
||||
parser.parse_peek("123,4 remaining"),
|
||||
Ok((" remaining", Point(123, 4),)),
|
||||
);
|
||||
assert_eq!(
|
||||
parser.parse_peek("123, remaining"),
|
||||
Err(ErrMode::Backtrack(ParserError::from_error_kind(
|
||||
&" remaining",
|
||||
ErrorKind::Fail
|
||||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
parser.parse_peek(""),
|
||||
Err(ErrMode::Backtrack(ParserError::from_error_kind(
|
||||
&"",
|
||||
ErrorKind::Fail
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seq_tuple_struct_trailing_comma_elided() {
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct Point(u32, u32);
|
||||
|
||||
fn parser(input: &mut &str) -> PResult<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(input: &mut &str) -> PResult<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(input: &mut &str) -> PResult<Point> {
|
||||
seq! {
|
||||
Point(
|
||||
dec_uint,
|
||||
_: ',',
|
||||
dec_uint,
|
||||
_: empty
|
||||
)
|
||||
}
|
||||
.parse_next(input)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seq_tuple_basics() {
|
||||
fn parser(input: &mut &str) -> PResult<(u32, u32)> {
|
||||
seq! {
|
||||
(
|
||||
dec_uint,
|
||||
_: ',',
|
||||
dec_uint,
|
||||
)
|
||||
}
|
||||
.parse_next(input)
|
||||
}
|
||||
assert_eq!(
|
||||
parser.parse_peek("123,4 remaining"),
|
||||
Ok((" remaining", (123, 4),)),
|
||||
);
|
||||
assert_eq!(
|
||||
parser.parse_peek("123, remaining"),
|
||||
Err(ErrMode::Backtrack(ParserError::from_error_kind(
|
||||
&" remaining",
|
||||
ErrorKind::Fail
|
||||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
parser.parse_peek(""),
|
||||
Err(ErrMode::Backtrack(ParserError::from_error_kind(
|
||||
&"",
|
||||
ErrorKind::Fail
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seq_tuple_trailing_comma_elided() {
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn parser(input: &mut &str) -> PResult<(u32, u32)> {
|
||||
seq! {
|
||||
(
|
||||
dec_uint,
|
||||
_: ',',
|
||||
dec_uint,
|
||||
_: empty,
|
||||
)
|
||||
}
|
||||
.parse_next(input)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seq_tuple_no_trailing_comma() {
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn parser(input: &mut &str) -> PResult<(u32, u32)> {
|
||||
seq! {
|
||||
(
|
||||
dec_uint,
|
||||
_: ',',
|
||||
dec_uint
|
||||
)
|
||||
}
|
||||
.parse_next(input)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seq_tuple_no_trailing_comma_elided() {
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn parser(input: &mut &str) -> PResult<(u32, u32)> {
|
||||
seq! {
|
||||
(
|
||||
dec_uint,
|
||||
_: ',',
|
||||
dec_uint,
|
||||
_: empty
|
||||
)
|
||||
}
|
||||
.parse_next(input)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seq_tuple_no_parens() {
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn parser(input: &mut &str) -> PResult<(u32, u32)> {
|
||||
seq! (
|
||||
dec_uint,
|
||||
_: ',',
|
||||
dec_uint,
|
||||
)
|
||||
.parse_next(input)
|
||||
}
|
||||
}
|
||||
1205
third-party/vendor/winnow/src/parser.rs
vendored
Normal file
1205
third-party/vendor/winnow/src/parser.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
537
third-party/vendor/winnow/src/stream/impls.rs
vendored
Normal file
537
third-party/vendor/winnow/src/stream/impls.rs
vendored
Normal file
|
|
@ -0,0 +1,537 @@
|
|||
macro_rules! impl_partial_eq {
|
||||
($lhs:ty, $rhs:ty) => {
|
||||
impl<'a, 'b> PartialEq<$rhs> for $lhs {
|
||||
#[inline]
|
||||
fn eq(&self, other: &$rhs) -> bool {
|
||||
let l = self.as_ref();
|
||||
let r: &Self = other.as_ref();
|
||||
PartialEq::eq(l, r)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> PartialEq<$lhs> for $rhs {
|
||||
#[inline]
|
||||
fn eq(&self, other: &$lhs) -> bool {
|
||||
PartialEq::eq(other, self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_partial_ord {
|
||||
($lhs:ty, $rhs:ty) => {
|
||||
impl<'a, 'b> PartialOrd<$rhs> for $lhs {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
|
||||
let l = self.as_ref();
|
||||
let r: &Self = other.as_ref();
|
||||
PartialOrd::partial_cmp(l, r)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> PartialOrd<$lhs> for $rhs {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
|
||||
PartialOrd::partial_cmp(other, self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mod bytes {
|
||||
use crate::lib::std::{cmp::Ordering, fmt, ops};
|
||||
|
||||
use crate::stream::Bytes;
|
||||
|
||||
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, "{:0>2x}", byte)?;
|
||||
}
|
||||
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, "{:0>2X}", byte)?;
|
||||
}
|
||||
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(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;
|
||||
|
||||
#[test]
|
||||
fn test_debug() {
|
||||
assert_eq!(
|
||||
"000000206674797069736F6D0000020069736F6D69736F32617663316D70",
|
||||
format!(
|
||||
"{:?}",
|
||||
Bytes::new(b"\0\0\0 ftypisom\0\0\x02\0isomiso2avc1mp")
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pretty_debug() {
|
||||
// Output can change from run-to-run
|
||||
format!(
|
||||
"{:#?}",
|
||||
Bytes::new(b"\0\0\0 ftypisom\0\0\x02\0isomiso2avc1mp")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sliced() {
|
||||
// Output can change from run-to-run
|
||||
let total = Bytes::new(b"12345678901234567890");
|
||||
format!("{:#?}", total);
|
||||
format!("{:#?}", &total[1..]);
|
||||
format!("{:#?}", &total[10..]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod bstr {
|
||||
use crate::lib::std::{cmp::Ordering, fmt, ops};
|
||||
|
||||
use crate::stream::BStr;
|
||||
|
||||
#[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(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;
|
||||
|
||||
#[test]
|
||||
fn test_debug() {
|
||||
assert_eq!(&format!("{:?}", BStr::new(b"abc")), "\"abc\"");
|
||||
|
||||
assert_eq!(
|
||||
"\"\\0\\0\\0 ftypisom\\0\\0\\u{2}\\0isomiso2avc1mp\"",
|
||||
format!(
|
||||
"{:?}",
|
||||
BStr::new(b"\0\0\0 ftypisom\0\0\x02\0isomiso2avc1mp")
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pretty_debug() {
|
||||
assert_eq!(&format!("{:#?}", BStr::new(b"abc")), "abc");
|
||||
}
|
||||
}
|
||||
}
|
||||
3775
third-party/vendor/winnow/src/stream/mod.rs
vendored
Normal file
3775
third-party/vendor/winnow/src/stream/mod.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
228
third-party/vendor/winnow/src/stream/tests.rs
vendored
Normal file
228
third-party/vendor/winnow/src/stream/tests.rs
vendored
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
#[cfg(feature = "std")]
|
||||
use proptest::prelude::*;
|
||||
|
||||
use crate::error::ErrMode::Backtrack;
|
||||
use crate::error::{ErrorKind, InputError};
|
||||
use crate::token::tag;
|
||||
use crate::{
|
||||
combinator::{separated, separated_pair},
|
||||
PResult, Parser,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn test_fxhashmap_compiles() {
|
||||
let input = "a=b";
|
||||
fn pair(i: &mut &str) -> PResult<(char, char)> {
|
||||
let out = separated_pair('a', '=', 'b').parse_next(i)?;
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
let _: rustc_hash::FxHashMap<char, char> = separated(0.., pair, ',').parse(input).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_offset_u8() {
|
||||
let s = b"abcd123";
|
||||
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_input, actual_slice) = i.peek_slice(0);
|
||||
assert_eq!(actual_input, (&b""[..], 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((next_i, _token)) = curr_i.peek_token() {
|
||||
let to_offset = curr_i.offset_from(&i);
|
||||
assert_eq!(curr_offset, to_offset);
|
||||
|
||||
let (slice_i, _) = i.peek_slice(curr_offset);
|
||||
assert_eq!(curr_i, slice_i);
|
||||
|
||||
let at_offset = i.offset_at(curr_offset).unwrap();
|
||||
assert_eq!(curr_offset, at_offset);
|
||||
|
||||
let eof_offset = curr_i.eof_offset();
|
||||
let (next_eof_i, eof_slice) = curr_i.peek_slice(eof_offset);
|
||||
assert_eq!(next_eof_i, (&b""[..], 0));
|
||||
let eof_slice_i = (eof_slice.0, eof_slice.1);
|
||||
assert_eq!(eof_slice_i, curr_i);
|
||||
|
||||
curr_offset += 1;
|
||||
curr_i = next_i;
|
||||
}
|
||||
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_tag_support_char() {
|
||||
assert_eq!(
|
||||
tag::<_, _, InputError<_>>('π').parse_peek("π"),
|
||||
Ok(("", "π"))
|
||||
);
|
||||
assert_eq!(
|
||||
tag::<_, _, InputError<_>>('π').parse_peek("π3.14"),
|
||||
Ok(("3.14", "π"))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
tag::<_, _, InputError<_>>("π").parse_peek("π3.14"),
|
||||
Ok(("3.14", "π"))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
tag::<_, _, InputError<_>>('-').parse_peek("π"),
|
||||
Err(Backtrack(InputError::new("π", ErrorKind::Tag)))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
tag::<_, Partial<&[u8]>, InputError<_>>('π').parse_peek(Partial::new(b"\xCF\x80")),
|
||||
Ok((Partial::new(Default::default()), "π".as_bytes()))
|
||||
);
|
||||
assert_eq!(
|
||||
tag::<_, &[u8], InputError<_>>('π').parse_peek(b"\xCF\x80"),
|
||||
Ok((Default::default(), "π".as_bytes()))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
tag::<_, Partial<&[u8]>, InputError<_>>('π').parse_peek(Partial::new(b"\xCF\x803.14")),
|
||||
Ok((Partial::new(&b"3.14"[..]), "π".as_bytes()))
|
||||
);
|
||||
assert_eq!(
|
||||
tag::<_, &[u8], InputError<_>>('π').parse_peek(b"\xCF\x80"),
|
||||
Ok((Default::default(), "π".as_bytes()))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
tag::<_, &[u8], InputError<_>>('π').parse_peek(b"\xCF\x803.14"),
|
||||
Ok((&b"3.14"[..], "π".as_bytes()))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
tag::<_, &[u8], InputError<_>>(AsciiCaseless('a')).parse_peek(b"ABCxyz"),
|
||||
Ok((&b"BCxyz"[..], &b"A"[..]))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
tag::<_, &[u8], InputError<_>>('a').parse_peek(b"ABCxyz"),
|
||||
Err(Backtrack(InputError::new(&b"ABCxyz"[..], ErrorKind::Tag)))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
tag::<_, &[u8], InputError<_>>(AsciiCaseless('π')).parse_peek(b"\xCF\x803.14"),
|
||||
Ok((&b"3.14"[..], "π".as_bytes()))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
tag::<_, _, InputError<_>>(AsciiCaseless('🧑')).parse_peek("🧑你好"),
|
||||
Ok(("你好", "🧑"))
|
||||
);
|
||||
|
||||
let mut buffer = [0; 4];
|
||||
let input = '\u{241b}'.encode_utf8(&mut buffer);
|
||||
assert_eq!(
|
||||
tag::<_, &[u8], InputError<_>>(AsciiCaseless('␛')).parse_peek(input.as_bytes()),
|
||||
Ok((&b""[..], [226, 144, 155].as_slice()))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
tag::<_, &[u8], InputError<_>>('-').parse_peek(b"\xCF\x80"),
|
||||
Err(Backtrack(InputError::new(&b"\xCF\x80"[..], ErrorKind::Tag)))
|
||||
);
|
||||
}
|
||||
1243
third-party/vendor/winnow/src/token/mod.rs
vendored
Normal file
1243
third-party/vendor/winnow/src/token/mod.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
807
third-party/vendor/winnow/src/token/tests.rs
vendored
Normal file
807
third-party/vendor/winnow/src/token/tests.rs
vendored
Normal file
|
|
@ -0,0 +1,807 @@
|
|||
use super::*;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use proptest::prelude::*;
|
||||
|
||||
use crate::ascii::Caseless;
|
||||
use crate::combinator::delimited;
|
||||
use crate::error::ErrMode;
|
||||
use crate::error::ErrorKind;
|
||||
use crate::error::InputError;
|
||||
use crate::error::Needed;
|
||||
use crate::stream::AsChar;
|
||||
use crate::token::tag;
|
||||
use crate::unpeek;
|
||||
use crate::IResult;
|
||||
use crate::Parser;
|
||||
use crate::Partial;
|
||||
|
||||
#[test]
|
||||
fn complete_take_while_m_n_utf8_all_matching() {
|
||||
let result: IResult<&str, &str> =
|
||||
take_while(1..=4, |c: char| c.is_alphabetic()).parse_peek("øn");
|
||||
assert_eq!(result, Ok(("", "øn")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complete_take_while_m_n_utf8_all_matching_substring() {
|
||||
let result: IResult<&str, &str> = take_while(1, |c: char| c.is_alphabetic()).parse_peek("øn");
|
||||
assert_eq!(result, Ok(("n", "ø")));
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
fn model_complete_take_while_m_n(
|
||||
m: usize,
|
||||
n: usize,
|
||||
valid: usize,
|
||||
input: &str,
|
||||
) -> IResult<&str, &str> {
|
||||
if n < m {
|
||||
Err(crate::error::ErrMode::from_error_kind(
|
||||
&input,
|
||||
crate::error::ErrorKind::Slice,
|
||||
))
|
||||
} else if m <= valid {
|
||||
let offset = n.min(valid);
|
||||
Ok((&input[offset..], &input[0..offset]))
|
||||
} else {
|
||||
Err(crate::error::ErrMode::from_error_kind(
|
||||
&input,
|
||||
crate::error::ErrorKind::Slice,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
proptest! {
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253
|
||||
fn complete_take_while_m_n_bounds(m in 0..20usize, n in 0..20usize, valid in 0..20usize, invalid in 0..20usize) {
|
||||
let input = format!("{:a<valid$}{:b<invalid$}", "", "", valid=valid, invalid=invalid);
|
||||
let expected = model_complete_take_while_m_n(m, n, valid, &input);
|
||||
if m <= n {
|
||||
let actual = take_while(m..=n, |c: char| c == 'a').parse_peek(input.as_str());
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complete_take_until() {
|
||||
fn take_until_5_10(i: &str) -> IResult<&str, &str> {
|
||||
take_until(5..=8, "end").parse_peek(i)
|
||||
}
|
||||
assert_eq!(
|
||||
take_until_5_10("end"),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&"end",
|
||||
ErrorKind::Slice
|
||||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
take_until_5_10("1234end"),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&"1234end",
|
||||
ErrorKind::Slice
|
||||
)))
|
||||
);
|
||||
assert_eq!(take_until_5_10("12345end"), Ok(("end", "12345")));
|
||||
assert_eq!(take_until_5_10("123456end"), Ok(("end", "123456")));
|
||||
assert_eq!(take_until_5_10("12345678end"), Ok(("end", "12345678")));
|
||||
assert_eq!(
|
||||
take_until_5_10("123456789end"),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&"123456789end",
|
||||
ErrorKind::Slice
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complete_tag_case_insensitive() {
|
||||
fn caseless_bytes(i: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||
tag(Caseless("ABcd")).parse_peek(i)
|
||||
}
|
||||
assert_eq!(
|
||||
caseless_bytes(&b"aBCdefgh"[..]),
|
||||
Ok((&b"efgh"[..], &b"aBCd"[..]))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_bytes(&b"abcdefgh"[..]),
|
||||
Ok((&b"efgh"[..], &b"abcd"[..]))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_bytes(&b"ABCDefgh"[..]),
|
||||
Ok((&b"efgh"[..], &b"ABCD"[..]))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_bytes(&b"ab"[..]),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&&b"ab"[..],
|
||||
ErrorKind::Tag
|
||||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_bytes(&b"Hello"[..]),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&&b"Hello"[..],
|
||||
ErrorKind::Tag
|
||||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_bytes(&b"Hel"[..]),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&&b"Hel"[..],
|
||||
ErrorKind::Tag
|
||||
)))
|
||||
);
|
||||
|
||||
fn caseless_str(i: &str) -> IResult<&str, &str> {
|
||||
tag(Caseless("ABcd")).parse_peek(i)
|
||||
}
|
||||
assert_eq!(caseless_str("aBCdefgh"), Ok(("efgh", "aBCd")));
|
||||
assert_eq!(caseless_str("abcdefgh"), Ok(("efgh", "abcd")));
|
||||
assert_eq!(caseless_str("ABCDefgh"), Ok(("efgh", "ABCD")));
|
||||
assert_eq!(
|
||||
caseless_str("ab"),
|
||||
Err(ErrMode::Backtrack(error_position!(&"ab", ErrorKind::Tag)))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_str("Hello"),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&"Hello",
|
||||
ErrorKind::Tag
|
||||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_str("Hel"),
|
||||
Err(ErrMode::Backtrack(error_position!(&"Hel", ErrorKind::Tag)))
|
||||
);
|
||||
|
||||
fn matches_kelvin(i: &str) -> IResult<&str, &str> {
|
||||
tag(Caseless("k")).parse_peek(i)
|
||||
}
|
||||
assert_eq!(
|
||||
matches_kelvin("K"),
|
||||
Err(ErrMode::Backtrack(error_position!(&"K", ErrorKind::Tag)))
|
||||
);
|
||||
|
||||
fn is_kelvin(i: &str) -> IResult<&str, &str> {
|
||||
tag(Caseless("K")).parse_peek(i)
|
||||
}
|
||||
assert_eq!(
|
||||
is_kelvin("k"),
|
||||
Err(ErrMode::Backtrack(error_position!(&"k", ErrorKind::Tag)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complete_tag_fixed_size_array() {
|
||||
fn test(i: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||
tag([0x42]).parse_peek(i)
|
||||
}
|
||||
fn test2(i: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||
tag(&[0x42]).parse_peek(i)
|
||||
}
|
||||
|
||||
let input = &[0x42, 0x00][..];
|
||||
assert_eq!(test(input), Ok((&b"\x00"[..], &b"\x42"[..])));
|
||||
assert_eq!(test2(input), Ok((&b"\x00"[..], &b"\x42"[..])));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complete_tag_char() {
|
||||
fn test(i: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||
tag('B').parse_peek(i)
|
||||
}
|
||||
assert_eq!(test(&[0x42, 0x00][..]), Ok((&b"\x00"[..], &b"\x42"[..])));
|
||||
assert_eq!(
|
||||
test(&[b'A', b'\0'][..]),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&&b"A\0"[..],
|
||||
ErrorKind::Tag
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complete_tag_byte() {
|
||||
fn test(i: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||
tag(b'B').parse_peek(i)
|
||||
}
|
||||
assert_eq!(test(&[0x42, 0x00][..]), Ok((&b"\x00"[..], &b"\x42"[..])));
|
||||
assert_eq!(
|
||||
test(&[b'A', b'\0'][..]),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&&b"A\0"[..],
|
||||
ErrorKind::Tag
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_any_str() {
|
||||
use super::any;
|
||||
assert_eq!(
|
||||
any::<_, InputError<Partial<&str>>>.parse_peek(Partial::new("Ә")),
|
||||
Ok((Partial::new(""), 'Ә'))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_one_of_test() {
|
||||
fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, u8> {
|
||||
one_of(['a', 'b']).parse_peek(i)
|
||||
}
|
||||
|
||||
let a = &b"abcd"[..];
|
||||
assert_eq!(f(Partial::new(a)), Ok((Partial::new(&b"bcd"[..]), b'a')));
|
||||
|
||||
let b = &b"cde"[..];
|
||||
assert_eq!(
|
||||
f(Partial::new(b)),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&Partial::new(b),
|
||||
ErrorKind::Verify
|
||||
)))
|
||||
);
|
||||
|
||||
fn utf8(i: Partial<&str>) -> IResult<Partial<&str>, char> {
|
||||
one_of(['+', '\u{FF0B}']).parse_peek(i)
|
||||
}
|
||||
|
||||
assert!(utf8(Partial::new("+")).is_ok());
|
||||
assert!(utf8(Partial::new("\u{FF0B}")).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char_byteslice() {
|
||||
fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, u8> {
|
||||
'c'.parse_peek(i)
|
||||
}
|
||||
|
||||
let a = &b"abcd"[..];
|
||||
assert_eq!(
|
||||
f(Partial::new(a)),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&Partial::new(a),
|
||||
ErrorKind::Verify
|
||||
)))
|
||||
);
|
||||
|
||||
let b = &b"cde"[..];
|
||||
assert_eq!(f(Partial::new(b)), Ok((Partial::new(&b"de"[..]), b'c')));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char_str() {
|
||||
fn f(i: Partial<&str>) -> IResult<Partial<&str>, char> {
|
||||
'c'.parse_peek(i)
|
||||
}
|
||||
|
||||
let a = "abcd";
|
||||
assert_eq!(
|
||||
f(Partial::new(a)),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&Partial::new(a),
|
||||
ErrorKind::Verify
|
||||
)))
|
||||
);
|
||||
|
||||
let b = "cde";
|
||||
assert_eq!(f(Partial::new(b)), Ok((Partial::new("de"), 'c')));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_none_of_test() {
|
||||
fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, u8> {
|
||||
none_of(['a', 'b']).parse_peek(i)
|
||||
}
|
||||
|
||||
let a = &b"abcd"[..];
|
||||
assert_eq!(
|
||||
f(Partial::new(a)),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&Partial::new(a),
|
||||
ErrorKind::Verify
|
||||
)))
|
||||
);
|
||||
|
||||
let b = &b"cde"[..];
|
||||
assert_eq!(f(Partial::new(b)), Ok((Partial::new(&b"de"[..]), b'c')));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_is_a() {
|
||||
fn a_or_b(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
take_while(1.., ['a', 'b']).parse_peek(i)
|
||||
}
|
||||
|
||||
let a = Partial::new(&b"abcd"[..]);
|
||||
assert_eq!(a_or_b(a), Ok((Partial::new(&b"cd"[..]), &b"ab"[..])));
|
||||
|
||||
let b = Partial::new(&b"bcde"[..]);
|
||||
assert_eq!(a_or_b(b), Ok((Partial::new(&b"cde"[..]), &b"b"[..])));
|
||||
|
||||
let c = Partial::new(&b"cdef"[..]);
|
||||
assert_eq!(
|
||||
a_or_b(c),
|
||||
Err(ErrMode::Backtrack(error_position!(&c, ErrorKind::Slice)))
|
||||
);
|
||||
|
||||
let d = Partial::new(&b"bacdef"[..]);
|
||||
assert_eq!(a_or_b(d), Ok((Partial::new(&b"cdef"[..]), &b"ba"[..])));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_is_not() {
|
||||
fn a_or_b(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
take_till(1.., ['a', 'b']).parse_peek(i)
|
||||
}
|
||||
|
||||
let a = Partial::new(&b"cdab"[..]);
|
||||
assert_eq!(a_or_b(a), Ok((Partial::new(&b"ab"[..]), &b"cd"[..])));
|
||||
|
||||
let b = Partial::new(&b"cbde"[..]);
|
||||
assert_eq!(a_or_b(b), Ok((Partial::new(&b"bde"[..]), &b"c"[..])));
|
||||
|
||||
let c = Partial::new(&b"abab"[..]);
|
||||
assert_eq!(
|
||||
a_or_b(c),
|
||||
Err(ErrMode::Backtrack(error_position!(&c, ErrorKind::Slice)))
|
||||
);
|
||||
|
||||
let d = Partial::new(&b"cdefba"[..]);
|
||||
assert_eq!(a_or_b(d), Ok((Partial::new(&b"ba"[..]), &b"cdef"[..])));
|
||||
|
||||
let e = Partial::new(&b"e"[..]);
|
||||
assert_eq!(a_or_b(e), Err(ErrMode::Incomplete(Needed::new(1))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_take_until_incomplete() {
|
||||
fn y(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
take_until(0.., "end").parse_peek(i)
|
||||
}
|
||||
assert_eq!(
|
||||
y(Partial::new(&b"nd"[..])),
|
||||
Err(ErrMode::Incomplete(Needed::Unknown))
|
||||
);
|
||||
assert_eq!(
|
||||
y(Partial::new(&b"123"[..])),
|
||||
Err(ErrMode::Incomplete(Needed::Unknown))
|
||||
);
|
||||
assert_eq!(
|
||||
y(Partial::new(&b"123en"[..])),
|
||||
Err(ErrMode::Incomplete(Needed::Unknown))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_take_until_incomplete_s() {
|
||||
fn ys(i: Partial<&str>) -> IResult<Partial<&str>, &str> {
|
||||
take_until(0.., "end").parse_peek(i)
|
||||
}
|
||||
assert_eq!(
|
||||
ys(Partial::new("123en")),
|
||||
Err(ErrMode::Incomplete(Needed::Unknown))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_recognize() {
|
||||
use crate::ascii::{
|
||||
alpha1 as alpha, alphanumeric1 as alphanumeric, digit1 as digit, hex_digit1 as hex_digit,
|
||||
multispace1 as multispace, oct_digit1 as oct_digit, space1 as space,
|
||||
};
|
||||
|
||||
fn x(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
delimited("<!--", take(5_usize), "-->")
|
||||
.recognize()
|
||||
.parse_peek(i)
|
||||
}
|
||||
let r = x(Partial::new(&b"<!-- abc --> aaa"[..]));
|
||||
assert_eq!(r, Ok((Partial::new(&b" aaa"[..]), &b"<!-- abc -->"[..])));
|
||||
|
||||
let semicolon = &b";"[..];
|
||||
|
||||
fn ya(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
alpha.recognize().parse_peek(i)
|
||||
}
|
||||
let ra = ya(Partial::new(&b"abc;"[..]));
|
||||
assert_eq!(ra, Ok((Partial::new(semicolon), &b"abc"[..])));
|
||||
|
||||
fn yd(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
digit.recognize().parse_peek(i)
|
||||
}
|
||||
let rd = yd(Partial::new(&b"123;"[..]));
|
||||
assert_eq!(rd, Ok((Partial::new(semicolon), &b"123"[..])));
|
||||
|
||||
fn yhd(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
hex_digit.recognize().parse_peek(i)
|
||||
}
|
||||
let rhd = yhd(Partial::new(&b"123abcDEF;"[..]));
|
||||
assert_eq!(rhd, Ok((Partial::new(semicolon), &b"123abcDEF"[..])));
|
||||
|
||||
fn yod(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
oct_digit.recognize().parse_peek(i)
|
||||
}
|
||||
let rod = yod(Partial::new(&b"1234567;"[..]));
|
||||
assert_eq!(rod, Ok((Partial::new(semicolon), &b"1234567"[..])));
|
||||
|
||||
fn yan(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
alphanumeric.recognize().parse_peek(i)
|
||||
}
|
||||
let ran = yan(Partial::new(&b"123abc;"[..]));
|
||||
assert_eq!(ran, Ok((Partial::new(semicolon), &b"123abc"[..])));
|
||||
|
||||
fn ys(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
space.recognize().parse_peek(i)
|
||||
}
|
||||
let rs = ys(Partial::new(&b" \t;"[..]));
|
||||
assert_eq!(rs, Ok((Partial::new(semicolon), &b" \t"[..])));
|
||||
|
||||
fn yms(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
multispace.recognize().parse_peek(i)
|
||||
}
|
||||
let rms = yms(Partial::new(&b" \t\r\n;"[..]));
|
||||
assert_eq!(rms, Ok((Partial::new(semicolon), &b" \t\r\n"[..])));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_take_while0() {
|
||||
fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
take_while(0.., AsChar::is_alpha).parse_peek(i)
|
||||
}
|
||||
let a = &b""[..];
|
||||
let b = &b"abcd"[..];
|
||||
let c = &b"abcd123"[..];
|
||||
let d = &b"123"[..];
|
||||
|
||||
assert_eq!(f(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(1))));
|
||||
assert_eq!(f(Partial::new(b)), Err(ErrMode::Incomplete(Needed::new(1))));
|
||||
assert_eq!(f(Partial::new(c)), Ok((Partial::new(d), b)));
|
||||
assert_eq!(f(Partial::new(d)), Ok((Partial::new(d), a)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_take_while1() {
|
||||
fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
take_while(1.., AsChar::is_alpha).parse_peek(i)
|
||||
}
|
||||
let a = &b""[..];
|
||||
let b = &b"abcd"[..];
|
||||
let c = &b"abcd123"[..];
|
||||
let d = &b"123"[..];
|
||||
|
||||
assert_eq!(f(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(1))));
|
||||
assert_eq!(f(Partial::new(b)), Err(ErrMode::Incomplete(Needed::new(1))));
|
||||
assert_eq!(f(Partial::new(c)), Ok((Partial::new(&b"123"[..]), b)));
|
||||
assert_eq!(
|
||||
f(Partial::new(d)),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&Partial::new(d),
|
||||
ErrorKind::Slice
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_take_while_m_n() {
|
||||
fn x(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
take_while(2..=4, AsChar::is_alpha).parse_peek(i)
|
||||
}
|
||||
let a = &b""[..];
|
||||
let b = &b"a"[..];
|
||||
let c = &b"abc"[..];
|
||||
let d = &b"abc123"[..];
|
||||
let e = &b"abcde"[..];
|
||||
let f = &b"123"[..];
|
||||
|
||||
assert_eq!(x(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(2))));
|
||||
assert_eq!(x(Partial::new(b)), Err(ErrMode::Incomplete(Needed::new(1))));
|
||||
assert_eq!(x(Partial::new(c)), Err(ErrMode::Incomplete(Needed::new(1))));
|
||||
assert_eq!(x(Partial::new(d)), Ok((Partial::new(&b"123"[..]), c)));
|
||||
assert_eq!(
|
||||
x(Partial::new(e)),
|
||||
Ok((Partial::new(&b"e"[..]), &b"abcd"[..]))
|
||||
);
|
||||
assert_eq!(
|
||||
x(Partial::new(f)),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&Partial::new(f),
|
||||
ErrorKind::Slice
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_take_till0() {
|
||||
fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
take_till(0.., AsChar::is_alpha).parse_peek(i)
|
||||
}
|
||||
let a = &b""[..];
|
||||
let b = &b"abcd"[..];
|
||||
let c = &b"123abcd"[..];
|
||||
let d = &b"123"[..];
|
||||
|
||||
assert_eq!(f(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(1))));
|
||||
assert_eq!(
|
||||
f(Partial::new(b)),
|
||||
Ok((Partial::new(&b"abcd"[..]), &b""[..]))
|
||||
);
|
||||
assert_eq!(
|
||||
f(Partial::new(c)),
|
||||
Ok((Partial::new(&b"abcd"[..]), &b"123"[..]))
|
||||
);
|
||||
assert_eq!(f(Partial::new(d)), Err(ErrMode::Incomplete(Needed::new(1))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_take_till1() {
|
||||
fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
take_till(1.., AsChar::is_alpha).parse_peek(i)
|
||||
}
|
||||
let a = &b""[..];
|
||||
let b = &b"abcd"[..];
|
||||
let c = &b"123abcd"[..];
|
||||
let d = &b"123"[..];
|
||||
|
||||
assert_eq!(f(Partial::new(a)), Err(ErrMode::Incomplete(Needed::new(1))));
|
||||
assert_eq!(
|
||||
f(Partial::new(b)),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&Partial::new(b),
|
||||
ErrorKind::Slice
|
||||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
f(Partial::new(c)),
|
||||
Ok((Partial::new(&b"abcd"[..]), &b"123"[..]))
|
||||
);
|
||||
assert_eq!(f(Partial::new(d)), Err(ErrMode::Incomplete(Needed::new(1))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_take_while_utf8() {
|
||||
fn f(i: Partial<&str>) -> IResult<Partial<&str>, &str> {
|
||||
take_while(0.., |c| c != '點').parse_peek(i)
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
f(Partial::new("")),
|
||||
Err(ErrMode::Incomplete(Needed::new(1)))
|
||||
);
|
||||
assert_eq!(
|
||||
f(Partial::new("abcd")),
|
||||
Err(ErrMode::Incomplete(Needed::new(1)))
|
||||
);
|
||||
assert_eq!(f(Partial::new("abcd點")), Ok((Partial::new("點"), "abcd")));
|
||||
assert_eq!(
|
||||
f(Partial::new("abcd點a")),
|
||||
Ok((Partial::new("點a"), "abcd"))
|
||||
);
|
||||
|
||||
fn g(i: Partial<&str>) -> IResult<Partial<&str>, &str> {
|
||||
take_while(0.., |c| c == '點').parse_peek(i)
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
g(Partial::new("")),
|
||||
Err(ErrMode::Incomplete(Needed::new(1)))
|
||||
);
|
||||
assert_eq!(g(Partial::new("點abcd")), Ok((Partial::new("abcd"), "點")));
|
||||
assert_eq!(
|
||||
g(Partial::new("點點點a")),
|
||||
Ok((Partial::new("a"), "點點點"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_take_till0_utf8() {
|
||||
fn f(i: Partial<&str>) -> IResult<Partial<&str>, &str> {
|
||||
take_till(0.., |c| c == '點').parse_peek(i)
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
f(Partial::new("")),
|
||||
Err(ErrMode::Incomplete(Needed::new(1)))
|
||||
);
|
||||
assert_eq!(
|
||||
f(Partial::new("abcd")),
|
||||
Err(ErrMode::Incomplete(Needed::new(1)))
|
||||
);
|
||||
assert_eq!(f(Partial::new("abcd點")), Ok((Partial::new("點"), "abcd")));
|
||||
assert_eq!(
|
||||
f(Partial::new("abcd點a")),
|
||||
Ok((Partial::new("點a"), "abcd"))
|
||||
);
|
||||
|
||||
fn g(i: Partial<&str>) -> IResult<Partial<&str>, &str> {
|
||||
take_till(0.., |c| c != '點').parse_peek(i)
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
g(Partial::new("")),
|
||||
Err(ErrMode::Incomplete(Needed::new(1)))
|
||||
);
|
||||
assert_eq!(g(Partial::new("點abcd")), Ok((Partial::new("abcd"), "點")));
|
||||
assert_eq!(
|
||||
g(Partial::new("點點點a")),
|
||||
Ok((Partial::new("a"), "點點點"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_take_utf8() {
|
||||
fn f(i: Partial<&str>) -> IResult<Partial<&str>, &str> {
|
||||
take(3_usize).parse_peek(i)
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
f(Partial::new("")),
|
||||
Err(ErrMode::Incomplete(Needed::Unknown))
|
||||
);
|
||||
assert_eq!(
|
||||
f(Partial::new("ab")),
|
||||
Err(ErrMode::Incomplete(Needed::Unknown))
|
||||
);
|
||||
assert_eq!(
|
||||
f(Partial::new("點")),
|
||||
Err(ErrMode::Incomplete(Needed::Unknown))
|
||||
);
|
||||
assert_eq!(f(Partial::new("ab點cd")), Ok((Partial::new("cd"), "ab點")));
|
||||
assert_eq!(f(Partial::new("a點bcd")), Ok((Partial::new("cd"), "a點b")));
|
||||
assert_eq!(f(Partial::new("a點b")), Ok((Partial::new(""), "a點b")));
|
||||
|
||||
fn g(i: Partial<&str>) -> IResult<Partial<&str>, &str> {
|
||||
take_while(0.., |c| c == '點').parse_peek(i)
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
g(Partial::new("")),
|
||||
Err(ErrMode::Incomplete(Needed::new(1)))
|
||||
);
|
||||
assert_eq!(g(Partial::new("點abcd")), Ok((Partial::new("abcd"), "點")));
|
||||
assert_eq!(
|
||||
g(Partial::new("點點點a")),
|
||||
Ok((Partial::new("a"), "點點點"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_take_while_m_n_utf8_fixed() {
|
||||
fn parser(i: Partial<&str>) -> IResult<Partial<&str>, &str> {
|
||||
take_while(1, |c| c == 'A' || c == '😃').parse_peek(i)
|
||||
}
|
||||
assert_eq!(parser(Partial::new("A!")), Ok((Partial::new("!"), "A")));
|
||||
assert_eq!(parser(Partial::new("😃!")), Ok((Partial::new("!"), "😃")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_take_while_m_n_utf8_range() {
|
||||
fn parser(i: Partial<&str>) -> IResult<Partial<&str>, &str> {
|
||||
take_while(1..=2, |c| c == 'A' || c == '😃').parse_peek(i)
|
||||
}
|
||||
assert_eq!(parser(Partial::new("A!")), Ok((Partial::new("!"), "A")));
|
||||
assert_eq!(parser(Partial::new("😃!")), Ok((Partial::new("!"), "😃")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_take_while_m_n_utf8_full_match_fixed() {
|
||||
fn parser(i: Partial<&str>) -> IResult<Partial<&str>, &str> {
|
||||
take_while(1, |c: char| c.is_alphabetic()).parse_peek(i)
|
||||
}
|
||||
assert_eq!(parser(Partial::new("øn")), Ok((Partial::new("n"), "ø")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_take_while_m_n_utf8_full_match_range() {
|
||||
fn parser(i: Partial<&str>) -> IResult<Partial<&str>, &str> {
|
||||
take_while(1..=2, |c: char| c.is_alphabetic()).parse_peek(i)
|
||||
}
|
||||
assert_eq!(parser(Partial::new("øn")), Ok((Partial::new(""), "øn")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "std")]
|
||||
fn partial_recognize_take_while0() {
|
||||
fn x(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
take_while(0.., AsChar::is_alphanum).parse_peek(i)
|
||||
}
|
||||
fn y(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
unpeek(x).recognize().parse_peek(i)
|
||||
}
|
||||
assert_eq!(
|
||||
x(Partial::new(&b"ab."[..])),
|
||||
Ok((Partial::new(&b"."[..]), &b"ab"[..]))
|
||||
);
|
||||
assert_eq!(
|
||||
y(Partial::new(&b"ab."[..])),
|
||||
Ok((Partial::new(&b"."[..]), &b"ab"[..]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_tag_case_insensitive() {
|
||||
fn caseless_bytes(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
tag(Caseless("ABcd")).parse_peek(i)
|
||||
}
|
||||
assert_eq!(
|
||||
caseless_bytes(Partial::new(&b"aBCdefgh"[..])),
|
||||
Ok((Partial::new(&b"efgh"[..]), &b"aBCd"[..]))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_bytes(Partial::new(&b"abcdefgh"[..])),
|
||||
Ok((Partial::new(&b"efgh"[..]), &b"abcd"[..]))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_bytes(Partial::new(&b"ABCDefgh"[..])),
|
||||
Ok((Partial::new(&b"efgh"[..]), &b"ABCD"[..]))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_bytes(Partial::new(&b"ab"[..])),
|
||||
Err(ErrMode::Incomplete(Needed::new(2)))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_bytes(Partial::new(&b"Hello"[..])),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&Partial::new(&b"Hello"[..]),
|
||||
ErrorKind::Tag
|
||||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_bytes(Partial::new(&b"Hel"[..])),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&Partial::new(&b"Hel"[..]),
|
||||
ErrorKind::Tag
|
||||
)))
|
||||
);
|
||||
|
||||
fn caseless_str(i: Partial<&str>) -> IResult<Partial<&str>, &str> {
|
||||
tag(Caseless("ABcd")).parse_peek(i)
|
||||
}
|
||||
assert_eq!(
|
||||
caseless_str(Partial::new("aBCdefgh")),
|
||||
Ok((Partial::new("efgh"), "aBCd"))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_str(Partial::new("abcdefgh")),
|
||||
Ok((Partial::new("efgh"), "abcd"))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_str(Partial::new("ABCDefgh")),
|
||||
Ok((Partial::new("efgh"), "ABCD"))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_str(Partial::new("ab")),
|
||||
Err(ErrMode::Incomplete(Needed::new(2)))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_str(Partial::new("Hello")),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&Partial::new("Hello"),
|
||||
ErrorKind::Tag
|
||||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
caseless_str(Partial::new("Hel")),
|
||||
Err(ErrMode::Backtrack(error_position!(
|
||||
&Partial::new("Hel"),
|
||||
ErrorKind::Tag
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_tag_fixed_size_array() {
|
||||
fn test(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
tag([0x42]).parse_peek(i)
|
||||
}
|
||||
fn test2(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> {
|
||||
tag(&[0x42]).parse_peek(i)
|
||||
}
|
||||
let input = Partial::new(&[0x42, 0x00][..]);
|
||||
assert_eq!(test(input), Ok((Partial::new(&b"\x00"[..]), &b"\x42"[..])));
|
||||
assert_eq!(test2(input), Ok((Partial::new(&b"\x00"[..]), &b"\x42"[..])));
|
||||
}
|
||||
11
third-party/vendor/winnow/src/trace.rs
vendored
Normal file
11
third-party/vendor/winnow/src/trace.rs
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
//! Deprecated, replaced with [`winnow::combinator`][crate::combinator]
|
||||
|
||||
/// Deprecated, replaced with [`winnow::combinator::trace`][crate::combinator::trace]
|
||||
#[deprecated(since = "0.5.35", note = "Replaced with `winnow::combinator::trace`")]
|
||||
#[inline(always)]
|
||||
pub fn trace<I: crate::stream::Stream, O, E>(
|
||||
name: impl crate::lib::std::fmt::Display,
|
||||
parser: impl crate::Parser<I, O, E>,
|
||||
) -> impl crate::Parser<I, O, E> {
|
||||
crate::combinator::trace(name, parser)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue