mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
Bug 1414254 - Vendor Rust dependencies r=jgraham
MozReview-Commit-ID: CnT3DLl2KBR --HG-- rename : third_party/rust/base64-0.5.2/LICENSE-APACHE => third_party/rust/cc/LICENSE-APACHE rename : third_party/rust/gcc-0.3.42/LICENSE-MIT => third_party/rust/cc/LICENSE-MIT rename : third_party/rust/gcc-0.3.42/src/bin/gcc-shim.rs => third_party/rust/cc/src/bin/gcc-shim.rs rename : third_party/rust/gcc-0.3.42/src/registry.rs => third_party/rust/cc/src/registry.rs rename : third_party/rust/clap/.cargo-checksum.json => third_party/rust/clap-2.25.0/.cargo-checksum.json rename : third_party/rust/clap-2.24.2/.clog.toml => third_party/rust/clap-2.25.0/.clog.toml rename : third_party/rust/clap-2.24.2/.github/CONTRIBUTING.md => third_party/rust/clap-2.25.0/.github/CONTRIBUTING.md rename : third_party/rust/clap-2.24.2/.github/ISSUE_TEMPLATE.md => third_party/rust/clap-2.25.0/.github/ISSUE_TEMPLATE.md rename : third_party/rust/clap-2.24.2/.travis.yml => third_party/rust/clap-2.25.0/.travis.yml rename : third_party/rust/clap/CHANGELOG.md => third_party/rust/clap-2.25.0/CHANGELOG.md rename : third_party/rust/clap-2.24.2/CONTRIBUTORS.md => third_party/rust/clap-2.25.0/CONTRIBUTORS.md rename : third_party/rust/clap/Cargo.toml => third_party/rust/clap-2.25.0/Cargo.toml rename : third_party/rust/clap-2.24.2/LICENSE-MIT => third_party/rust/clap-2.25.0/LICENSE-MIT rename : third_party/rust/clap/README.md => third_party/rust/clap-2.25.0/README.md rename : third_party/rust/clap-2.24.2/index.html => third_party/rust/clap-2.25.0/index.html rename : third_party/rust/clap-2.24.2/justfile => third_party/rust/clap-2.25.0/justfile rename : third_party/rust/clap-2.24.2/rustfmt.toml => third_party/rust/clap-2.25.0/rustfmt.toml rename : third_party/rust/clap/src/app/help.rs => third_party/rust/clap-2.25.0/src/app/help.rs rename : third_party/rust/clap/src/app/macros.rs => third_party/rust/clap-2.25.0/src/app/macros.rs rename : third_party/rust/clap-2.24.2/src/app/meta.rs => third_party/rust/clap-2.25.0/src/app/meta.rs rename : third_party/rust/clap-2.24.2/src/app/mod.rs => third_party/rust/clap-2.25.0/src/app/mod.rs rename : third_party/rust/clap/src/app/parser.rs => third_party/rust/clap-2.25.0/src/app/parser.rs rename : third_party/rust/clap/src/app/settings.rs => third_party/rust/clap-2.25.0/src/app/settings.rs rename : third_party/rust/clap/src/app/validator.rs => third_party/rust/clap-2.25.0/src/app/validator.rs rename : third_party/rust/clap-2.24.2/src/args/any_arg.rs => third_party/rust/clap-2.25.0/src/args/any_arg.rs rename : third_party/rust/clap-2.24.2/src/args/arg.rs => third_party/rust/clap-2.25.0/src/args/arg.rs rename : third_party/rust/clap-2.24.2/src/args/arg_builder/base.rs => third_party/rust/clap-2.25.0/src/args/arg_builder/base.rs rename : third_party/rust/clap-2.24.2/src/args/arg_builder/flag.rs => third_party/rust/clap-2.25.0/src/args/arg_builder/flag.rs rename : third_party/rust/clap-2.24.2/src/args/arg_builder/mod.rs => third_party/rust/clap-2.25.0/src/args/arg_builder/mod.rs rename : third_party/rust/clap-2.24.2/src/args/arg_builder/option.rs => third_party/rust/clap-2.25.0/src/args/arg_builder/option.rs rename : third_party/rust/clap/src/args/arg_builder/positional.rs => third_party/rust/clap-2.25.0/src/args/arg_builder/positional.rs rename : third_party/rust/clap-2.24.2/src/args/arg_builder/switched.rs => third_party/rust/clap-2.25.0/src/args/arg_builder/switched.rs rename : third_party/rust/clap-2.24.2/src/args/arg_builder/valued.rs => third_party/rust/clap-2.25.0/src/args/arg_builder/valued.rs rename : third_party/rust/clap-2.24.2/src/args/arg_matcher.rs => third_party/rust/clap-2.25.0/src/args/arg_matcher.rs rename : third_party/rust/clap-2.24.2/src/args/arg_matches.rs => third_party/rust/clap-2.25.0/src/args/arg_matches.rs rename : third_party/rust/clap-2.24.2/src/args/matched_arg.rs => third_party/rust/clap-2.25.0/src/args/matched_arg.rs rename : third_party/rust/clap-2.24.2/src/args/mod.rs => third_party/rust/clap-2.25.0/src/args/mod.rs rename : third_party/rust/clap-2.24.2/src/args/subcommand.rs => third_party/rust/clap-2.25.0/src/args/subcommand.rs rename : third_party/rust/clap-2.24.2/src/completions/bash.rs => third_party/rust/clap-2.25.0/src/completions/bash.rs rename : third_party/rust/clap-2.24.2/src/completions/fish.rs => third_party/rust/clap-2.25.0/src/completions/fish.rs rename : third_party/rust/clap-2.24.2/src/completions/macros.rs => third_party/rust/clap-2.25.0/src/completions/macros.rs rename : third_party/rust/clap-2.24.2/src/completions/mod.rs => third_party/rust/clap-2.25.0/src/completions/mod.rs rename : third_party/rust/clap-2.24.2/src/completions/shell.rs => third_party/rust/clap-2.25.0/src/completions/shell.rs rename : third_party/rust/clap-2.24.2/src/completions/zsh.rs => third_party/rust/clap-2.25.0/src/completions/zsh.rs rename : third_party/rust/clap/src/lib.rs => third_party/rust/clap-2.25.0/src/lib.rs rename : third_party/rust/clap/src/macros.rs => third_party/rust/clap-2.25.0/src/macros.rs rename : third_party/rust/clap-2.24.2/src/osstringext.rs => third_party/rust/clap-2.25.0/src/osstringext.rs rename : third_party/rust/clap-2.24.2/src/strext.rs => third_party/rust/clap-2.25.0/src/strext.rs rename : third_party/rust/clap/src/suggestions.rs => third_party/rust/clap-2.25.0/src/suggestions.rs rename : third_party/rust/clap-2.24.2/src/usage_parser.rs => third_party/rust/clap-2.25.0/src/usage_parser.rs rename : third_party/rust/gcc-0.3.42/LICENSE-APACHE => third_party/rust/libc-0.2.30/LICENSE-APACHE rename : third_party/rust/log-0.3.6/LICENSE-MIT => third_party/rust/libc-0.2.30/LICENSE-MIT rename : third_party/rust/num-integer/.cargo-checksum.json => third_party/rust/num-integer-0.1.33/.cargo-checksum.json rename : third_party/rust/num-integer/Cargo.toml => third_party/rust/num-integer-0.1.33/Cargo.toml rename : third_party/rust/log-0.3.6/LICENSE-APACHE => third_party/rust/num-integer-0.1.33/LICENSE-APACHE rename : third_party/rust/num-traits-0.1.37/LICENSE-MIT => third_party/rust/num-integer-0.1.33/LICENSE-MIT rename : third_party/rust/num-integer/src/lib.rs => third_party/rust/num-integer-0.1.33/src/lib.rs rename : third_party/rust/num-traits/.cargo-checksum.json => third_party/rust/num-traits-0.1.39/.cargo-checksum.json rename : third_party/rust/num-traits/Cargo.toml => third_party/rust/num-traits-0.1.39/Cargo.toml rename : third_party/rust/num-traits-0.1.37/LICENSE-APACHE => third_party/rust/num-traits-0.1.39/LICENSE-APACHE rename : third_party/rust/regex-0.2.1/LICENSE-MIT => third_party/rust/num-traits-0.1.39/LICENSE-MIT rename : third_party/rust/num-traits-0.1.37/src/float.rs => third_party/rust/num-traits-0.1.39/src/float.rs rename : third_party/rust/num-traits-0.1.37/src/int.rs => third_party/rust/num-traits-0.1.39/src/int.rs rename : third_party/rust/num-traits-0.1.37/src/ops/mod.rs => third_party/rust/num-traits-0.1.39/src/ops/mod.rs rename : third_party/rust/num-traits-0.1.37/src/ops/saturating.rs => third_party/rust/num-traits-0.1.39/src/ops/saturating.rs rename : third_party/rust/num-traits-0.1.37/src/pow.rs => third_party/rust/num-traits-0.1.39/src/pow.rs rename : third_party/rust/num_cpus-1.2.1/.travis.yml => third_party/rust/num_cpus-1.6.2/.travis.yml rename : third_party/rust/num_cpus-1.2.1/LICENSE-APACHE => third_party/rust/num_cpus-1.6.2/LICENSE-APACHE rename : third_party/rust/num_cpus-1.2.1/LICENSE-MIT => third_party/rust/num_cpus-1.6.2/LICENSE-MIT rename : third_party/rust/textwrap/.appveyor.yml => third_party/rust/textwrap-0.6.0/.appveyor.yml rename : third_party/rust/textwrap/.cargo-checksum.json => third_party/rust/textwrap-0.6.0/.cargo-checksum.json rename : third_party/rust/textwrap/.travis.yml => third_party/rust/textwrap-0.6.0/.travis.yml rename : third_party/rust/textwrap/Cargo.toml => third_party/rust/textwrap-0.6.0/Cargo.toml rename : third_party/rust/textwrap/README.md => third_party/rust/textwrap-0.6.0/README.md rename : third_party/rust/textwrap/benches/linear.rs => third_party/rust/textwrap-0.6.0/benches/linear.rs rename : third_party/rust/textwrap/examples/layout.rs => third_party/rust/textwrap-0.6.0/examples/layout.rs rename : third_party/rust/textwrap/examples/termwidth.rs => third_party/rust/textwrap-0.6.0/examples/termwidth.rs rename : third_party/rust/textwrap/src/lib.rs => third_party/rust/textwrap-0.6.0/src/lib.rs extra : rebase_source : 75ee4cb067c477d9bd7921594fd0138355392635
This commit is contained in:
parent
cc0d8c0695
commit
318d3094c5
@ -1 +0,0 @@
|
||||
{"files":{".travis.yml":"e17babe5ba0bdd19ec59a37b4a099fd4313bff58be63a2ff506075f9a97dc172","COPYING":"01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f","Cargo.toml":"367c53caf576e1c811c77b5234f4d00ee23f5b1052d5e11bdc0c3153a8d9ae82","LICENSE-MIT":"0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f","Makefile":"a45a128685a2ae7d4fa39d310786674417ee113055ef290a11f88002285865fc","README.md":"9bc60d2cec222b50f87c85cf9475349bb228a36f89796c5d6481c52560ddde3a","UNLICENSE":"7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c","benches/bench.rs":"acf4844efadeafc7bc396c2b16f2a184e140b6c17d1084dbaf454196de2090cd","benches/random.txt":"9386fb3efedc7ffbd09fb49088347f1056bc2d90a861009fa2f804cdb714efcb","ctags.rust":"3d128d3cc59f702e68953ba2fe6c3f46bc6991fc575308db060482d5da0c79f3","examples/dict-search.rs":"30eb44b1a0b599507db4c23a90f74199faabc64a8ae1d603ecdf3bba7428eb1e","session.vim":"95cb1d7caf0ff7fbe76ec911988d908ddd883381c925ba64b537695bc9f021c4","src/autiter.rs":"dc8817af24825c356842c814d771868fb07b6965addf4780e8b9dea9718344a0","src/full.rs":"b83a9c8ff3ef611c316b68650915df2d7f361a49b59dab103dc2c5476f2d8303","src/lib.rs":"68bf2ed02d58bebee6f7f7579038f1e4b60a2c4acc334263cb837bcbe15ffe94","src/main.rs":"fc867cb5f0b02d0f49ecab06b72c05a247cbcf3bf9228c235de8e787bda7bef5"},"package":"0638fd549427caa90c499814196d1b9e3725eb4d15d7339d6de073a680ed0ca2"}
|
13
third_party/rust/aho-corasick-0.6.2/.travis.yml
vendored
13
third_party/rust/aho-corasick-0.6.2/.travis.yml
vendored
@ -1,13 +0,0 @@
|
||||
language: rust
|
||||
rust:
|
||||
- 1.12.0
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
script:
|
||||
- cargo build --verbose
|
||||
- cargo test --verbose
|
||||
- cargo doc
|
||||
- if [ "$TRAVIS_RUST_VERSION" = "nightly" ]; then
|
||||
cargo bench --verbose;
|
||||
fi
|
3
third_party/rust/aho-corasick-0.6.2/COPYING
vendored
3
third_party/rust/aho-corasick-0.6.2/COPYING
vendored
@ -1,3 +0,0 @@
|
||||
This project is dual-licensed under the Unlicense and MIT licenses.
|
||||
|
||||
You may use this code under the terms of either license.
|
47
third_party/rust/aho-corasick-0.6.2/Cargo.toml
vendored
47
third_party/rust/aho-corasick-0.6.2/Cargo.toml
vendored
@ -1,47 +0,0 @@
|
||||
[package]
|
||||
name = "aho-corasick"
|
||||
version = "0.6.2" #:version
|
||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||
description = "Fast multiple substring searching with finite state machines."
|
||||
documentation = "http://burntsushi.net/rustdoc/aho_corasick/"
|
||||
homepage = "https://github.com/BurntSushi/aho-corasick"
|
||||
repository = "https://github.com/BurntSushi/aho-corasick"
|
||||
readme = "README.md"
|
||||
keywords = ["string", "search", "text", "aho", "corasick"]
|
||||
license = "Unlicense/MIT"
|
||||
exclude = ["benches/sherlock.txt"]
|
||||
|
||||
[lib]
|
||||
name = "aho_corasick"
|
||||
|
||||
[[bin]]
|
||||
name = "aho-corasick-dot"
|
||||
test = false
|
||||
doc = false
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
memchr = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
csv = "0.15"
|
||||
docopt = "0.7"
|
||||
memmap = "0.5"
|
||||
quickcheck = { version = "0.4", default-features = false }
|
||||
rand = "0.3"
|
||||
rustc-serialize = "0.3"
|
||||
|
||||
[[bench]]
|
||||
name = "bench"
|
||||
path = "benches/bench.rs"
|
||||
test = false
|
||||
bench = true
|
||||
|
||||
[profile.test]
|
||||
debug = true
|
||||
|
||||
[profile.bench]
|
||||
debug = true
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
21
third_party/rust/aho-corasick-0.6.2/LICENSE-MIT
vendored
21
third_party/rust/aho-corasick-0.6.2/LICENSE-MIT
vendored
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Andrew Gallant
|
||||
|
||||
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.
|
14
third_party/rust/aho-corasick-0.6.2/Makefile
vendored
14
third_party/rust/aho-corasick-0.6.2/Makefile
vendored
@ -1,14 +0,0 @@
|
||||
all:
|
||||
echo Nothing to do...
|
||||
|
||||
ctags:
|
||||
ctags --recurse --options=ctags.rust --languages=Rust
|
||||
|
||||
docs:
|
||||
cargo doc
|
||||
in-dir ./target/doc fix-perms
|
||||
rscp ./target/doc/* gopher:~/www/burntsushi.net/rustdoc/
|
||||
|
||||
push:
|
||||
git push origin master
|
||||
git push github master
|
55
third_party/rust/aho-corasick-0.6.2/README.md
vendored
55
third_party/rust/aho-corasick-0.6.2/README.md
vendored
@ -1,55 +0,0 @@
|
||||
This crate provides an implementation of the
|
||||
[Aho-Corasick](http://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm)
|
||||
algorithm. Its intended use case is for fast substring matching, particularly
|
||||
when matching multiple substrings in a search text. This is achieved by
|
||||
compiling the substrings into a finite state machine.
|
||||
|
||||
This implementation provides optimal algorithmic time complexity. Construction
|
||||
of the finite state machine is `O(p)` where `p` is the length of the substrings
|
||||
concatenated. Matching against search text is `O(n + p + m)`, where `n` is
|
||||
the length of the search text and `m` is the number of matches.
|
||||
|
||||
[![Build status](https://api.travis-ci.org/BurntSushi/aho-corasick.png)](https://travis-ci.org/BurntSushi/aho-corasick)
|
||||
[![](http://meritbadge.herokuapp.com/aho-corasick)](https://crates.io/crates/aho-corasick)
|
||||
|
||||
Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org).
|
||||
|
||||
|
||||
### Documentation
|
||||
|
||||
[http://burntsushi.net/rustdoc/aho_corasick/](http://burntsushi.net/rustdoc/aho_corasick/).
|
||||
|
||||
|
||||
### Example
|
||||
|
||||
The documentation contains several examples, and there is a more complete
|
||||
example as a full program in `examples/dict-search.rs`.
|
||||
|
||||
Here is a quick example showing simple substring matching:
|
||||
|
||||
```rust
|
||||
use aho_corasick::{Automaton, AcAutomaton, Match};
|
||||
|
||||
let aut = AcAutomaton::new(vec!["apple", "maple"]);
|
||||
let mut it = aut.find("I like maple apples.");
|
||||
assert_eq!(it.next(), Some(Match {
|
||||
pati: 1,
|
||||
start: 7,
|
||||
end: 12,
|
||||
}));
|
||||
assert_eq!(it.next(), Some(Match {
|
||||
pati: 0,
|
||||
start: 13,
|
||||
end: 18,
|
||||
}));
|
||||
assert_eq!(it.next(), None);
|
||||
```
|
||||
|
||||
|
||||
### Alternatives
|
||||
|
||||
Aho-Corasick is useful for matching multiple substrings against many long
|
||||
strings. If your long string is fixed, then you might consider building a
|
||||
[suffix array](https://github.com/BurntSushi/suffix)
|
||||
of the search text (which takes `O(n)` time). Matches can then be found in
|
||||
`O(plogn)` time.
|
24
third_party/rust/aho-corasick-0.6.2/UNLICENSE
vendored
24
third_party/rust/aho-corasick-0.6.2/UNLICENSE
vendored
@ -1,24 +0,0 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
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 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.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
339
third_party/rust/aho-corasick-0.6.2/benches/bench.rs
vendored
339
third_party/rust/aho-corasick-0.6.2/benches/bench.rs
vendored
@ -1,339 +0,0 @@
|
||||
#![feature(test)]
|
||||
|
||||
extern crate aho_corasick;
|
||||
extern crate test;
|
||||
|
||||
use std::iter;
|
||||
|
||||
use aho_corasick::{Automaton, AcAutomaton, Transitions};
|
||||
use test::Bencher;
|
||||
|
||||
const HAYSTACK_RANDOM: &'static str = include_str!("random.txt");
|
||||
const HAYSTACK_SHERLOCK: &'static str = include_str!("sherlock.txt");
|
||||
|
||||
fn bench_aut_no_match<P: AsRef<[u8]>, T: Transitions>(
|
||||
b: &mut Bencher,
|
||||
aut: AcAutomaton<P, T>,
|
||||
haystack: &str,
|
||||
) {
|
||||
b.bytes = haystack.len() as u64;
|
||||
b.iter(|| assert!(aut.find(haystack).next().is_none()));
|
||||
}
|
||||
|
||||
fn bench_box_aut_no_match<P: AsRef<[u8]>, T: Transitions>(
|
||||
b: &mut Bencher,
|
||||
aut: AcAutomaton<P, T>,
|
||||
haystack: &str,
|
||||
) {
|
||||
b.bytes = haystack.len() as u64;
|
||||
let aut: &Automaton<P> = &aut;
|
||||
b.iter(|| assert!(Automaton::find(&aut, haystack).next().is_none()));
|
||||
}
|
||||
|
||||
fn bench_full_aut_no_match<P: AsRef<[u8]>, T: Transitions>(
|
||||
b: &mut Bencher,
|
||||
aut: AcAutomaton<P, T>,
|
||||
haystack: &str,
|
||||
) {
|
||||
let aut = aut.into_full();
|
||||
b.bytes = haystack.len() as u64;
|
||||
b.iter(|| assert!(aut.find(haystack).next().is_none()));
|
||||
}
|
||||
|
||||
fn bench_full_aut_overlapping_no_match<P: AsRef<[u8]>, T: Transitions>(
|
||||
b: &mut Bencher,
|
||||
aut: AcAutomaton<P, T>,
|
||||
haystack: &str,
|
||||
) {
|
||||
let aut = aut.into_full();
|
||||
b.bytes = haystack.len() as u64;
|
||||
b.iter(|| assert!(aut.find_overlapping(haystack).count() == 0));
|
||||
}
|
||||
|
||||
fn bench_naive_no_match<S>(b: &mut Bencher, needles: Vec<S>, haystack: &str)
|
||||
where S: Into<String> {
|
||||
b.bytes = haystack.len() as u64;
|
||||
let needles: Vec<String> = needles.into_iter().map(Into::into).collect();
|
||||
b.iter(|| assert!(!naive_find(&needles, haystack)));
|
||||
}
|
||||
|
||||
fn haystack_same(letter: char) -> String {
|
||||
iter::repeat(letter).take(10000).collect()
|
||||
}
|
||||
|
||||
macro_rules! aut_benches {
|
||||
($prefix:ident, $aut:expr, $bench:expr) => {
|
||||
mod $prefix {
|
||||
#![allow(unused_imports)]
|
||||
use aho_corasick::{Automaton, AcAutomaton, Sparse};
|
||||
use test::Bencher;
|
||||
|
||||
use super::{
|
||||
HAYSTACK_RANDOM, haystack_same,
|
||||
bench_aut_no_match, bench_box_aut_no_match,
|
||||
bench_full_aut_no_match, bench_full_aut_overlapping_no_match,
|
||||
};
|
||||
|
||||
#[bench]
|
||||
fn ac_one_byte(b: &mut Bencher) {
|
||||
let aut = $aut(vec!["a"]);
|
||||
$bench(b, aut, &haystack_same('z'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ac_one_prefix_byte_no_match(b: &mut Bencher) {
|
||||
let aut = $aut(vec!["zbc"]);
|
||||
$bench(b, aut, &haystack_same('y'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ac_one_prefix_byte_every_match(b: &mut Bencher) {
|
||||
// We lose the benefit of `memchr` because the first byte matches
|
||||
// in every position in the haystack.
|
||||
let aut = $aut(vec!["zbc"]);
|
||||
$bench(b, aut, &haystack_same('z'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ac_one_prefix_byte_random(b: &mut Bencher) {
|
||||
let aut = $aut(vec!["zbc\x00"]);
|
||||
$bench(b, aut, HAYSTACK_RANDOM);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ac_two_bytes(b: &mut Bencher) {
|
||||
let aut = $aut(vec!["a", "b"]);
|
||||
$bench(b, aut, &haystack_same('z'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ac_two_diff_prefix(b: &mut Bencher) {
|
||||
let aut = $aut(vec!["abcdef", "bmnopq"]);
|
||||
$bench(b, aut, &haystack_same('z'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ac_two_one_prefix_byte_every_match(b: &mut Bencher) {
|
||||
let aut = $aut(vec!["zbcdef", "zmnopq"]);
|
||||
$bench(b, aut, &haystack_same('z'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ac_two_one_prefix_byte_no_match(b: &mut Bencher) {
|
||||
let aut = $aut(vec!["zbcdef", "zmnopq"]);
|
||||
$bench(b, aut, &haystack_same('y'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ac_two_one_prefix_byte_random(b: &mut Bencher) {
|
||||
let aut = $aut(vec!["zbcdef\x00", "zmnopq\x00"]);
|
||||
$bench(b, aut, HAYSTACK_RANDOM);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ac_ten_bytes(b: &mut Bencher) {
|
||||
let aut = $aut(vec!["a", "b", "c", "d", "e",
|
||||
"f", "g", "h", "i", "j"]);
|
||||
$bench(b, aut, &haystack_same('z'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ac_ten_diff_prefix(b: &mut Bencher) {
|
||||
let aut = $aut(vec!["abcdef", "bbcdef", "cbcdef", "dbcdef",
|
||||
"ebcdef", "fbcdef", "gbcdef", "hbcdef",
|
||||
"ibcdef", "jbcdef"]);
|
||||
$bench(b, aut, &haystack_same('z'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ac_ten_one_prefix_byte_every_match(b: &mut Bencher) {
|
||||
let aut = $aut(vec!["zacdef", "zbcdef", "zccdef", "zdcdef",
|
||||
"zecdef", "zfcdef", "zgcdef", "zhcdef",
|
||||
"zicdef", "zjcdef"]);
|
||||
$bench(b, aut, &haystack_same('z'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ac_ten_one_prefix_byte_no_match(b: &mut Bencher) {
|
||||
let aut = $aut(vec!["zacdef", "zbcdef", "zccdef", "zdcdef",
|
||||
"zecdef", "zfcdef", "zgcdef", "zhcdef",
|
||||
"zicdef", "zjcdef"]);
|
||||
$bench(b, aut, &haystack_same('y'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ac_ten_one_prefix_byte_random(b: &mut Bencher) {
|
||||
let aut = $aut(vec!["zacdef\x00", "zbcdef\x00", "zccdef\x00",
|
||||
"zdcdef\x00", "zecdef\x00", "zfcdef\x00",
|
||||
"zgcdef\x00", "zhcdef\x00", "zicdef\x00",
|
||||
"zjcdef\x00"]);
|
||||
$bench(b, aut, HAYSTACK_RANDOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aut_benches!(dense, AcAutomaton::new, bench_aut_no_match);
|
||||
aut_benches!(dense_boxed, AcAutomaton::new, bench_box_aut_no_match);
|
||||
aut_benches!(sparse, AcAutomaton::<&str, Sparse>::with_transitions,
|
||||
bench_aut_no_match);
|
||||
aut_benches!(full, AcAutomaton::new, bench_full_aut_no_match);
|
||||
aut_benches!(full_overlap, AcAutomaton::new, bench_full_aut_overlapping_no_match);
|
||||
|
||||
// A naive multi-pattern search.
|
||||
// We use this to benchmark *throughput*, so it should never match anything.
|
||||
fn naive_find(needles: &[String], haystack: &str) -> bool {
|
||||
for hi in 0..haystack.len() {
|
||||
let rest = &haystack.as_bytes()[hi..];
|
||||
for needle in needles {
|
||||
let needle = needle.as_bytes();
|
||||
if needle.len() > rest.len() {
|
||||
continue;
|
||||
}
|
||||
if needle == &rest[..needle.len()] {
|
||||
// should never happen in throughput benchmarks.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn naive_one_byte(b: &mut Bencher) {
|
||||
bench_naive_no_match(b, vec!["a"], &haystack_same('z'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn naive_one_prefix_byte_no_match(b: &mut Bencher) {
|
||||
bench_naive_no_match(b, vec!["zbc"], &haystack_same('y'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn naive_one_prefix_byte_every_match(b: &mut Bencher) {
|
||||
bench_naive_no_match(b, vec!["zbc"], &haystack_same('z'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn naive_one_prefix_byte_random(b: &mut Bencher) {
|
||||
bench_naive_no_match(b, vec!["zbc\x00"], HAYSTACK_RANDOM);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn naive_two_bytes(b: &mut Bencher) {
|
||||
bench_naive_no_match(b, vec!["a", "b"], &haystack_same('z'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn naive_two_diff_prefix(b: &mut Bencher) {
|
||||
bench_naive_no_match(b, vec!["abcdef", "bmnopq"], &haystack_same('z'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn naive_two_one_prefix_byte_every_match(b: &mut Bencher) {
|
||||
bench_naive_no_match(b, vec!["zbcdef", "zmnopq"], &haystack_same('z'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn naive_two_one_prefix_byte_no_match(b: &mut Bencher) {
|
||||
bench_naive_no_match(b, vec!["zbcdef", "zmnopq"], &haystack_same('y'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn naive_two_one_prefix_byte_random(b: &mut Bencher) {
|
||||
bench_naive_no_match(b, vec!["zbcdef\x00", "zmnopq\x00"], HAYSTACK_RANDOM);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn naive_ten_bytes(b: &mut Bencher) {
|
||||
let needles = vec!["a", "b", "c", "d", "e",
|
||||
"f", "g", "h", "i", "j"];
|
||||
bench_naive_no_match(b, needles, &haystack_same('z'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn naive_ten_diff_prefix(b: &mut Bencher) {
|
||||
let needles = vec!["abcdef", "bbcdef", "cbcdef", "dbcdef",
|
||||
"ebcdef", "fbcdef", "gbcdef", "hbcdef",
|
||||
"ibcdef", "jbcdef"];
|
||||
bench_naive_no_match(b, needles, &haystack_same('z'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn naive_ten_one_prefix_byte_every_match(b: &mut Bencher) {
|
||||
let needles = vec!["zacdef", "zbcdef", "zccdef", "zdcdef",
|
||||
"zecdef", "zfcdef", "zgcdef", "zhcdef",
|
||||
"zicdef", "zjcdef"];
|
||||
bench_naive_no_match(b, needles, &haystack_same('z'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn naive_ten_one_prefix_byte_no_match(b: &mut Bencher) {
|
||||
let needles = vec!["zacdef", "zbcdef", "zccdef", "zdcdef",
|
||||
"zecdef", "zfcdef", "zgcdef", "zhcdef",
|
||||
"zicdef", "zjcdef"];
|
||||
bench_naive_no_match(b, needles, &haystack_same('y'));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn naive_ten_one_prefix_byte_random(b: &mut Bencher) {
|
||||
let needles = vec!["zacdef\x00", "zbcdef\x00", "zccdef\x00",
|
||||
"zdcdef\x00", "zecdef\x00", "zfcdef\x00",
|
||||
"zgcdef\x00", "zhcdef\x00", "zicdef\x00",
|
||||
"zjcdef\x00"];
|
||||
bench_naive_no_match(b, needles, HAYSTACK_RANDOM);
|
||||
}
|
||||
|
||||
|
||||
// The organization above is just awful. Let's start over...
|
||||
|
||||
mod sherlock {
|
||||
use aho_corasick::{Automaton, AcAutomaton};
|
||||
use test::Bencher;
|
||||
use super::HAYSTACK_SHERLOCK;
|
||||
|
||||
macro_rules! sherlock {
|
||||
($name:ident, $count:expr, $pats:expr) => {
|
||||
#[bench]
|
||||
fn $name(b: &mut Bencher) {
|
||||
let haystack = HAYSTACK_SHERLOCK;
|
||||
let aut = AcAutomaton::new($pats).into_full();
|
||||
b.bytes = haystack.len() as u64;
|
||||
b.iter(|| assert_eq!($count, aut.find(haystack).count()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sherlock!(name_alt1, 158, vec!["Sherlock", "Street"]);
|
||||
|
||||
sherlock!(name_alt2, 558, vec!["Sherlock", "Holmes"]);
|
||||
|
||||
sherlock!(name_alt3, 740, vec![
|
||||
"Sherlock", "Holmes", "Watson", "Irene", "Adler", "John", "Baker",
|
||||
]);
|
||||
|
||||
sherlock!(name_alt3_nocase, 1764, vec![
|
||||
"ADL", "ADl", "AdL", "Adl", "BAK", "BAk", "BAK", "BaK", "Bak", "BaK",
|
||||
"HOL", "HOl", "HoL", "Hol", "IRE", "IRe", "IrE", "Ire", "JOH", "JOh",
|
||||
"JoH", "Joh", "SHE", "SHe", "ShE", "She", "WAT", "WAt", "WaT", "Wat",
|
||||
"aDL", "aDl", "adL", "adl", "bAK", "bAk", "bAK", "baK", "bak", "baK",
|
||||
"hOL", "hOl", "hoL", "hol", "iRE", "iRe", "irE", "ire", "jOH", "jOh",
|
||||
"joH", "joh", "sHE", "sHe", "shE", "she", "wAT", "wAt", "waT", "wat",
|
||||
"ſHE", "ſHe", "ſhE", "ſhe",
|
||||
]);
|
||||
|
||||
sherlock!(name_alt4, 582, vec!["Sher", "Hol"]);
|
||||
|
||||
sherlock!(name_alt4_nocase, 1307, vec![
|
||||
"HOL", "HOl", "HoL", "Hol", "SHE", "SHe", "ShE", "She", "hOL", "hOl",
|
||||
"hoL", "hol", "sHE", "sHe", "shE", "she", "ſHE", "ſHe", "ſhE", "ſhe",
|
||||
]);
|
||||
|
||||
sherlock!(name_alt5, 639, vec!["Sherlock", "Holmes", "Watson"]);
|
||||
|
||||
sherlock!(name_alt5_nocase, 1442, vec![
|
||||
"HOL", "HOl", "HoL", "Hol", "SHE", "SHe", "ShE", "She", "WAT", "WAt",
|
||||
"WaT", "Wat", "hOL", "hOl", "hoL", "hol", "sHE", "sHe", "shE", "she",
|
||||
"wAT", "wAt", "waT", "wat", "ſHE", "ſHe", "ſhE", "ſhe",
|
||||
]);
|
||||
}
|
@ -1,513 +0,0 @@
|
||||
|
||||
mnxnsynfvuugtbxsxbfxwreuspglnplefzwsp
|
||||
tacfqcwnmodnmgnyiuvqoco
|
||||
z
|
||||
|
||||
qjuozfkexn
|
||||
zoaxzncje
|
||||
sldhqtmgxzyurfyzwazmmu
|
||||
bbeuv
|
||||
mzsrihycwcb
|
||||
xzfqozfmlnpmrzpxxxytqs
|
||||
xrg
|
||||
mcplby
|
||||
nmslhfgjowhzfxsvyddydnsyehdskbydbjksqtpet
|
||||
indvfw
|
||||
bvjvvw
|
||||
|
||||
pddufodyqtyixbndtumndyz
|
||||
xjjhtuvmsxhuwqulqtjhqrdqrmtbcphvyuqllocrnkpfv
|
||||
zemshhz
|
||||
wss
|
||||
xewlrxfmgxnwgphcgefa
|
||||
mbgsgbzrtthxweimcqzcaaheurdmd
|
||||
osqefupespvh
|
||||
z
|
||||
tvvlakwzwjbrgjzfgubsmmonav
|
||||
pjdskxcfgapsm
|
||||
zqktqgkrcdrlskx
|
||||
zwwfebhguskho
|
||||
zlvvw
|
||||
czwm
|
||||
gojnpmboehlsazbexjjnuscqftrfufngygjdxcydib
|
||||
d
|
||||
afigycivicnknfxl
|
||||
ljuwuopctiftfwctxecwipjnljyef
|
||||
jonwbkodomzhqvlf
|
||||
jdkizhognqsdogunwedjsmsdzho
|
||||
zxvni
|
||||
oynfjf
|
||||
muvokjuqz
|
||||
azuwrwtuxzfopwrcex
|
||||
ixrjinlvxjmn
|
||||
blaegnmbhsgsbmebwazaeguugtkowexgnqtbfkldadddv
|
||||
tzabyoftyov
|
||||
ctbtqbzscxzviuvcigwuwusrdro
|
||||
ljynr
|
||||
gnnnyyxslrhsbj
|
||||
hhzlw
|
||||
hijalf
|
||||
rxlfqk
|
||||
mhaofforwznvmcgplinludpgkucpa
|
||||
gvvxsqqfmu
|
||||
xxqhoyosixjfhjuxpv
|
||||
faadjpvamjekreepizurntvwdynozfawsfawyms
|
||||
|
||||
lcbutr
|
||||
aqyxvpozkjrecrkl
|
||||
lfmochahrr
|
||||
ptqyomjlwo
|
||||
vcmslulznx
|
||||
lmlsskcihrmxauztuarydlp
|
||||
beiqsrfnmvmlmybmwpektjbikvpggthpabqsgmjhnthvysuhwbigillugjsp
|
||||
dfsuegseffwcsnvsrqedytblbpzbfeyfsq
|
||||
kypvqctrkuds
|
||||
ylqeduokzgdqaxelhftxnxbidu
|
||||
bprzyayfopxdsmfhhfqowa
|
||||
ymiutdtlfaaxpbtaeslv
|
||||
ggago
|
||||
|
||||
owpbicekdeykzfgcbgzobdvvrtetvcv
|
||||
xsrlgingstiez
|
||||
gyncqvq
|
||||
xasohmeiwyscpehctmzmsnjklg
|
||||
xsudghakxlw
|
||||
dzqlfptjogzpkvwuticcyugnyopypuqqc
|
||||
wlxshxbhdvuherumoppcc
|
||||
|
||||
znyaptivzncvkpeyeipynqefjxjjcsgfqbnezeebtowdrbjaqjlbxwvyikrmxjwoxngqgvfpbniftnmszuxg
|
||||
umwpwwyvufy
|
||||
pallkjtnrmtauqxauewgygwkjjwebbkabhtxticxmxfujpxlrpzlrozfslkzfdsswlmmsbdgjwmjnummk
|
||||
dhsxylejzityahtqqzmohrpzjprrsraztpnuagtyzfjdekthvdogfidksrdppr
|
||||
ybc
|
||||
fyukknoqfnkllkwflwempjijxgo
|
||||
dltvlau
|
||||
rhvrvlwsribfctuzodfqkdczfzxnetqqzflnhiyl
|
||||
goxmcasmq
|
||||
wljbhwkpahdotqhhrbhqzijv
|
||||
lszewkgdmkezvgmbmllhpksdkoiwgkvqjmurshrptlctqsosuurndcuzjfwherotv
|
||||
dudxxihygxblhgchbgzyzffb
|
||||
eht
|
||||
fvwxvqoltdcsd
|
||||
rkuig
|
||||
e
|
||||
axhsacsmnicugul
|
||||
rubtdlhjqndxdzzwfnkuzy
|
||||
swxteuyxxsktkjgv
|
||||
hzwwodlqaq
|
||||
vxgecev
|
||||
qnwla
|
||||
vdxjuzpyoqhpmuunyffptopmeauhycs
|
||||
dkzo
|
||||
awrfzatzohslgvqlaezepmli
|
||||
qgxatixvpkkhvkumbwmwcagtgyfljdok
|
||||
amdnzstpvcqj
|
||||
xsrvwvhjirzfgkessve
|
||||
qezwbfltfbikbmoasvoflozsjhrljnszqiciuqmflrlqowwkoevuumh
|
||||
babskcvavmtvsxqsewirucwzajjcfcqwsydydqo
|
||||
ywfurpsl
|
||||
edacsjjkjjewkxfoh
|
||||
dcgkfpcjezurnuhiatrczcp
|
||||
xsatnimwbcciu
|
||||
grzmbrsvvcyigcbmcqfwiiknrohveubhyijxeyzfm
|
||||
kqyewccgcqrrrznwxmoztlyseagbpyho
|
||||
najju
|
||||
nis
|
||||
awgzdvfjkzlrsjcqfeacx
|
||||
oisuflfigrjaex
|
||||
desbdulyuwqxuxianyypybxwlql
|
||||
ekmqgspvqpftpwswayh
|
||||
egbyj
|
||||
fznzprhvnnwcxgcc
|
||||
wfdsueieosmugirxbymbpmfrspvrktjzguxm
|
||||
qkjrufshwnfwwpbhukdjlaqvljlgubmqmhnha
|
||||
hwqpudgnblhlxppbrmbznotteivuzguuwlhtkytky
|
||||
w
|
||||
yofkyzbpg
|
||||
cenolnfnllkvhikrpttcxgqxmufvorekjruyjxmr
|
||||
|
||||
hyexmpjijgzumawp
|
||||
cdbevdilgopbzlo
|
||||
fivelagckslkugdxprjxkylizewcptwxfhomzuituujixchadmnjoktnqa
|
||||
csojvlinzmmkkfzqueamnuwkanzdzsavgohposbuoamoevehqrmcxdsuyelvvctoejzoertqormhaaxwofvjzekwt
|
||||
sbkghhnhutrvwtyjaxndzyjamrhx
|
||||
jjyqy
|
||||
majwbnrhveuhrsbbbjrwpwuplifeseylqh
|
||||
wyvutpxnkrnkuxxetjkkifpqb
|
||||
dyzucmbcvgnjeecm
|
||||
hz
|
||||
uhnuipthxrzkqluosvk
|
||||
lwqqzsdwiwvwaqfwlvubadlyizlo
|
||||
jbd
|
||||
oyzjeu
|
||||
kydjkbsqxnbfiuesc
|
||||
smeubjqrcxdvhsabzceyglqjzbfmoacmwvwjbhhxbr
|
||||
uabipgecujfdfxpmdzrscdyvefizabgspqjrrkmgjt
|
||||
xgvdgzryz
|
||||
lw
|
||||
uimob
|
||||
ifhn
|
||||
bqph
|
||||
ole
|
||||
g
|
||||
wt
|
||||
k
|
||||
yslzrkwkundxfdibwqvucemepqxlmlpyngabbeciuzhptpjdetyngrtxrdtzmvq
|
||||
ccwapidp
|
||||
|
||||
bwvrgvmtshevrophy
|
||||
ni
|
||||
fdkplu
|
||||
mdykey
|
||||
i
|
||||
rhsrenoetdggpjb
|
||||
djmkplpeabsholx
|
||||
judxtub
|
||||
fooakqwvocvpcrvxqhvtmpvhkrecy
|
||||
uuxscjillynilbkrgt
|
||||
evtinrmilniguarqritpeipwochmdw
|
||||
sxaqzjybydyvnmmjtdcgkjnqfcklbfpkdfyewgcukqoiegyfp
|
||||
kg
|
||||
ovrwieqhy
|
||||
jcxqtkerzjwhs
|
||||
xeonglszbgypafhmqcaseimzjgebkvigbqwsayrnrprtuvhsxyitfqygohgorcdnufbcyvevvgzmjrgjqqquwkszplogx
|
||||
zdketqqv
|
||||
yebckucwayckeezfvtnavglpjh
|
||||
zorkfrwk
|
||||
pad
|
||||
xqaquxudybwtgixbfktinctfirjfdayh
|
||||
rieknj
|
||||
ebk
|
||||
qzbcfywfdmhsdruhopovemafijbscagllkmhmof
|
||||
|
||||
asbsnbddlobwoqatfhkbhhsymzqxjuixwreheugvngmgcuqpkjhhfwpbarqaxrwgwnjbanljlds
|
||||
etevdvlc
|
||||
lqyjrnmenhn
|
||||
k
|
||||
tsf
|
||||
zczgeavcexh
|
||||
jlpuxywtsrvnvluruqhecjca
|
||||
ir
|
||||
rikrgkmhwaosodkxgcnrexfmdrszhnmutpvwztg
|
||||
bffjqovvkemctnsgeh
|
||||
weysbhzixiipfithjfsk
|
||||
usyzvaiyuhmksfluoirfbnsu
|
||||
o
|
||||
cgawpdakaszeafdtbdkqtlzkrpnoqomqvuaqcfmzgvfegovtfaonelpv
|
||||
izmrcjlk
|
||||
xmzemniyrzy
|
||||
knqexaafsdlimdamcrprlshq
|
||||
qkmqw
|
||||
dntgjwsibclvposdwjuklvtejjjdjibgpyynqpgprvvaetshhmvfkcpb
|
||||
otvazkrkklrxfotpopyjte
|
||||
fghkcnpi
|
||||
rulyaihsowvcgbzeiblhuhhfbmncqsuuqcxvseorn
|
||||
exirzfmojnxcoqom
|
||||
zsgpgtokun
|
||||
zvamxfocorganbtlafifwdqmqtsnktbwwtewborq
|
||||
|
||||
cxlnaspjqvsitjyzyriqsuorjsrvzqenisprttudxntsbqrpjtdkxnwcwgjyxmgtqljcrmrbrmyvosojzlumcmjcgfjsdehec
|
||||
mvx
|
||||
mt
|
||||
mckr
|
||||
teulvroifk
|
||||
laaicc
|
||||
koufy
|
||||
bexmwsvyarnznebdfy
|
||||
ripvviosbqijsxnjilwddaqaqemzsdarnxmfooxghoypizwtbueo
|
||||
ljycycuqwfnzbambibqdixmkkvwtubepla
|
||||
cis
|
||||
kcg
|
||||
vmbbiuuoamenzepuagpfujevfstqtndjxjchdvycfrrrowochtjdmkklgnhf
|
||||
pmorrwguxkvdxpluatagaziin
|
||||
|
||||
uwvzbmkmykjkmknzppklx
|
||||
pnzxuvsrjunqxercsnvayhykcazdeclomdsasgkpqpiufyfqsxhj
|
||||
yceizkddwojgweegcllaagpvrpo
|
||||
ek
|
||||
kuxxgbezqyxvfaxdwnqdgqsmneijunxzlwxkrs
|
||||
ldldbrxmvtjlqxifngmactzqcygkvuteffcmvphevilabgukatqakamjlridznodcvblvlogulmcixxfimh
|
||||
iuzjootuywjqklolzzhpeaynydjwtufjavbozxnzckuzdodkvkjfmhinelv
|
||||
swlfkcufscfcovmghqwcrtxjukwafoeogrkgubbqgwzm
|
||||
gjcylkwgzroubdssuqeykqjcmguso
|
||||
fzq
|
||||
srfvysoxtlylctp
|
||||
|
||||
pbfeiuzwoyixews
|
||||
ocvvunfsjnrtklmuuzjojw
|
||||
xdjcnrpqhmpmpcwacpcdtmbsczvhllkqapzjuaf
|
||||
nfnuvjz
|
||||
fwnuiyqpn
|
||||
wshxxxpzzxp
|
||||
hibrxcfeqca
|
||||
|
||||
wqhlllarl
|
||||
bukcbojv
|
||||
plrytapy
|
||||
xm
|
||||
vlgfqoyzdczqbbaxjwbjjevjhxgopuqvqcrj
|
||||
vpjqfbdnsdxlbuuiqocvrhap
|
||||
mgumjbvnnzgnrdru
|
||||
gcgzugazxdcamrhczfzhtmdjj
|
||||
uislwq
|
||||
vooai
|
||||
zjuqfmebuzsqngzekyajujkopvayxtdzvugwwucvlsbrnhitfotmhhmgddlzlvqrkcponictrfweuilfjiuoabkfdvpjiqjrrgi
|
||||
aptjfhmrnxaq
|
||||
hbs
|
||||
w
|
||||
mwmoxqvucwygunplzvxtxpk
|
||||
fgmqmtlorfzytjdzffsosfccnfwugrsrynuej
|
||||
rpmpenrhsxoefnblyumjqwvuyszyppnttuyvazjdug
|
||||
zdzxraxkroknkmqgvuoqeqdtvclsvvuwmdwzfugcpteohlogxubyoebvrzbqzklvehfcqadtdrkpubfhmokzwyosogepwragcpwxo
|
||||
ax
|
||||
dz
|
||||
de
|
||||
|
||||
thvkdmnbdws
|
||||
|
||||
ejmubw
|
||||
umvwkaubzurf
|
||||
wyxtxeluaoox
|
||||
wwbioobtgmkebxo
|
||||
miglgnafmdarzkeblyjctuayzyoeqnfnbtrcbymdzkzg
|
||||
loavxq
|
||||
kzhllgsenxlbgdbfzwbg
|
||||
yxflogzsohlcycbyzegeubfflouvtuatixhjvicjegltjiy
|
||||
jigqfjppafdiarc
|
||||
mcnmwtachgearonfcymvjbrnljjxmlzkudvzqsarnfysmxlfrtlvjxwvpdbhvwysnvcdozfcruhjwnucdzakkilmlfgjiolcatpfusm
|
||||
|
||||
n
|
||||
pdjunfcz
|
||||
dc
|
||||
edxkkxabsbvmvifiinnoccki
|
||||
bc
|
||||
gwtwsvorwzfqpz
|
||||
exidmexstfflkhi
|
||||
s
|
||||
s
|
||||
c
|
||||
wtcjfywlayhpbqktcepoybowtkrmnumqsg
|
||||
ozclkgjdmdk
|
||||
jmegtbunyexurvfexhqptnqzie
|
||||
tkoenpagzwqfawlxvzaijsjqhmg
|
||||
swodqfjpdqcbkc
|
||||
ujokogocyaygdibgpglecis
|
||||
shlmdmgonvpuaxlhrymkxtiytmv
|
||||
brhk
|
||||
jmsyiuomiywxhegilycjprkyfgojdo
|
||||
|
||||
wzdzrgpdiosdsvkcw
|
||||
odlnmsfnjrcsnflviwvawybpczdkzvdocpwrmavz
|
||||
p
|
||||
ubowamlskcqhdxuckrxa
|
||||
fawhntiwhmdwkddnahmtajqqazpdygttqivhdiodkcpcwv
|
||||
gmxujmmaufmbipaiulhurzkfdg
|
||||
eixjhmbaeoybiwk
|
||||
kumntgrgiofcmujlzbcopuobambsw
|
||||
mnjkqiyb
|
||||
iktwnsnv
|
||||
hfuzcl
|
||||
tqiyqvagbqgtowpjbedgjot
|
||||
dfemvamelxadkztogliizdtsddoboafawficudlefo
|
||||
raecmxiiibljryswntpfed
|
||||
mbwrtsebkeegw
|
||||
x
|
||||
epp
|
||||
he
|
||||
|
||||
vnztrswhiusokqdkmsnpuswucvfhcthjbtam
|
||||
baxlwidsgbdpzvnlj
|
||||
tcbjjoadrzo
|
||||
aiidahyllzzsg
|
||||
|
||||
igebuubweicbssgddpmqxunrawavuglmpxrtkqsvjjtscibqiejjfgfnovokodmqcqitlteiakooupvzkwucucrfdzjvjbqbkgutoybmpfvhbutigdxhfiqfplyciz
|
||||
cnrhbjdnjftwfwlwzrdkwhajgsizsi
|
||||
qfntnt
|
||||
okqyfnbresp
|
||||
asyg
|
||||
mjqdkdyggdxzwuzglays
|
||||
h
|
||||
ifaqcazoy
|
||||
fol
|
||||
vvsusbnugduxsceozmsarbp
|
||||
epjwtorx
|
||||
bwiuxxiyc
|
||||
cw
|
||||
bwogruhctwkfvbexjnwircykxyzjmats
|
||||
kygiochfwlpsvmxcgmtjrgvfdptd
|
||||
q
|
||||
qmpqe
|
||||
|
||||
z
|
||||
jghffhqfoecmszunhxmzmzhlmbrvjabhrkihgjmvckhkfpaygjkg
|
||||
|
||||
kfiyfgounmhlvhupswqdgws
|
||||
ezzdpyqucqoocsdcjtruqpokldfkmjhqzoynirybsifyaxnaxppthjoqy
|
||||
nwetlgzwrhkhtuubbkbepuhbllxspvagxrqokwnrhkbwdwtp
|
||||
hlazomrhqogoaxypqaszwfxxmutvbpuuvpdffuqskcbzlwyzcssnflkwiydoveyxjnzllzhyozbsa
|
||||
hwnitkwbxcyibbqsluuqywbk
|
||||
|
||||
ozpfjsdrc
|
||||
yoepefuy
|
||||
lvmspzepnetra
|
||||
genbrcrmuqfvkaouvuymoxhcxotjjhk
|
||||
pcshyqgbmqdubsdajnyfqvxkqvywffzn
|
||||
ukhcbyzwslqeq
|
||||
otfrmcbnhbyffxqregqoufdxucjunwdhlqqeiiawbxlpqeyzzopfungrryqdykgizrhqodirvazm
|
||||
dhpfhzyq
|
||||
cloz
|
||||
eduupqifolfekve
|
||||
qiec
|
||||
ishnjukvomntmdthlkajxpiwk
|
||||
y
|
||||
axl
|
||||
tmyskjqkjsvumizlal
|
||||
wvvolwewsfxhhdieuagdcuhwsgqvswpbkdkpxskloalmr
|
||||
ryfmhe
|
||||
z
|
||||
mmbpgsyrfvzdatbjrjhuipwt
|
||||
llzwizmmuulgwocowwmugtaoewkhnqxparvtynlffffdfcocdbba
|
||||
|
||||
pyczkzbmcgrdnxnmezsx
|
||||
gsqe
|
||||
mcocxcolcynhpecstsn
|
||||
opnpplkccobjuhtbhirpzfxuktmpsiwbvsgiaavvdge
|
||||
wpaldxzasnrbvtugjwytvtfttrh
|
||||
zxecurevkjiyxy
|
||||
wtnovebcmglkktic
|
||||
fdpwfgvlvovxrwh
|
||||
bmwgdullzy
|
||||
uzwhagxinwqifxjbcntqzqoxkmpqxhe
|
||||
jrfizsnwxwnnhb
|
||||
inapddlahrp
|
||||
|
||||
ndtvkceobe
|
||||
buskgghihdjmjlwfc
|
||||
j
|
||||
rkvffxwtmzoeruhlsurwtnuh
|
||||
cbvkhfepkdishfpqvijzrpleuy
|
||||
jzdpxjhcgqnybssfegvrnpgyehdqpgjwudbwrjbavp
|
||||
xzzvgqdrdwajmdmj
|
||||
vfatwsxvwfdbdhnijdujoyotwvwjipuuetichcfmvgrsnjpqaaezjtkvc
|
||||
lbfoqgfshrtwgdqufwnfuitdrjydqctqixlzufkdbp
|
||||
zgau
|
||||
qefdpmtkecvtj
|
||||
kuphldkvnzdtpd
|
||||
dti
|
||||
fpd
|
||||
gfrliyegxsb
|
||||
i
|
||||
qsddsrmkyfgzrjeqnitmnypbcakh
|
||||
vfbvbrpuogzhzrbmklvhji
|
||||
nkz
|
||||
xlufbaoblbmeub
|
||||
alwuzxzmobwdukvwnkiwmuqhuxfhevogdnqtmxjptqznrk
|
||||
cngpoty
|
||||
|
||||
ms
|
||||
qvenfg
|
||||
dmeaffm
|
||||
jycfgnanbmoamhmarkmjcagbp
|
||||
ysqmbhopgx
|
||||
jczbzgwedsp
|
||||
|
||||
zxzwjrxcwdtleizjlvifjwgxiibezwxhtzywqdi
|
||||
mtgnlu
|
||||
xboxirdchurkfnklnpkapnqfxnhrxyseiujrznjm
|
||||
|
||||
zm
|
||||
atddskbghcahlhql
|
||||
szshwzmmvu
|
||||
befdtpouamwhiisyybispkchpjhownatawjfbx
|
||||
|
||||
ennkzbrlygd
|
||||
zbt
|
||||
upphzpdwzmlhhhbqvjsfmbnrar
|
||||
ddcs
|
||||
ipbxgzyudjyongtcyygncojdufnufqpdppgvq
|
||||
gc
|
||||
isu
|
||||
foa
|
||||
wf
|
||||
jdlvqxgfbowhohhyyngbcs
|
||||
zjuwjyucdwblatsnywaaoftlcamfbcnw
|
||||
lzrioesuhoeevczuwrnltmkahfwiu
|
||||
uicggfbddqltnjyxfltbnaekncnyxsit
|
||||
zkxsqkqrwrzrxgxbsgxatybfr
|
||||
|
||||
ptvmfyxdcglbfipcguqthjygzqnpqssscukzawynidtchjrrxwuxifoe
|
||||
w
|
||||
ohu
|
||||
vg
|
||||
zagpowezvbniybgold
|
||||
lhqseqcxteiqtgnpanpvrmvvlltxh
|
||||
mtfnxn
|
||||
wyodtg
|
||||
|
||||
rawpbgtpbaktqzmmpzxmrlwpvvmdsl
|
||||
widcfbirvswraukbmkhf
|
||||
vplrueuxomjkqrtjgyxjdkexttzyozawyq
|
||||
hrpbahllznvmjudzxpbbv
|
||||
tlavfrxygjfipkupwnbacltcfepeg
|
||||
icu
|
||||
otxcu
|
||||
aewazy
|
||||
hl
|
||||
|
||||
fmrp
|
||||
qaacthwzohenzjr
|
||||
xbyebba
|
||||
rvkph
|
||||
mkhhmh
|
||||
swme
|
||||
zjmdoypaktglcyzobquunvthcdwegtbywpijxd
|
||||
jvkuhnxqc
|
||||
gibhqgjojsxt
|
||||
bodbktzomiqujtbstqiyquwvqgufphqstenxvddkvtdh
|
||||
bpusrxkfi
|
||||
zgp
|
||||
pmxvgamydyakituvvsucsuidrlznupcsinltmrahulhepxmhoqtfvpjkxzhrrinncuh
|
||||
jzgkjjhjqykzelaszvcwvvwbnzsxdeaerfnaravk
|
||||
ynanrqyrxo
|
||||
zsmuxofullob
|
||||
brklgrcqefdyoczy
|
||||
qkpls
|
||||
snhqumae
|
||||
iqdtzjadzzvnqvdvjfsaf
|
||||
nfqfdqiramueblxkaqxbbkxwywzgdbndjjiqk
|
||||
tc
|
||||
kp
|
||||
cpuckbjsxhtxmomfesgxdpz
|
||||
oseif
|
||||
ybhxbvyxrpkrexrhjzoaxxohrhsniewsrktjnaztn
|
||||
ggelspdzhzbchruhbjbjidgjwdlhdycetqaswh
|
||||
jkgivsngygkbqtlmoj
|
||||
dwpnanfvitxg
|
||||
ospxbwxp
|
||||
wgvmvrnjescemdoiralbkvemalifxnyhrbdgodml
|
||||
hjtsnkzknkplbzsiwmneefdkihnhsamjsrxggclyjqgpqltizi
|
||||
|
||||
|
||||
sykgbuypwwhweab
|
||||
nvdkkkskmtiwpoerkon
|
||||
sx
|
||||
sbyflwwiqylbskdlxesmylpaz
|
||||
dnwcjenaluwesyywfaezznwkdwpoesxpu
|
||||
kie
|
||||
dslccwfryol
|
||||
gfhomgfn
|
||||
zprjtfqvkotktzidmoyrivall
|
||||
bunvsqkysdelozemnjoeqfolruulpbipm
|
||||
ullyzfahpkhkja
|
||||
hwd
|
||||
kvyqtprpuulgsk
|
||||
zotbkcadnxmfvqmtlbxalhughceyfcibtzzj
|
||||
vvpjbgxygl
|
||||
hpic
|
||||
mhrqd
|
||||
dv
|
||||
thehuzdbaacoidjoljbysnqwrrxxplrdznmgiukkvjqbopb
|
||||
moszjt
|
||||
rmtbunktkywqirveeqfa
|
||||
kse
|
||||
wbfflnatgzobjrxghjgvcsyxoruenxhyomutbptswjajawqjpqafpdcstkiyjuilimecgejpqmyciolgcmdpcstzdozbmnza
|
11
third_party/rust/aho-corasick-0.6.2/ctags.rust
vendored
11
third_party/rust/aho-corasick-0.6.2/ctags.rust
vendored
@ -1,11 +0,0 @@
|
||||
--langdef=Rust
|
||||
--langmap=Rust:.rs
|
||||
--regex-Rust=/^[ \t]*(#\[[^\]]\][ \t]*)*(pub[ \t]+)?(extern[ \t]+)?("[^"]+"[ \t]+)?(unsafe[ \t]+)?fn[ \t]+([a-zA-Z0-9_]+)/\6/f,functions,function definitions/
|
||||
--regex-Rust=/^[ \t]*(pub[ \t]+)?type[ \t]+([a-zA-Z0-9_]+)/\2/T,types,type definitions/
|
||||
--regex-Rust=/^[ \t]*(pub[ \t]+)?enum[ \t]+([a-zA-Z0-9_]+)/\2/g,enum,enumeration names/
|
||||
--regex-Rust=/^[ \t]*(pub[ \t]+)?struct[ \t]+([a-zA-Z0-9_]+)/\2/s,structure names/
|
||||
--regex-Rust=/^[ \t]*(pub[ \t]+)?mod[ \t]+([a-zA-Z0-9_]+)/\2/m,modules,module names/
|
||||
--regex-Rust=/^[ \t]*(pub[ \t]+)?static[ \t]+([a-zA-Z0-9_]+)/\2/c,consts,static constants/
|
||||
--regex-Rust=/^[ \t]*(pub[ \t]+)?trait[ \t]+([a-zA-Z0-9_]+)/\2/t,traits,traits/
|
||||
--regex-Rust=/^[ \t]*(pub[ \t]+)?impl([ \t\n]+<.*>)?[ \t]+([a-zA-Z0-9_]+)/\3/i,impls,trait implementations/
|
||||
--regex-Rust=/^[ \t]*macro_rules![ \t]+([a-zA-Z0-9_]+)/\1/d,macros,macro definitions/
|
@ -1,151 +0,0 @@
|
||||
// This example demonstrates how to use the Aho-Corasick algorithm to rapidly
|
||||
// scan text for matches in a large dictionary of keywords. This example by
|
||||
// default reads your system's dictionary (~120,000 words).
|
||||
extern crate aho_corasick;
|
||||
extern crate csv;
|
||||
extern crate docopt;
|
||||
extern crate memmap;
|
||||
extern crate rustc_serialize;
|
||||
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead, Write};
|
||||
use std::process;
|
||||
|
||||
use aho_corasick::{Automaton, AcAutomaton, Match};
|
||||
use docopt::Docopt;
|
||||
use memmap::{Mmap, Protection};
|
||||
|
||||
static USAGE: &'static str = "
|
||||
Usage: dict-search [options] <input>
|
||||
dict-search --help
|
||||
|
||||
Options:
|
||||
-d <path>, --dict <path> Path to dictionary of keywords to search.
|
||||
[default: /usr/share/dict/words]
|
||||
-m <len>, --min-len <len> The minimum length for a keyword in UTF-8
|
||||
encoded bytes. [default: 5]
|
||||
--overlapping Report overlapping matches.
|
||||
-c, --count Show only the numebr of matches.
|
||||
--memory-usage Show memory usage of automaton.
|
||||
--full Use fully expanded transition matrix.
|
||||
Warning: may use lots of memory.
|
||||
-h, --help Show this usage message.
|
||||
";
|
||||
|
||||
#[derive(Clone, Debug, RustcDecodable)]
|
||||
struct Args {
|
||||
arg_input: String,
|
||||
flag_dict: String,
|
||||
flag_min_len: usize,
|
||||
flag_overlapping: bool,
|
||||
flag_memory_usage: bool,
|
||||
flag_full: bool,
|
||||
flag_count: bool,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Args = Docopt::new(USAGE)
|
||||
.and_then(|d| d.decode())
|
||||
.unwrap_or_else(|e| e.exit());
|
||||
match run(&args) {
|
||||
Ok(()) => {}
|
||||
Err(err) => {
|
||||
writeln!(&mut io::stderr(), "{}", err).unwrap();
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run(args: &Args) -> Result<(), Box<Error>> {
|
||||
let aut = try!(build_automaton(&args.flag_dict, args.flag_min_len));
|
||||
if args.flag_memory_usage {
|
||||
let (bytes, states) = if args.flag_full {
|
||||
let aut = aut.into_full();
|
||||
(aut.heap_bytes(), aut.num_states())
|
||||
} else {
|
||||
(aut.heap_bytes(), aut.num_states())
|
||||
};
|
||||
println!("{} bytes, {} states", bytes, states);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if args.flag_full {
|
||||
let aut = aut.into_full();
|
||||
if args.flag_overlapping {
|
||||
if args.flag_count {
|
||||
let mmap = Mmap::open_path(
|
||||
&args.arg_input, Protection::Read).unwrap();
|
||||
let text = unsafe { mmap.as_slice() };
|
||||
println!("{}", aut.find_overlapping(text).count());
|
||||
} else {
|
||||
let rdr = try!(File::open(&args.arg_input));
|
||||
try!(write_matches(&aut, aut.stream_find_overlapping(rdr)));
|
||||
}
|
||||
} else {
|
||||
if args.flag_count {
|
||||
let mmap = Mmap::open_path(
|
||||
&args.arg_input, Protection::Read).unwrap();
|
||||
let text = unsafe { mmap.as_slice() };
|
||||
println!("{}", aut.find(text).count());
|
||||
} else {
|
||||
let rdr = try!(File::open(&args.arg_input));
|
||||
try!(write_matches(&aut, aut.stream_find(rdr)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if args.flag_overlapping {
|
||||
if args.flag_count {
|
||||
let mmap = Mmap::open_path(
|
||||
&args.arg_input, Protection::Read).unwrap();
|
||||
let text = unsafe { mmap.as_slice() };
|
||||
println!("{}", aut.find_overlapping(text).count());
|
||||
} else {
|
||||
let rdr = try!(File::open(&args.arg_input));
|
||||
try!(write_matches(&aut, aut.stream_find_overlapping(rdr)));
|
||||
}
|
||||
} else {
|
||||
if args.flag_count {
|
||||
let mmap = Mmap::open_path(
|
||||
&args.arg_input, Protection::Read).unwrap();
|
||||
let text = unsafe { mmap.as_slice() };
|
||||
println!("{}", aut.find(text).count());
|
||||
} else {
|
||||
let rdr = try!(File::open(&args.arg_input));
|
||||
try!(write_matches(&aut, aut.stream_find(rdr)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_matches<A, I>(aut: &A, it: I) -> Result<(), Box<Error>>
|
||||
where A: Automaton<String>, I: Iterator<Item=io::Result<Match>> {
|
||||
let mut wtr = csv::Writer::from_writer(io::stdout());
|
||||
try!(wtr.write(["pattern", "start", "end"].iter()));
|
||||
for m in it {
|
||||
let m = try!(m);
|
||||
try!(wtr.write([
|
||||
aut.pattern(m.pati),
|
||||
&m.start.to_string(),
|
||||
&m.end.to_string(),
|
||||
].iter()));
|
||||
}
|
||||
try!(wtr.flush());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_automaton(
|
||||
dict_path: &str,
|
||||
min_len: usize,
|
||||
) -> Result<AcAutomaton<String>, Box<Error>> {
|
||||
let buf = io::BufReader::new(try!(File::open(dict_path)));
|
||||
let mut lines = Vec::with_capacity(1 << 10);
|
||||
for line in buf.lines() {
|
||||
let line = try!(line);
|
||||
if line.len() >= min_len {
|
||||
lines.push(line);
|
||||
}
|
||||
}
|
||||
Ok(AcAutomaton::with_transitions(lines))
|
||||
}
|
@ -1 +0,0 @@
|
||||
au BufWritePost *.rs silent!make ctags > /dev/null 2>&1
|
503
third_party/rust/aho-corasick-0.6.2/src/autiter.rs
vendored
503
third_party/rust/aho-corasick-0.6.2/src/autiter.rs
vendored
@ -1,503 +0,0 @@
|
||||
use std::io::{self, BufRead};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use memchr::{memchr, memchr2, memchr3};
|
||||
|
||||
use super::{ROOT_STATE, StateIdx};
|
||||
|
||||
/// An abstraction over automatons and their corresponding iterators.
|
||||
/// The type parameter `P` is the type of the pattern that was used to
|
||||
/// construct this Automaton.
|
||||
pub trait Automaton<P> {
|
||||
/// Return the next state given the current state and next character.
|
||||
fn next_state(&self, si: StateIdx, b: u8) -> StateIdx;
|
||||
|
||||
/// Return true if and only if the given state and current pattern index
|
||||
/// indicate a match.
|
||||
fn has_match(&self, si: StateIdx, outi: usize) -> bool;
|
||||
|
||||
/// Build a match given the current state, pattern index and input index.
|
||||
fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match;
|
||||
|
||||
/// Return the set of bytes that have transitions in the root state.
|
||||
fn start_bytes(&self) -> &[u8];
|
||||
|
||||
/// Returns all of the patterns matched by this automaton.
|
||||
///
|
||||
/// The order of the patterns is the order in which they were added.
|
||||
fn patterns(&self) -> &[P];
|
||||
|
||||
/// Returns the pattern indexed at `i`.
|
||||
///
|
||||
/// The index corresponds to the position at which the pattern was added
|
||||
/// to the automaton, starting at `0`.
|
||||
fn pattern(&self, i: usize) -> &P;
|
||||
|
||||
/// Return the number of patterns in the automaton.
|
||||
#[inline]
|
||||
fn len(&self) -> usize {
|
||||
self.patterns().len()
|
||||
}
|
||||
|
||||
/// Returns true if the automaton has no patterns.
|
||||
#[inline]
|
||||
fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Returns an iterator of non-overlapping matches in `s`.
|
||||
fn find<'a, 's, Q: ?Sized + AsRef<[u8]>>(
|
||||
&'a self,
|
||||
s: &'s Q,
|
||||
) -> Matches<'a, 's, P, Self>
|
||||
where Self: Sized {
|
||||
Matches {
|
||||
aut: self,
|
||||
text: s.as_ref(),
|
||||
texti: 0,
|
||||
si: ROOT_STATE,
|
||||
_m: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator of overlapping matches in `s`.
|
||||
fn find_overlapping<'a, 's, Q: ?Sized + AsRef<[u8]>>(
|
||||
&'a self,
|
||||
s: &'s Q,
|
||||
) -> MatchesOverlapping<'a, 's, P, Self>
|
||||
where Self: Sized {
|
||||
MatchesOverlapping {
|
||||
aut: self,
|
||||
text: s.as_ref(),
|
||||
texti: 0,
|
||||
si: ROOT_STATE,
|
||||
outi: 0,
|
||||
_m: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator of non-overlapping matches in the given reader.
|
||||
fn stream_find<'a, R: io::Read>(
|
||||
&'a self,
|
||||
rdr: R,
|
||||
) -> StreamMatches<'a, R, P, Self>
|
||||
where Self: Sized {
|
||||
StreamMatches {
|
||||
aut: self,
|
||||
buf: io::BufReader::new(rdr),
|
||||
texti: 0,
|
||||
si: ROOT_STATE,
|
||||
_m: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator of overlapping matches in the given reader.
|
||||
fn stream_find_overlapping<'a, R: io::Read>(
|
||||
&'a self,
|
||||
rdr: R,
|
||||
) -> StreamMatchesOverlapping<'a, R, P, Self>
|
||||
where Self: Sized {
|
||||
StreamMatchesOverlapping {
|
||||
aut: self,
|
||||
buf: io::BufReader::new(rdr),
|
||||
texti: 0,
|
||||
si: ROOT_STATE,
|
||||
outi: 0,
|
||||
_m: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, P: AsRef<[u8]>, A: 'a + Automaton<P> + ?Sized>
|
||||
Automaton<P> for &'a A {
|
||||
fn next_state(&self, si: StateIdx, b: u8) -> StateIdx {
|
||||
(**self).next_state(si, b)
|
||||
}
|
||||
|
||||
fn has_match(&self, si: StateIdx, outi: usize) -> bool {
|
||||
(**self).has_match(si, outi)
|
||||
}
|
||||
|
||||
fn start_bytes(&self) -> &[u8] {
|
||||
(**self).start_bytes()
|
||||
}
|
||||
|
||||
fn patterns(&self) -> &[P] {
|
||||
(**self).patterns()
|
||||
}
|
||||
|
||||
fn pattern(&self, i: usize) -> &P {
|
||||
(**self).pattern(i)
|
||||
}
|
||||
|
||||
fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match {
|
||||
(**self).get_match(si, outi, texti)
|
||||
}
|
||||
}
|
||||
|
||||
/// Records a match in the search text.
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct Match {
|
||||
/// The pattern index.
|
||||
///
|
||||
/// This corresponds to the ordering in which the matched pattern was
|
||||
/// added to the automaton, starting at `0`.
|
||||
pub pati: usize,
|
||||
/// The starting byte offset of the match in the search text.
|
||||
pub start: usize,
|
||||
/// The ending byte offset of the match in the search text.
|
||||
///
|
||||
/// (This can be re-captiulated with `pati` and adding the pattern's
|
||||
/// length to `start`, but it is convenient to have it here.)
|
||||
pub end: usize,
|
||||
}
|
||||
|
||||
/// An iterator of non-overlapping matches for in-memory text.
|
||||
///
|
||||
/// This iterator yields `Match` values.
|
||||
///
|
||||
/// `'a` is the lifetime of the automaton, `'s` is the lifetime of the
|
||||
/// search text, and `P` is the type of the Automaton's pattern.
|
||||
#[derive(Debug)]
|
||||
pub struct Matches<'a, 's, P, A: 'a + Automaton<P> + ?Sized> {
|
||||
aut: &'a A,
|
||||
text: &'s [u8],
|
||||
texti: usize,
|
||||
si: StateIdx,
|
||||
_m: PhantomData<P>,
|
||||
}
|
||||
|
||||
// When there's an initial lone start byte, it is usually worth it
|
||||
// to use `memchr` to skip along the input. The problem is that
|
||||
// the skipping function is called in the inner match loop, which
|
||||
// can be quite costly if the skipping condition is never met.
|
||||
// Therefore, we lift the case analysis outside of the inner loop at
|
||||
// the cost of repeating code.
|
||||
//
|
||||
// `step_to_match` is the version of the inner loop without skipping,
|
||||
// and `skip_to_match` is the version with skipping.
|
||||
#[inline(never)]
|
||||
fn step_to_match<P, A: Automaton<P> + ?Sized>(
|
||||
aut: &A,
|
||||
text: &[u8],
|
||||
mut texti: usize,
|
||||
mut si: StateIdx
|
||||
) -> Option<(usize, StateIdx)> {
|
||||
while texti < text.len() {
|
||||
si = aut.next_state(si, text[texti]);
|
||||
if aut.has_match(si, 0) {
|
||||
return Some((texti, si));
|
||||
}
|
||||
texti += 1;
|
||||
if texti + 4 < text.len() {
|
||||
si = aut.next_state(si, text[texti]);
|
||||
if aut.has_match(si, 0) {
|
||||
return Some((texti, si));
|
||||
}
|
||||
texti += 1;
|
||||
si = aut.next_state(si, text[texti]);
|
||||
if aut.has_match(si, 0) {
|
||||
return Some((texti, si));
|
||||
}
|
||||
texti += 1;
|
||||
si = aut.next_state(si, text[texti]);
|
||||
if aut.has_match(si, 0) {
|
||||
return Some((texti, si));
|
||||
}
|
||||
texti += 1;
|
||||
si = aut.next_state(si, text[texti]);
|
||||
if aut.has_match(si, 0) {
|
||||
return Some((texti, si));
|
||||
}
|
||||
texti += 1;
|
||||
si = aut.next_state(si, text[texti]);
|
||||
if aut.has_match(si, 0) {
|
||||
return Some((texti, si));
|
||||
}
|
||||
texti += 1;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn skip_to_match<P, A: Automaton<P> + ?Sized, F: Fn(&A, &[u8], usize) -> usize>(
|
||||
aut: &A,
|
||||
text: &[u8],
|
||||
mut texti: usize,
|
||||
mut si: StateIdx,
|
||||
skip: F,
|
||||
) -> Option<(usize, StateIdx)> {
|
||||
if si == ROOT_STATE {
|
||||
texti = skip(aut, text, texti);
|
||||
}
|
||||
while texti < text.len() {
|
||||
si = aut.next_state(si, text[texti]);
|
||||
if aut.has_match(si, 0) {
|
||||
return Some((texti, si));
|
||||
}
|
||||
if si == ROOT_STATE {
|
||||
texti = skip(aut, text, texti + 1);
|
||||
} else {
|
||||
texti += 1;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn skip1<P, A: Automaton<P> + ?Sized>(
|
||||
aut: &A,
|
||||
text: &[u8],
|
||||
at: usize,
|
||||
) -> usize {
|
||||
debug_assert!(aut.start_bytes().len() == 1);
|
||||
let b = aut.start_bytes()[0];
|
||||
match memchr(b, &text[at..]) {
|
||||
None => text.len(),
|
||||
Some(i) => at + i,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn skip2<P, A: Automaton<P> + ?Sized>(
|
||||
aut: &A,
|
||||
text: &[u8],
|
||||
at: usize,
|
||||
) -> usize {
|
||||
debug_assert!(aut.start_bytes().len() == 2);
|
||||
let (b1, b2) = (aut.start_bytes()[0], aut.start_bytes()[1]);
|
||||
match memchr2(b1, b2, &text[at..]) {
|
||||
None => text.len(),
|
||||
Some(i) => at + i,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn skip3<P, A: Automaton<P> + ?Sized>(
|
||||
aut: &A,
|
||||
text: &[u8],
|
||||
at: usize,
|
||||
) -> usize {
|
||||
debug_assert!(aut.start_bytes().len() == 3);
|
||||
let (b1, b2, b3) = (
|
||||
aut.start_bytes()[0], aut.start_bytes()[1], aut.start_bytes()[2],
|
||||
);
|
||||
match memchr3(b1, b2, b3, &text[at..]) {
|
||||
None => text.len(),
|
||||
Some(i) => at + i,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 's, P, A: Automaton<P> + ?Sized> Iterator for Matches<'a, 's, P, A> {
|
||||
type Item = Match;
|
||||
|
||||
fn next(&mut self) -> Option<Match> {
|
||||
if self.aut.start_bytes().len() == 1 {
|
||||
let skip = skip_to_match(
|
||||
self.aut, self.text, self.texti, self.si, skip1);
|
||||
if let Some((texti, si)) = skip {
|
||||
self.texti = texti + 1;
|
||||
self.si = ROOT_STATE;
|
||||
return Some(self.aut.get_match(si, 0, texti));
|
||||
}
|
||||
} else if self.aut.start_bytes().len() == 2 {
|
||||
let skip = skip_to_match(
|
||||
self.aut, self.text, self.texti, self.si, skip2);
|
||||
if let Some((texti, si)) = skip {
|
||||
self.texti = texti + 1;
|
||||
self.si = ROOT_STATE;
|
||||
return Some(self.aut.get_match(si, 0, texti));
|
||||
}
|
||||
} else if self.aut.start_bytes().len() == 3 {
|
||||
let skip = skip_to_match(
|
||||
self.aut, self.text, self.texti, self.si, skip3);
|
||||
if let Some((texti, si)) = skip {
|
||||
self.texti = texti + 1;
|
||||
self.si = ROOT_STATE;
|
||||
return Some(self.aut.get_match(si, 0, texti));
|
||||
}
|
||||
} else {
|
||||
let step = step_to_match(self.aut, self.text, self.texti, self.si);
|
||||
if let Some((texti, si)) = step {
|
||||
self.texti = texti + 1;
|
||||
self.si = ROOT_STATE;
|
||||
return Some(self.aut.get_match(si, 0, texti));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator of non-overlapping matches for streaming text.
|
||||
///
|
||||
/// This iterator yields `io::Result<Match>` values.
|
||||
///
|
||||
/// `'a` is the lifetime of the automaton, `R` is the type of the underlying
|
||||
/// `io::Read`er, and P is the type of the Automaton's pattern.
|
||||
#[derive(Debug)]
|
||||
pub struct StreamMatches<'a, R, P, A: 'a + Automaton<P> + ?Sized> {
|
||||
aut: &'a A,
|
||||
buf: io::BufReader<R>,
|
||||
texti: usize,
|
||||
si: StateIdx,
|
||||
_m: PhantomData<P>,
|
||||
}
|
||||
|
||||
impl<'a, R: io::Read, P, A: Automaton<P>>
|
||||
Iterator for StreamMatches<'a, R, P, A> {
|
||||
type Item = io::Result<Match>;
|
||||
|
||||
fn next(&mut self) -> Option<io::Result<Match>> {
|
||||
let mut m = None;
|
||||
let mut consumed = 0;
|
||||
'LOOP: loop {
|
||||
self.buf.consume(consumed);
|
||||
let bs = match self.buf.fill_buf() {
|
||||
Err(err) => return Some(Err(err)),
|
||||
Ok(bs) if bs.len() == 0 => break,
|
||||
Ok(bs) => bs,
|
||||
};
|
||||
consumed = bs.len(); // is shortened if we find a match
|
||||
for (i, &b) in bs.iter().enumerate() {
|
||||
self.si = self.aut.next_state(self.si, b);
|
||||
if self.aut.has_match(self.si, 0) {
|
||||
m = Some(Ok(self.aut.get_match(self.si, 0, self.texti)));
|
||||
consumed = i + 1;
|
||||
self.texti += 1;
|
||||
self.si = ROOT_STATE;
|
||||
break 'LOOP;
|
||||
}
|
||||
self.texti += 1;
|
||||
}
|
||||
}
|
||||
self.buf.consume(consumed);
|
||||
m
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator of overlapping matches for in-memory text.
|
||||
///
|
||||
/// This iterator yields `Match` values.
|
||||
///
|
||||
/// `'a` is the lifetime of the automaton, `'s` is the lifetime of the
|
||||
/// search text, and `P` is the type of the Automaton's pattern.
|
||||
#[derive(Debug)]
|
||||
pub struct MatchesOverlapping<'a, 's, P, A: 'a + Automaton<P> + ?Sized> {
|
||||
aut: &'a A,
|
||||
text: &'s [u8],
|
||||
texti: usize,
|
||||
si: StateIdx,
|
||||
outi: usize,
|
||||
_m: PhantomData<P>,
|
||||
}
|
||||
|
||||
impl<'a, 's, P, A: Automaton<P> + ?Sized>
|
||||
Iterator for MatchesOverlapping<'a, 's, P, A> {
|
||||
type Item = Match;
|
||||
|
||||
fn next(&mut self) -> Option<Match> {
|
||||
if self.aut.has_match(self.si, self.outi) {
|
||||
let m = self.aut.get_match(self.si, self.outi, self.texti);
|
||||
self.outi += 1;
|
||||
if !self.aut.has_match(self.si, self.outi) {
|
||||
self.texti += 1;
|
||||
}
|
||||
return Some(m);
|
||||
}
|
||||
|
||||
self.outi = 0;
|
||||
if self.aut.start_bytes().len() == 1 {
|
||||
let skip = skip_to_match(
|
||||
self.aut, self.text, self.texti, self.si, skip1);
|
||||
if let Some((texti, si)) = skip {
|
||||
self.texti = texti;
|
||||
self.si = si;
|
||||
return self.next();
|
||||
}
|
||||
} else if self.aut.start_bytes().len() == 2 {
|
||||
let skip = skip_to_match(
|
||||
self.aut, self.text, self.texti, self.si, skip2);
|
||||
if let Some((texti, si)) = skip {
|
||||
self.texti = texti;
|
||||
self.si = si;
|
||||
return self.next();
|
||||
}
|
||||
} else if self.aut.start_bytes().len() == 3 {
|
||||
let skip = skip_to_match(
|
||||
self.aut, self.text, self.texti, self.si, skip3);
|
||||
if let Some((texti, si)) = skip {
|
||||
self.texti = texti;
|
||||
self.si = si;
|
||||
return self.next();
|
||||
}
|
||||
} else {
|
||||
let step = step_to_match(self.aut, self.text, self.texti, self.si);
|
||||
if let Some((texti, si)) = step {
|
||||
self.texti = texti;
|
||||
self.si = si;
|
||||
return self.next();
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator of overlapping matches for streaming text.
|
||||
///
|
||||
/// This iterator yields `io::Result<Match>` values.
|
||||
///
|
||||
/// `'a` is the lifetime of the automaton, `R` is the type of the underlying
|
||||
/// `io::Read`er, and P is the type of the Automaton's pattern.
|
||||
#[derive(Debug)]
|
||||
pub struct StreamMatchesOverlapping<'a, R, P, A: 'a + Automaton<P> + ?Sized> {
|
||||
aut: &'a A,
|
||||
buf: io::BufReader<R>,
|
||||
texti: usize,
|
||||
si: StateIdx,
|
||||
outi: usize,
|
||||
_m: PhantomData<P>,
|
||||
}
|
||||
|
||||
impl<'a, R: io::Read, P, A: Automaton<P> + ?Sized>
|
||||
Iterator for StreamMatchesOverlapping<'a, R, P, A> {
|
||||
type Item = io::Result<Match>;
|
||||
|
||||
fn next(&mut self) -> Option<io::Result<Match>> {
|
||||
if self.aut.has_match(self.si, self.outi) {
|
||||
let m = self.aut.get_match(self.si, self.outi, self.texti);
|
||||
self.outi += 1;
|
||||
if !self.aut.has_match(self.si, self.outi) {
|
||||
self.texti += 1;
|
||||
}
|
||||
return Some(Ok(m));
|
||||
}
|
||||
let mut m = None;
|
||||
let mut consumed = 0;
|
||||
self.outi = 0;
|
||||
'LOOP: loop {
|
||||
self.buf.consume(consumed);
|
||||
let bs = match self.buf.fill_buf() {
|
||||
Err(err) => return Some(Err(err)),
|
||||
Ok(bs) if bs.len() == 0 => break,
|
||||
Ok(bs) => bs,
|
||||
};
|
||||
consumed = bs.len(); // is shortened if we find a match
|
||||
for (i, &b) in bs.iter().enumerate() {
|
||||
self.si = self.aut.next_state(self.si, b);
|
||||
if self.aut.has_match(self.si, self.outi) {
|
||||
m = Some(Ok(self.aut.get_match(
|
||||
self.si, self.outi, self.texti)));
|
||||
consumed = i + 1;
|
||||
self.outi += 1;
|
||||
if !self.aut.has_match(self.si, self.outi) {
|
||||
self.texti += 1;
|
||||
}
|
||||
break 'LOOP;
|
||||
}
|
||||
self.texti += 1;
|
||||
}
|
||||
}
|
||||
self.buf.consume(consumed);
|
||||
m
|
||||
}
|
||||
}
|
136
third_party/rust/aho-corasick-0.6.2/src/full.rs
vendored
136
third_party/rust/aho-corasick-0.6.2/src/full.rs
vendored
@ -1,136 +0,0 @@
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
|
||||
use super::{
|
||||
FAIL_STATE,
|
||||
StateIdx, AcAutomaton, Transitions, Match,
|
||||
usize_bytes, vec_bytes,
|
||||
};
|
||||
use super::autiter::Automaton;
|
||||
|
||||
/// A complete Aho-Corasick automaton.
|
||||
///
|
||||
/// This uses a single transition matrix that permits each input character
|
||||
/// to move to the next state with a single lookup in the matrix.
|
||||
///
|
||||
/// This is as fast as it gets, but it is guaranteed to use a lot of memory.
|
||||
/// Namely, it will use at least `4 * 256 * #states`, where the number of
|
||||
/// states is capped at length of all patterns concatenated.
|
||||
#[derive(Clone)]
|
||||
pub struct FullAcAutomaton<P> {
|
||||
pats: Vec<P>,
|
||||
trans: Vec<StateIdx>, // row-major, where states are rows
|
||||
out: Vec<Vec<usize>>, // indexed by StateIdx
|
||||
start_bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
impl<P: AsRef<[u8]>> FullAcAutomaton<P> {
|
||||
/// Build a new expanded Aho-Corasick automaton from an existing
|
||||
/// Aho-Corasick automaton.
|
||||
pub fn new<T: Transitions>(ac: AcAutomaton<P, T>) -> FullAcAutomaton<P> {
|
||||
let mut fac = FullAcAutomaton {
|
||||
pats: vec![],
|
||||
trans: vec![FAIL_STATE; 256 * ac.states.len()],
|
||||
out: vec![vec![]; ac.states.len()],
|
||||
start_bytes: vec![],
|
||||
};
|
||||
fac.build_matrix(&ac);
|
||||
fac.pats = ac.pats;
|
||||
fac.start_bytes = ac.start_bytes;
|
||||
fac
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn memory_usage(&self) -> usize {
|
||||
self.pats.iter()
|
||||
.map(|p| vec_bytes() + p.as_ref().len())
|
||||
.fold(0, |a, b| a + b)
|
||||
+ (4 * self.trans.len())
|
||||
+ self.out.iter()
|
||||
.map(|v| vec_bytes() + (usize_bytes() * v.len()))
|
||||
.fold(0, |a, b| a + b)
|
||||
+ self.start_bytes.len()
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn heap_bytes(&self) -> usize {
|
||||
self.pats.iter()
|
||||
.map(|p| mem::size_of::<P>() + p.as_ref().len())
|
||||
.fold(0, |a, b| a + b)
|
||||
+ (4 * self.trans.len())
|
||||
+ self.out.iter()
|
||||
.map(|v| vec_bytes() + (usize_bytes() * v.len()))
|
||||
.fold(0, |a, b| a + b)
|
||||
+ self.start_bytes.len()
|
||||
}
|
||||
|
||||
fn set(&mut self, si: StateIdx, i: u8, goto: StateIdx) {
|
||||
let ns = self.num_states();
|
||||
self.trans[i as usize * ns + si as usize] = goto;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
pub fn num_states(&self) -> usize {
|
||||
self.out.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: AsRef<[u8]>> Automaton<P> for FullAcAutomaton<P> {
|
||||
#[inline]
|
||||
fn next_state(&self, si: StateIdx, i: u8) -> StateIdx {
|
||||
let at = i as usize * self.num_states() + si as usize;
|
||||
unsafe { *self.trans.get_unchecked(at) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match {
|
||||
let pati = self.out[si as usize][outi];
|
||||
let patlen = self.pats[pati].as_ref().len();
|
||||
let start = texti + 1 - patlen;
|
||||
Match {
|
||||
pati: pati,
|
||||
start: start,
|
||||
end: start + patlen,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn has_match(&self, si: StateIdx, outi: usize) -> bool {
|
||||
unsafe { outi < self.out.get_unchecked(si as usize).len() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn start_bytes(&self) -> &[u8] {
|
||||
&self.start_bytes
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn patterns(&self) -> &[P] {
|
||||
&self.pats
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pattern(&self, i: usize) -> &P {
|
||||
&self.pats[i]
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: AsRef<[u8]>> FullAcAutomaton<P> {
|
||||
fn build_matrix<T: Transitions>(&mut self, ac: &AcAutomaton<P, T>) {
|
||||
for (si, s) in ac.states.iter().enumerate().skip(1) {
|
||||
for b in (0..256).map(|b| b as u8) {
|
||||
self.set(si as StateIdx, b, ac.next_state(si as StateIdx, b));
|
||||
}
|
||||
for &pati in &s.out {
|
||||
self.out[si].push(pati);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: AsRef<[u8]> + fmt::Debug> fmt::Debug for FullAcAutomaton<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "FullAcAutomaton({:?})", self.pats)
|
||||
}
|
||||
}
|
925
third_party/rust/aho-corasick-0.6.2/src/lib.rs
vendored
925
third_party/rust/aho-corasick-0.6.2/src/lib.rs
vendored
@ -1,925 +0,0 @@
|
||||
/*!
|
||||
An implementation of the
|
||||
[Aho-Corasick string search algorithm](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm).
|
||||
|
||||
The Aho-Corasick algorithm is principally useful when you need to search many
|
||||
large texts for a fixed (possibly large) set of keywords. In particular, the
|
||||
Aho-Corasick algorithm preprocesses the set of keywords by constructing a
|
||||
finite state machine. The search phase is then a quick linear scan through the
|
||||
text. Each character in the search text causes a state transition in the
|
||||
automaton. Matches are reported when the automaton enters a match state.
|
||||
|
||||
# Examples
|
||||
|
||||
The main type exposed by this crate is `AcAutomaton`, which can be constructed
|
||||
from an iterator of pattern strings:
|
||||
|
||||
```rust
|
||||
use aho_corasick::{Automaton, AcAutomaton};
|
||||
|
||||
let aut = AcAutomaton::new(vec!["apple", "maple"]);
|
||||
|
||||
// AcAutomaton also implements `FromIterator`:
|
||||
let aut: AcAutomaton<&str> = ["apple", "maple"].iter().cloned().collect();
|
||||
```
|
||||
|
||||
Finding matches can be done with `find`:
|
||||
|
||||
```rust
|
||||
use aho_corasick::{Automaton, AcAutomaton, Match};
|
||||
|
||||
let aut = AcAutomaton::new(vec!["apple", "maple"]);
|
||||
let mut it = aut.find("I like maple apples.");
|
||||
assert_eq!(it.next(), Some(Match {
|
||||
pati: 1,
|
||||
start: 7,
|
||||
end: 12,
|
||||
}));
|
||||
assert_eq!(it.next(), Some(Match {
|
||||
pati: 0,
|
||||
start: 13,
|
||||
end: 18,
|
||||
}));
|
||||
assert_eq!(it.next(), None);
|
||||
```
|
||||
|
||||
Use `find_overlapping` if you want to report all matches, even if they
|
||||
overlap with each other.
|
||||
|
||||
```rust
|
||||
use aho_corasick::{Automaton, AcAutomaton, Match};
|
||||
|
||||
let aut = AcAutomaton::new(vec!["abc", "a"]);
|
||||
let matches: Vec<_> = aut.find_overlapping("abc").collect();
|
||||
assert_eq!(matches, vec![
|
||||
Match { pati: 1, start: 0, end: 1}, Match { pati: 0, start: 0, end: 3 },
|
||||
]);
|
||||
|
||||
// Regular `find` will report only one match:
|
||||
let matches: Vec<_> = aut.find("abc").collect();
|
||||
assert_eq!(matches, vec![Match { pati: 1, start: 0, end: 1}]);
|
||||
```
|
||||
|
||||
Finally, there are also methods for finding matches on *streams*. Namely, the
|
||||
search text does not have to live in memory. It's useful to run this on files
|
||||
that can't fit into memory:
|
||||
|
||||
```no_run
|
||||
use std::fs::File;
|
||||
|
||||
use aho_corasick::{Automaton, AcAutomaton};
|
||||
|
||||
let aut = AcAutomaton::new(vec!["foo", "bar", "baz"]);
|
||||
let rdr = File::open("search.txt").unwrap();
|
||||
for m in aut.stream_find(rdr) {
|
||||
let m = m.unwrap(); // could be an IO error
|
||||
println!("Pattern '{}' matched at: ({}, {})",
|
||||
aut.pattern(m.pati), m.start, m.end);
|
||||
}
|
||||
```
|
||||
|
||||
There is also `stream_find_overlapping`, which is just like `find_overlapping`,
|
||||
but it operates on streams.
|
||||
|
||||
Please see `dict-search.rs` in this crate's `examples` directory for a more
|
||||
complete example. It creates a large automaton from a dictionary and can do a
|
||||
streaming match over arbitrarily large data.
|
||||
|
||||
# Memory usage
|
||||
|
||||
A key aspect of an Aho-Corasick implementation is how the state transitions
|
||||
are represented. The easiest way to make the automaton fast is to store a
|
||||
sparse 256-slot map in each state. It maps an input byte to a state index.
|
||||
This makes the matching loop extremely fast, since it translates to a simple
|
||||
pointer read.
|
||||
|
||||
The problem is that as the automaton accumulates more states, you end up paying
|
||||
a `256 * 4` (`4` is for the `u32` state index) byte penalty for every state
|
||||
regardless of how many transitions it has.
|
||||
|
||||
To solve this, only states near the root of the automaton have this sparse
|
||||
map representation. States near the leaves of the automaton use a dense mapping
|
||||
that requires a linear scan.
|
||||
|
||||
(The specific limit currently set is `3`, so that states with a depth less than
|
||||
or equal to `3` are less memory efficient. The result is that the memory usage
|
||||
of the automaton stops growing rapidly past ~60MB, even for automatons with
|
||||
thousands of patterns.)
|
||||
|
||||
If you'd like to opt for the less-memory-efficient-but-faster version, then
|
||||
you can construct an `AcAutomaton` with a `Sparse` transition strategy:
|
||||
|
||||
```rust
|
||||
use aho_corasick::{Automaton, AcAutomaton, Match, Sparse};
|
||||
|
||||
let aut = AcAutomaton::<&str, Sparse>::with_transitions(vec!["abc", "a"]);
|
||||
let matches: Vec<_> = aut.find("abc").collect();
|
||||
assert_eq!(matches, vec![Match { pati: 1, start: 0, end: 1}]);
|
||||
```
|
||||
*/
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
extern crate memchr;
|
||||
#[cfg(test)] extern crate quickcheck;
|
||||
#[cfg(test)] extern crate rand;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt;
|
||||
use std::iter::FromIterator;
|
||||
use std::mem;
|
||||
|
||||
pub use self::autiter::{
|
||||
Automaton, Match,
|
||||
Matches, MatchesOverlapping, StreamMatches, StreamMatchesOverlapping,
|
||||
};
|
||||
pub use self::full::FullAcAutomaton;
|
||||
|
||||
// We're specifying paths explicitly so that we can use
|
||||
// these modules simultaneously from `main.rs`.
|
||||
// Should probably make just make `main.rs` a separate crate.
|
||||
#[path = "autiter.rs"]
|
||||
mod autiter;
|
||||
#[path = "full.rs"]
|
||||
mod full;
|
||||
|
||||
/// The integer type used for the state index.
|
||||
///
|
||||
/// Limiting this to 32 bit integers can have a big impact on memory usage
|
||||
/// when using the `Sparse` transition representation.
|
||||
pub type StateIdx = u32;
|
||||
|
||||
// Constants for special state indexes.
|
||||
const FAIL_STATE: u32 = 0;
|
||||
const ROOT_STATE: u32 = 1;
|
||||
|
||||
// Limit the depth at which we use a sparse alphabet map. Once the limit is
|
||||
// reached, a dense set is used (and lookup becomes O(n)).
|
||||
//
|
||||
// This does have a performance hit, but the (straight forward) alternative
|
||||
// is to have a `256 * 4` byte overhead for every state.
|
||||
// Given that Aho-Corasick is typically used for dictionary searching, this
|
||||
// can lead to dramatic memory bloat.
|
||||
//
|
||||
// This limit should only be increased at your peril. Namely, in the worst
|
||||
// case, `256^DENSE_DEPTH_THRESHOLD * 4` corresponds to the memory usage in
|
||||
// bytes. A value of `1` gives us a good balance. This is also a happy point
|
||||
// in the benchmarks. A value of `0` gives considerably worse times on certain
|
||||
// benchmarks (e.g., `ac_ten_one_prefix_byte_every_match`) than even a value
|
||||
// of `1`. A value of `2` is slightly better than `1` and it looks like gains
|
||||
// level off at that point with not much observable difference when set to
|
||||
// `3`.
|
||||
//
|
||||
// Why not make this user configurable? Well, it doesn't make much sense
|
||||
// because we pay for it with case analysis in the matching loop. Increasing it
|
||||
// doesn't have much impact on performance (outside of pathological cases?).
|
||||
//
|
||||
// N.B. Someone else seems to have discovered an alternative, but I haven't
|
||||
// grokked it yet: https://github.com/mischasan/aho-corasick
|
||||
const DENSE_DEPTH_THRESHOLD: u32 = 1;
|
||||
|
||||
/// An Aho-Corasick finite automaton.
|
||||
///
|
||||
/// The type parameter `P` is the type of the pattern that was used to
|
||||
/// construct this AcAutomaton.
|
||||
#[derive(Clone)]
|
||||
pub struct AcAutomaton<P, T=Dense> {
|
||||
pats: Vec<P>,
|
||||
states: Vec<State<T>>,
|
||||
start_bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct State<T> {
|
||||
out: Vec<usize>,
|
||||
fail: StateIdx,
|
||||
goto: T,
|
||||
depth: u32,
|
||||
}
|
||||
|
||||
impl<P: AsRef<[u8]>> AcAutomaton<P> {
|
||||
/// Create a new automaton from an iterator of patterns.
|
||||
///
|
||||
/// The patterns must be convertible to bytes (`&[u8]`) via the `AsRef`
|
||||
/// trait.
|
||||
pub fn new<I>(pats: I) -> AcAutomaton<P, Dense>
|
||||
where I: IntoIterator<Item=P> {
|
||||
AcAutomaton::with_transitions(pats)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: AsRef<[u8]>, T: Transitions> AcAutomaton<P, T> {
|
||||
/// Create a new automaton from an iterator of patterns.
|
||||
///
|
||||
/// This constructor allows one to choose the transition representation.
|
||||
///
|
||||
/// The patterns must be convertible to bytes (`&[u8]`) via the `AsRef`
|
||||
/// trait.
|
||||
pub fn with_transitions<I>(pats: I) -> AcAutomaton<P, T>
|
||||
where I: IntoIterator<Item=P> {
|
||||
AcAutomaton {
|
||||
pats: vec![], // filled in later, avoid wrath of borrow checker
|
||||
states: vec![State::new(0), State::new(0)], // empty and root
|
||||
start_bytes: vec![], // also filled in later
|
||||
}.build(pats.into_iter().collect())
|
||||
}
|
||||
|
||||
/// Build out the entire automaton into a single matrix.
|
||||
///
|
||||
/// This will make searching as fast as possible at the expense of using
|
||||
/// at least `4 * 256 * #states` bytes of memory.
|
||||
pub fn into_full(self) -> FullAcAutomaton<P> {
|
||||
FullAcAutomaton::new(self)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn num_states(&self) -> usize {
|
||||
self.states.len()
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn heap_bytes(&self) -> usize {
|
||||
self.pats.iter()
|
||||
.map(|p| mem::size_of::<P>() + p.as_ref().len())
|
||||
.fold(0, |a, b| a + b)
|
||||
+ self.states.iter()
|
||||
.map(|s| mem::size_of::<State<T>>() + s.heap_bytes())
|
||||
.fold(0, |a, b| a + b)
|
||||
+ self.start_bytes.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: AsRef<[u8]>, T: Transitions> Automaton<P> for AcAutomaton<P, T> {
|
||||
#[inline]
|
||||
fn next_state(&self, mut si: StateIdx, b: u8) -> StateIdx {
|
||||
loop {
|
||||
let maybe_si = self.states[si as usize].goto(b);
|
||||
if maybe_si != FAIL_STATE {
|
||||
si = maybe_si;
|
||||
break;
|
||||
} else {
|
||||
si = self.states[si as usize].fail;
|
||||
}
|
||||
}
|
||||
si
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match {
|
||||
let pati = self.states[si as usize].out[outi];
|
||||
let patlen = self.pats[pati].as_ref().len();
|
||||
let start = texti + 1 - patlen;
|
||||
Match {
|
||||
pati: pati,
|
||||
start: start,
|
||||
end: start + patlen,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn has_match(&self, si: StateIdx, outi: usize) -> bool {
|
||||
outi < self.states[si as usize].out.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn start_bytes(&self) -> &[u8] {
|
||||
&self.start_bytes
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn patterns(&self) -> &[P] {
|
||||
&self.pats
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pattern(&self, i: usize) -> &P {
|
||||
&self.pats[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Below contains code for *building* the automaton. It's a reasonably faithful
|
||||
// translation of the description/psuedo-code from:
|
||||
// http://www.cs.uku.fi/~kilpelai/BSA05/lectures/slides04.pdf
|
||||
|
||||
impl<P: AsRef<[u8]>, T: Transitions> AcAutomaton<P, T> {
|
||||
// This is the first phase and builds the initial keyword tree.
|
||||
fn build(mut self, pats: Vec<P>) -> AcAutomaton<P, T> {
|
||||
for (pati, pat) in pats.iter().enumerate() {
|
||||
if pat.as_ref().is_empty() {
|
||||
continue;
|
||||
}
|
||||
let mut previ = ROOT_STATE;
|
||||
for &b in pat.as_ref() {
|
||||
if self.states[previ as usize].goto(b) != FAIL_STATE {
|
||||
previ = self.states[previ as usize].goto(b);
|
||||
} else {
|
||||
let depth = self.states[previ as usize].depth + 1;
|
||||
let nexti = self.add_state(State::new(depth));
|
||||
self.states[previ as usize].set_goto(b, nexti);
|
||||
previ = nexti;
|
||||
}
|
||||
}
|
||||
self.states[previ as usize].out.push(pati);
|
||||
}
|
||||
for c in (0..256).into_iter().map(|c| c as u8) {
|
||||
if self.states[ROOT_STATE as usize].goto(c) == FAIL_STATE {
|
||||
self.states[ROOT_STATE as usize].set_goto(c, ROOT_STATE);
|
||||
} else {
|
||||
self.start_bytes.push(c);
|
||||
}
|
||||
}
|
||||
// If any of the start bytes are non-ASCII, then remove them all,
|
||||
// because we don't want to be calling memchr on non-ASCII bytes.
|
||||
// (Well, we could, but it requires being more clever. Simply using
|
||||
// the prefix byte isn't good enough.)
|
||||
if self.start_bytes.iter().any(|&b| b > 0x7F) {
|
||||
self.start_bytes.clear();
|
||||
}
|
||||
self.pats = pats;
|
||||
self.fill()
|
||||
}
|
||||
|
||||
// The second phase that fills in the back links.
|
||||
fn fill(mut self) -> AcAutomaton<P, T> {
|
||||
// Fill up the queue with all non-root transitions out of the root
|
||||
// node. Then proceed by breadth first traversal.
|
||||
let mut q = VecDeque::new();
|
||||
for c in (0..256).into_iter().map(|c| c as u8) {
|
||||
let si = self.states[ROOT_STATE as usize].goto(c);
|
||||
if si != ROOT_STATE {
|
||||
q.push_front(si);
|
||||
}
|
||||
}
|
||||
while let Some(si) = q.pop_back() {
|
||||
for c in (0..256).into_iter().map(|c| c as u8) {
|
||||
let u = self.states[si as usize].goto(c);
|
||||
if u != FAIL_STATE {
|
||||
q.push_front(u);
|
||||
let mut v = self.states[si as usize].fail;
|
||||
while self.states[v as usize].goto(c) == FAIL_STATE {
|
||||
v = self.states[v as usize].fail;
|
||||
}
|
||||
let ufail = self.states[v as usize].goto(c);
|
||||
self.states[u as usize].fail = ufail;
|
||||
let ufail_out = self.states[ufail as usize].out.clone();
|
||||
self.states[u as usize].out.extend(ufail_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
fn add_state(&mut self, state: State<T>) -> StateIdx {
|
||||
let i = self.states.len();
|
||||
self.states.push(state);
|
||||
i as StateIdx
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Transitions> State<T> {
|
||||
fn new(depth: u32) -> State<T> {
|
||||
State {
|
||||
out: vec![],
|
||||
fail: 1,
|
||||
goto: Transitions::new(depth),
|
||||
depth: depth,
|
||||
}
|
||||
}
|
||||
|
||||
fn goto(&self, b: u8) -> StateIdx {
|
||||
self.goto.goto(b)
|
||||
}
|
||||
|
||||
fn set_goto(&mut self, b: u8, si: StateIdx) {
|
||||
self.goto.set_goto(b, si);
|
||||
}
|
||||
|
||||
fn heap_bytes(&self) -> usize {
|
||||
(self.out.len() * usize_bytes())
|
||||
+ self.goto.heap_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
/// An abstraction over state transition strategies.
|
||||
///
|
||||
/// This is an attempt to let the caller choose the space/time trade offs
|
||||
/// used for state transitions.
|
||||
///
|
||||
/// (It's possible that this interface is merely good enough for just the two
|
||||
/// implementations in this crate.)
|
||||
pub trait Transitions {
|
||||
/// Return a new state at the given depth.
|
||||
fn new(depth: u32) -> Self;
|
||||
/// Return the next state index given the next character.
|
||||
fn goto(&self, alpha: u8) -> StateIdx;
|
||||
/// Set the next state index for the character given.
|
||||
fn set_goto(&mut self, alpha: u8, si: StateIdx);
|
||||
/// The memory use in bytes (on the heap) of this set of transitions.
|
||||
fn heap_bytes(&self) -> usize;
|
||||
}
|
||||
|
||||
/// State transitions that can be stored either sparsely or densely.
|
||||
///
|
||||
/// This uses less space but at the expense of slower matching.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Dense(DenseChoice);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum DenseChoice {
|
||||
Sparse(Vec<StateIdx>), // indexed by alphabet
|
||||
Dense(Vec<(u8, StateIdx)>),
|
||||
}
|
||||
|
||||
impl Transitions for Dense {
|
||||
fn new(depth: u32) -> Dense {
|
||||
if depth <= DENSE_DEPTH_THRESHOLD {
|
||||
Dense(DenseChoice::Sparse(vec![0; 256]))
|
||||
} else {
|
||||
Dense(DenseChoice::Dense(vec![]))
|
||||
}
|
||||
}
|
||||
|
||||
fn goto(&self, b1: u8) -> StateIdx {
|
||||
match self.0 {
|
||||
DenseChoice::Sparse(ref m) => m[b1 as usize],
|
||||
DenseChoice::Dense(ref m) => {
|
||||
for &(b2, si) in m {
|
||||
if b1 == b2 {
|
||||
return si;
|
||||
}
|
||||
}
|
||||
FAIL_STATE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_goto(&mut self, b: u8, si: StateIdx) {
|
||||
match self.0 {
|
||||
DenseChoice::Sparse(ref mut m) => m[b as usize] = si,
|
||||
DenseChoice::Dense(ref mut m) => m.push((b, si)),
|
||||
}
|
||||
}
|
||||
|
||||
fn heap_bytes(&self) -> usize {
|
||||
match self.0 {
|
||||
DenseChoice::Sparse(ref m) => m.len() * 4,
|
||||
DenseChoice::Dense(ref m) => m.len() * (1 + 4),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// State transitions that are always sparse.
|
||||
///
|
||||
/// This can use enormous amounts of memory when there are many patterns,
|
||||
/// but matching is very fast.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Sparse(Vec<StateIdx>);
|
||||
|
||||
impl Transitions for Sparse {
|
||||
fn new(_: u32) -> Sparse {
|
||||
Sparse(vec![0; 256])
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn goto(&self, b: u8) -> StateIdx {
|
||||
self.0[b as usize]
|
||||
}
|
||||
|
||||
fn set_goto(&mut self, b: u8, si: StateIdx) {
|
||||
self.0[b as usize] = si;
|
||||
}
|
||||
|
||||
fn heap_bytes(&self) -> usize {
|
||||
self.0.len() * 4
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: AsRef<[u8]>> FromIterator<S> for AcAutomaton<S> {
|
||||
/// Create an automaton from an iterator of strings.
|
||||
fn from_iter<T>(it: T) -> AcAutomaton<S> where T: IntoIterator<Item=S> {
|
||||
AcAutomaton::new(it)
|
||||
}
|
||||
}
|
||||
|
||||
// Provide some question debug impls for viewing automatons.
|
||||
// The custom impls mostly exist for special showing of sparse maps.
|
||||
|
||||
impl<P: AsRef<[u8]> + fmt::Debug, T: Transitions>
|
||||
fmt::Debug for AcAutomaton<P, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use std::iter::repeat;
|
||||
|
||||
try!(writeln!(f, "{}", repeat('-').take(79).collect::<String>()));
|
||||
try!(writeln!(f, "Patterns: {:?}", self.pats));
|
||||
for (i, state) in self.states.iter().enumerate().skip(1) {
|
||||
try!(writeln!(f, "{:3}: {}", i, state.debug(i == 1)));
|
||||
}
|
||||
write!(f, "{}", repeat('-').take(79).collect::<String>())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Transitions> State<T> {
|
||||
fn debug(&self, root: bool) -> String {
|
||||
format!("State {{ depth: {:?}, out: {:?}, fail: {:?}, goto: {{{}}} }}",
|
||||
self.depth, self.out, self.fail, self.goto_string(root))
|
||||
}
|
||||
|
||||
fn goto_string(&self, root: bool) -> String {
|
||||
use std::char::from_u32;
|
||||
|
||||
let mut goto = vec![];
|
||||
for b in (0..256).map(|b| b as u8) {
|
||||
let si = self.goto(b);
|
||||
if (!root && si == FAIL_STATE) || (root && si == ROOT_STATE) {
|
||||
continue;
|
||||
}
|
||||
goto.push(format!("{} => {}", from_u32(b as u32).unwrap(), si));
|
||||
}
|
||||
goto.join(", ")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Transitions> fmt::Debug for State<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.debug(false))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Transitions> AcAutomaton<String, T> {
|
||||
#[doc(hidden)]
|
||||
pub fn dot(&self) -> String {
|
||||
use std::fmt::Write;
|
||||
let mut out = String::new();
|
||||
macro_rules! w {
|
||||
($w:expr, $($tt:tt)*) => { {write!($w, $($tt)*)}.unwrap() }
|
||||
}
|
||||
|
||||
w!(out, r#"
|
||||
digraph automaton {{
|
||||
label=<<FONT POINT-SIZE="20">{}</FONT>>;
|
||||
labelloc="l";
|
||||
labeljust="l";
|
||||
rankdir="LR";
|
||||
"#, self.pats.join(", "));
|
||||
for (i, s) in self.states.iter().enumerate().skip(1) {
|
||||
let i = i as u32;
|
||||
if s.out.len() == 0 {
|
||||
w!(out, " {};\n", i);
|
||||
} else {
|
||||
w!(out, " {} [peripheries=2];\n", i);
|
||||
}
|
||||
w!(out, " {} -> {} [style=dashed];\n", i, s.fail);
|
||||
for b in (0..256).map(|b| b as u8) {
|
||||
let si = s.goto(b);
|
||||
if si == FAIL_STATE || (i == ROOT_STATE && si == ROOT_STATE) {
|
||||
continue;
|
||||
}
|
||||
w!(out, " {} -> {} [label={}];\n", i, si, b as char);
|
||||
}
|
||||
}
|
||||
w!(out, "}}");
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
fn vec_bytes() -> usize {
|
||||
usize_bytes() * 3
|
||||
}
|
||||
|
||||
fn usize_bytes() -> usize {
|
||||
let bits = usize::max_value().count_ones() as usize;
|
||||
bits / 8
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashSet;
|
||||
use std::io;
|
||||
|
||||
use quickcheck::{Arbitrary, Gen, quickcheck};
|
||||
|
||||
use super::{Automaton, AcAutomaton, Match};
|
||||
|
||||
fn aut_find<S>(xs: &[S], haystack: &str) -> Vec<Match>
|
||||
where S: Clone + AsRef<[u8]> {
|
||||
AcAutomaton::new(xs.to_vec()).find(&haystack).collect()
|
||||
}
|
||||
|
||||
fn aut_finds<S>(xs: &[S], haystack: &str) -> Vec<Match>
|
||||
where S: Clone + AsRef<[u8]> {
|
||||
let cur = io::Cursor::new(haystack.as_bytes());
|
||||
AcAutomaton::new(xs.to_vec())
|
||||
.stream_find(cur).map(|r| r.unwrap()).collect()
|
||||
}
|
||||
|
||||
fn aut_findf<S>(xs: &[S], haystack: &str) -> Vec<Match>
|
||||
where S: Clone + AsRef<[u8]> {
|
||||
AcAutomaton::new(xs.to_vec()).into_full().find(haystack).collect()
|
||||
}
|
||||
|
||||
fn aut_findfs<S>(xs: &[S], haystack: &str) -> Vec<Match>
|
||||
where S: Clone + AsRef<[u8]> {
|
||||
let cur = io::Cursor::new(haystack.as_bytes());
|
||||
AcAutomaton::new(xs.to_vec())
|
||||
.into_full()
|
||||
.stream_find(cur).map(|r| r.unwrap()).collect()
|
||||
}
|
||||
|
||||
fn aut_findo<S>(xs: &[S], haystack: &str) -> Vec<Match>
|
||||
where S: Clone + AsRef<[u8]> {
|
||||
AcAutomaton::new(xs.to_vec()).find_overlapping(haystack).collect()
|
||||
}
|
||||
|
||||
fn aut_findos<S>(xs: &[S], haystack: &str) -> Vec<Match>
|
||||
where S: Clone + AsRef<[u8]> {
|
||||
let cur = io::Cursor::new(haystack.as_bytes());
|
||||
AcAutomaton::new(xs.to_vec())
|
||||
.stream_find_overlapping(cur).map(|r| r.unwrap()).collect()
|
||||
}
|
||||
|
||||
fn aut_findfo<S>(xs: &[S], haystack: &str) -> Vec<Match>
|
||||
where S: Clone + AsRef<[u8]> {
|
||||
AcAutomaton::new(xs.to_vec())
|
||||
.into_full().find_overlapping(haystack).collect()
|
||||
}
|
||||
|
||||
fn aut_findfos<S>(xs: &[S], haystack: &str) -> Vec<Match>
|
||||
where S: Clone + AsRef<[u8]> {
|
||||
let cur = io::Cursor::new(haystack.as_bytes());
|
||||
AcAutomaton::new(xs.to_vec())
|
||||
.into_full()
|
||||
.stream_find_overlapping(cur).map(|r| r.unwrap()).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_pattern_one_match() {
|
||||
let ns = vec!["a"];
|
||||
let hay = "za";
|
||||
let matches = vec![
|
||||
Match { pati: 0, start: 1, end: 2 },
|
||||
];
|
||||
assert_eq!(&aut_find(&ns, hay), &matches);
|
||||
assert_eq!(&aut_finds(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findf(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findfs(&ns, hay), &matches);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_pattern_many_match() {
|
||||
let ns = vec!["a"];
|
||||
let hay = "zazazzzza";
|
||||
let matches = vec![
|
||||
Match { pati: 0, start: 1, end: 2 },
|
||||
Match { pati: 0, start: 3, end: 4 },
|
||||
Match { pati: 0, start: 8, end: 9 },
|
||||
];
|
||||
assert_eq!(&aut_find(&ns, hay), &matches);
|
||||
assert_eq!(&aut_finds(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findf(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findfs(&ns, hay), &matches);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_longer_pattern_one_match() {
|
||||
let ns = vec!["abc"];
|
||||
let hay = "zazabcz";
|
||||
let matches = vec![ Match { pati: 0, start: 3, end: 6 } ];
|
||||
assert_eq!(&aut_find(&ns, hay), &matches);
|
||||
assert_eq!(&aut_finds(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findf(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findfs(&ns, hay), &matches);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_longer_pattern_many_match() {
|
||||
let ns = vec!["abc"];
|
||||
let hay = "zazabczzzzazzzabc";
|
||||
let matches = vec![
|
||||
Match { pati: 0, start: 3, end: 6 },
|
||||
Match { pati: 0, start: 14, end: 17 },
|
||||
];
|
||||
assert_eq!(&aut_find(&ns, hay), &matches);
|
||||
assert_eq!(&aut_finds(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findf(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findfs(&ns, hay), &matches);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_pattern_one_match() {
|
||||
let ns = vec!["a", "b"];
|
||||
let hay = "zb";
|
||||
let matches = vec![ Match { pati: 1, start: 1, end: 2 } ];
|
||||
assert_eq!(&aut_find(&ns, hay), &matches);
|
||||
assert_eq!(&aut_finds(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findf(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findfs(&ns, hay), &matches);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_pattern_many_match() {
|
||||
let ns = vec!["a", "b"];
|
||||
let hay = "zbzazzzzb";
|
||||
let matches = vec![
|
||||
Match { pati: 1, start: 1, end: 2 },
|
||||
Match { pati: 0, start: 3, end: 4 },
|
||||
Match { pati: 1, start: 8, end: 9 },
|
||||
];
|
||||
assert_eq!(&aut_find(&ns, hay), &matches);
|
||||
assert_eq!(&aut_finds(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findf(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findfs(&ns, hay), &matches);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_longer_pattern_one_match() {
|
||||
let ns = vec!["abc", "xyz"];
|
||||
let hay = "zazxyzz";
|
||||
let matches = vec![ Match { pati: 1, start: 3, end: 6 } ];
|
||||
assert_eq!(&aut_find(&ns, hay), &matches);
|
||||
assert_eq!(&aut_finds(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findf(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findfs(&ns, hay), &matches);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_longer_pattern_many_match() {
|
||||
let ns = vec!["abc", "xyz"];
|
||||
let hay = "zazxyzzzzzazzzabcxyz";
|
||||
let matches = vec![
|
||||
Match { pati: 1, start: 3, end: 6 },
|
||||
Match { pati: 0, start: 14, end: 17 },
|
||||
Match { pati: 1, start: 17, end: 20 },
|
||||
];
|
||||
assert_eq!(&aut_find(&ns, hay), &matches);
|
||||
assert_eq!(&aut_finds(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findf(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findfs(&ns, hay), &matches);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_longer_pattern_overlap_one_match() {
|
||||
let ns = vec!["abc", "bc"];
|
||||
let hay = "zazabcz";
|
||||
let matches = vec![
|
||||
Match { pati: 0, start: 3, end: 6 },
|
||||
Match { pati: 1, start: 4, end: 6 },
|
||||
];
|
||||
assert_eq!(&aut_findo(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findos(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findfo(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findfos(&ns, hay), &matches);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_longer_pattern_overlap_one_match_reverse() {
|
||||
let ns = vec!["abc", "bc"];
|
||||
let hay = "xbc";
|
||||
let matches = vec![ Match { pati: 1, start: 1, end: 3 } ];
|
||||
assert_eq!(&aut_findo(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findos(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findfo(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findfos(&ns, hay), &matches);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_longer_pattern_overlap_many_match() {
|
||||
let ns = vec!["abc", "bc", "c"];
|
||||
let hay = "zzzabczzzbczzzc";
|
||||
let matches = vec![
|
||||
Match { pati: 0, start: 3, end: 6 },
|
||||
Match { pati: 1, start: 4, end: 6 },
|
||||
Match { pati: 2, start: 5, end: 6 },
|
||||
Match { pati: 1, start: 9, end: 11 },
|
||||
Match { pati: 2, start: 10, end: 11 },
|
||||
Match { pati: 2, start: 14, end: 15 },
|
||||
];
|
||||
assert_eq!(&aut_findo(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findos(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findfo(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findfos(&ns, hay), &matches);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_longer_pattern_overlap_many_match_reverse() {
|
||||
let ns = vec!["abc", "bc", "c"];
|
||||
let hay = "zzzczzzbczzzabc";
|
||||
let matches = vec![
|
||||
Match { pati: 2, start: 3, end: 4 },
|
||||
Match { pati: 1, start: 7, end: 9 },
|
||||
Match { pati: 2, start: 8, end: 9 },
|
||||
Match { pati: 0, start: 12, end: 15 },
|
||||
Match { pati: 1, start: 13, end: 15 },
|
||||
Match { pati: 2, start: 14, end: 15 },
|
||||
];
|
||||
assert_eq!(&aut_findo(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findos(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findfo(&ns, hay), &matches);
|
||||
assert_eq!(&aut_findfos(&ns, hay), &matches);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pattern_returns_original_type() {
|
||||
let aut = AcAutomaton::new(vec!["apple", "maple"]);
|
||||
|
||||
// Explicitly given this type to assert that the thing returned
|
||||
// from the function is our original type.
|
||||
let pat: &str = aut.pattern(0);
|
||||
assert_eq!(pat, "apple");
|
||||
|
||||
// Also check the return type of the `patterns` function.
|
||||
let pats: &[&str] = aut.patterns();
|
||||
assert_eq!(pats, &["apple", "maple"]);
|
||||
}
|
||||
|
||||
// Quickcheck time.
|
||||
|
||||
// This generates very small ascii strings, which makes them more likely
|
||||
// to interact in interesting ways with larger haystack strings.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct SmallAscii(String);
|
||||
|
||||
impl Arbitrary for SmallAscii {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> SmallAscii {
|
||||
use std::char::from_u32;
|
||||
SmallAscii((0..2)
|
||||
.map(|_| from_u32(g.gen_range(97, 123)).unwrap())
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn shrink(&self) -> Box<Iterator<Item=SmallAscii>> {
|
||||
Box::new(self.0.shrink().map(SmallAscii))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SmallAscii> for String {
|
||||
fn from(s: SmallAscii) -> String { s.0 }
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for SmallAscii {
|
||||
fn as_ref(&self) -> &[u8] { self.0.as_ref() }
|
||||
}
|
||||
|
||||
// This is the same arbitrary impl as `String`, except it has a bias toward
|
||||
// ASCII characters.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct BiasAscii(String);
|
||||
|
||||
impl Arbitrary for BiasAscii {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> BiasAscii {
|
||||
use std::char::from_u32;
|
||||
let size = { let s = g.size(); g.gen_range(0, s) };
|
||||
let mut s = String::with_capacity(size);
|
||||
for _ in 0..size {
|
||||
if g.gen_weighted_bool(3) {
|
||||
s.push(char::arbitrary(g));
|
||||
} else {
|
||||
for _ in 0..5 {
|
||||
s.push(from_u32(g.gen_range(97, 123)).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
BiasAscii(s)
|
||||
}
|
||||
|
||||
fn shrink(&self) -> Box<Iterator<Item=BiasAscii>> {
|
||||
Box::new(self.0.shrink().map(BiasAscii))
|
||||
}
|
||||
}
|
||||
|
||||
fn naive_find<S>(xs: &[S], haystack: &str) -> Vec<Match>
|
||||
where S: Clone + Into<String> {
|
||||
let needles: Vec<String> =
|
||||
xs.to_vec().into_iter().map(Into::into).collect();
|
||||
let mut matches = vec![];
|
||||
for hi in 0..haystack.len() {
|
||||
for (pati, needle) in needles.iter().enumerate() {
|
||||
let needle = needle.as_bytes();
|
||||
if needle.len() == 0 || needle.len() > haystack.len() - hi {
|
||||
continue;
|
||||
}
|
||||
if needle == &haystack.as_bytes()[hi..hi+needle.len()] {
|
||||
matches.push(Match {
|
||||
pati: pati,
|
||||
start: hi,
|
||||
end: hi + needle.len(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
matches
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn qc_ac_equals_naive() {
|
||||
fn prop(needles: Vec<SmallAscii>, haystack: BiasAscii) -> bool {
|
||||
let aut_matches = aut_findo(&needles, &haystack.0);
|
||||
let naive_matches = naive_find(&needles, &haystack.0);
|
||||
// Ordering isn't always the same. I don't think we care, so do
|
||||
// an unordered comparison.
|
||||
let aset: HashSet<Match> = aut_matches.iter().cloned().collect();
|
||||
let nset: HashSet<Match> = naive_matches.iter().cloned().collect();
|
||||
aset == nset
|
||||
}
|
||||
quickcheck(prop as fn(Vec<SmallAscii>, BiasAscii) -> bool);
|
||||
}
|
||||
}
|
13
third_party/rust/aho-corasick-0.6.2/src/main.rs
vendored
13
third_party/rust/aho-corasick-0.6.2/src/main.rs
vendored
@ -1,13 +0,0 @@
|
||||
extern crate memchr;
|
||||
|
||||
use std::env;
|
||||
|
||||
use lib::AcAutomaton;
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod lib;
|
||||
|
||||
fn main() {
|
||||
let aut = AcAutomaton::new(env::args().skip(1));
|
||||
println!("{}", aut.dot().trim());
|
||||
}
|
@ -1 +0,0 @@
|
||||
{"files":{"Cargo.toml":"79fbb792e6c1d05c44188c808ef7120c592e50291a706fe0f669b8ac9a2ad5e5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0dd882e53de11566d50f8e8e2d5a651bcf3fabee4987d70f306233cf39094ba7","README.md":"b2da2fd61c4f3abf45127d183b61eb2dabc1c97cd191854987aa0328549a663f","benches/benchmarks.rs":"f0469f65f901c3e92fa506c0deb277fd136a7f968cae7cc4f030c0c15e52322f","examples/make_tables.rs":"3c80f2a8cdb204168cc1b60f8904d544b2da067b9e6a7b40ade5fb4a994b4175","src/lib.rs":"a3ac363513ae99a9b0049c19c92bc46b57ac9a0ebfd3317b7b387c5fbaa16a8a","src/tables.rs":"378743892907cde87c1a92e6afee2df36ce590311e61381b2cc0404b3e018039","tests/tests.rs":"dc2c293bae576cc596bdfb6ef783dc1d24d3bf992bf532caaebe1738cb0608cc"},"package":"30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557"}
|
21
third_party/rust/base64-0.5.2/Cargo.toml
vendored
21
third_party/rust/base64-0.5.2/Cargo.toml
vendored
@ -1,21 +0,0 @@
|
||||
[package]
|
||||
name = "base64"
|
||||
version = "0.5.2"
|
||||
authors = ["Alice Maz <alice@alicemaz.com>", "Marshall Pierce <marshall@mpierce.org>"]
|
||||
description = "encodes and decodes base64 as bytes or utf8"
|
||||
repository = "https://github.com/alicemaz/rust-base64"
|
||||
documentation = "https://github.com/alicemaz/rust-base64/blob/master/README.md"
|
||||
readme = "README.md"
|
||||
keywords = ["base64", "utf8", "encode", "decode"]
|
||||
categories = ["encoding"]
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "=0.3.15"
|
||||
|
||||
[profile.bench]
|
||||
# Uncomment when using `perf record`
|
||||
#debug = true
|
21
third_party/rust/base64-0.5.2/LICENSE-MIT
vendored
21
third_party/rust/base64-0.5.2/LICENSE-MIT
vendored
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Alice Maz
|
||||
|
||||
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.
|
112
third_party/rust/base64-0.5.2/README.md
vendored
112
third_party/rust/base64-0.5.2/README.md
vendored
@ -1,112 +0,0 @@
|
||||
[base64](https://crates.io/crates/base64)
|
||||
===
|
||||
|
||||
It's base64. What more could anyone want?
|
||||
|
||||
Example
|
||||
---
|
||||
|
||||
In Cargo.toml: `base64 = "~0.5.0"`
|
||||
|
||||
```rust
|
||||
extern crate base64;
|
||||
|
||||
use base64::{encode, decode};
|
||||
|
||||
fn main() {
|
||||
let a = b"hello world";
|
||||
let b = "aGVsbG8gd29ybGQ=";
|
||||
|
||||
assert_eq!(encode(a), b);
|
||||
assert_eq!(a, &decode(b).unwrap()[..]);
|
||||
}
|
||||
```
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
base64 exposes six functions:
|
||||
|
||||
```rust
|
||||
fn encode<T: ?Sized + AsRef<[u8]>>(&T) -> String;
|
||||
fn decode<T: ?Sized + AsRef<[u8]>>(&T) -> Result<Vec<u8>, DecodeError>;
|
||||
fn encode_config<T: ?Sized + AsRef<[u8]>>(&T, Config) -> String;
|
||||
fn encode_config_buf<T: ?Sized + AsRef<[u8]>>(&T, Config, &mut String);
|
||||
fn decode_config<T: ?Sized + AsRef<[u8]>>(&T, Config) -> Result<Vec<u8>, DecodeError>;
|
||||
fn decode_config_buf<T: ?Sized + AsRef<[u8]>>(&T, Config, &mut Vec<u8>) -> Result<(), DecodeError>;
|
||||
```
|
||||
|
||||
`STANDARD`, `URL_SAFE`, `URL_SAFE_NO_PAD`, and `MIME` configuation structs are provided for convenience. `encode` and `decode` are convenience wrappers for the `_config` functions called with the `STANDARD` config, and they are themselves wrappers of the `_buf` functions that allocate on the user's behalf. Encode produces valid padding absent a config that states otherwise; decode produces the same output for valid or omitted padding in all cases, but errors on invalid (superfluous) padding. Whitespace in the input to decode is an error for all modes except `MIME`, which disregards it ("whitespace" according to POSIX-locale `isspace`, meaning \n \r \f \t \v and space).
|
||||
|
||||
`Config` exposes a constructor to allow custom combinations of character set, output padding, input whitespace permissiveness, linewrapping, and line ending character(s). The vast majority of usecases should be covered by the four provided, however.
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
||||
I have a fondness for small dependency footprints, ecosystems where you can pick and choose what functionality you need, and no more. Unix philosophy sort of thing I guess, many tiny utilities interoperating across a common interface. One time making a Twitter bot, I ran into the need to correctly pluralize arbitrary words. I found on npm a module that did nothing but pluralize words. Nothing else, just a couple of functions. I'd like for this to be that "just a couple of functions."
|
||||
|
||||
Developing
|
||||
---
|
||||
|
||||
Benchmarks are in `benches/`. Running them requires nightly rust, but `rustup` makes it easy:
|
||||
|
||||
```
|
||||
rustup run nightly cargo bench
|
||||
```
|
||||
|
||||
Decoding is aided by some pre-calculated tables, which are generated by:
|
||||
|
||||
```
|
||||
cargo run --example make_tables > src/tables.rs.tmp && mv src/tables.rs.tmp src/tables.rs
|
||||
```
|
||||
|
||||
Profiling
|
||||
---
|
||||
|
||||
On Linux, you can use [perf](https://perf.wiki.kernel.org/index.php/Main_Page) for profiling. First, enable debug symbols in Cargo.toml. Don't commit this change, though, since it's usually not what you want (and costs some performance):
|
||||
|
||||
```
|
||||
[profile.release]
|
||||
debug = true
|
||||
```
|
||||
|
||||
Then compile the benchmarks. (Just re-run them and ^C once the benchmarks start running; all that's needed is to recompile them.)
|
||||
|
||||
Run the benchmark binary with `perf` (shown here filtering to one particular benchmark, which will make the results easier to read). `perf` is only available to the root user on most systems as it fiddles with event counters in your CPU, so use `sudo`. We need to run the actual benchmark binary, hence the path into `target`. You can see the actual full path with `rustup run nightly cargo bench -v`; it will print out the commands it runs. If you use the exact path that `bench` outputs, make sure you get the one that's for the benchmarks, not the tests. You may also want to `cargo clean` so you have only one `benchmarks-` binary (they tend to accumulate).
|
||||
|
||||
```
|
||||
sudo perf record target/release/deps/benchmarks-* --bench decode_10mib_reuse
|
||||
```
|
||||
|
||||
Then analyze the results, again with perf:
|
||||
|
||||
```
|
||||
sudo perf annotate -l
|
||||
```
|
||||
|
||||
You'll see a bunch of interleaved rust source and assembly like this. The section with `lib.rs:327` is telling us that 4.02% of samples saw the `movzbl` aka bit shift as the active instruction. However, this percentage is not as exact as it seems due to a phenomenon called *skid*. Basically, a consequence of how fancy modern CPUs are is that this sort of instruction profiling is inherently inaccurate, especially in branch-heavy code.
|
||||
|
||||
```
|
||||
lib.rs:322 0.70 : 10698: mov %rdi,%rax
|
||||
2.82 : 1069b: shr $0x38,%rax
|
||||
: if morsel == decode_tables::INVALID_VALUE {
|
||||
: bad_byte_index = input_index;
|
||||
: break;
|
||||
: };
|
||||
: accum = (morsel as u64) << 58;
|
||||
lib.rs:327 4.02 : 1069f: movzbl (%r9,%rax,1),%r15d
|
||||
: // fast loop of 8 bytes at a time
|
||||
: while input_index < length_of_full_chunks {
|
||||
: let mut accum: u64;
|
||||
:
|
||||
: let input_chunk = BigEndian::read_u64(&input_bytes[input_index..(input_index + 8)]);
|
||||
: morsel = decode_table[(input_chunk >> 56) as usize];
|
||||
lib.rs:322 3.68 : 106a4: cmp $0xff,%r15
|
||||
: if morsel == decode_tables::INVALID_VALUE {
|
||||
0.00 : 106ab: je 1090e <base64::decode_config_buf::hbf68a45fefa299c1+0x46e>
|
||||
```
|
||||
|
||||
License
|
||||
---
|
||||
|
||||
This project is dual-licensed under MIT and Apache 2.0.
|
230
third_party/rust/base64-0.5.2/benches/benchmarks.rs
vendored
230
third_party/rust/base64-0.5.2/benches/benchmarks.rs
vendored
@ -1,230 +0,0 @@
|
||||
#![feature(test)]
|
||||
|
||||
extern crate base64;
|
||||
extern crate test;
|
||||
extern crate rand;
|
||||
|
||||
use base64::{decode, decode_config_buf, encode, encode_config_buf, STANDARD};
|
||||
|
||||
use test::Bencher;
|
||||
use rand::Rng;
|
||||
|
||||
#[bench]
|
||||
fn encode_3b(b: &mut Bencher) {
|
||||
do_encode_bench(b, 3)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_3b_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 3)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_50b(b: &mut Bencher) {
|
||||
do_encode_bench(b, 50)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_50b_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 50)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_100b(b: &mut Bencher) {
|
||||
do_encode_bench(b, 100)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_100b_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 100)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_500b(b: &mut Bencher) {
|
||||
do_encode_bench(b, 500)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_500b_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 500)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_3kib(b: &mut Bencher) {
|
||||
do_encode_bench(b, 3 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_3kib_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 3 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_3mib(b: &mut Bencher) {
|
||||
do_encode_bench(b, 3 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_3mib_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 3 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_10mib(b: &mut Bencher) {
|
||||
do_encode_bench(b, 10 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_10mib_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 10 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_30mib(b: &mut Bencher) {
|
||||
do_encode_bench(b, 30 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn encode_30mib_reuse_buf(b: &mut Bencher) {
|
||||
do_encode_bench_reuse_buf(b, 30 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_3b(b: &mut Bencher) {
|
||||
do_decode_bench(b, 3)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_3b_reuse_buf(b: &mut Bencher) {
|
||||
do_decode_bench_reuse_buf(b, 3)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_50b(b: &mut Bencher) {
|
||||
do_decode_bench(b, 50)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_50b_reuse_buf(b: &mut Bencher) {
|
||||
do_decode_bench_reuse_buf(b, 50)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_100b(b: &mut Bencher) {
|
||||
do_decode_bench(b, 100)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_100b_reuse_buf(b: &mut Bencher) {
|
||||
do_decode_bench_reuse_buf(b, 100)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_500b(b: &mut Bencher) {
|
||||
do_decode_bench(b, 500)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_500b_reuse_buf(b: &mut Bencher) {
|
||||
do_decode_bench_reuse_buf(b, 500)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_3kib(b: &mut Bencher) {
|
||||
do_decode_bench(b, 3 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_3kib_reuse_buf(b: &mut Bencher) {
|
||||
do_decode_bench_reuse_buf(b, 3 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_3mib(b: &mut Bencher) {
|
||||
do_decode_bench(b, 3 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_3mib_reuse_buf(b: &mut Bencher) {
|
||||
do_decode_bench_reuse_buf(b, 3 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_10mib(b: &mut Bencher) {
|
||||
do_decode_bench(b, 10 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_10mib_reuse_buf(b: &mut Bencher) {
|
||||
do_decode_bench_reuse_buf(b, 10 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_30mib(b: &mut Bencher) {
|
||||
do_decode_bench(b, 30 * 1024 * 1024)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn decode_30mib_reuse_buf(b: &mut Bencher) {
|
||||
do_decode_bench_reuse_buf(b, 30 * 1024 * 1024)
|
||||
}
|
||||
|
||||
fn do_decode_bench(b: &mut Bencher, size: usize) {
|
||||
let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
|
||||
fill(&mut v);
|
||||
let encoded = encode(&v);
|
||||
|
||||
b.bytes = encoded.len() as u64;
|
||||
b.iter(|| {
|
||||
let orig = decode(&encoded);
|
||||
test::black_box(&orig);
|
||||
});
|
||||
}
|
||||
|
||||
fn do_decode_bench_reuse_buf(b: &mut Bencher, size: usize) {
|
||||
let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
|
||||
fill(&mut v);
|
||||
let encoded = encode(&v);
|
||||
|
||||
let mut buf = Vec::new();
|
||||
b.bytes = encoded.len() as u64;
|
||||
b.iter(|| {
|
||||
decode_config_buf(&encoded, STANDARD, &mut buf).unwrap();
|
||||
test::black_box(&buf);
|
||||
buf.clear();
|
||||
});
|
||||
}
|
||||
|
||||
fn do_encode_bench(b: &mut Bencher, size: usize) {
|
||||
let mut v: Vec<u8> = Vec::with_capacity(size);
|
||||
fill(&mut v);
|
||||
|
||||
b.bytes = v.len() as u64;
|
||||
b.iter(|| {
|
||||
let e = encode(&v);
|
||||
test::black_box(&e);
|
||||
});
|
||||
}
|
||||
|
||||
fn do_encode_bench_reuse_buf(b: &mut Bencher, size: usize) {
|
||||
let mut v: Vec<u8> = Vec::with_capacity(size);
|
||||
fill(&mut v);
|
||||
|
||||
let mut buf = String::new();
|
||||
|
||||
b.bytes = v.len() as u64;
|
||||
b.iter(|| {
|
||||
let e = encode_config_buf(&v, STANDARD, &mut buf);
|
||||
test::black_box(&e);
|
||||
buf.clear();
|
||||
});
|
||||
}
|
||||
|
||||
fn fill(v: &mut Vec<u8>) {
|
||||
let cap = v.capacity();
|
||||
// weak randomness is plenty; we just want to not be completely friendly to the branch predictor
|
||||
let mut r = rand::weak_rng();
|
||||
while v.len() < cap {
|
||||
v.push(r.gen::<u8>());
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
use std::collections::HashMap;
|
||||
use std::iter::Iterator;
|
||||
|
||||
fn main() {
|
||||
println!("pub const INVALID_VALUE: u8 = 255;");
|
||||
|
||||
// A-Z
|
||||
let standard_alphabet: Vec<u8> = (0x41..0x5B)
|
||||
// a-z
|
||||
.chain(0x61..0x7B)
|
||||
// 0-9
|
||||
.chain(0x30..0x3A)
|
||||
// +
|
||||
.chain(0x2B..0x2C)
|
||||
// /
|
||||
.chain(0x2F..0x30)
|
||||
.collect();
|
||||
print_encode_table(&standard_alphabet, "STANDARD_ENCODE", 0);
|
||||
print_decode_table(&standard_alphabet, "STANDARD_DECODE", 0);
|
||||
|
||||
// A-Z
|
||||
let url_alphabet: Vec<u8> = (0x41..0x5B)
|
||||
// a-z
|
||||
.chain(0x61..0x7B)
|
||||
// 0-9
|
||||
.chain(0x30..0x3A)
|
||||
// -
|
||||
.chain(0x2D..0x2E)
|
||||
// _s
|
||||
.chain(0x5F..0x60)
|
||||
.collect();
|
||||
print_encode_table(&url_alphabet, "URL_SAFE_ENCODE", 0);
|
||||
print_decode_table(&url_alphabet, "URL_SAFE_DECODE", 0);
|
||||
|
||||
}
|
||||
|
||||
fn print_encode_table(alphabet: &[u8], const_name: &str, indent_depth: usize) {
|
||||
println!("{:width$}pub const {}: &'static [u8; 64] = &[", "", const_name, width=indent_depth);
|
||||
|
||||
for (i, b) in alphabet.iter().enumerate() {
|
||||
println!("{:width$}{}, // input {} (0x{:X}) => '{}' (0x{:X})", "",
|
||||
b, i, i, String::from_utf8(vec!(*b as u8)).unwrap(), b, width=indent_depth + 4);
|
||||
}
|
||||
|
||||
println!("{:width$}];", "", width=indent_depth);
|
||||
}
|
||||
|
||||
fn print_decode_table(alphabet: &[u8], const_name: &str, indent_depth: usize) {
|
||||
// map of alphabet bytes to 6-bit morsels
|
||||
let mut input_to_morsel = HashMap::<u8, u8>::new();
|
||||
|
||||
// standard base64 alphabet bytes, in order
|
||||
for (morsel, ascii_byte) in alphabet.iter().enumerate() {
|
||||
// truncation cast is fine here
|
||||
let _ = input_to_morsel.insert(*ascii_byte, morsel as u8);
|
||||
}
|
||||
|
||||
println!("{:width$}pub const {}: &'static [u8; 256] = &[", "", const_name, width=indent_depth);
|
||||
for ascii_byte in 0..256 {
|
||||
let (value, comment) = match input_to_morsel.get(&(ascii_byte as u8)) {
|
||||
None => ("INVALID_VALUE".to_string(),
|
||||
format!("input {} (0x{:X})", ascii_byte, ascii_byte)),
|
||||
Some(v) => (format!("{}", *v),
|
||||
format!("input {} (0x{:X} char '{}') => {} (0x{:X})",
|
||||
ascii_byte,
|
||||
ascii_byte,
|
||||
String::from_utf8(vec!(ascii_byte as u8)).unwrap(), *v, *v))
|
||||
};
|
||||
|
||||
println!("{:width$}{}, // {}", "", value, comment, width=indent_depth + 4);
|
||||
}
|
||||
println!("{:width$}];", "", width=indent_depth);
|
||||
}
|
675
third_party/rust/base64-0.5.2/src/lib.rs
vendored
675
third_party/rust/base64-0.5.2/src/lib.rs
vendored
@ -1,675 +0,0 @@
|
||||
extern crate byteorder;
|
||||
|
||||
use std::{fmt, error, str};
|
||||
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
|
||||
mod tables;
|
||||
|
||||
/// Available encoding character sets
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum CharacterSet {
|
||||
/// The standard character set (uses `+` and `/`)
|
||||
Standard,
|
||||
/// The URL safe character set (uses `-` and `_`)
|
||||
UrlSafe
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum LineEnding {
|
||||
LF,
|
||||
CRLF,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum LineWrap {
|
||||
NoWrap,
|
||||
Wrap(usize, LineEnding)
|
||||
}
|
||||
|
||||
/// Contains configuration parameters for base64 encoding
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Config {
|
||||
/// Character set to use
|
||||
char_set: CharacterSet,
|
||||
/// True to pad output with `=` characters
|
||||
pad: bool,
|
||||
/// Remove whitespace before decoding, at the cost of an allocation
|
||||
strip_whitespace: bool,
|
||||
/// ADT signifying whether to linewrap output, and if so by how many characters and with what ending
|
||||
line_wrap: LineWrap,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new(char_set: CharacterSet,
|
||||
pad: bool,
|
||||
strip_whitespace: bool,
|
||||
input_line_wrap: LineWrap) -> Config {
|
||||
let line_wrap = match input_line_wrap {
|
||||
LineWrap::Wrap(0, _) => LineWrap::NoWrap,
|
||||
_ => input_line_wrap,
|
||||
};
|
||||
|
||||
Config {
|
||||
char_set: char_set,
|
||||
pad: pad,
|
||||
strip_whitespace: strip_whitespace,
|
||||
line_wrap: line_wrap,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub static STANDARD: Config = Config {
|
||||
char_set: CharacterSet::Standard,
|
||||
pad: true,
|
||||
strip_whitespace: false,
|
||||
line_wrap: LineWrap::NoWrap,
|
||||
};
|
||||
|
||||
pub static MIME: Config = Config {
|
||||
char_set: CharacterSet::Standard,
|
||||
pad: true,
|
||||
strip_whitespace: true,
|
||||
line_wrap: LineWrap::Wrap(76, LineEnding::CRLF),
|
||||
};
|
||||
|
||||
pub static URL_SAFE: Config = Config {
|
||||
char_set: CharacterSet::UrlSafe,
|
||||
pad: true,
|
||||
strip_whitespace: false,
|
||||
line_wrap: LineWrap::NoWrap,
|
||||
};
|
||||
|
||||
pub static URL_SAFE_NO_PAD: Config = Config {
|
||||
char_set: CharacterSet::UrlSafe,
|
||||
pad: false,
|
||||
strip_whitespace: false,
|
||||
line_wrap: LineWrap::NoWrap,
|
||||
};
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum DecodeError {
|
||||
InvalidByte(usize, u8),
|
||||
InvalidLength,
|
||||
}
|
||||
|
||||
impl fmt::Display for DecodeError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
DecodeError::InvalidByte(index, byte) =>
|
||||
write!(f, "Invalid byte {}, offset {}.", byte, index),
|
||||
DecodeError::InvalidLength =>
|
||||
write!(f, "Encoded text cannot have a 6-bit remainder.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for DecodeError {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
DecodeError::InvalidByte(_, _) => "invalid byte",
|
||||
DecodeError::InvalidLength => "invalid length"
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
///Encode arbitrary octets as base64.
|
||||
///Returns a String.
|
||||
///Convenience for `encode_config(input, base64::STANDARD);`.
|
||||
///
|
||||
///# Example
|
||||
///
|
||||
///```rust
|
||||
///extern crate base64;
|
||||
///
|
||||
///fn main() {
|
||||
/// let b64 = base64::encode(b"hello world");
|
||||
/// println!("{}", b64);
|
||||
///}
|
||||
///```
|
||||
pub fn encode<T: ?Sized + AsRef<[u8]>>(input: &T) -> String {
|
||||
encode_config(input, STANDARD)
|
||||
}
|
||||
|
||||
///Decode from string reference as octets.
|
||||
///Returns a Result containing a Vec<u8>.
|
||||
///Convenience `decode_config(input, base64::STANDARD);`.
|
||||
///
|
||||
///# Example
|
||||
///
|
||||
///```rust
|
||||
///extern crate base64;
|
||||
///
|
||||
///fn main() {
|
||||
/// let bytes = base64::decode("aGVsbG8gd29ybGQ=").unwrap();
|
||||
/// println!("{:?}", bytes);
|
||||
///}
|
||||
///```
|
||||
pub fn decode<T: ?Sized + AsRef<[u8]>>(input: &T) -> Result<Vec<u8>, DecodeError> {
|
||||
decode_config(input, STANDARD)
|
||||
}
|
||||
|
||||
///Encode arbitrary octets as base64.
|
||||
///Returns a String.
|
||||
///
|
||||
///# Example
|
||||
///
|
||||
///```rust
|
||||
///extern crate base64;
|
||||
///
|
||||
///fn main() {
|
||||
/// let b64 = base64::encode_config(b"hello world~", base64::STANDARD);
|
||||
/// println!("{}", b64);
|
||||
///
|
||||
/// let b64_url = base64::encode_config(b"hello internet~", base64::URL_SAFE);
|
||||
/// println!("{}", b64_url);
|
||||
///}
|
||||
///```
|
||||
pub fn encode_config<T: ?Sized + AsRef<[u8]>>(input: &T, config: Config) -> String {
|
||||
let mut buf = match encoded_size(input.as_ref().len(), config) {
|
||||
Some(n) => String::with_capacity(n),
|
||||
None => panic!("integer overflow when calculating buffer size")
|
||||
};
|
||||
|
||||
encode_config_buf(input, config, &mut buf);
|
||||
|
||||
buf
|
||||
}
|
||||
|
||||
/// calculate the base64 encoded string size, including padding
|
||||
fn encoded_size(bytes_len: usize, config: Config) -> Option<usize> {
|
||||
let printing_output_chars = bytes_len
|
||||
.checked_add(2)
|
||||
.map(|x| x / 3)
|
||||
.and_then(|x| x.checked_mul(4));
|
||||
|
||||
//TODO this is subtly wrong but in a not dangerous way
|
||||
//pushing patch with identical to previous behavior, then fixing
|
||||
let line_ending_output_chars = match config.line_wrap {
|
||||
LineWrap::NoWrap => Some(0),
|
||||
LineWrap::Wrap(n, LineEnding::CRLF) =>
|
||||
printing_output_chars.map(|y| y / n).and_then(|y| y.checked_mul(2)),
|
||||
LineWrap::Wrap(n, LineEnding::LF) =>
|
||||
printing_output_chars.map(|y| y / n),
|
||||
};
|
||||
|
||||
printing_output_chars.and_then(|x|
|
||||
line_ending_output_chars.and_then(|y| x.checked_add(y))
|
||||
)
|
||||
}
|
||||
|
||||
///Encode arbitrary octets as base64.
|
||||
///Writes into the supplied buffer to avoid allocations.
|
||||
///
|
||||
///# Example
|
||||
///
|
||||
///```rust
|
||||
///extern crate base64;
|
||||
///
|
||||
///fn main() {
|
||||
/// let mut buf = String::new();
|
||||
/// base64::encode_config_buf(b"hello world~", base64::STANDARD, &mut buf);
|
||||
/// println!("{}", buf);
|
||||
///
|
||||
/// buf.clear();
|
||||
/// base64::encode_config_buf(b"hello internet~", base64::URL_SAFE, &mut buf);
|
||||
/// println!("{}", buf);
|
||||
///}
|
||||
///```
|
||||
pub fn encode_config_buf<T: ?Sized + AsRef<[u8]>>(input: &T, config: Config, buf: &mut String) {
|
||||
let input_bytes = input.as_ref();
|
||||
let ref charset = match config.char_set {
|
||||
CharacterSet::Standard => tables::STANDARD_ENCODE,
|
||||
CharacterSet::UrlSafe => tables::URL_SAFE_ENCODE,
|
||||
};
|
||||
|
||||
// reserve to make sure the memory we'll be writing to with unsafe is allocated
|
||||
let resv_size = match encoded_size(input_bytes.len(), config) {
|
||||
Some(n) => n,
|
||||
None => panic!("integer overflow when calculating buffer size"),
|
||||
};
|
||||
buf.reserve(resv_size);
|
||||
|
||||
let orig_buf_len = buf.len();
|
||||
let mut fast_loop_output_buf_len = orig_buf_len;
|
||||
|
||||
let input_chunk_len = 6;
|
||||
|
||||
let last_fast_index = input_bytes.len().saturating_sub(8);
|
||||
|
||||
// we're only going to insert valid utf8
|
||||
let mut raw = unsafe { buf.as_mut_vec() };
|
||||
// start at the first free part of the output buf
|
||||
let mut output_ptr = unsafe { raw.as_mut_ptr().offset(orig_buf_len as isize) };
|
||||
let mut input_index: usize = 0;
|
||||
if input_bytes.len() >= 8 {
|
||||
while input_index <= last_fast_index {
|
||||
let input_chunk = BigEndian::read_u64(&input_bytes[input_index..(input_index + 8)]);
|
||||
|
||||
// strip off 6 bits at a time for the first 6 bytes
|
||||
unsafe {
|
||||
std::ptr::write(output_ptr, charset[((input_chunk >> 58) & 0x3F) as usize]);
|
||||
std::ptr::write(output_ptr.offset(1), charset[((input_chunk >> 52) & 0x3F) as usize]);
|
||||
std::ptr::write(output_ptr.offset(2), charset[((input_chunk >> 46) & 0x3F) as usize]);
|
||||
std::ptr::write(output_ptr.offset(3), charset[((input_chunk >> 40) & 0x3F) as usize]);
|
||||
std::ptr::write(output_ptr.offset(4), charset[((input_chunk >> 34) & 0x3F) as usize]);
|
||||
std::ptr::write(output_ptr.offset(5), charset[((input_chunk >> 28) & 0x3F) as usize]);
|
||||
std::ptr::write(output_ptr.offset(6), charset[((input_chunk >> 22) & 0x3F) as usize]);
|
||||
std::ptr::write(output_ptr.offset(7), charset[((input_chunk >> 16) & 0x3F) as usize]);
|
||||
output_ptr = output_ptr.offset(8);
|
||||
}
|
||||
|
||||
input_index += input_chunk_len;
|
||||
fast_loop_output_buf_len += 8;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// expand len to include the bytes we just wrote
|
||||
raw.set_len(fast_loop_output_buf_len);
|
||||
}
|
||||
|
||||
// encode the 0 to 7 bytes left after the fast loop
|
||||
|
||||
let rem = input_bytes.len() % 3;
|
||||
let start_of_rem = input_bytes.len() - rem;
|
||||
|
||||
// start at the first index not handled by fast loop, which may be 0.
|
||||
let mut leftover_index = input_index;
|
||||
|
||||
while leftover_index < start_of_rem {
|
||||
raw.push(charset[(input_bytes[leftover_index] >> 2) as usize]);
|
||||
raw.push(charset[((input_bytes[leftover_index] << 4 | input_bytes[leftover_index + 1] >> 4) & 0x3f) as usize]);
|
||||
raw.push(charset[((input_bytes[leftover_index + 1] << 2 | input_bytes[leftover_index + 2] >> 6) & 0x3f) as usize]);
|
||||
raw.push(charset[(input_bytes[leftover_index + 2] & 0x3f) as usize]);
|
||||
|
||||
leftover_index += 3;
|
||||
}
|
||||
|
||||
if rem == 2 {
|
||||
raw.push(charset[(input_bytes[start_of_rem] >> 2) as usize]);
|
||||
raw.push(charset[((input_bytes[start_of_rem] << 4 | input_bytes[start_of_rem + 1] >> 4) & 0x3f) as usize]);
|
||||
raw.push(charset[(input_bytes[start_of_rem + 1] << 2 & 0x3f) as usize]);
|
||||
} else if rem == 1 {
|
||||
raw.push(charset[(input_bytes[start_of_rem] >> 2) as usize]);
|
||||
raw.push(charset[(input_bytes[start_of_rem] << 4 & 0x3f) as usize]);
|
||||
}
|
||||
|
||||
if config.pad {
|
||||
for _ in 0..((3 - rem) % 3) {
|
||||
raw.push(0x3d);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO FIXME this does the wrong thing for nonempty buffers
|
||||
if orig_buf_len == 0 {
|
||||
if let LineWrap::Wrap(line_size, line_end) = config.line_wrap {
|
||||
let len = raw.len();
|
||||
let mut i = 0;
|
||||
let mut j = 0;
|
||||
|
||||
while i < len {
|
||||
if i > 0 && i % line_size == 0 {
|
||||
match line_end {
|
||||
LineEnding::LF => { raw.insert(j, b'\n'); j += 1; }
|
||||
LineEnding::CRLF => { raw.insert(j, b'\r'); raw.insert(j + 1, b'\n'); j += 2; }
|
||||
}
|
||||
}
|
||||
|
||||
i += 1;
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Decode from string reference as octets.
|
||||
///Returns a Result containing a Vec<u8>.
|
||||
///
|
||||
///# Example
|
||||
///
|
||||
///```rust
|
||||
///extern crate base64;
|
||||
///
|
||||
///fn main() {
|
||||
/// let bytes = base64::decode_config("aGVsbG8gd29ybGR+Cg==", base64::STANDARD).unwrap();
|
||||
/// println!("{:?}", bytes);
|
||||
///
|
||||
/// let bytes_url = base64::decode_config("aGVsbG8gaW50ZXJuZXR-Cg==", base64::URL_SAFE).unwrap();
|
||||
/// println!("{:?}", bytes_url);
|
||||
///}
|
||||
///```
|
||||
pub fn decode_config<T: ?Sized + AsRef<[u8]>>(input: &T, config: Config) -> Result<Vec<u8>, DecodeError> {
|
||||
let mut buffer = Vec::<u8>::with_capacity(input.as_ref().len() * 4 / 3);
|
||||
|
||||
decode_config_buf(input, config, &mut buffer).map(|_| buffer)
|
||||
}
|
||||
|
||||
///Decode from string reference as octets.
|
||||
///Writes into the supplied buffer to avoid allocation.
|
||||
///Returns a Result containing an empty tuple, aka ().
|
||||
///
|
||||
///# Example
|
||||
///
|
||||
///```rust
|
||||
///extern crate base64;
|
||||
///
|
||||
///fn main() {
|
||||
/// let mut buffer = Vec::<u8>::new();
|
||||
/// base64::decode_config_buf("aGVsbG8gd29ybGR+Cg==", base64::STANDARD, &mut buffer).unwrap();
|
||||
/// println!("{:?}", buffer);
|
||||
///
|
||||
/// buffer.clear();
|
||||
///
|
||||
/// base64::decode_config_buf("aGVsbG8gaW50ZXJuZXR-Cg==", base64::URL_SAFE, &mut buffer).unwrap();
|
||||
/// println!("{:?}", buffer);
|
||||
///}
|
||||
///```
|
||||
pub fn decode_config_buf<T: ?Sized + AsRef<[u8]>>(input: &T,
|
||||
config: Config,
|
||||
buffer: &mut Vec<u8>)
|
||||
-> Result<(), DecodeError> {
|
||||
let mut input_copy;
|
||||
let input_bytes = if config.strip_whitespace {
|
||||
input_copy = Vec::<u8>::with_capacity(input.as_ref().len());
|
||||
input_copy.extend(input.as_ref().iter().filter(|b| !b" \n\t\r\x0b\x0c".contains(b)));
|
||||
|
||||
input_copy.as_ref()
|
||||
} else {
|
||||
input.as_ref()
|
||||
};
|
||||
|
||||
let ref decode_table = match config.char_set {
|
||||
CharacterSet::Standard => tables::STANDARD_DECODE,
|
||||
CharacterSet::UrlSafe => tables::URL_SAFE_DECODE,
|
||||
};
|
||||
|
||||
buffer.reserve(input_bytes.len() * 3 / 4);
|
||||
|
||||
// the fast loop only handles complete chunks of 8 input bytes without padding
|
||||
let chunk_len = 8;
|
||||
let decoded_chunk_len = 6;
|
||||
let remainder_len = input_bytes.len() % chunk_len;
|
||||
let trailing_bytes_to_skip = if remainder_len == 0 {
|
||||
// if input is a multiple of the chunk size, ignore the last chunk as it may have padding
|
||||
chunk_len
|
||||
} else {
|
||||
remainder_len
|
||||
};
|
||||
|
||||
let length_of_full_chunks = input_bytes.len().saturating_sub(trailing_bytes_to_skip);
|
||||
|
||||
let starting_output_index = buffer.len();
|
||||
// Resize to hold decoded output from fast loop. Need the extra two bytes because
|
||||
// we write a full 8 bytes for the last 6-byte decoded chunk and then truncate off two
|
||||
let new_size = starting_output_index
|
||||
+ length_of_full_chunks / chunk_len * decoded_chunk_len
|
||||
+ (chunk_len - decoded_chunk_len);
|
||||
buffer.resize(new_size, 0);
|
||||
|
||||
let mut output_index = starting_output_index;
|
||||
|
||||
{
|
||||
let buffer_slice = buffer.as_mut_slice();
|
||||
|
||||
let mut input_index = 0;
|
||||
// initial value is never used; always set if fast loop breaks
|
||||
let mut bad_byte_index: usize = 0;
|
||||
// a non-invalid value means it's not an error if fast loop never runs
|
||||
let mut morsel: u8 = 0;
|
||||
|
||||
// fast loop of 8 bytes at a time
|
||||
while input_index < length_of_full_chunks {
|
||||
let mut accum: u64;
|
||||
|
||||
let input_chunk = BigEndian::read_u64(&input_bytes[input_index..(input_index + 8)]);
|
||||
morsel = decode_table[(input_chunk >> 56) as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
bad_byte_index = input_index;
|
||||
break;
|
||||
};
|
||||
accum = (morsel as u64) << 58;
|
||||
|
||||
morsel = decode_table[(input_chunk >> 48 & 0xFF) as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
bad_byte_index = input_index + 1;
|
||||
break;
|
||||
};
|
||||
accum |= (morsel as u64) << 52;
|
||||
|
||||
morsel = decode_table[(input_chunk >> 40 & 0xFF) as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
bad_byte_index = input_index + 2;
|
||||
break;
|
||||
};
|
||||
accum |= (morsel as u64) << 46;
|
||||
|
||||
morsel = decode_table[(input_chunk >> 32 & 0xFF) as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
bad_byte_index = input_index + 3;
|
||||
break;
|
||||
};
|
||||
accum |= (morsel as u64) << 40;
|
||||
|
||||
morsel = decode_table[(input_chunk >> 24 & 0xFF) as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
bad_byte_index = input_index + 4;
|
||||
break;
|
||||
};
|
||||
accum |= (morsel as u64) << 34;
|
||||
|
||||
morsel = decode_table[(input_chunk >> 16 & 0xFF) as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
bad_byte_index = input_index + 5;
|
||||
break;
|
||||
};
|
||||
accum |= (morsel as u64) << 28;
|
||||
|
||||
morsel = decode_table[(input_chunk >> 8 & 0xFF) as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
bad_byte_index = input_index + 6;
|
||||
break;
|
||||
};
|
||||
accum |= (morsel as u64) << 22;
|
||||
|
||||
morsel = decode_table[(input_chunk & 0xFF) as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
bad_byte_index = input_index + 7;
|
||||
break;
|
||||
};
|
||||
accum |= (morsel as u64) << 16;
|
||||
|
||||
BigEndian::write_u64(&mut buffer_slice[(output_index)..(output_index + 8)],
|
||||
accum);
|
||||
|
||||
output_index += 6;
|
||||
input_index += chunk_len;
|
||||
};
|
||||
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
// we got here from a break
|
||||
return Err(DecodeError::InvalidByte(bad_byte_index, input_bytes[bad_byte_index]));
|
||||
}
|
||||
}
|
||||
|
||||
// Truncate off the last two bytes from writing the last u64.
|
||||
// Unconditional because we added on the extra 2 bytes in the resize before the loop,
|
||||
// so it will never underflow.
|
||||
let new_len = buffer.len() - (chunk_len - decoded_chunk_len);
|
||||
buffer.truncate(new_len);
|
||||
|
||||
// handle leftovers (at most 8 bytes, decoded to 6).
|
||||
// Use a u64 as a stack-resident 8 bytes buffer.
|
||||
let mut leftover_bits: u64 = 0;
|
||||
let mut morsels_in_leftover = 0;
|
||||
let mut padding_bytes = 0;
|
||||
let mut first_padding_index: usize = 0;
|
||||
for (i, b) in input_bytes[length_of_full_chunks..].iter().enumerate() {
|
||||
// '=' padding
|
||||
if *b == 0x3D {
|
||||
// There can be bad padding in a few ways:
|
||||
// 1 - Padding with non-padding characters after it
|
||||
// 2 - Padding after zero or one non-padding characters before it
|
||||
// in the current quad.
|
||||
// 3 - More than two characters of padding. If 3 or 4 padding chars
|
||||
// are in the same quad, that implies it will be caught by #2.
|
||||
// If it spreads from one quad to another, it will be caught by
|
||||
// #2 in the second quad.
|
||||
|
||||
if i % 4 < 2 {
|
||||
// Check for case #2.
|
||||
// TODO InvalidPadding error
|
||||
return Err(DecodeError::InvalidByte(length_of_full_chunks + i, *b));
|
||||
};
|
||||
|
||||
if padding_bytes == 0 {
|
||||
first_padding_index = i;
|
||||
};
|
||||
|
||||
padding_bytes += 1;
|
||||
continue;
|
||||
};
|
||||
|
||||
// Check for case #1.
|
||||
// To make '=' handling consistent with the main loop, don't allow
|
||||
// non-suffix '=' in trailing chunk either. Report error as first
|
||||
// erroneous padding.
|
||||
if padding_bytes > 0 {
|
||||
return Err(DecodeError::InvalidByte(
|
||||
length_of_full_chunks + first_padding_index, 0x3D));
|
||||
};
|
||||
|
||||
// can use up to 8 * 6 = 48 bits of the u64, if last chunk has no padding.
|
||||
// To minimize shifts, pack the leftovers from left to right.
|
||||
let shift = 64 - (morsels_in_leftover + 1) * 6;
|
||||
// tables are all 256 elements, cannot overflow from a u8 index
|
||||
let morsel = decode_table[*b as usize];
|
||||
if morsel == tables::INVALID_VALUE {
|
||||
return Err(DecodeError::InvalidByte(length_of_full_chunks + i, *b));
|
||||
};
|
||||
|
||||
leftover_bits |= (morsel as u64) << shift;
|
||||
morsels_in_leftover += 1;
|
||||
};
|
||||
|
||||
let leftover_bits_ready_to_append = match morsels_in_leftover {
|
||||
0 => 0,
|
||||
1 => return Err(DecodeError::InvalidLength),
|
||||
2 => 8,
|
||||
3 => 16,
|
||||
4 => 24,
|
||||
5 => return Err(DecodeError::InvalidLength),
|
||||
6 => 32,
|
||||
7 => 40,
|
||||
8 => 48,
|
||||
_ => panic!("Impossible: must only have 0 to 4 input bytes in last quad")
|
||||
};
|
||||
|
||||
let mut leftover_bits_appended_to_buf = 0;
|
||||
while leftover_bits_appended_to_buf < leftover_bits_ready_to_append {
|
||||
// `as` simply truncates the higher bits, which is what we want here
|
||||
let selected_bits = (leftover_bits >> (56 - leftover_bits_appended_to_buf)) as u8;
|
||||
buffer.push(selected_bits);
|
||||
|
||||
leftover_bits_appended_to_buf += 8;
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn encoded_size_correct() {
|
||||
assert_eq!(Some(0), encoded_size(0, STANDARD));
|
||||
|
||||
assert_eq!(Some(4), encoded_size(1, STANDARD));
|
||||
assert_eq!(Some(4), encoded_size(2, STANDARD));
|
||||
assert_eq!(Some(4), encoded_size(3, STANDARD));
|
||||
|
||||
assert_eq!(Some(8), encoded_size(4, STANDARD));
|
||||
assert_eq!(Some(8), encoded_size(5, STANDARD));
|
||||
assert_eq!(Some(8), encoded_size(6, STANDARD));
|
||||
|
||||
assert_eq!(Some(12), encoded_size(7, STANDARD));
|
||||
assert_eq!(Some(12), encoded_size(8, STANDARD));
|
||||
assert_eq!(Some(12), encoded_size(9, STANDARD));
|
||||
|
||||
assert_eq!(Some(72), encoded_size(54, STANDARD));
|
||||
|
||||
assert_eq!(Some(76), encoded_size(55, STANDARD));
|
||||
assert_eq!(Some(76), encoded_size(56, STANDARD));
|
||||
assert_eq!(Some(76), encoded_size(57, STANDARD));
|
||||
|
||||
assert_eq!(Some(80), encoded_size(58, STANDARD));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encoded_size_correct_mime() {
|
||||
assert_eq!(Some(0), encoded_size(0, MIME));
|
||||
|
||||
assert_eq!(Some(4), encoded_size(1, MIME));
|
||||
assert_eq!(Some(4), encoded_size(2, MIME));
|
||||
assert_eq!(Some(4), encoded_size(3, MIME));
|
||||
|
||||
assert_eq!(Some(8), encoded_size(4, MIME));
|
||||
assert_eq!(Some(8), encoded_size(5, MIME));
|
||||
assert_eq!(Some(8), encoded_size(6, MIME));
|
||||
|
||||
assert_eq!(Some(12), encoded_size(7, MIME));
|
||||
assert_eq!(Some(12), encoded_size(8, MIME));
|
||||
assert_eq!(Some(12), encoded_size(9, MIME));
|
||||
|
||||
assert_eq!(Some(72), encoded_size(54, MIME));
|
||||
|
||||
assert_eq!(Some(78), encoded_size(55, MIME));
|
||||
assert_eq!(Some(78), encoded_size(56, MIME));
|
||||
assert_eq!(Some(78), encoded_size(57, MIME));
|
||||
|
||||
assert_eq!(Some(82), encoded_size(58, MIME));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encoded_size_correct_lf() {
|
||||
let config = Config::new(
|
||||
CharacterSet::Standard,
|
||||
true,
|
||||
false,
|
||||
LineWrap::Wrap(76, LineEnding::LF)
|
||||
);
|
||||
|
||||
assert_eq!(Some(0), encoded_size(0, config));
|
||||
|
||||
assert_eq!(Some(4), encoded_size(1, config));
|
||||
assert_eq!(Some(4), encoded_size(2, config));
|
||||
assert_eq!(Some(4), encoded_size(3, config));
|
||||
|
||||
assert_eq!(Some(8), encoded_size(4, config));
|
||||
assert_eq!(Some(8), encoded_size(5, config));
|
||||
assert_eq!(Some(8), encoded_size(6, config));
|
||||
|
||||
assert_eq!(Some(12), encoded_size(7, config));
|
||||
assert_eq!(Some(12), encoded_size(8, config));
|
||||
assert_eq!(Some(12), encoded_size(9, config));
|
||||
|
||||
assert_eq!(Some(72), encoded_size(54, config));
|
||||
|
||||
assert_eq!(Some(77), encoded_size(55, config));
|
||||
assert_eq!(Some(77), encoded_size(56, config));
|
||||
assert_eq!(Some(77), encoded_size(57, config));
|
||||
|
||||
assert_eq!(Some(81), encoded_size(58, config));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encoded_size_overflow() {
|
||||
assert_eq!(None, encoded_size(std::usize::MAX, STANDARD));
|
||||
}
|
||||
}
|
649
third_party/rust/base64-0.5.2/src/tables.rs
vendored
649
third_party/rust/base64-0.5.2/src/tables.rs
vendored
@ -1,649 +0,0 @@
|
||||
pub const INVALID_VALUE: u8 = 255;
|
||||
pub const STANDARD_ENCODE: &'static [u8; 64] = &[
|
||||
65, // input 0 (0x0) => 'A' (0x41)
|
||||
66, // input 1 (0x1) => 'B' (0x42)
|
||||
67, // input 2 (0x2) => 'C' (0x43)
|
||||
68, // input 3 (0x3) => 'D' (0x44)
|
||||
69, // input 4 (0x4) => 'E' (0x45)
|
||||
70, // input 5 (0x5) => 'F' (0x46)
|
||||
71, // input 6 (0x6) => 'G' (0x47)
|
||||
72, // input 7 (0x7) => 'H' (0x48)
|
||||
73, // input 8 (0x8) => 'I' (0x49)
|
||||
74, // input 9 (0x9) => 'J' (0x4A)
|
||||
75, // input 10 (0xA) => 'K' (0x4B)
|
||||
76, // input 11 (0xB) => 'L' (0x4C)
|
||||
77, // input 12 (0xC) => 'M' (0x4D)
|
||||
78, // input 13 (0xD) => 'N' (0x4E)
|
||||
79, // input 14 (0xE) => 'O' (0x4F)
|
||||
80, // input 15 (0xF) => 'P' (0x50)
|
||||
81, // input 16 (0x10) => 'Q' (0x51)
|
||||
82, // input 17 (0x11) => 'R' (0x52)
|
||||
83, // input 18 (0x12) => 'S' (0x53)
|
||||
84, // input 19 (0x13) => 'T' (0x54)
|
||||
85, // input 20 (0x14) => 'U' (0x55)
|
||||
86, // input 21 (0x15) => 'V' (0x56)
|
||||
87, // input 22 (0x16) => 'W' (0x57)
|
||||
88, // input 23 (0x17) => 'X' (0x58)
|
||||
89, // input 24 (0x18) => 'Y' (0x59)
|
||||
90, // input 25 (0x19) => 'Z' (0x5A)
|
||||
97, // input 26 (0x1A) => 'a' (0x61)
|
||||
98, // input 27 (0x1B) => 'b' (0x62)
|
||||
99, // input 28 (0x1C) => 'c' (0x63)
|
||||
100, // input 29 (0x1D) => 'd' (0x64)
|
||||
101, // input 30 (0x1E) => 'e' (0x65)
|
||||
102, // input 31 (0x1F) => 'f' (0x66)
|
||||
103, // input 32 (0x20) => 'g' (0x67)
|
||||
104, // input 33 (0x21) => 'h' (0x68)
|
||||
105, // input 34 (0x22) => 'i' (0x69)
|
||||
106, // input 35 (0x23) => 'j' (0x6A)
|
||||
107, // input 36 (0x24) => 'k' (0x6B)
|
||||
108, // input 37 (0x25) => 'l' (0x6C)
|
||||
109, // input 38 (0x26) => 'm' (0x6D)
|
||||
110, // input 39 (0x27) => 'n' (0x6E)
|
||||
111, // input 40 (0x28) => 'o' (0x6F)
|
||||
112, // input 41 (0x29) => 'p' (0x70)
|
||||
113, // input 42 (0x2A) => 'q' (0x71)
|
||||
114, // input 43 (0x2B) => 'r' (0x72)
|
||||
115, // input 44 (0x2C) => 's' (0x73)
|
||||
116, // input 45 (0x2D) => 't' (0x74)
|
||||
117, // input 46 (0x2E) => 'u' (0x75)
|
||||
118, // input 47 (0x2F) => 'v' (0x76)
|
||||
119, // input 48 (0x30) => 'w' (0x77)
|
||||
120, // input 49 (0x31) => 'x' (0x78)
|
||||
121, // input 50 (0x32) => 'y' (0x79)
|
||||
122, // input 51 (0x33) => 'z' (0x7A)
|
||||
48, // input 52 (0x34) => '0' (0x30)
|
||||
49, // input 53 (0x35) => '1' (0x31)
|
||||
50, // input 54 (0x36) => '2' (0x32)
|
||||
51, // input 55 (0x37) => '3' (0x33)
|
||||
52, // input 56 (0x38) => '4' (0x34)
|
||||
53, // input 57 (0x39) => '5' (0x35)
|
||||
54, // input 58 (0x3A) => '6' (0x36)
|
||||
55, // input 59 (0x3B) => '7' (0x37)
|
||||
56, // input 60 (0x3C) => '8' (0x38)
|
||||
57, // input 61 (0x3D) => '9' (0x39)
|
||||
43, // input 62 (0x3E) => '+' (0x2B)
|
||||
47, // input 63 (0x3F) => '/' (0x2F)
|
||||
];
|
||||
pub const STANDARD_DECODE: &'static [u8; 256] = &[
|
||||
INVALID_VALUE, // input 0 (0x0)
|
||||
INVALID_VALUE, // input 1 (0x1)
|
||||
INVALID_VALUE, // input 2 (0x2)
|
||||
INVALID_VALUE, // input 3 (0x3)
|
||||
INVALID_VALUE, // input 4 (0x4)
|
||||
INVALID_VALUE, // input 5 (0x5)
|
||||
INVALID_VALUE, // input 6 (0x6)
|
||||
INVALID_VALUE, // input 7 (0x7)
|
||||
INVALID_VALUE, // input 8 (0x8)
|
||||
INVALID_VALUE, // input 9 (0x9)
|
||||
INVALID_VALUE, // input 10 (0xA)
|
||||
INVALID_VALUE, // input 11 (0xB)
|
||||
INVALID_VALUE, // input 12 (0xC)
|
||||
INVALID_VALUE, // input 13 (0xD)
|
||||
INVALID_VALUE, // input 14 (0xE)
|
||||
INVALID_VALUE, // input 15 (0xF)
|
||||
INVALID_VALUE, // input 16 (0x10)
|
||||
INVALID_VALUE, // input 17 (0x11)
|
||||
INVALID_VALUE, // input 18 (0x12)
|
||||
INVALID_VALUE, // input 19 (0x13)
|
||||
INVALID_VALUE, // input 20 (0x14)
|
||||
INVALID_VALUE, // input 21 (0x15)
|
||||
INVALID_VALUE, // input 22 (0x16)
|
||||
INVALID_VALUE, // input 23 (0x17)
|
||||
INVALID_VALUE, // input 24 (0x18)
|
||||
INVALID_VALUE, // input 25 (0x19)
|
||||
INVALID_VALUE, // input 26 (0x1A)
|
||||
INVALID_VALUE, // input 27 (0x1B)
|
||||
INVALID_VALUE, // input 28 (0x1C)
|
||||
INVALID_VALUE, // input 29 (0x1D)
|
||||
INVALID_VALUE, // input 30 (0x1E)
|
||||
INVALID_VALUE, // input 31 (0x1F)
|
||||
INVALID_VALUE, // input 32 (0x20)
|
||||
INVALID_VALUE, // input 33 (0x21)
|
||||
INVALID_VALUE, // input 34 (0x22)
|
||||
INVALID_VALUE, // input 35 (0x23)
|
||||
INVALID_VALUE, // input 36 (0x24)
|
||||
INVALID_VALUE, // input 37 (0x25)
|
||||
INVALID_VALUE, // input 38 (0x26)
|
||||
INVALID_VALUE, // input 39 (0x27)
|
||||
INVALID_VALUE, // input 40 (0x28)
|
||||
INVALID_VALUE, // input 41 (0x29)
|
||||
INVALID_VALUE, // input 42 (0x2A)
|
||||
62, // input 43 (0x2B char '+') => 62 (0x3E)
|
||||
INVALID_VALUE, // input 44 (0x2C)
|
||||
INVALID_VALUE, // input 45 (0x2D)
|
||||
INVALID_VALUE, // input 46 (0x2E)
|
||||
63, // input 47 (0x2F char '/') => 63 (0x3F)
|
||||
52, // input 48 (0x30 char '0') => 52 (0x34)
|
||||
53, // input 49 (0x31 char '1') => 53 (0x35)
|
||||
54, // input 50 (0x32 char '2') => 54 (0x36)
|
||||
55, // input 51 (0x33 char '3') => 55 (0x37)
|
||||
56, // input 52 (0x34 char '4') => 56 (0x38)
|
||||
57, // input 53 (0x35 char '5') => 57 (0x39)
|
||||
58, // input 54 (0x36 char '6') => 58 (0x3A)
|
||||
59, // input 55 (0x37 char '7') => 59 (0x3B)
|
||||
60, // input 56 (0x38 char '8') => 60 (0x3C)
|
||||
61, // input 57 (0x39 char '9') => 61 (0x3D)
|
||||
INVALID_VALUE, // input 58 (0x3A)
|
||||
INVALID_VALUE, // input 59 (0x3B)
|
||||
INVALID_VALUE, // input 60 (0x3C)
|
||||
INVALID_VALUE, // input 61 (0x3D)
|
||||
INVALID_VALUE, // input 62 (0x3E)
|
||||
INVALID_VALUE, // input 63 (0x3F)
|
||||
INVALID_VALUE, // input 64 (0x40)
|
||||
0, // input 65 (0x41 char 'A') => 0 (0x0)
|
||||
1, // input 66 (0x42 char 'B') => 1 (0x1)
|
||||
2, // input 67 (0x43 char 'C') => 2 (0x2)
|
||||
3, // input 68 (0x44 char 'D') => 3 (0x3)
|
||||
4, // input 69 (0x45 char 'E') => 4 (0x4)
|
||||
5, // input 70 (0x46 char 'F') => 5 (0x5)
|
||||
6, // input 71 (0x47 char 'G') => 6 (0x6)
|
||||
7, // input 72 (0x48 char 'H') => 7 (0x7)
|
||||
8, // input 73 (0x49 char 'I') => 8 (0x8)
|
||||
9, // input 74 (0x4A char 'J') => 9 (0x9)
|
||||
10, // input 75 (0x4B char 'K') => 10 (0xA)
|
||||
11, // input 76 (0x4C char 'L') => 11 (0xB)
|
||||
12, // input 77 (0x4D char 'M') => 12 (0xC)
|
||||
13, // input 78 (0x4E char 'N') => 13 (0xD)
|
||||
14, // input 79 (0x4F char 'O') => 14 (0xE)
|
||||
15, // input 80 (0x50 char 'P') => 15 (0xF)
|
||||
16, // input 81 (0x51 char 'Q') => 16 (0x10)
|
||||
17, // input 82 (0x52 char 'R') => 17 (0x11)
|
||||
18, // input 83 (0x53 char 'S') => 18 (0x12)
|
||||
19, // input 84 (0x54 char 'T') => 19 (0x13)
|
||||
20, // input 85 (0x55 char 'U') => 20 (0x14)
|
||||
21, // input 86 (0x56 char 'V') => 21 (0x15)
|
||||
22, // input 87 (0x57 char 'W') => 22 (0x16)
|
||||
23, // input 88 (0x58 char 'X') => 23 (0x17)
|
||||
24, // input 89 (0x59 char 'Y') => 24 (0x18)
|
||||
25, // input 90 (0x5A char 'Z') => 25 (0x19)
|
||||
INVALID_VALUE, // input 91 (0x5B)
|
||||
INVALID_VALUE, // input 92 (0x5C)
|
||||
INVALID_VALUE, // input 93 (0x5D)
|
||||
INVALID_VALUE, // input 94 (0x5E)
|
||||
INVALID_VALUE, // input 95 (0x5F)
|
||||
INVALID_VALUE, // input 96 (0x60)
|
||||
26, // input 97 (0x61 char 'a') => 26 (0x1A)
|
||||
27, // input 98 (0x62 char 'b') => 27 (0x1B)
|
||||
28, // input 99 (0x63 char 'c') => 28 (0x1C)
|
||||
29, // input 100 (0x64 char 'd') => 29 (0x1D)
|
||||
30, // input 101 (0x65 char 'e') => 30 (0x1E)
|
||||
31, // input 102 (0x66 char 'f') => 31 (0x1F)
|
||||
32, // input 103 (0x67 char 'g') => 32 (0x20)
|
||||
33, // input 104 (0x68 char 'h') => 33 (0x21)
|
||||
34, // input 105 (0x69 char 'i') => 34 (0x22)
|
||||
35, // input 106 (0x6A char 'j') => 35 (0x23)
|
||||
36, // input 107 (0x6B char 'k') => 36 (0x24)
|
||||
37, // input 108 (0x6C char 'l') => 37 (0x25)
|
||||
38, // input 109 (0x6D char 'm') => 38 (0x26)
|
||||
39, // input 110 (0x6E char 'n') => 39 (0x27)
|
||||
40, // input 111 (0x6F char 'o') => 40 (0x28)
|
||||
41, // input 112 (0x70 char 'p') => 41 (0x29)
|
||||
42, // input 113 (0x71 char 'q') => 42 (0x2A)
|
||||
43, // input 114 (0x72 char 'r') => 43 (0x2B)
|
||||
44, // input 115 (0x73 char 's') => 44 (0x2C)
|
||||
45, // input 116 (0x74 char 't') => 45 (0x2D)
|
||||
46, // input 117 (0x75 char 'u') => 46 (0x2E)
|
||||
47, // input 118 (0x76 char 'v') => 47 (0x2F)
|
||||
48, // input 119 (0x77 char 'w') => 48 (0x30)
|
||||
49, // input 120 (0x78 char 'x') => 49 (0x31)
|
||||
50, // input 121 (0x79 char 'y') => 50 (0x32)
|
||||
51, // input 122 (0x7A char 'z') => 51 (0x33)
|
||||
INVALID_VALUE, // input 123 (0x7B)
|
||||
INVALID_VALUE, // input 124 (0x7C)
|
||||
INVALID_VALUE, // input 125 (0x7D)
|
||||
INVALID_VALUE, // input 126 (0x7E)
|
||||
INVALID_VALUE, // input 127 (0x7F)
|
||||
INVALID_VALUE, // input 128 (0x80)
|
||||
INVALID_VALUE, // input 129 (0x81)
|
||||
INVALID_VALUE, // input 130 (0x82)
|
||||
INVALID_VALUE, // input 131 (0x83)
|
||||
INVALID_VALUE, // input 132 (0x84)
|
||||
INVALID_VALUE, // input 133 (0x85)
|
||||
INVALID_VALUE, // input 134 (0x86)
|
||||
INVALID_VALUE, // input 135 (0x87)
|
||||
INVALID_VALUE, // input 136 (0x88)
|
||||
INVALID_VALUE, // input 137 (0x89)
|
||||
INVALID_VALUE, // input 138 (0x8A)
|
||||
INVALID_VALUE, // input 139 (0x8B)
|
||||
INVALID_VALUE, // input 140 (0x8C)
|
||||
INVALID_VALUE, // input 141 (0x8D)
|
||||
INVALID_VALUE, // input 142 (0x8E)
|
||||
INVALID_VALUE, // input 143 (0x8F)
|
||||
INVALID_VALUE, // input 144 (0x90)
|
||||
INVALID_VALUE, // input 145 (0x91)
|
||||
INVALID_VALUE, // input 146 (0x92)
|
||||
INVALID_VALUE, // input 147 (0x93)
|
||||
INVALID_VALUE, // input 148 (0x94)
|
||||
INVALID_VALUE, // input 149 (0x95)
|
||||
INVALID_VALUE, // input 150 (0x96)
|
||||
INVALID_VALUE, // input 151 (0x97)
|
||||
INVALID_VALUE, // input 152 (0x98)
|
||||
INVALID_VALUE, // input 153 (0x99)
|
||||
INVALID_VALUE, // input 154 (0x9A)
|
||||
INVALID_VALUE, // input 155 (0x9B)
|
||||
INVALID_VALUE, // input 156 (0x9C)
|
||||
INVALID_VALUE, // input 157 (0x9D)
|
||||
INVALID_VALUE, // input 158 (0x9E)
|
||||
INVALID_VALUE, // input 159 (0x9F)
|
||||
INVALID_VALUE, // input 160 (0xA0)
|
||||
INVALID_VALUE, // input 161 (0xA1)
|
||||
INVALID_VALUE, // input 162 (0xA2)
|
||||
INVALID_VALUE, // input 163 (0xA3)
|
||||
INVALID_VALUE, // input 164 (0xA4)
|
||||
INVALID_VALUE, // input 165 (0xA5)
|
||||
INVALID_VALUE, // input 166 (0xA6)
|
||||
INVALID_VALUE, // input 167 (0xA7)
|
||||
INVALID_VALUE, // input 168 (0xA8)
|
||||
INVALID_VALUE, // input 169 (0xA9)
|
||||
INVALID_VALUE, // input 170 (0xAA)
|
||||
INVALID_VALUE, // input 171 (0xAB)
|
||||
INVALID_VALUE, // input 172 (0xAC)
|
||||
INVALID_VALUE, // input 173 (0xAD)
|
||||
INVALID_VALUE, // input 174 (0xAE)
|
||||
INVALID_VALUE, // input 175 (0xAF)
|
||||
INVALID_VALUE, // input 176 (0xB0)
|
||||
INVALID_VALUE, // input 177 (0xB1)
|
||||
INVALID_VALUE, // input 178 (0xB2)
|
||||
INVALID_VALUE, // input 179 (0xB3)
|
||||
INVALID_VALUE, // input 180 (0xB4)
|
||||
INVALID_VALUE, // input 181 (0xB5)
|
||||
INVALID_VALUE, // input 182 (0xB6)
|
||||
INVALID_VALUE, // input 183 (0xB7)
|
||||
INVALID_VALUE, // input 184 (0xB8)
|
||||
INVALID_VALUE, // input 185 (0xB9)
|
||||
INVALID_VALUE, // input 186 (0xBA)
|
||||
INVALID_VALUE, // input 187 (0xBB)
|
||||
INVALID_VALUE, // input 188 (0xBC)
|
||||
INVALID_VALUE, // input 189 (0xBD)
|
||||
INVALID_VALUE, // input 190 (0xBE)
|
||||
INVALID_VALUE, // input 191 (0xBF)
|
||||
INVALID_VALUE, // input 192 (0xC0)
|
||||
INVALID_VALUE, // input 193 (0xC1)
|
||||
INVALID_VALUE, // input 194 (0xC2)
|
||||
INVALID_VALUE, // input 195 (0xC3)
|
||||
INVALID_VALUE, // input 196 (0xC4)
|
||||
INVALID_VALUE, // input 197 (0xC5)
|
||||
INVALID_VALUE, // input 198 (0xC6)
|
||||
INVALID_VALUE, // input 199 (0xC7)
|
||||
INVALID_VALUE, // input 200 (0xC8)
|
||||
INVALID_VALUE, // input 201 (0xC9)
|
||||
INVALID_VALUE, // input 202 (0xCA)
|
||||
INVALID_VALUE, // input 203 (0xCB)
|
||||
INVALID_VALUE, // input 204 (0xCC)
|
||||
INVALID_VALUE, // input 205 (0xCD)
|
||||
INVALID_VALUE, // input 206 (0xCE)
|
||||
INVALID_VALUE, // input 207 (0xCF)
|
||||
INVALID_VALUE, // input 208 (0xD0)
|
||||
INVALID_VALUE, // input 209 (0xD1)
|
||||
INVALID_VALUE, // input 210 (0xD2)
|
||||
INVALID_VALUE, // input 211 (0xD3)
|
||||
INVALID_VALUE, // input 212 (0xD4)
|
||||
INVALID_VALUE, // input 213 (0xD5)
|
||||
INVALID_VALUE, // input 214 (0xD6)
|
||||
INVALID_VALUE, // input 215 (0xD7)
|
||||
INVALID_VALUE, // input 216 (0xD8)
|
||||
INVALID_VALUE, // input 217 (0xD9)
|
||||
INVALID_VALUE, // input 218 (0xDA)
|
||||
INVALID_VALUE, // input 219 (0xDB)
|
||||
INVALID_VALUE, // input 220 (0xDC)
|
||||
INVALID_VALUE, // input 221 (0xDD)
|
||||
INVALID_VALUE, // input 222 (0xDE)
|
||||
INVALID_VALUE, // input 223 (0xDF)
|
||||
INVALID_VALUE, // input 224 (0xE0)
|
||||
INVALID_VALUE, // input 225 (0xE1)
|
||||
INVALID_VALUE, // input 226 (0xE2)
|
||||
INVALID_VALUE, // input 227 (0xE3)
|
||||
INVALID_VALUE, // input 228 (0xE4)
|
||||
INVALID_VALUE, // input 229 (0xE5)
|
||||
INVALID_VALUE, // input 230 (0xE6)
|
||||
INVALID_VALUE, // input 231 (0xE7)
|
||||
INVALID_VALUE, // input 232 (0xE8)
|
||||
INVALID_VALUE, // input 233 (0xE9)
|
||||
INVALID_VALUE, // input 234 (0xEA)
|
||||
INVALID_VALUE, // input 235 (0xEB)
|
||||
INVALID_VALUE, // input 236 (0xEC)
|
||||
INVALID_VALUE, // input 237 (0xED)
|
||||
INVALID_VALUE, // input 238 (0xEE)
|
||||
INVALID_VALUE, // input 239 (0xEF)
|
||||
INVALID_VALUE, // input 240 (0xF0)
|
||||
INVALID_VALUE, // input 241 (0xF1)
|
||||
INVALID_VALUE, // input 242 (0xF2)
|
||||
INVALID_VALUE, // input 243 (0xF3)
|
||||
INVALID_VALUE, // input 244 (0xF4)
|
||||
INVALID_VALUE, // input 245 (0xF5)
|
||||
INVALID_VALUE, // input 246 (0xF6)
|
||||
INVALID_VALUE, // input 247 (0xF7)
|
||||
INVALID_VALUE, // input 248 (0xF8)
|
||||
INVALID_VALUE, // input 249 (0xF9)
|
||||
INVALID_VALUE, // input 250 (0xFA)
|
||||
INVALID_VALUE, // input 251 (0xFB)
|
||||
INVALID_VALUE, // input 252 (0xFC)
|
||||
INVALID_VALUE, // input 253 (0xFD)
|
||||
INVALID_VALUE, // input 254 (0xFE)
|
||||
INVALID_VALUE, // input 255 (0xFF)
|
||||
];
|
||||
pub const URL_SAFE_ENCODE: &'static [u8; 64] = &[
|
||||
65, // input 0 (0x0) => 'A' (0x41)
|
||||
66, // input 1 (0x1) => 'B' (0x42)
|
||||
67, // input 2 (0x2) => 'C' (0x43)
|
||||
68, // input 3 (0x3) => 'D' (0x44)
|
||||
69, // input 4 (0x4) => 'E' (0x45)
|
||||
70, // input 5 (0x5) => 'F' (0x46)
|
||||
71, // input 6 (0x6) => 'G' (0x47)
|
||||
72, // input 7 (0x7) => 'H' (0x48)
|
||||
73, // input 8 (0x8) => 'I' (0x49)
|
||||
74, // input 9 (0x9) => 'J' (0x4A)
|
||||
75, // input 10 (0xA) => 'K' (0x4B)
|
||||
76, // input 11 (0xB) => 'L' (0x4C)
|
||||
77, // input 12 (0xC) => 'M' (0x4D)
|
||||
78, // input 13 (0xD) => 'N' (0x4E)
|
||||
79, // input 14 (0xE) => 'O' (0x4F)
|
||||
80, // input 15 (0xF) => 'P' (0x50)
|
||||
81, // input 16 (0x10) => 'Q' (0x51)
|
||||
82, // input 17 (0x11) => 'R' (0x52)
|
||||
83, // input 18 (0x12) => 'S' (0x53)
|
||||
84, // input 19 (0x13) => 'T' (0x54)
|
||||
85, // input 20 (0x14) => 'U' (0x55)
|
||||
86, // input 21 (0x15) => 'V' (0x56)
|
||||
87, // input 22 (0x16) => 'W' (0x57)
|
||||
88, // input 23 (0x17) => 'X' (0x58)
|
||||
89, // input 24 (0x18) => 'Y' (0x59)
|
||||
90, // input 25 (0x19) => 'Z' (0x5A)
|
||||
97, // input 26 (0x1A) => 'a' (0x61)
|
||||
98, // input 27 (0x1B) => 'b' (0x62)
|
||||
99, // input 28 (0x1C) => 'c' (0x63)
|
||||
100, // input 29 (0x1D) => 'd' (0x64)
|
||||
101, // input 30 (0x1E) => 'e' (0x65)
|
||||
102, // input 31 (0x1F) => 'f' (0x66)
|
||||
103, // input 32 (0x20) => 'g' (0x67)
|
||||
104, // input 33 (0x21) => 'h' (0x68)
|
||||
105, // input 34 (0x22) => 'i' (0x69)
|
||||
106, // input 35 (0x23) => 'j' (0x6A)
|
||||
107, // input 36 (0x24) => 'k' (0x6B)
|
||||
108, // input 37 (0x25) => 'l' (0x6C)
|
||||
109, // input 38 (0x26) => 'm' (0x6D)
|
||||
110, // input 39 (0x27) => 'n' (0x6E)
|
||||
111, // input 40 (0x28) => 'o' (0x6F)
|
||||
112, // input 41 (0x29) => 'p' (0x70)
|
||||
113, // input 42 (0x2A) => 'q' (0x71)
|
||||
114, // input 43 (0x2B) => 'r' (0x72)
|
||||
115, // input 44 (0x2C) => 's' (0x73)
|
||||
116, // input 45 (0x2D) => 't' (0x74)
|
||||
117, // input 46 (0x2E) => 'u' (0x75)
|
||||
118, // input 47 (0x2F) => 'v' (0x76)
|
||||
119, // input 48 (0x30) => 'w' (0x77)
|
||||
120, // input 49 (0x31) => 'x' (0x78)
|
||||
121, // input 50 (0x32) => 'y' (0x79)
|
||||
122, // input 51 (0x33) => 'z' (0x7A)
|
||||
48, // input 52 (0x34) => '0' (0x30)
|
||||
49, // input 53 (0x35) => '1' (0x31)
|
||||
50, // input 54 (0x36) => '2' (0x32)
|
||||
51, // input 55 (0x37) => '3' (0x33)
|
||||
52, // input 56 (0x38) => '4' (0x34)
|
||||
53, // input 57 (0x39) => '5' (0x35)
|
||||
54, // input 58 (0x3A) => '6' (0x36)
|
||||
55, // input 59 (0x3B) => '7' (0x37)
|
||||
56, // input 60 (0x3C) => '8' (0x38)
|
||||
57, // input 61 (0x3D) => '9' (0x39)
|
||||
45, // input 62 (0x3E) => '-' (0x2D)
|
||||
95, // input 63 (0x3F) => '_' (0x5F)
|
||||
];
|
||||
pub const URL_SAFE_DECODE: &'static [u8; 256] = &[
|
||||
INVALID_VALUE, // input 0 (0x0)
|
||||
INVALID_VALUE, // input 1 (0x1)
|
||||
INVALID_VALUE, // input 2 (0x2)
|
||||
INVALID_VALUE, // input 3 (0x3)
|
||||
INVALID_VALUE, // input 4 (0x4)
|
||||
INVALID_VALUE, // input 5 (0x5)
|
||||
INVALID_VALUE, // input 6 (0x6)
|
||||
INVALID_VALUE, // input 7 (0x7)
|
||||
INVALID_VALUE, // input 8 (0x8)
|
||||
INVALID_VALUE, // input 9 (0x9)
|
||||
INVALID_VALUE, // input 10 (0xA)
|
||||
INVALID_VALUE, // input 11 (0xB)
|
||||
INVALID_VALUE, // input 12 (0xC)
|
||||
INVALID_VALUE, // input 13 (0xD)
|
||||
INVALID_VALUE, // input 14 (0xE)
|
||||
INVALID_VALUE, // input 15 (0xF)
|
||||
INVALID_VALUE, // input 16 (0x10)
|
||||
INVALID_VALUE, // input 17 (0x11)
|
||||
INVALID_VALUE, // input 18 (0x12)
|
||||
INVALID_VALUE, // input 19 (0x13)
|
||||
INVALID_VALUE, // input 20 (0x14)
|
||||
INVALID_VALUE, // input 21 (0x15)
|
||||
INVALID_VALUE, // input 22 (0x16)
|
||||
INVALID_VALUE, // input 23 (0x17)
|
||||
INVALID_VALUE, // input 24 (0x18)
|
||||
INVALID_VALUE, // input 25 (0x19)
|
||||
INVALID_VALUE, // input 26 (0x1A)
|
||||
INVALID_VALUE, // input 27 (0x1B)
|
||||
INVALID_VALUE, // input 28 (0x1C)
|
||||
INVALID_VALUE, // input 29 (0x1D)
|
||||
INVALID_VALUE, // input 30 (0x1E)
|
||||
INVALID_VALUE, // input 31 (0x1F)
|
||||
INVALID_VALUE, // input 32 (0x20)
|
||||
INVALID_VALUE, // input 33 (0x21)
|
||||
INVALID_VALUE, // input 34 (0x22)
|
||||
INVALID_VALUE, // input 35 (0x23)
|
||||
INVALID_VALUE, // input 36 (0x24)
|
||||
INVALID_VALUE, // input 37 (0x25)
|
||||
INVALID_VALUE, // input 38 (0x26)
|
||||
INVALID_VALUE, // input 39 (0x27)
|
||||
INVALID_VALUE, // input 40 (0x28)
|
||||
INVALID_VALUE, // input 41 (0x29)
|
||||
INVALID_VALUE, // input 42 (0x2A)
|
||||
INVALID_VALUE, // input 43 (0x2B)
|
||||
INVALID_VALUE, // input 44 (0x2C)
|
||||
62, // input 45 (0x2D char '-') => 62 (0x3E)
|
||||
INVALID_VALUE, // input 46 (0x2E)
|
||||
INVALID_VALUE, // input 47 (0x2F)
|
||||
52, // input 48 (0x30 char '0') => 52 (0x34)
|
||||
53, // input 49 (0x31 char '1') => 53 (0x35)
|
||||
54, // input 50 (0x32 char '2') => 54 (0x36)
|
||||
55, // input 51 (0x33 char '3') => 55 (0x37)
|
||||
56, // input 52 (0x34 char '4') => 56 (0x38)
|
||||
57, // input 53 (0x35 char '5') => 57 (0x39)
|
||||
58, // input 54 (0x36 char '6') => 58 (0x3A)
|
||||
59, // input 55 (0x37 char '7') => 59 (0x3B)
|
||||
60, // input 56 (0x38 char '8') => 60 (0x3C)
|
||||
61, // input 57 (0x39 char '9') => 61 (0x3D)
|
||||
INVALID_VALUE, // input 58 (0x3A)
|
||||
INVALID_VALUE, // input 59 (0x3B)
|
||||
INVALID_VALUE, // input 60 (0x3C)
|
||||
INVALID_VALUE, // input 61 (0x3D)
|
||||
INVALID_VALUE, // input 62 (0x3E)
|
||||
INVALID_VALUE, // input 63 (0x3F)
|
||||
INVALID_VALUE, // input 64 (0x40)
|
||||
0, // input 65 (0x41 char 'A') => 0 (0x0)
|
||||
1, // input 66 (0x42 char 'B') => 1 (0x1)
|
||||
2, // input 67 (0x43 char 'C') => 2 (0x2)
|
||||
3, // input 68 (0x44 char 'D') => 3 (0x3)
|
||||
4, // input 69 (0x45 char 'E') => 4 (0x4)
|
||||
5, // input 70 (0x46 char 'F') => 5 (0x5)
|
||||
6, // input 71 (0x47 char 'G') => 6 (0x6)
|
||||
7, // input 72 (0x48 char 'H') => 7 (0x7)
|
||||
8, // input 73 (0x49 char 'I') => 8 (0x8)
|
||||
9, // input 74 (0x4A char 'J') => 9 (0x9)
|
||||
10, // input 75 (0x4B char 'K') => 10 (0xA)
|
||||
11, // input 76 (0x4C char 'L') => 11 (0xB)
|
||||
12, // input 77 (0x4D char 'M') => 12 (0xC)
|
||||
13, // input 78 (0x4E char 'N') => 13 (0xD)
|
||||
14, // input 79 (0x4F char 'O') => 14 (0xE)
|
||||
15, // input 80 (0x50 char 'P') => 15 (0xF)
|
||||
16, // input 81 (0x51 char 'Q') => 16 (0x10)
|
||||
17, // input 82 (0x52 char 'R') => 17 (0x11)
|
||||
18, // input 83 (0x53 char 'S') => 18 (0x12)
|
||||
19, // input 84 (0x54 char 'T') => 19 (0x13)
|
||||
20, // input 85 (0x55 char 'U') => 20 (0x14)
|
||||
21, // input 86 (0x56 char 'V') => 21 (0x15)
|
||||
22, // input 87 (0x57 char 'W') => 22 (0x16)
|
||||
23, // input 88 (0x58 char 'X') => 23 (0x17)
|
||||
24, // input 89 (0x59 char 'Y') => 24 (0x18)
|
||||
25, // input 90 (0x5A char 'Z') => 25 (0x19)
|
||||
INVALID_VALUE, // input 91 (0x5B)
|
||||
INVALID_VALUE, // input 92 (0x5C)
|
||||
INVALID_VALUE, // input 93 (0x5D)
|
||||
INVALID_VALUE, // input 94 (0x5E)
|
||||
63, // input 95 (0x5F char '_') => 63 (0x3F)
|
||||
INVALID_VALUE, // input 96 (0x60)
|
||||
26, // input 97 (0x61 char 'a') => 26 (0x1A)
|
||||
27, // input 98 (0x62 char 'b') => 27 (0x1B)
|
||||
28, // input 99 (0x63 char 'c') => 28 (0x1C)
|
||||
29, // input 100 (0x64 char 'd') => 29 (0x1D)
|
||||
30, // input 101 (0x65 char 'e') => 30 (0x1E)
|
||||
31, // input 102 (0x66 char 'f') => 31 (0x1F)
|
||||
32, // input 103 (0x67 char 'g') => 32 (0x20)
|
||||
33, // input 104 (0x68 char 'h') => 33 (0x21)
|
||||
34, // input 105 (0x69 char 'i') => 34 (0x22)
|
||||
35, // input 106 (0x6A char 'j') => 35 (0x23)
|
||||
36, // input 107 (0x6B char 'k') => 36 (0x24)
|
||||
37, // input 108 (0x6C char 'l') => 37 (0x25)
|
||||
38, // input 109 (0x6D char 'm') => 38 (0x26)
|
||||
39, // input 110 (0x6E char 'n') => 39 (0x27)
|
||||
40, // input 111 (0x6F char 'o') => 40 (0x28)
|
||||
41, // input 112 (0x70 char 'p') => 41 (0x29)
|
||||
42, // input 113 (0x71 char 'q') => 42 (0x2A)
|
||||
43, // input 114 (0x72 char 'r') => 43 (0x2B)
|
||||
44, // input 115 (0x73 char 's') => 44 (0x2C)
|
||||
45, // input 116 (0x74 char 't') => 45 (0x2D)
|
||||
46, // input 117 (0x75 char 'u') => 46 (0x2E)
|
||||
47, // input 118 (0x76 char 'v') => 47 (0x2F)
|
||||
48, // input 119 (0x77 char 'w') => 48 (0x30)
|
||||
49, // input 120 (0x78 char 'x') => 49 (0x31)
|
||||
50, // input 121 (0x79 char 'y') => 50 (0x32)
|
||||
51, // input 122 (0x7A char 'z') => 51 (0x33)
|
||||
INVALID_VALUE, // input 123 (0x7B)
|
||||
INVALID_VALUE, // input 124 (0x7C)
|
||||
INVALID_VALUE, // input 125 (0x7D)
|
||||
INVALID_VALUE, // input 126 (0x7E)
|
||||
INVALID_VALUE, // input 127 (0x7F)
|
||||
INVALID_VALUE, // input 128 (0x80)
|
||||
INVALID_VALUE, // input 129 (0x81)
|
||||
INVALID_VALUE, // input 130 (0x82)
|
||||
INVALID_VALUE, // input 131 (0x83)
|
||||
INVALID_VALUE, // input 132 (0x84)
|
||||
INVALID_VALUE, // input 133 (0x85)
|
||||
INVALID_VALUE, // input 134 (0x86)
|
||||
INVALID_VALUE, // input 135 (0x87)
|
||||
INVALID_VALUE, // input 136 (0x88)
|
||||
INVALID_VALUE, // input 137 (0x89)
|
||||
INVALID_VALUE, // input 138 (0x8A)
|
||||
INVALID_VALUE, // input 139 (0x8B)
|
||||
INVALID_VALUE, // input 140 (0x8C)
|
||||
INVALID_VALUE, // input 141 (0x8D)
|
||||
INVALID_VALUE, // input 142 (0x8E)
|
||||
INVALID_VALUE, // input 143 (0x8F)
|
||||
INVALID_VALUE, // input 144 (0x90)
|
||||
INVALID_VALUE, // input 145 (0x91)
|
||||
INVALID_VALUE, // input 146 (0x92)
|
||||
INVALID_VALUE, // input 147 (0x93)
|
||||
INVALID_VALUE, // input 148 (0x94)
|
||||
INVALID_VALUE, // input 149 (0x95)
|
||||
INVALID_VALUE, // input 150 (0x96)
|
||||
INVALID_VALUE, // input 151 (0x97)
|
||||
INVALID_VALUE, // input 152 (0x98)
|
||||
INVALID_VALUE, // input 153 (0x99)
|
||||
INVALID_VALUE, // input 154 (0x9A)
|
||||
INVALID_VALUE, // input 155 (0x9B)
|
||||
INVALID_VALUE, // input 156 (0x9C)
|
||||
INVALID_VALUE, // input 157 (0x9D)
|
||||
INVALID_VALUE, // input 158 (0x9E)
|
||||
INVALID_VALUE, // input 159 (0x9F)
|
||||
INVALID_VALUE, // input 160 (0xA0)
|
||||
INVALID_VALUE, // input 161 (0xA1)
|
||||
INVALID_VALUE, // input 162 (0xA2)
|
||||
INVALID_VALUE, // input 163 (0xA3)
|
||||
INVALID_VALUE, // input 164 (0xA4)
|
||||
INVALID_VALUE, // input 165 (0xA5)
|
||||
INVALID_VALUE, // input 166 (0xA6)
|
||||
INVALID_VALUE, // input 167 (0xA7)
|
||||
INVALID_VALUE, // input 168 (0xA8)
|
||||
INVALID_VALUE, // input 169 (0xA9)
|
||||
INVALID_VALUE, // input 170 (0xAA)
|
||||
INVALID_VALUE, // input 171 (0xAB)
|
||||
INVALID_VALUE, // input 172 (0xAC)
|
||||
INVALID_VALUE, // input 173 (0xAD)
|
||||
INVALID_VALUE, // input 174 (0xAE)
|
||||
INVALID_VALUE, // input 175 (0xAF)
|
||||
INVALID_VALUE, // input 176 (0xB0)
|
||||
INVALID_VALUE, // input 177 (0xB1)
|
||||
INVALID_VALUE, // input 178 (0xB2)
|
||||
INVALID_VALUE, // input 179 (0xB3)
|
||||
INVALID_VALUE, // input 180 (0xB4)
|
||||
INVALID_VALUE, // input 181 (0xB5)
|
||||
INVALID_VALUE, // input 182 (0xB6)
|
||||
INVALID_VALUE, // input 183 (0xB7)
|
||||
INVALID_VALUE, // input 184 (0xB8)
|
||||
INVALID_VALUE, // input 185 (0xB9)
|
||||
INVALID_VALUE, // input 186 (0xBA)
|
||||
INVALID_VALUE, // input 187 (0xBB)
|
||||
INVALID_VALUE, // input 188 (0xBC)
|
||||
INVALID_VALUE, // input 189 (0xBD)
|
||||
INVALID_VALUE, // input 190 (0xBE)
|
||||
INVALID_VALUE, // input 191 (0xBF)
|
||||
INVALID_VALUE, // input 192 (0xC0)
|
||||
INVALID_VALUE, // input 193 (0xC1)
|
||||
INVALID_VALUE, // input 194 (0xC2)
|
||||
INVALID_VALUE, // input 195 (0xC3)
|
||||
INVALID_VALUE, // input 196 (0xC4)
|
||||
INVALID_VALUE, // input 197 (0xC5)
|
||||
INVALID_VALUE, // input 198 (0xC6)
|
||||
INVALID_VALUE, // input 199 (0xC7)
|
||||
INVALID_VALUE, // input 200 (0xC8)
|
||||
INVALID_VALUE, // input 201 (0xC9)
|
||||
INVALID_VALUE, // input 202 (0xCA)
|
||||
INVALID_VALUE, // input 203 (0xCB)
|
||||
INVALID_VALUE, // input 204 (0xCC)
|
||||
INVALID_VALUE, // input 205 (0xCD)
|
||||
INVALID_VALUE, // input 206 (0xCE)
|
||||
INVALID_VALUE, // input 207 (0xCF)
|
||||
INVALID_VALUE, // input 208 (0xD0)
|
||||
INVALID_VALUE, // input 209 (0xD1)
|
||||
INVALID_VALUE, // input 210 (0xD2)
|
||||
INVALID_VALUE, // input 211 (0xD3)
|
||||
INVALID_VALUE, // input 212 (0xD4)
|
||||
INVALID_VALUE, // input 213 (0xD5)
|
||||
INVALID_VALUE, // input 214 (0xD6)
|
||||
INVALID_VALUE, // input 215 (0xD7)
|
||||
INVALID_VALUE, // input 216 (0xD8)
|
||||
INVALID_VALUE, // input 217 (0xD9)
|
||||
INVALID_VALUE, // input 218 (0xDA)
|
||||
INVALID_VALUE, // input 219 (0xDB)
|
||||
INVALID_VALUE, // input 220 (0xDC)
|
||||
INVALID_VALUE, // input 221 (0xDD)
|
||||
INVALID_VALUE, // input 222 (0xDE)
|
||||
INVALID_VALUE, // input 223 (0xDF)
|
||||
INVALID_VALUE, // input 224 (0xE0)
|
||||
INVALID_VALUE, // input 225 (0xE1)
|
||||
INVALID_VALUE, // input 226 (0xE2)
|
||||
INVALID_VALUE, // input 227 (0xE3)
|
||||
INVALID_VALUE, // input 228 (0xE4)
|
||||
INVALID_VALUE, // input 229 (0xE5)
|
||||
INVALID_VALUE, // input 230 (0xE6)
|
||||
INVALID_VALUE, // input 231 (0xE7)
|
||||
INVALID_VALUE, // input 232 (0xE8)
|
||||
INVALID_VALUE, // input 233 (0xE9)
|
||||
INVALID_VALUE, // input 234 (0xEA)
|
||||
INVALID_VALUE, // input 235 (0xEB)
|
||||
INVALID_VALUE, // input 236 (0xEC)
|
||||
INVALID_VALUE, // input 237 (0xED)
|
||||
INVALID_VALUE, // input 238 (0xEE)
|
||||
INVALID_VALUE, // input 239 (0xEF)
|
||||
INVALID_VALUE, // input 240 (0xF0)
|
||||
INVALID_VALUE, // input 241 (0xF1)
|
||||
INVALID_VALUE, // input 242 (0xF2)
|
||||
INVALID_VALUE, // input 243 (0xF3)
|
||||
INVALID_VALUE, // input 244 (0xF4)
|
||||
INVALID_VALUE, // input 245 (0xF5)
|
||||
INVALID_VALUE, // input 246 (0xF6)
|
||||
INVALID_VALUE, // input 247 (0xF7)
|
||||
INVALID_VALUE, // input 248 (0xF8)
|
||||
INVALID_VALUE, // input 249 (0xF9)
|
||||
INVALID_VALUE, // input 250 (0xFA)
|
||||
INVALID_VALUE, // input 251 (0xFB)
|
||||
INVALID_VALUE, // input 252 (0xFC)
|
||||
INVALID_VALUE, // input 253 (0xFD)
|
||||
INVALID_VALUE, // input 254 (0xFE)
|
||||
INVALID_VALUE, // input 255 (0xFF)
|
||||
];
|
696
third_party/rust/base64-0.5.2/tests/tests.rs
vendored
696
third_party/rust/base64-0.5.2/tests/tests.rs
vendored
@ -1,696 +0,0 @@
|
||||
extern crate base64;
|
||||
extern crate rand;
|
||||
|
||||
use rand::Rng;
|
||||
|
||||
use base64::*;
|
||||
|
||||
fn compare_encode(expected: &str, target: &[u8]) {
|
||||
assert_eq!(expected, encode(target));
|
||||
}
|
||||
|
||||
fn compare_decode(expected: &str, target: &str) {
|
||||
assert_eq!(expected, String::from_utf8(decode(target).unwrap()).unwrap());
|
||||
assert_eq!(expected, String::from_utf8(decode(target.as_bytes()).unwrap()).unwrap());
|
||||
}
|
||||
|
||||
fn compare_decode_mime(expected: &str, target: &str) {
|
||||
assert_eq!(expected, String::from_utf8(decode_config(target, MIME).unwrap()).unwrap());
|
||||
}
|
||||
|
||||
fn push_rand(buf: &mut Vec<u8>, len: usize) {
|
||||
let mut r = rand::weak_rng();
|
||||
|
||||
for _ in 0..len {
|
||||
buf.push(r.gen::<u8>());
|
||||
}
|
||||
}
|
||||
|
||||
// generate every possible byte string recursively and test encode/decode roundtrip
|
||||
fn roundtrip_append_recurse(byte_buf: &mut Vec<u8>, str_buf: &mut String, remaining_bytes: usize) {
|
||||
let orig_length = byte_buf.len();
|
||||
for b in 0..256 {
|
||||
byte_buf.push(b as u8);
|
||||
|
||||
if remaining_bytes > 1 {
|
||||
roundtrip_append_recurse(byte_buf, str_buf, remaining_bytes - 1)
|
||||
} else {
|
||||
encode_config_buf(&byte_buf, STANDARD, str_buf);
|
||||
let roundtrip_bytes = decode_config(&str_buf, STANDARD).unwrap();
|
||||
assert_eq!(*byte_buf, roundtrip_bytes);
|
||||
|
||||
str_buf.clear();
|
||||
|
||||
}
|
||||
|
||||
byte_buf.truncate(orig_length);
|
||||
}
|
||||
}
|
||||
|
||||
// generate every possible byte string recursively and test encode/decode roundtrip with
|
||||
// padding removed
|
||||
fn roundtrip_append_recurse_strip_padding(byte_buf: &mut Vec<u8>, str_buf: &mut String,
|
||||
remaining_bytes: usize) {
|
||||
let orig_length = byte_buf.len();
|
||||
for b in 0..256 {
|
||||
byte_buf.push(b as u8);
|
||||
|
||||
if remaining_bytes > 1 {
|
||||
roundtrip_append_recurse_strip_padding(byte_buf, str_buf, remaining_bytes - 1)
|
||||
} else {
|
||||
encode_config_buf(&byte_buf, STANDARD, str_buf);
|
||||
{
|
||||
let trimmed = str_buf.trim_right_matches('=');
|
||||
let roundtrip_bytes = decode_config(&trimmed, STANDARD).unwrap();
|
||||
assert_eq!(*byte_buf, roundtrip_bytes);
|
||||
}
|
||||
str_buf.clear();
|
||||
}
|
||||
|
||||
byte_buf.truncate(orig_length);
|
||||
}
|
||||
}
|
||||
|
||||
// generate random contents of the specified length and test encode/decode roundtrip
|
||||
fn roundtrip_random(byte_buf: &mut Vec<u8>, str_buf: &mut String, byte_len: usize,
|
||||
approx_values_per_byte: u8, max_rounds: u64) {
|
||||
let num_rounds = calculate_number_of_rounds(byte_len, approx_values_per_byte, max_rounds);
|
||||
let mut r = rand::weak_rng();
|
||||
|
||||
for _ in 0..num_rounds {
|
||||
byte_buf.clear();
|
||||
str_buf.clear();
|
||||
while byte_buf.len() < byte_len {
|
||||
byte_buf.push(r.gen::<u8>());
|
||||
}
|
||||
|
||||
encode_config_buf(&byte_buf, STANDARD, str_buf);
|
||||
let roundtrip_bytes = decode_config(&str_buf, STANDARD).unwrap();
|
||||
|
||||
assert_eq!(*byte_buf, roundtrip_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// generate random contents of the specified length and test encode/decode roundtrip
|
||||
fn roundtrip_random_strip_padding(byte_buf: &mut Vec<u8>, str_buf: &mut String, byte_len: usize,
|
||||
approx_values_per_byte: u8, max_rounds: u64) {
|
||||
// let the short ones be short but don't let it get too crazy large
|
||||
let num_rounds = calculate_number_of_rounds(byte_len, approx_values_per_byte, max_rounds);
|
||||
let mut r = rand::weak_rng();
|
||||
|
||||
for _ in 0..num_rounds {
|
||||
byte_buf.clear();
|
||||
str_buf.clear();
|
||||
while byte_buf.len() < byte_len {
|
||||
byte_buf.push(r.gen::<u8>());
|
||||
}
|
||||
|
||||
encode_config_buf(&byte_buf, STANDARD, str_buf);
|
||||
let trimmed = str_buf.trim_right_matches('=');
|
||||
let roundtrip_bytes = decode_config(&trimmed, STANDARD).unwrap();
|
||||
|
||||
assert_eq!(*byte_buf, roundtrip_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_number_of_rounds(byte_len: usize, approx_values_per_byte: u8, max: u64) -> u64 {
|
||||
// don't overflow
|
||||
let mut prod = approx_values_per_byte as u64;
|
||||
|
||||
for _ in 0..byte_len {
|
||||
if prod > max {
|
||||
return max;
|
||||
}
|
||||
|
||||
prod = prod.saturating_mul(prod);
|
||||
}
|
||||
|
||||
return prod;
|
||||
}
|
||||
|
||||
//-------
|
||||
//decode
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_0() {
|
||||
compare_decode("", "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_1() {
|
||||
compare_decode("f", "Zg==");
|
||||
}
|
||||
#[test]
|
||||
fn decode_rfc4648_1_just_a_bit_of_padding() {
|
||||
// allows less padding than required
|
||||
compare_decode("f", "Zg=");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_1_no_padding() {
|
||||
compare_decode("f", "Zg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_2() {
|
||||
compare_decode("fo", "Zm8=");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_2_no_padding() {
|
||||
compare_decode("fo", "Zm8");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_3() {
|
||||
compare_decode("foo", "Zm9v");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_4() {
|
||||
compare_decode("foob", "Zm9vYg==");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_4_no_padding() {
|
||||
compare_decode("foob", "Zm9vYg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_5() {
|
||||
compare_decode("fooba", "Zm9vYmE=");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_5_no_padding() {
|
||||
compare_decode("fooba", "Zm9vYmE");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_rfc4648_6() {
|
||||
compare_decode("foobar", "Zm9vYmFy");
|
||||
}
|
||||
|
||||
//this is a MAY in the rfc: https://tools.ietf.org/html/rfc4648#section-3.3
|
||||
#[test]
|
||||
fn decode_pad_inside_fast_loop_chunk_error() {
|
||||
// can't PartialEq Base64Error, so we do this the hard way
|
||||
match decode("YWxpY2U=====").unwrap_err() {
|
||||
DecodeError::InvalidByte(offset, byte) => {
|
||||
// since the first 8 bytes are handled in the fast loop, the
|
||||
// padding is an error. Could argue that the *next* padding
|
||||
// byte is technically the first erroneous one, but reporting
|
||||
// that accurately is more complex and probably nobody cares
|
||||
assert_eq!(7, offset);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_extra_pad_after_fast_loop_chunk_error() {
|
||||
match decode("YWxpY2UABB===").unwrap_err() {
|
||||
DecodeError::InvalidByte(offset, byte) => {
|
||||
// extraneous third padding byte
|
||||
assert_eq!(12, offset);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
//same
|
||||
#[test]
|
||||
fn decode_absurd_pad_error() {
|
||||
match decode("==Y=Wx===pY=2U=====").unwrap_err() {
|
||||
DecodeError::InvalidByte(size, byte) => {
|
||||
assert_eq!(0, size);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_starts_with_padding_single_quad_error() {
|
||||
match decode("====").unwrap_err() {
|
||||
DecodeError::InvalidByte(offset, byte) => {
|
||||
// with no real input, first padding byte is bogus
|
||||
assert_eq!(0, offset);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_extra_padding_in_trailing_quad_returns_error() {
|
||||
match decode("zzz==").unwrap_err() {
|
||||
DecodeError::InvalidByte(size, byte) => {
|
||||
// first unneeded padding byte
|
||||
assert_eq!(4, size);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_extra_padding_in_trailing_quad_2_returns_error() {
|
||||
match decode("zz===").unwrap_err() {
|
||||
DecodeError::InvalidByte(size, byte) => {
|
||||
// first unneeded padding byte
|
||||
assert_eq!(4, size);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn decode_start_second_quad_with_padding_returns_error() {
|
||||
match decode("zzzz=").unwrap_err() {
|
||||
DecodeError::InvalidByte(size, byte) => {
|
||||
// first unneeded padding byte
|
||||
assert_eq!(4, size);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_padding_in_last_quad_followed_by_non_padding_returns_error() {
|
||||
match decode("zzzz==z").unwrap_err() {
|
||||
DecodeError::InvalidByte(size, byte) => {
|
||||
assert_eq!(4, size);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_too_short_with_padding_error() {
|
||||
match decode("z==").unwrap_err() {
|
||||
DecodeError::InvalidByte(size, byte) => {
|
||||
// first unneeded padding byte
|
||||
assert_eq!(1, size);
|
||||
assert_eq!(0x3D, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_too_short_without_padding_error() {
|
||||
match decode("z").unwrap_err() {
|
||||
DecodeError::InvalidLength => {}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_too_short_second_quad_without_padding_error() {
|
||||
match decode("zzzzX").unwrap_err() {
|
||||
DecodeError::InvalidLength => {}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_error_for_bogus_char_in_right_position() {
|
||||
for length in 1..25 {
|
||||
for error_position in 0_usize..length {
|
||||
let prefix: String = std::iter::repeat("A").take(error_position).collect();
|
||||
let suffix: String = std::iter::repeat("B").take(length - error_position - 1).collect();
|
||||
|
||||
let input = prefix + "%" + &suffix;
|
||||
assert_eq!(length, input.len(),
|
||||
"length {} error position {}", length, error_position);
|
||||
|
||||
match decode(&input).unwrap_err() {
|
||||
DecodeError::InvalidByte(size, byte) => {
|
||||
assert_eq!(error_position, size,
|
||||
"length {} error position {}", length, error_position);
|
||||
assert_eq!(0x25, byte);
|
||||
}
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_into_nonempty_buffer_doesnt_clobber_existing_contents() {
|
||||
let mut orig_data = Vec::new();
|
||||
let mut encoded_data = String::new();
|
||||
let mut decoded_with_prefix = Vec::new();
|
||||
let mut decoded_without_prefix = Vec::new();
|
||||
let mut prefix = Vec::new();
|
||||
for encoded_length in 0_usize..26 {
|
||||
if encoded_length % 4 == 1 {
|
||||
// can't have a lone byte in a quad of input
|
||||
continue;
|
||||
};
|
||||
|
||||
let raw_data_byte_triples = encoded_length / 4;
|
||||
// 4 base64 bytes -> 3 input bytes, 3 -> 2, 2 -> 1, 0 -> 0
|
||||
let raw_data_byte_leftovers = (encoded_length % 4).saturating_sub(1);
|
||||
|
||||
// we'll borrow buf to make some data to encode
|
||||
orig_data.clear();
|
||||
push_rand(&mut orig_data, raw_data_byte_triples * 3 + raw_data_byte_leftovers);
|
||||
|
||||
encoded_data.clear();
|
||||
encode_config_buf(&orig_data, STANDARD, &mut encoded_data);
|
||||
|
||||
assert_eq!(encoded_length, encoded_data.trim_right_matches('=').len());
|
||||
|
||||
for prefix_length in 1..26 {
|
||||
decoded_with_prefix.clear();
|
||||
decoded_without_prefix.clear();
|
||||
prefix.clear();
|
||||
|
||||
// fill the buf with a prefix
|
||||
push_rand(&mut prefix, prefix_length);
|
||||
decoded_with_prefix.resize(prefix_length, 0);
|
||||
decoded_with_prefix.copy_from_slice(&prefix);
|
||||
|
||||
// decode into the non-empty buf
|
||||
decode_config_buf(&encoded_data, STANDARD, &mut decoded_with_prefix).unwrap();
|
||||
// also decode into the empty buf
|
||||
decode_config_buf(&encoded_data, STANDARD, &mut decoded_without_prefix).unwrap();
|
||||
|
||||
assert_eq!(prefix_length + decoded_without_prefix.len(), decoded_with_prefix.len());
|
||||
|
||||
// append plain decode onto prefix
|
||||
prefix.append(&mut decoded_without_prefix);
|
||||
|
||||
assert_eq!(prefix, decoded_with_prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_random_no_fast_loop() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
|
||||
for input_len in 0..9 {
|
||||
roundtrip_random(&mut byte_buf, &mut str_buf, input_len, 4, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_random_with_fast_loop() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
|
||||
for input_len in 9..26 {
|
||||
roundtrip_random(&mut byte_buf, &mut str_buf, input_len, 4, 100000);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_random_no_fast_loop_no_padding() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
|
||||
for input_len in 0..9 {
|
||||
roundtrip_random_strip_padding(&mut byte_buf, &mut str_buf, input_len, 4, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_random_with_fast_loop_no_padding() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
|
||||
for input_len in 9..26 {
|
||||
roundtrip_random_strip_padding(&mut byte_buf, &mut str_buf, input_len, 4, 100000);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_all_1_byte() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
roundtrip_append_recurse(&mut byte_buf, &mut str_buf, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_all_1_byte_no_padding() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
roundtrip_append_recurse_strip_padding(&mut byte_buf, &mut str_buf, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_all_2_byte() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
roundtrip_append_recurse(&mut byte_buf, &mut str_buf, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_all_2_byte_no_padding() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
roundtrip_append_recurse_strip_padding(&mut byte_buf, &mut str_buf, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_all_3_byte() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
roundtrip_append_recurse(&mut byte_buf, &mut str_buf, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_random_4_byte() {
|
||||
let mut byte_buf: Vec<u8> = Vec::new();
|
||||
let mut str_buf = String::new();
|
||||
|
||||
roundtrip_random(&mut byte_buf, &mut str_buf, 4, 48, 10000);
|
||||
}
|
||||
|
||||
//TODO like, write a thing to test every ascii val lol
|
||||
//prolly just yankput the 64 array and a 256 one later
|
||||
//is there a way to like, not have to write a fn every time
|
||||
//"hi test harness this should panic 192 times" would be nice
|
||||
//oh well whatever this is better done by a fuzzer
|
||||
|
||||
//strip yr whitespace kids
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn decode_reject_space() {
|
||||
assert!(decode("YWx pY2U=").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn decode_reject_tab() {
|
||||
assert!(decode("YWx\tpY2U=").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn decode_reject_ff() {
|
||||
assert!(decode("YWx\x0cpY2U=").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn decode_reject_vtab() {
|
||||
assert!(decode("YWx\x0bpY2U=").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn decode_reject_nl() {
|
||||
assert!(decode("YWx\npY2U=").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn decode_reject_crnl() {
|
||||
assert!(decode("YWx\r\npY2U=").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn decode_reject_null() {
|
||||
assert!(decode("YWx\0pY2U=").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_mime_allow_space() {
|
||||
assert!(decode_config("YWx pY2U=", MIME).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_mime_allow_tab() {
|
||||
assert!(decode_config("YWx\tpY2U=", MIME).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_mime_allow_ff() {
|
||||
assert!(decode_config("YWx\x0cpY2U=", MIME).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_mime_allow_vtab() {
|
||||
assert!(decode_config("YWx\x0bpY2U=", MIME).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_mime_allow_nl() {
|
||||
assert!(decode_config("YWx\npY2U=", MIME).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_mime_allow_crnl() {
|
||||
assert!(decode_config("YWx\r\npY2U=", MIME).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn decode_mime_reject_null() {
|
||||
assert!(decode_config("YWx\0pY2U=", MIME).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_mime_absurd_whitespace() {
|
||||
compare_decode_mime("how could you let this happen",
|
||||
"\n aG93I\n\nG\x0bNvd\r\nWxkI HlvdSB \tsZXQgdGh\rpcyBo\x0cYXBwZW4 = ");
|
||||
}
|
||||
|
||||
//-------
|
||||
//encode
|
||||
|
||||
#[test]
|
||||
fn encode_rfc4648_0() {
|
||||
compare_encode("", b"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_rfc4648_1() {
|
||||
compare_encode("Zg==", b"f");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_rfc4648_2() {
|
||||
compare_encode("Zm8=", b"fo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_rfc4648_3() {
|
||||
compare_encode("Zm9v", b"foo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_rfc4648_4() {
|
||||
compare_encode("Zm9vYg==", b"foob");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_rfc4648_5() {
|
||||
compare_encode("Zm9vYmE=", b"fooba");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_rfc4648_6() {
|
||||
compare_encode("Zm9vYmFy", b"foobar");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_all_ascii() {
|
||||
let mut ascii = Vec::<u8>::with_capacity(128);
|
||||
|
||||
for i in 0..128 {
|
||||
ascii.push(i);
|
||||
}
|
||||
|
||||
compare_encode("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8=", &ascii);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_all_bytes() {
|
||||
let mut bytes = Vec::<u8>::with_capacity(256);
|
||||
|
||||
for i in 0..255 {
|
||||
bytes.push(i);
|
||||
}
|
||||
bytes.push(255); //bug with "overflowing" ranges?
|
||||
|
||||
compare_encode("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==", &bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_all_bytes_url() {
|
||||
let mut bytes = Vec::<u8>::with_capacity(256);
|
||||
|
||||
for i in 0..255 {
|
||||
bytes.push(i);
|
||||
}
|
||||
bytes.push(255); //bug with "overflowing" ranges?
|
||||
|
||||
assert_eq!("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7i5uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T19vf4-fr7_P3-_w==", encode_config(&bytes, URL_SAFE));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_into_nonempty_buffer_doesnt_clobber_existing_contents() {
|
||||
let mut orig_data = Vec::new();
|
||||
let mut encoded_with_prefix = String::new();
|
||||
let mut encoded_without_prefix = String::new();
|
||||
let mut prefix = String::new();
|
||||
for orig_data_length in 0_usize..26 {
|
||||
// we'll borrow buf to make some data to encode
|
||||
orig_data.clear();
|
||||
push_rand(&mut orig_data, orig_data_length);
|
||||
|
||||
for prefix_length in 1..26 {
|
||||
encoded_with_prefix.clear();
|
||||
encoded_without_prefix.clear();
|
||||
prefix.clear();
|
||||
|
||||
for _ in 0..prefix_length {
|
||||
prefix.push('~');
|
||||
}
|
||||
|
||||
encoded_with_prefix.push_str(&prefix);
|
||||
|
||||
// encode into the non-empty buf
|
||||
encode_config_buf(&orig_data, STANDARD, &mut encoded_with_prefix);
|
||||
// also encode into the empty buf
|
||||
encode_config_buf(&orig_data, STANDARD, &mut encoded_without_prefix);
|
||||
|
||||
assert_eq!(prefix_length + encoded_without_prefix.len(), encoded_with_prefix.len());
|
||||
|
||||
// append plain decode onto prefix
|
||||
prefix.push_str(&mut encoded_without_prefix);
|
||||
|
||||
assert_eq!(prefix, encoded_with_prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn because_we_can() {
|
||||
compare_decode("alice", "YWxpY2U=");
|
||||
compare_decode("alice", &encode(b"alice"));
|
||||
compare_decode("alice", &encode(&decode(&encode(b"alice")).unwrap()));
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn encode_url_safe_without_padding() {
|
||||
let encoded = encode_config(b"alice", URL_SAFE_NO_PAD);
|
||||
assert_eq!(&encoded, "YWxpY2U");
|
||||
assert_eq!(String::from_utf8(decode(&encoded).unwrap()).unwrap(), "alice");
|
||||
}
|
File diff suppressed because one or more lines are too long
36
third_party/rust/bzip2-sys/Cargo.toml
vendored
36
third_party/rust/bzip2-sys/Cargo.toml
vendored
@ -1,26 +1,32 @@
|
||||
[package]
|
||||
# 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 believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "bzip2-sys"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
links = "bzip2"
|
||||
build = "build.rs"
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/alexcrichton/bzip2-rs"
|
||||
links = "bzip2"
|
||||
description = "Bindings to libbzip2 for bzip2 compression and decompression exposed as\nReader/Writer streams.\n"
|
||||
homepage = "https://github.com/alexcrichton/bzip2-rs"
|
||||
documentation = "https://docs.rs/bzip2-sys"
|
||||
description = """
|
||||
Bindings to libbzip2 for bzip2 compression and decompression exposed as
|
||||
Reader/Writer streams.
|
||||
"""
|
||||
categories = ["external-ffi-bindings"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/alexcrichton/bzip2-rs"
|
||||
|
||||
[lib]
|
||||
name = "bzip2_sys"
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[build-dependencies]
|
||||
gcc = "0.3"
|
||||
[dependencies.libc]
|
||||
version = "0.2"
|
||||
[build-dependencies.cc]
|
||||
version = "1.0"
|
||||
|
5
third_party/rust/bzip2-sys/build.rs
vendored
5
third_party/rust/bzip2-sys/build.rs
vendored
@ -1,9 +1,10 @@
|
||||
extern crate gcc;
|
||||
extern crate cc;
|
||||
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
let mut cfg = gcc::Config::new();
|
||||
let mut cfg = cc::Build::new();
|
||||
cfg.warnings(false);
|
||||
|
||||
if env::var("TARGET").unwrap().contains("windows") {
|
||||
cfg.define("_WIN32", None);
|
||||
|
2
third_party/rust/bzip2-sys/lib.rs
vendored
2
third_party/rust/bzip2-sys/lib.rs
vendored
@ -48,7 +48,7 @@ macro_rules! abi_compat {
|
||||
extern "system" {
|
||||
$(pub fn $name($($arg: $t),*) -> $ret;)*
|
||||
}
|
||||
#[cfg(unix)]
|
||||
#[cfg(any(unix, target_os = "redox"))]
|
||||
extern {
|
||||
$(pub fn $name($($arg: $t),*) -> $ret;)*
|
||||
}
|
||||
|
1
third_party/rust/cc/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/cc/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"files":{".travis.yml":"3ca887c3f17391bd915265fbb6015b403263fbb13b9dedc8ea9ab8aa5c5ef163","Cargo.toml":"abe25a5fc35c2fe24c2f93b00f9488886310a3b7a25975984cc7030e826bb2e5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"d73ba5602263665e2d3987db4378787f6aa1e449b699a2530cee478acc7586dc","appveyor.yml":"ab45bfdcf2596f357225a54e730c34d518a8f3ad56c2ed33af682cfd45bddc02","src/bin/gcc-shim.rs":"d6be9137cb48b86891e7b263adbf492e1193ffe682db9ba4a88eb1079b874b58","src/com.rs":"0cb06f5db0fb70d27db0e5917ca337de6e7032119e6aabfea1bad9c719f5f34b","src/lib.rs":"164a360f504c7614be1f51dd9c76ef84bf8195e94ea5f1a914a90c1a036db6b8","src/registry.rs":"3876ef9573e3bbc050aef41a684b9a510cc1a91b15ae874fe032cf4377b4d116","src/setup_config.rs":"1a3eeb11c6847c31f2a4685b62ab35c76f0b6d5a17f7ed99e9df164283a771f7","src/winapi.rs":"cb5e6cab3eb570b0f97c660ca448ccfb5024262c0c7b245c181daad91a79f211","src/windows_registry.rs":"6de548aa94215e449f0e58e9a3b1702939d7c2f7b63a9040901c948bf138201d","tests/cc_env.rs":"7402315eea7ffa23b29b393c1de8e236294ede9de562ff0a562704a157135341","tests/support/mod.rs":"092551f9f6e3a999fa0aa02f93314aac0bda2b09268f948c423df56a43575e0b","tests/test.rs":"b1164258714e13173f3861126e97bedf1e29aa24618993c4eb0edd57c431dcc7"},"package":"a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719"}
|
@ -6,7 +6,7 @@ rust:
|
||||
matrix:
|
||||
include:
|
||||
# Minimum version supported
|
||||
- rust: 1.6.0
|
||||
- rust: 1.13.0
|
||||
install:
|
||||
script: cargo build
|
||||
|
||||
@ -14,17 +14,16 @@ sudo: false
|
||||
install:
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then OS=unknown-linux-gnu; else OS=apple-darwin; fi
|
||||
- export TARGET=$ARCH-$OS
|
||||
- curl https://static.rust-lang.org/rustup.sh |
|
||||
sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot`
|
||||
- if [ -z "$NO_ADD" ]; then rustup target add $TARGET; fi
|
||||
before_script:
|
||||
- pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
|
||||
script:
|
||||
- cargo build --verbose
|
||||
- cargo test --verbose
|
||||
- cargo test --verbose --features parallel
|
||||
- cargo test --manifest-path gcc-test/Cargo.toml --target $TARGET
|
||||
- cargo test --manifest-path gcc-test/Cargo.toml --target $TARGET --features parallel
|
||||
- cargo test --manifest-path gcc-test/Cargo.toml --target $TARGET --release
|
||||
- cargo test --manifest-path cc-test/Cargo.toml --target $TARGET
|
||||
- cargo test --manifest-path cc-test/Cargo.toml --target $TARGET --features parallel
|
||||
- cargo test --manifest-path cc-test/Cargo.toml --target $TARGET --release
|
||||
- cargo doc
|
||||
- cargo clean && cargo build
|
||||
- rustdoc --test README.md -L target/debug -L target/debug/deps
|
||||
@ -35,7 +34,7 @@ env:
|
||||
secure: "CBtqrudgE0PS8x3kTr44jKbC2D4nfnmdYVecooNm0qnER4B4TSvZpZSQoCgKK6k4BYQuOSyFTOwYx6M79w39ZMOgyCP9ytB+tyMWL0/+ZuUQL04yVg4M5vd3oJMkOaXbvG56ncgPyFrseY+FPDg+mXAzvJk/nily37YXjkQj2D0="
|
||||
|
||||
matrix:
|
||||
- ARCH=x86_64
|
||||
- ARCH=x86_64 NO_ADD=1
|
||||
- ARCH=i686
|
||||
notifications:
|
||||
email:
|
37
third_party/rust/cc/Cargo.toml
vendored
Normal file
37
third_party/rust/cc/Cargo.toml
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
# 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 believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "cc"
|
||||
version = "1.0.3"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
description = "A build-time dependency for Cargo build scripts to assist in invoking the native\nC compiler to compile native C code into a static archive to be linked into Rust\ncode.\n"
|
||||
homepage = "https://github.com/alexcrichton/cc-rs"
|
||||
documentation = "https://docs.rs/cc"
|
||||
readme = "README.md"
|
||||
keywords = ["build-dependencies"]
|
||||
categories = ["development-tools"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/alexcrichton/cc-rs"
|
||||
[dependencies.rayon]
|
||||
version = "0.8"
|
||||
optional = true
|
||||
[dev-dependencies.tempdir]
|
||||
version = "0.3"
|
||||
|
||||
[features]
|
||||
parallel = ["rayon"]
|
||||
[badges.travis-ci]
|
||||
repository = "alexcrichton/cc-rs"
|
||||
|
||||
[badges.appveyor]
|
||||
repository = "alexcrichton/cc-rs"
|
@ -1,30 +1,27 @@
|
||||
# gcc-rs
|
||||
# cc-rs
|
||||
|
||||
A library to compile C/C++ code into a Rust library/application.
|
||||
A library to compile C/C++/assembly into a Rust library/application.
|
||||
|
||||
[![Build Status](https://travis-ci.org/alexcrichton/gcc-rs.svg?branch=master)](https://travis-ci.org/alexcrichton/gcc-rs)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/onu270iw98h81nwv?svg=true)](https://ci.appveyor.com/project/alexcrichton/gcc-rs)
|
||||
[![Build Status](https://travis-ci.org/alexcrichton/cc-rs.svg?branch=master)](https://travis-ci.org/alexcrichton/cc-rs)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/onu270iw98h81nwv?svg=true)](https://ci.appveyor.com/project/alexcrichton/cc-rs)
|
||||
|
||||
[Documentation](https://docs.rs/gcc)
|
||||
[Documentation](https://docs.rs/cc)
|
||||
|
||||
A simple library meant to be used as a build dependency with Cargo packages in
|
||||
order to build a set of C/C++ files into a static archive. Note that while this
|
||||
crate is called "gcc", it actually calls out to the most relevant compile for
|
||||
a platform, for example using `cl` on MSVC. That is, this crate does indeed work
|
||||
on MSVC!
|
||||
order to build a set of C/C++ files into a static archive. This crate calls out
|
||||
to the most relevant compiler for a platform, for example using `cl` on MSVC.
|
||||
|
||||
## Using gcc-rs
|
||||
> **Note**: this crate was recently renamed from the `gcc` crate, so if you're
|
||||
> looking for the `gcc` crate you're in the right spot!
|
||||
|
||||
## Using cc-rs
|
||||
|
||||
First, you'll want to both add a build script for your crate (`build.rs`) and
|
||||
also add this crate to your `Cargo.toml` via:
|
||||
|
||||
```toml
|
||||
[package]
|
||||
# ...
|
||||
build = "build.rs"
|
||||
|
||||
[build-dependencies]
|
||||
gcc = "0.3"
|
||||
cc = "1.0"
|
||||
```
|
||||
|
||||
Next up, you'll want to write a build script like so:
|
||||
@ -32,16 +29,20 @@ Next up, you'll want to write a build script like so:
|
||||
```rust,no_run
|
||||
// build.rs
|
||||
|
||||
extern crate gcc;
|
||||
extern crate cc;
|
||||
|
||||
fn main() {
|
||||
gcc::compile_library("libfoo.a", &["foo.c", "bar.c"]);
|
||||
cc::Build::new()
|
||||
.file("foo.c")
|
||||
.file("bar.c")
|
||||
.compile("foo");
|
||||
}
|
||||
```
|
||||
|
||||
And that's it! Running `cargo build` should take care of the rest and your Rust
|
||||
application will now have the C files `foo.c` and `bar.c` compiled into it. You
|
||||
can call the functions in Rust by declaring functions in your Rust code like so:
|
||||
application will now have the C files `foo.c` and `bar.c` compiled into a file
|
||||
named libfoo.a. You can call the functions in Rust by declaring functions in
|
||||
your Rust code like so:
|
||||
|
||||
```
|
||||
extern {
|
||||
@ -66,7 +67,7 @@ fn main() {
|
||||
To control the programs and flags used for building, the builder can set a
|
||||
number of different environment variables.
|
||||
|
||||
* `CFLAGS` - a series of space separated flags passed to "gcc". Note that
|
||||
* `CFLAGS` - a series of space separated flags passed to compilers. Note that
|
||||
individual flags cannot currently contain spaces, so doing
|
||||
something like: "-L=foo\ bar" is not possible.
|
||||
* `CC` - the actual C compiler used. Note that this is used as an exact
|
||||
@ -85,9 +86,9 @@ in the following prioritized order:
|
||||
3. `<build-kind>_<var>` - for example, `HOST_CC` or `TARGET_CFLAGS`
|
||||
4. `<var>` - a plain `CC`, `AR` as above.
|
||||
|
||||
If none of these variables exist, gcc-rs uses built-in defaults
|
||||
If none of these variables exist, cc-rs uses built-in defaults
|
||||
|
||||
In addition to the the above optional environment variables, `gcc-rs` has some
|
||||
In addition to the the above optional environment variables, `cc-rs` has some
|
||||
functions with hard requirements on some variables supplied by [cargo's
|
||||
build-script driver][cargo] that it has the `TARGET`, `OUT_DIR`, `OPT_LEVEL`,
|
||||
and `HOST` variables.
|
||||
@ -96,17 +97,21 @@ and `HOST` variables.
|
||||
|
||||
## Optional features
|
||||
|
||||
Currently gcc-rs supports parallel compilation (think `make -jN`) but this
|
||||
feature is turned off by default. To enable gcc-rs to compile C/C++ in parallel,
|
||||
### Parallel
|
||||
|
||||
Currently cc-rs supports parallel compilation (think `make -jN`) but this
|
||||
feature is turned off by default. To enable cc-rs to compile C/C++ in parallel,
|
||||
you can change your dependency to:
|
||||
|
||||
```toml
|
||||
[build-dependencies]
|
||||
gcc = { version = "0.3", features = ["parallel"] }
|
||||
cc = { version = "1.0", features = ["parallel"] }
|
||||
```
|
||||
|
||||
By default gcc-rs will limit parallelism to `$NUM_JOBS`, or if not present it
|
||||
will limit it to the number of cpus on the machine.
|
||||
By default cc-rs will limit parallelism to `$NUM_JOBS`, or if not present it
|
||||
will limit it to the number of cpus on the machine. If you are using cargo,
|
||||
use `-jN` option of `build`, `test` and `run` commands as `$NUM_JOBS`
|
||||
is supplied by cargo.
|
||||
|
||||
## Compile-time Requirements
|
||||
|
||||
@ -115,13 +120,13 @@ is being run. This crate does not ship a C compiler with it. The compiler
|
||||
required varies per platform, but there are three broad categories:
|
||||
|
||||
* Unix platforms require `cc` to be the C compiler. This can be found by
|
||||
installing gcc/clang on Linux distributions and Xcode on OSX, for example.
|
||||
installing cc/clang on Linux distributions and Xcode on OSX, for example.
|
||||
* Windows platforms targeting MSVC (e.g. your target triple ends in `-msvc`)
|
||||
require `cl.exe` to be available and in `PATH`. This is typically found in
|
||||
standard Visual Studio installations and the `PATH` can be set up by running
|
||||
the appropriate developer tools shell.
|
||||
* Windows platforms targeting MinGW (e.g. your target triple ends in `-gnu`)
|
||||
require `gcc` to be available in `PATH`. We recommend the
|
||||
require `cc` to be available in `PATH`. We recommend the
|
||||
[MinGW-w64](http://mingw-w64.org) distribution, which is using the
|
||||
[Win-builds](http://win-builds.org) installation system.
|
||||
You may also acquire it via
|
||||
@ -134,14 +139,14 @@ required varies per platform, but there are three broad categories:
|
||||
|
||||
## C++ support
|
||||
|
||||
`gcc-rs` supports C++ libraries compilation by using the `cpp` method on
|
||||
`Config`:
|
||||
`cc-rs` supports C++ libraries compilation by using the `cpp` method on
|
||||
`Build`:
|
||||
|
||||
```rust,no_run
|
||||
extern crate gcc;
|
||||
extern crate cc;
|
||||
|
||||
fn main() {
|
||||
gcc::Config::new()
|
||||
cc::Build::new()
|
||||
.cpp(true) // Switch to C++ library compilation.
|
||||
.file("foo.cpp")
|
||||
.compile("libfoo.a");
|
||||
@ -154,7 +159,7 @@ linked to the crate target.
|
||||
|
||||
## License
|
||||
|
||||
`gcc-rs` is primarily distributed under the terms of both the MIT license and
|
||||
`cc-rs` is primarily distributed under the terms of both the MIT license and
|
||||
the Apache License (Version 2.0), with portions covered by various BSD-like
|
||||
licenses.
|
||||
|
55
third_party/rust/cc/appveyor.yml
vendored
Normal file
55
third_party/rust/cc/appveyor.yml
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
environment:
|
||||
|
||||
# At the time this was added AppVeyor was having troubles with checking
|
||||
# revocation of SSL certificates of sites like static.rust-lang.org and what
|
||||
# we think is crates.io. The libcurl HTTP client by default checks for
|
||||
# revocation on Windows and according to a mailing list [1] this can be
|
||||
# disabled.
|
||||
#
|
||||
# The `CARGO_HTTP_CHECK_REVOKE` env var here tells cargo to disable SSL
|
||||
# revocation checking on Windows in libcurl. Note, though, that rustup, which
|
||||
# we're using to download Rust here, also uses libcurl as the default backend.
|
||||
# Unlike Cargo, however, rustup doesn't have a mechanism to disable revocation
|
||||
# checking. To get rustup working we set `RUSTUP_USE_HYPER` which forces it to
|
||||
# use the Hyper instead of libcurl backend. Both Hyper and libcurl use
|
||||
# schannel on Windows but it appears that Hyper configures it slightly
|
||||
# differently such that revocation checking isn't turned on by default.
|
||||
#
|
||||
# [1]: https://curl.haxx.se/mail/lib-2016-03/0202.html
|
||||
RUSTUP_USE_HYPER: 1
|
||||
CARGO_HTTP_CHECK_REVOKE: false
|
||||
|
||||
matrix:
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
ARCH: amd64
|
||||
VS: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
ARCH: amd64
|
||||
VS: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
ARCH: x86
|
||||
VS: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
ARCH: x86
|
||||
VS: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat
|
||||
- TARGET: x86_64-pc-windows-gnu
|
||||
MSYS_BITS: 64
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
MSYS_BITS: 32
|
||||
install:
|
||||
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
|
||||
- rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
|
||||
- if defined VS call "%VS%" %ARCH%
|
||||
- set PATH=%PATH%;C:\Program Files (x86)\Rust\bin
|
||||
- if defined MSYS_BITS set PATH=%PATH%;C:\msys64\mingw%MSYS_BITS%\bin
|
||||
- rustc -V
|
||||
- cargo -V
|
||||
|
||||
build: false
|
||||
|
||||
test_script:
|
||||
- cargo test --target %TARGET%
|
||||
- cargo test --features parallel --target %TARGET%
|
||||
- cargo test --manifest-path cc-test/Cargo.toml --target %TARGET%
|
||||
- cargo test --manifest-path cc-test/Cargo.toml --features parallel --target %TARGET%
|
||||
- cargo test --manifest-path cc-test/Cargo.toml --release --target %TARGET%
|
125
third_party/rust/cc/src/com.rs
vendored
Normal file
125
third_party/rust/cc/src/com.rs
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
// Copyright © 2017 winapi-rs developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
|
||||
// All files in the project carrying such notice may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(unused)]
|
||||
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::mem::forget;
|
||||
use std::ops::Deref;
|
||||
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
||||
use std::ptr::null_mut;
|
||||
use std::slice::from_raw_parts;
|
||||
use winapi::Interface;
|
||||
use winapi::BSTR;
|
||||
use winapi::CoInitializeEx;
|
||||
use winapi::COINIT_MULTITHREADED;
|
||||
use winapi::{SysFreeString, SysStringLen};
|
||||
use winapi::IUnknown;
|
||||
use winapi::{S_OK, S_FALSE, HRESULT};
|
||||
|
||||
pub fn initialize() -> Result<(), HRESULT> {
|
||||
let err = unsafe { CoInitializeEx(null_mut(), COINIT_MULTITHREADED) };
|
||||
if err != S_OK && err != S_FALSE {
|
||||
// S_FALSE just means COM is already initialized
|
||||
return Err(err);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct ComPtr<T>(*mut T) where T: Interface;
|
||||
impl<T> ComPtr<T> where T: Interface {
|
||||
/// Creates a `ComPtr` to wrap a raw pointer.
|
||||
/// It takes ownership over the pointer which means it does __not__ call `AddRef`.
|
||||
/// `T` __must__ be a COM interface that inherits from `IUnknown`.
|
||||
pub unsafe fn from_raw(ptr: *mut T) -> ComPtr<T> {
|
||||
assert!(!ptr.is_null());
|
||||
ComPtr(ptr)
|
||||
}
|
||||
/// Casts up the inheritance chain
|
||||
pub fn up<U>(self) -> ComPtr<U> where T: Deref<Target=U>, U: Interface {
|
||||
ComPtr(self.into_raw() as *mut U)
|
||||
}
|
||||
/// Extracts the raw pointer.
|
||||
/// You are now responsible for releasing it yourself.
|
||||
pub fn into_raw(self) -> *mut T {
|
||||
let p = self.0;
|
||||
forget(self);
|
||||
p
|
||||
}
|
||||
/// For internal use only.
|
||||
fn as_unknown(&self) -> &IUnknown {
|
||||
unsafe { &*(self.0 as *mut IUnknown) }
|
||||
}
|
||||
/// Performs QueryInterface fun.
|
||||
pub fn cast<U>(&self) -> Result<ComPtr<U>, i32> where U: Interface {
|
||||
let mut obj = null_mut();
|
||||
let err = unsafe { self.as_unknown().QueryInterface(&U::uuidof(), &mut obj) };
|
||||
if err < 0 { return Err(err); }
|
||||
Ok(unsafe { ComPtr::from_raw(obj as *mut U) })
|
||||
}
|
||||
}
|
||||
impl<T> Deref for ComPtr<T> where T: Interface {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
unsafe { &*self.0 }
|
||||
}
|
||||
}
|
||||
impl<T> Clone for ComPtr<T> where T: Interface {
|
||||
fn clone(&self) -> Self {
|
||||
unsafe {
|
||||
self.as_unknown().AddRef();
|
||||
ComPtr::from_raw(self.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> Drop for ComPtr<T> where T: Interface {
|
||||
fn drop(&mut self) {
|
||||
unsafe { self.as_unknown().Release(); }
|
||||
}
|
||||
}
|
||||
pub struct BStr(BSTR);
|
||||
impl BStr {
|
||||
pub unsafe fn from_raw(s: BSTR) -> BStr {
|
||||
BStr(s)
|
||||
}
|
||||
pub fn to_osstring(&self) -> OsString {
|
||||
let len = unsafe { SysStringLen(self.0) };
|
||||
let slice = unsafe { from_raw_parts(self.0, len as usize) };
|
||||
OsStringExt::from_wide(slice)
|
||||
}
|
||||
}
|
||||
impl Drop for BStr {
|
||||
fn drop(&mut self) {
|
||||
unsafe { SysFreeString(self.0) };
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToWide {
|
||||
fn to_wide(&self) -> Vec<u16>;
|
||||
fn to_wide_null(&self) -> Vec<u16>;
|
||||
}
|
||||
impl<T> ToWide for T where T: AsRef<OsStr> {
|
||||
fn to_wide(&self) -> Vec<u16> {
|
||||
self.as_ref().encode_wide().collect()
|
||||
}
|
||||
fn to_wide_null(&self) -> Vec<u16> {
|
||||
self.as_ref().encode_wide().chain(Some(0)).collect()
|
||||
}
|
||||
}
|
||||
pub trait FromWide where Self: Sized {
|
||||
fn from_wide(wide: &[u16]) -> Self;
|
||||
fn from_wide_null(wide: &[u16]) -> Self {
|
||||
let len = wide.iter().take_while(|&&c| c != 0).count();
|
||||
Self::from_wide(&wide[..len])
|
||||
}
|
||||
}
|
||||
impl FromWide for OsString {
|
||||
fn from_wide(wide: &[u16]) -> OsString {
|
||||
OsStringExt::from_wide(wide)
|
||||
}
|
||||
}
|
||||
|
1888
third_party/rust/cc/src/lib.rs
vendored
Normal file
1888
third_party/rust/cc/src/lib.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
257
third_party/rust/cc/src/setup_config.rs
vendored
Normal file
257
third_party/rust/cc/src/setup_config.rs
vendored
Normal file
@ -0,0 +1,257 @@
|
||||
// Copyright © 2017 winapi-rs developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
|
||||
// All files in the project carrying such notice may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(bad_style)]
|
||||
#![allow(unused)]
|
||||
|
||||
use std::ffi::OsString;
|
||||
use std::ptr::null_mut;
|
||||
use winapi::Interface;
|
||||
use winapi::{LPFILETIME, ULONG};
|
||||
use winapi::S_FALSE;
|
||||
use winapi::BSTR;
|
||||
use winapi::LPCOLESTR;
|
||||
use winapi::{CLSCTX_ALL, CoCreateInstance};
|
||||
use winapi::LPSAFEARRAY;
|
||||
use winapi::{IUnknown, IUnknownVtbl};
|
||||
use winapi::{HRESULT, LCID, LPCWSTR, PULONGLONG};
|
||||
|
||||
use com::{BStr, ComPtr};
|
||||
|
||||
// Bindings to the Setup.Configuration stuff
|
||||
pub type InstanceState = u32;
|
||||
|
||||
pub const eNone: InstanceState = 0;
|
||||
pub const eLocal: InstanceState = 1;
|
||||
pub const eRegistered: InstanceState = 2;
|
||||
pub const eNoRebootRequired: InstanceState = 4;
|
||||
pub const eComplete: InstanceState = -1i32 as u32;
|
||||
|
||||
RIDL!{#[uuid(0xb41463c3, 0x8866, 0x43b5, 0xbc, 0x33, 0x2b, 0x06, 0x76, 0xf7, 0xf4, 0x2e)]
|
||||
interface ISetupInstance(ISetupInstanceVtbl): IUnknown(IUnknownVtbl) {
|
||||
fn GetInstanceId(
|
||||
pbstrInstanceId: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetInstallDate(
|
||||
pInstallDate: LPFILETIME,
|
||||
) -> HRESULT,
|
||||
fn GetInstallationName(
|
||||
pbstrInstallationName: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetInstallationPath(
|
||||
pbstrInstallationPath: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetInstallationVersion(
|
||||
pbstrInstallationVersion: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetDisplayName(
|
||||
lcid: LCID,
|
||||
pbstrDisplayName: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetDescription(
|
||||
lcid: LCID,
|
||||
pbstrDescription: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn ResolvePath(
|
||||
pwszRelativePath: LPCOLESTR,
|
||||
pbstrAbsolutePath: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
}}
|
||||
|
||||
RIDL!{#[uuid(0x89143c9a, 0x05af, 0x49b0, 0xb7, 0x17, 0x72, 0xe2, 0x18, 0xa2, 0x18, 0x5c)]
|
||||
interface ISetupInstance2(ISetupInstance2Vtbl): ISetupInstance(ISetupInstanceVtbl) {
|
||||
fn GetState(
|
||||
pState: *mut InstanceState,
|
||||
) -> HRESULT,
|
||||
fn GetPackages(
|
||||
ppsaPackages: *mut LPSAFEARRAY,
|
||||
) -> HRESULT,
|
||||
fn GetProduct(
|
||||
ppPackage: *mut *mut ISetupPackageReference,
|
||||
) -> HRESULT,
|
||||
fn GetProductPath(
|
||||
pbstrProductPath: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
}}
|
||||
|
||||
RIDL!{#[uuid(0x6380bcff, 0x41d3, 0x4b2e, 0x8b, 0x2e, 0xbf, 0x8a, 0x68, 0x10, 0xc8, 0x48)]
|
||||
interface IEnumSetupInstances(IEnumSetupInstancesVtbl): IUnknown(IUnknownVtbl) {
|
||||
fn Next(
|
||||
celt: ULONG,
|
||||
rgelt: *mut *mut ISetupInstance,
|
||||
pceltFetched: *mut ULONG,
|
||||
) -> HRESULT,
|
||||
fn Skip(
|
||||
celt: ULONG,
|
||||
) -> HRESULT,
|
||||
fn Reset() -> HRESULT,
|
||||
fn Clone(
|
||||
ppenum: *mut *mut IEnumSetupInstances,
|
||||
) -> HRESULT,
|
||||
}}
|
||||
|
||||
RIDL!{#[uuid(0x42843719, 0xdb4c, 0x46c2, 0x8e, 0x7c, 0x64, 0xf1, 0x81, 0x6e, 0xfd, 0x5b)]
|
||||
interface ISetupConfiguration(ISetupConfigurationVtbl): IUnknown(IUnknownVtbl) {
|
||||
fn EnumInstances(
|
||||
ppEnumInstances: *mut *mut IEnumSetupInstances,
|
||||
) -> HRESULT,
|
||||
fn GetInstanceForCurrentProcess(
|
||||
ppInstance: *mut *mut ISetupInstance,
|
||||
) -> HRESULT,
|
||||
fn GetInstanceForPath(
|
||||
wzPath: LPCWSTR,
|
||||
ppInstance: *mut *mut ISetupInstance,
|
||||
) -> HRESULT,
|
||||
}}
|
||||
|
||||
RIDL!{#[uuid(0x26aab78c, 0x4a60, 0x49d6, 0xaf, 0x3b, 0x3c, 0x35, 0xbc, 0x93, 0x36, 0x5d)]
|
||||
interface ISetupConfiguration2(ISetupConfiguration2Vtbl):
|
||||
ISetupConfiguration(ISetupConfigurationVtbl) {
|
||||
fn EnumAllInstances(
|
||||
ppEnumInstances: *mut *mut IEnumSetupInstances,
|
||||
) -> HRESULT,
|
||||
}}
|
||||
|
||||
RIDL!{#[uuid(0xda8d8a16, 0xb2b6, 0x4487, 0xa2, 0xf1, 0x59, 0x4c, 0xcc, 0xcd, 0x6b, 0xf5)]
|
||||
interface ISetupPackageReference(ISetupPackageReferenceVtbl): IUnknown(IUnknownVtbl) {
|
||||
fn GetId(
|
||||
pbstrId: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetVersion(
|
||||
pbstrVersion: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetChip(
|
||||
pbstrChip: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetLanguage(
|
||||
pbstrLanguage: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetBranch(
|
||||
pbstrBranch: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetType(
|
||||
pbstrType: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetUniqueId(
|
||||
pbstrUniqueId: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
}}
|
||||
|
||||
RIDL!{#[uuid(0x42b21b78, 0x6192, 0x463e, 0x87, 0xbf, 0xd5, 0x77, 0x83, 0x8f, 0x1d, 0x5c)]
|
||||
interface ISetupHelper(ISetupHelperVtbl): IUnknown(IUnknownVtbl) {
|
||||
fn ParseVersion(
|
||||
pwszVersion: LPCOLESTR,
|
||||
pullVersion: PULONGLONG,
|
||||
) -> HRESULT,
|
||||
fn ParseVersionRange(
|
||||
pwszVersionRange: LPCOLESTR,
|
||||
pullMinVersion: PULONGLONG,
|
||||
pullMaxVersion: PULONGLONG,
|
||||
) -> HRESULT,
|
||||
}}
|
||||
|
||||
DEFINE_GUID!{CLSID_SetupConfiguration,
|
||||
0x177f0c4a, 0x1cd3, 0x4de7, 0xa3, 0x2c, 0x71, 0xdb, 0xbb, 0x9f, 0xa3, 0x6d}
|
||||
|
||||
// Safe wrapper around the COM interfaces
|
||||
pub struct SetupConfiguration(ComPtr<ISetupConfiguration>);
|
||||
|
||||
impl SetupConfiguration {
|
||||
pub fn new() -> Result<SetupConfiguration, i32> {
|
||||
let mut obj = null_mut();
|
||||
let err = unsafe { CoCreateInstance(
|
||||
&CLSID_SetupConfiguration, null_mut(), CLSCTX_ALL,
|
||||
&ISetupConfiguration::uuidof(), &mut obj,
|
||||
) };
|
||||
if err < 0 { return Err(err); }
|
||||
let obj = unsafe { ComPtr::from_raw(obj as *mut ISetupConfiguration) };
|
||||
Ok(SetupConfiguration(obj))
|
||||
}
|
||||
pub fn get_instance_for_current_process(&self) -> Result<SetupInstance, i32> {
|
||||
let mut obj = null_mut();
|
||||
let err = unsafe { self.0.GetInstanceForCurrentProcess(&mut obj) };
|
||||
if err < 0 { return Err(err); }
|
||||
Ok(unsafe { SetupInstance::from_raw(obj) })
|
||||
}
|
||||
pub fn enum_instances(&self) -> Result<EnumSetupInstances, i32> {
|
||||
let mut obj = null_mut();
|
||||
let err = unsafe { self.0.EnumInstances(&mut obj) };
|
||||
if err < 0 { return Err(err); }
|
||||
Ok(unsafe { EnumSetupInstances::from_raw(obj) })
|
||||
}
|
||||
pub fn enum_all_instances(&self) -> Result<EnumSetupInstances, i32> {
|
||||
let mut obj = null_mut();
|
||||
let this = try!(self.0.cast::<ISetupConfiguration2>());
|
||||
let err = unsafe { this.EnumAllInstances(&mut obj) };
|
||||
if err < 0 { return Err(err); }
|
||||
Ok(unsafe { EnumSetupInstances::from_raw(obj) })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SetupInstance(ComPtr<ISetupInstance>);
|
||||
|
||||
impl SetupInstance {
|
||||
pub unsafe fn from_raw(obj: *mut ISetupInstance) -> SetupInstance {
|
||||
SetupInstance(ComPtr::from_raw(obj))
|
||||
}
|
||||
pub fn instance_id(&self) -> Result<OsString, i32> {
|
||||
let mut s = null_mut();
|
||||
let err = unsafe { self.0.GetInstanceId(&mut s) };
|
||||
let bstr = unsafe { BStr::from_raw(s) };
|
||||
if err < 0 { return Err(err); }
|
||||
Ok(bstr.to_osstring())
|
||||
}
|
||||
pub fn installation_name(&self) -> Result<OsString, i32> {
|
||||
let mut s = null_mut();
|
||||
let err = unsafe { self.0.GetInstallationName(&mut s) };
|
||||
let bstr = unsafe { BStr::from_raw(s) };
|
||||
if err < 0 { return Err(err); }
|
||||
Ok(bstr.to_osstring())
|
||||
}
|
||||
pub fn installation_path(&self) -> Result<OsString, i32> {
|
||||
let mut s = null_mut();
|
||||
let err = unsafe { self.0.GetInstallationPath(&mut s) };
|
||||
let bstr = unsafe { BStr::from_raw(s) };
|
||||
if err < 0 { return Err(err); }
|
||||
Ok(bstr.to_osstring())
|
||||
}
|
||||
pub fn installation_version(&self) -> Result<OsString, i32> {
|
||||
let mut s = null_mut();
|
||||
let err = unsafe { self.0.GetInstallationVersion(&mut s) };
|
||||
let bstr = unsafe { BStr::from_raw(s) };
|
||||
if err < 0 { return Err(err); }
|
||||
Ok(bstr.to_osstring())
|
||||
}
|
||||
pub fn product_path(&self) -> Result<OsString, i32> {
|
||||
let mut s = null_mut();
|
||||
let this = try!(self.0.cast::<ISetupInstance2>());
|
||||
let err = unsafe { this.GetProductPath(&mut s) };
|
||||
let bstr = unsafe { BStr::from_raw(s) };
|
||||
if err < 0 { return Err(err); }
|
||||
Ok(bstr.to_osstring())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EnumSetupInstances(ComPtr<IEnumSetupInstances>);
|
||||
|
||||
impl EnumSetupInstances {
|
||||
pub unsafe fn from_raw(obj: *mut IEnumSetupInstances) -> EnumSetupInstances {
|
||||
EnumSetupInstances(ComPtr::from_raw(obj))
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for EnumSetupInstances {
|
||||
type Item = Result<SetupInstance, i32>;
|
||||
fn next(&mut self) -> Option<Result<SetupInstance, i32>> {
|
||||
let mut obj = null_mut();
|
||||
let err = unsafe { self.0.Next(1, &mut obj, null_mut()) };
|
||||
if err < 0 { return Some(Err(err)); }
|
||||
if err == S_FALSE { return None; }
|
||||
Some(Ok(unsafe { SetupInstance::from_raw(obj) }))
|
||||
}
|
||||
}
|
||||
|
214
third_party/rust/cc/src/winapi.rs
vendored
Normal file
214
third_party/rust/cc/src/winapi.rs
vendored
Normal file
@ -0,0 +1,214 @@
|
||||
// Copyright © 2015-2017 winapi-rs developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
|
||||
// All files in the project carrying such notice may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(bad_style)]
|
||||
|
||||
use std::os::raw;
|
||||
|
||||
pub type wchar_t = u16;
|
||||
|
||||
pub type UINT = raw::c_uint;
|
||||
pub type LPUNKNOWN = *mut IUnknown;
|
||||
pub type REFIID = *const IID;
|
||||
pub type IID = GUID;
|
||||
pub type REFCLSID = *const IID;
|
||||
pub type PVOID = *mut raw::c_void;
|
||||
pub type USHORT = raw::c_ushort;
|
||||
pub type ULONG = raw::c_ulong;
|
||||
pub type LONG = raw::c_long;
|
||||
pub type DWORD = u32;
|
||||
pub type LPVOID = *mut raw::c_void;
|
||||
pub type HRESULT = raw::c_long;
|
||||
pub type LPFILETIME = *mut FILETIME;
|
||||
pub type BSTR = *mut OLECHAR;
|
||||
pub type OLECHAR = WCHAR;
|
||||
pub type WCHAR = wchar_t;
|
||||
pub type LPCOLESTR = *const OLECHAR;
|
||||
pub type LCID = DWORD;
|
||||
pub type LPCWSTR = *const WCHAR;
|
||||
pub type PULONGLONG = *mut ULONGLONG;
|
||||
pub type ULONGLONG = u64;
|
||||
|
||||
pub const S_OK: HRESULT = 0;
|
||||
pub const S_FALSE: HRESULT = 1;
|
||||
pub const COINIT_MULTITHREADED: u32 = 0x0;
|
||||
|
||||
pub type CLSCTX = u32;
|
||||
|
||||
pub const CLSCTX_INPROC_SERVER: CLSCTX = 0x1;
|
||||
pub const CLSCTX_INPROC_HANDLER: CLSCTX = 0x2;
|
||||
pub const CLSCTX_LOCAL_SERVER: CLSCTX = 0x4;
|
||||
pub const CLSCTX_REMOTE_SERVER: CLSCTX = 0x10;
|
||||
|
||||
pub const CLSCTX_ALL: CLSCTX = CLSCTX_INPROC_SERVER |
|
||||
CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct GUID {
|
||||
pub Data1: raw::c_ulong,
|
||||
pub Data2: raw::c_ushort,
|
||||
pub Data3: raw::c_ushort,
|
||||
pub Data4: [raw::c_uchar; 8],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct FILETIME {
|
||||
pub dwLowDateTime: DWORD,
|
||||
pub dwHighDateTime: DWORD,
|
||||
}
|
||||
|
||||
pub trait Interface {
|
||||
fn uuidof() -> GUID;
|
||||
}
|
||||
|
||||
#[link(name = "ole32")]
|
||||
#[link(name = "oleaut32")]
|
||||
extern { }
|
||||
|
||||
extern "system" {
|
||||
pub fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) -> HRESULT;
|
||||
pub fn CoCreateInstance(rclsid: REFCLSID, pUnkOuter: LPUNKNOWN,
|
||||
dwClsContext: DWORD, riid: REFIID,
|
||||
ppv: *mut LPVOID) -> HRESULT;
|
||||
pub fn SysFreeString(bstrString: BSTR);
|
||||
pub fn SysStringLen(pbstr: BSTR) -> UINT;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct SAFEARRAYBOUND {
|
||||
pub cElements: ULONG,
|
||||
pub lLbound: LONG,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct SAFEARRAY {
|
||||
pub cDims: USHORT,
|
||||
pub fFeatures: USHORT,
|
||||
pub cbElements: ULONG,
|
||||
pub cLocks: ULONG,
|
||||
pub pvData: PVOID,
|
||||
pub rgsabound: [SAFEARRAYBOUND; 1],
|
||||
}
|
||||
|
||||
pub type LPSAFEARRAY = *mut SAFEARRAY;
|
||||
|
||||
macro_rules! DEFINE_GUID {
|
||||
(
|
||||
$name:ident, $l:expr, $w1:expr, $w2:expr,
|
||||
$b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr
|
||||
) => {
|
||||
pub const $name: $crate::winapi::GUID = $crate::winapi::GUID {
|
||||
Data1: $l,
|
||||
Data2: $w1,
|
||||
Data3: $w2,
|
||||
Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! RIDL {
|
||||
(#[uuid($($uuid:expr),+)]
|
||||
interface $interface:ident ($vtbl:ident) {$(
|
||||
fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty,
|
||||
)+}) => (
|
||||
#[repr(C)]
|
||||
pub struct $vtbl {
|
||||
$(pub $method: unsafe extern "system" fn(
|
||||
This: *mut $interface,
|
||||
$($p: $t),*
|
||||
) -> $rtr,)+
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct $interface {
|
||||
pub lpVtbl: *const $vtbl,
|
||||
}
|
||||
RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}}
|
||||
RIDL!{@uuid $interface $($uuid),+}
|
||||
);
|
||||
(#[uuid($($uuid:expr),+)]
|
||||
interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {
|
||||
}) => (
|
||||
#[repr(C)]
|
||||
pub struct $vtbl {
|
||||
pub parent: $pvtbl,
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct $interface {
|
||||
pub lpVtbl: *const $vtbl,
|
||||
}
|
||||
RIDL!{@deref $interface $pinterface}
|
||||
RIDL!{@uuid $interface $($uuid),+}
|
||||
);
|
||||
(#[uuid($($uuid:expr),+)]
|
||||
interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {$(
|
||||
fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty,
|
||||
)+}) => (
|
||||
#[repr(C)]
|
||||
pub struct $vtbl {
|
||||
pub parent: $pvtbl,
|
||||
$(pub $method: unsafe extern "system" fn(
|
||||
This: *mut $interface,
|
||||
$($p: $t,)*
|
||||
) -> $rtr,)+
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct $interface {
|
||||
pub lpVtbl: *const $vtbl,
|
||||
}
|
||||
RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}}
|
||||
RIDL!{@deref $interface $pinterface}
|
||||
RIDL!{@uuid $interface $($uuid),+}
|
||||
);
|
||||
(@deref $interface:ident $pinterface:ident) => (
|
||||
impl ::std::ops::Deref for $interface {
|
||||
type Target = $pinterface;
|
||||
#[inline]
|
||||
fn deref(&self) -> &$pinterface {
|
||||
unsafe { &*(self as *const $interface as *const $pinterface) }
|
||||
}
|
||||
}
|
||||
);
|
||||
(@impl $interface:ident {$(
|
||||
fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty,
|
||||
)+}) => (
|
||||
impl $interface {
|
||||
$(#[inline] pub unsafe fn $method(&self, $($p: $t,)*) -> $rtr {
|
||||
((*self.lpVtbl).$method)(self as *const _ as *mut _, $($p,)*)
|
||||
})+
|
||||
}
|
||||
);
|
||||
(@uuid $interface:ident
|
||||
$l:expr, $w1:expr, $w2:expr,
|
||||
$b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr
|
||||
) => (
|
||||
impl $crate::winapi::Interface for $interface {
|
||||
#[inline]
|
||||
fn uuidof() -> $crate::winapi::GUID {
|
||||
$crate::winapi::GUID {
|
||||
Data1: $l,
|
||||
Data2: $w1,
|
||||
Data3: $w2,
|
||||
Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8],
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
RIDL!{#[uuid(0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)]
|
||||
interface IUnknown(IUnknownVtbl) {
|
||||
fn QueryInterface(
|
||||
riid: REFIID,
|
||||
ppvObject: *mut *mut raw::c_void,
|
||||
) -> HRESULT,
|
||||
fn AddRef() -> ULONG,
|
||||
fn Release() -> ULONG,
|
||||
}}
|
@ -15,6 +15,7 @@ use std::process::Command;
|
||||
|
||||
use Tool;
|
||||
|
||||
#[cfg(windows)]
|
||||
macro_rules! otry {
|
||||
($expr:expr) => (match $expr {
|
||||
Some(val) => val,
|
||||
@ -50,10 +51,121 @@ pub fn find_tool(_target: &str, _tool: &str) -> Option<Tool> {
|
||||
#[cfg(windows)]
|
||||
pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
|
||||
use std::env;
|
||||
|
||||
// This logic is all tailored for MSVC, if we're not that then bail out
|
||||
// early.
|
||||
if !target.contains("msvc") {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Looks like msbuild isn't located in the same location as other tools like
|
||||
// cl.exe and lib.exe. To handle this we probe for it manually with
|
||||
// dedicated registry keys.
|
||||
if tool.contains("msbuild") {
|
||||
return impl_::find_msbuild(target);
|
||||
}
|
||||
|
||||
// If VCINSTALLDIR is set, then someone's probably already run vcvars and we
|
||||
// should just find whatever that indicates.
|
||||
if env::var_os("VCINSTALLDIR").is_some() {
|
||||
return env::var_os("PATH")
|
||||
.and_then(|path| env::split_paths(&path).map(|p| p.join(tool)).find(|p| p.exists()))
|
||||
.map(|path| Tool::new(path.into()));
|
||||
}
|
||||
|
||||
// Ok, if we're here, now comes the fun part of the probing. Default shells
|
||||
// or shells like MSYS aren't really configured to execute `cl.exe` and the
|
||||
// various compiler tools shipped as part of Visual Studio. Here we try to
|
||||
// first find the relevant tool, then we also have to be sure to fill in
|
||||
// environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that
|
||||
// the tool is actually usable.
|
||||
|
||||
return impl_::find_msvc_15(tool, target)
|
||||
.or_else(|| impl_::find_msvc_14(tool, target))
|
||||
.or_else(|| impl_::find_msvc_12(tool, target))
|
||||
.or_else(|| impl_::find_msvc_11(tool, target));
|
||||
}
|
||||
|
||||
/// A version of Visual Studio
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
pub enum VsVers {
|
||||
/// Visual Studio 12 (2013)
|
||||
Vs12,
|
||||
/// Visual Studio 14 (2015)
|
||||
Vs14,
|
||||
/// Visual Studio 15 (2017)
|
||||
Vs15,
|
||||
|
||||
/// Hidden variant that should not be matched on. Callers that want to
|
||||
/// handle an enumeration of `VsVers` instances should always have a default
|
||||
/// case meaning that it's a VS version they don't understand.
|
||||
#[doc(hidden)]
|
||||
#[allow(bad_style)]
|
||||
__Nonexhaustive_do_not_match_this_or_your_code_will_break,
|
||||
}
|
||||
|
||||
/// Find the most recent installed version of Visual Studio
|
||||
///
|
||||
/// This is used by the cmake crate to figure out the correct
|
||||
/// generator.
|
||||
#[cfg(not(windows))]
|
||||
pub fn find_vs_version() -> Result<VsVers, String> {
|
||||
Err(format!("not windows"))
|
||||
}
|
||||
|
||||
/// Documented above
|
||||
#[cfg(windows)]
|
||||
pub fn find_vs_version() -> Result<VsVers, String> {
|
||||
use std::env;
|
||||
|
||||
match env::var("VisualStudioVersion") {
|
||||
Ok(version) => {
|
||||
match &version[..] {
|
||||
"15.0" => Ok(VsVers::Vs15),
|
||||
"14.0" => Ok(VsVers::Vs14),
|
||||
"12.0" => Ok(VsVers::Vs12),
|
||||
vers => Err(format!("\n\n\
|
||||
unsupported or unknown VisualStudio version: {}\n\
|
||||
if another version is installed consider running \
|
||||
the appropriate vcvars script before building this \
|
||||
crate\n\
|
||||
", vers)),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Check for the presense of a specific registry key
|
||||
// that indicates visual studio is installed.
|
||||
if impl_::has_msbuild_version("15.0") {
|
||||
Ok(VsVers::Vs15)
|
||||
} else if impl_::has_msbuild_version("14.0") {
|
||||
Ok(VsVers::Vs14)
|
||||
} else if impl_::has_msbuild_version("12.0") {
|
||||
Ok(VsVers::Vs12)
|
||||
} else {
|
||||
Err(format!("\n\n\
|
||||
couldn't determine visual studio generator\n\
|
||||
if VisualStudio is installed, however, consider \
|
||||
running the appropriate vcvars script before building \
|
||||
this crate\n\
|
||||
"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
mod impl_ {
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::mem;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use registry::{RegistryKey, LOCAL_MACHINE};
|
||||
use com;
|
||||
use setup_config::{SetupConfiguration, SetupInstance};
|
||||
|
||||
use Tool;
|
||||
|
||||
struct MsvcTool {
|
||||
tool: PathBuf,
|
||||
@ -82,47 +194,102 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
|
||||
}
|
||||
}
|
||||
|
||||
// This logic is all tailored for MSVC, if we're not that then bail out
|
||||
// early.
|
||||
if !target.contains("msvc") {
|
||||
return None;
|
||||
// In MSVC 15 (2017) MS once again changed the scheme for locating
|
||||
// the tooling. Now we must go through some COM interfaces, which
|
||||
// is super fun for Rust.
|
||||
//
|
||||
// Note that much of this logic can be found [online] wrt paths, COM, etc.
|
||||
//
|
||||
// [online]: https://blogs.msdn.microsoft.com/vcblog/2017/03/06/finding-the-visual-c-compiler-tools-in-visual-studio-2017/
|
||||
pub fn find_msvc_15(tool: &str, target: &str) -> Option<Tool> {
|
||||
otry!(com::initialize().ok());
|
||||
|
||||
let config = otry!(SetupConfiguration::new().ok());
|
||||
let iter = otry!(config.enum_all_instances().ok());
|
||||
for instance in iter {
|
||||
let instance = otry!(instance.ok());
|
||||
let tool = tool_from_vs15_instance(tool, target, &instance);
|
||||
if tool.is_some() {
|
||||
return tool;
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
// Looks like msbuild isn't located in the same location as other tools like
|
||||
// cl.exe and lib.exe. To handle this we probe for it manually with
|
||||
// dedicated registry keys.
|
||||
if tool.contains("msbuild") {
|
||||
return find_msbuild(target);
|
||||
fn tool_from_vs15_instance(tool: &str, target: &str,
|
||||
instance: &SetupInstance) -> Option<Tool> {
|
||||
let (bin_path, host_dylib_path, lib_path, include_path) = otry!(vs15_vc_paths(target, instance));
|
||||
let tool_path = bin_path.join(tool);
|
||||
if !tool_path.exists() { return None };
|
||||
|
||||
let mut tool = MsvcTool::new(tool_path);
|
||||
tool.path.push(host_dylib_path);
|
||||
tool.libs.push(lib_path);
|
||||
tool.include.push(include_path);
|
||||
|
||||
if let Some((atl_lib_path, atl_include_path)) = atl_paths(target, &bin_path) {
|
||||
tool.libs.push(atl_lib_path);
|
||||
tool.include.push(atl_include_path);
|
||||
}
|
||||
|
||||
otry!(add_sdks(&mut tool, target));
|
||||
|
||||
Some(tool.into_tool())
|
||||
}
|
||||
|
||||
// If VCINSTALLDIR is set, then someone's probably already run vcvars and we
|
||||
// should just find whatever that indicates.
|
||||
if env::var_os("VCINSTALLDIR").is_some() {
|
||||
return env::var_os("PATH")
|
||||
.and_then(|path| env::split_paths(&path).map(|p| p.join(tool)).find(|p| p.exists()))
|
||||
.map(|path| Tool::new(path.into()));
|
||||
fn vs15_vc_paths(target: &str, instance: &SetupInstance) -> Option<(PathBuf, PathBuf, PathBuf, PathBuf)> {
|
||||
let instance_path: PathBuf = otry!(instance.installation_path().ok()).into();
|
||||
let version_path = instance_path.join(r"VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt");
|
||||
let mut version_file = otry!(File::open(version_path).ok());
|
||||
let mut version = String::new();
|
||||
otry!(version_file.read_to_string(&mut version).ok());
|
||||
let version = version.trim();
|
||||
let host = match host_arch() {
|
||||
X86 => "X86",
|
||||
X86_64 => "X64",
|
||||
_ => return None,
|
||||
};
|
||||
let target = otry!(lib_subdir(target));
|
||||
// The directory layout here is MSVC/bin/Host$host/$target/
|
||||
let path = instance_path.join(r"VC\Tools\MSVC").join(version);
|
||||
// This is the path to the toolchain for a particular target, running
|
||||
// on a given host
|
||||
let bin_path = path.join("bin").join(&format!("Host{}", host)).join(&target);
|
||||
// But! we also need PATH to contain the target directory for the host
|
||||
// architecture, because it contains dlls like mspdb140.dll compiled for
|
||||
// the host architecture.
|
||||
let host_dylib_path = path.join("bin").join(&format!("Host{}", host)).join(&host.to_lowercase());
|
||||
let lib_path = path.join("lib").join(&target);
|
||||
let include_path = path.join("include");
|
||||
Some((bin_path, host_dylib_path, lib_path, include_path))
|
||||
}
|
||||
|
||||
// Ok, if we're here, now comes the fun part of the probing. Default shells
|
||||
// or shells like MSYS aren't really configured to execute `cl.exe` and the
|
||||
// various compiler tools shipped as part of Visual Studio. Here we try to
|
||||
// first find the relevant tool, then we also have to be sure to fill in
|
||||
// environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that
|
||||
// the tool is actually usable.
|
||||
fn atl_paths(target: &str, path: &Path) -> Option<(PathBuf, PathBuf)> {
|
||||
let atl_path = path.join("atlfmc");
|
||||
let sub = otry!(lib_subdir(target));
|
||||
if atl_path.exists() {
|
||||
Some((atl_path.join("lib").join(sub), atl_path.join("include")))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
return find_msvc_latest(tool, target, "15.0")
|
||||
.or_else(|| find_msvc_latest(tool, target, "14.0"))
|
||||
.or_else(|| find_msvc_12(tool, target))
|
||||
.or_else(|| find_msvc_11(tool, target));
|
||||
|
||||
// For MSVC 14 or newer we need to find the Universal CRT as well as either
|
||||
// For MSVC 14 we need to find the Universal CRT as well as either
|
||||
// the Windows 10 SDK or Windows 8.1 SDK.
|
||||
fn find_msvc_latest(tool: &str, target: &str, ver: &str) -> Option<Tool> {
|
||||
let vcdir = otry!(get_vc_dir(ver));
|
||||
pub fn find_msvc_14(tool: &str, target: &str) -> Option<Tool> {
|
||||
let vcdir = otry!(get_vc_dir("14.0"));
|
||||
let mut tool = otry!(get_tool(tool, &vcdir, target));
|
||||
otry!(add_sdks(&mut tool, target));
|
||||
Some(tool.into_tool())
|
||||
}
|
||||
|
||||
fn add_sdks(tool: &mut MsvcTool, target: &str) -> Option<()> {
|
||||
let sub = otry!(lib_subdir(target));
|
||||
let (ucrt, ucrt_version) = otry!(get_ucrt_dir());
|
||||
|
||||
tool.path.push(ucrt.join("bin").join(&ucrt_version).join(sub));
|
||||
|
||||
let ucrt_include = ucrt.join("include").join(&ucrt_version);
|
||||
tool.include.push(ucrt_include.join("ucrt"));
|
||||
|
||||
@ -145,14 +312,13 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
|
||||
tool.include.push(sdk_include.join("um"));
|
||||
tool.include.push(sdk_include.join("winrt"));
|
||||
tool.include.push(sdk_include.join("shared"));
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
Some(tool.into_tool())
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
// For MSVC 12 we need to find the Windows 8.1 SDK.
|
||||
fn find_msvc_12(tool: &str, target: &str) -> Option<Tool> {
|
||||
pub fn find_msvc_12(tool: &str, target: &str) -> Option<Tool> {
|
||||
let vcdir = otry!(get_vc_dir("12.0"));
|
||||
let mut tool = otry!(get_tool(tool, &vcdir, target));
|
||||
let sub = otry!(lib_subdir(target));
|
||||
@ -168,7 +334,7 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
|
||||
}
|
||||
|
||||
// For MSVC 11 we need to find the Windows 8 SDK.
|
||||
fn find_msvc_11(tool: &str, target: &str) -> Option<Tool> {
|
||||
pub fn find_msvc_11(tool: &str, target: &str) -> Option<Tool> {
|
||||
let vcdir = otry!(get_vc_dir("11.0"));
|
||||
let mut tool = otry!(get_tool(tool, &vcdir, target));
|
||||
let sub = otry!(lib_subdir(target));
|
||||
@ -403,8 +569,52 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
|
||||
max_key
|
||||
}
|
||||
|
||||
pub fn has_msbuild_version(version: &str) -> bool {
|
||||
match version {
|
||||
"15.0" => {
|
||||
find_msbuild_vs15("x86_64-pc-windows-msvc").is_some() ||
|
||||
find_msbuild_vs15("i686-pc-windows-msvc").is_some()
|
||||
}
|
||||
"12.0" | "14.0" => {
|
||||
LOCAL_MACHINE.open(
|
||||
&OsString::from(format!("SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\{}",
|
||||
version))).is_ok()
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
// see http://stackoverflow.com/questions/328017/path-to-msbuild
|
||||
fn find_msbuild(target: &str) -> Option<Tool> {
|
||||
pub fn find_msbuild(target: &str) -> Option<Tool> {
|
||||
// VS 15 (2017) changed how to locate msbuild
|
||||
if let Some(r) = find_msbuild_vs15(target) {
|
||||
return Some(r);
|
||||
} else {
|
||||
find_old_msbuild(target)
|
||||
}
|
||||
}
|
||||
|
||||
fn find_msbuild_vs15(target: &str) -> Option<Tool> {
|
||||
// Seems like this could also go through SetupConfiguration,
|
||||
// or that find_msvc_15 could just use this registry key
|
||||
// instead of the COM interface.
|
||||
let key = r"SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7";
|
||||
LOCAL_MACHINE.open(key.as_ref())
|
||||
.ok()
|
||||
.and_then(|key| {
|
||||
key.query_str("15.0").ok()
|
||||
})
|
||||
.map(|path| {
|
||||
let path = PathBuf::from(path).join(r"MSBuild\15.0\Bin\MSBuild.exe");
|
||||
let mut tool = Tool::new(path);
|
||||
if target.contains("x86_64") {
|
||||
tool.env.push(("Platform".into(), "X64".into()));
|
||||
}
|
||||
tool
|
||||
})
|
||||
}
|
||||
|
||||
fn find_old_msbuild(target: &str) -> Option<Tool> {
|
||||
let key = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions";
|
||||
LOCAL_MACHINE.open(key.as_ref())
|
||||
.ok()
|
73
third_party/rust/cc/tests/cc_env.rs
vendored
Normal file
73
third_party/rust/cc/tests/cc_env.rs
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
extern crate cc;
|
||||
extern crate tempdir;
|
||||
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
use std::ffi::OsString;
|
||||
|
||||
mod support;
|
||||
use support::Test;
|
||||
|
||||
#[test]
|
||||
fn main() {
|
||||
ccache();
|
||||
distcc();
|
||||
ccache_spaces();
|
||||
ccache_env_flags();
|
||||
}
|
||||
|
||||
fn ccache() {
|
||||
let test = Test::gnu();
|
||||
|
||||
env::set_var("CC", "ccache cc");
|
||||
let compiler = test.gcc().file("foo.c").get_compiler();
|
||||
|
||||
assert_eq!(compiler.path(), Path::new("cc"));
|
||||
}
|
||||
|
||||
fn ccache_spaces() {
|
||||
let test = Test::gnu();
|
||||
test.shim("ccache");
|
||||
|
||||
env::set_var("CC", "ccache cc");
|
||||
let compiler = test.gcc().file("foo.c").get_compiler();
|
||||
assert_eq!(compiler.path(), Path::new("cc"));
|
||||
}
|
||||
|
||||
fn distcc() {
|
||||
let test = Test::gnu();
|
||||
test.shim("distcc");
|
||||
|
||||
env::set_var("CC", "distcc cc");
|
||||
let compiler = test.gcc().file("foo.c").get_compiler();
|
||||
assert_eq!(compiler.path(), Path::new("cc"));
|
||||
}
|
||||
|
||||
fn ccache_env_flags() {
|
||||
let test = Test::gnu();
|
||||
test.shim("ccache");
|
||||
|
||||
env::set_var("CC", "ccache lol-this-is-not-a-compiler");
|
||||
let compiler = test.gcc().file("foo.c").get_compiler();
|
||||
assert_eq!(compiler.path(), Path::new("lol-this-is-not-a-compiler"));
|
||||
assert_eq!(
|
||||
compiler.cc_env(),
|
||||
OsString::from("ccache lol-this-is-not-a-compiler")
|
||||
);
|
||||
assert!(
|
||||
compiler
|
||||
.cflags_env()
|
||||
.into_string()
|
||||
.unwrap()
|
||||
.contains("ccache") == false
|
||||
);
|
||||
assert!(
|
||||
compiler
|
||||
.cflags_env()
|
||||
.into_string()
|
||||
.unwrap()
|
||||
.contains(" lol-this-is-not-a-compiler") == false
|
||||
);
|
||||
|
||||
env::set_var("CC", "");
|
||||
}
|
@ -6,7 +6,7 @@ use std::fs::{self, File};
|
||||
use std::io::prelude::*;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use gcc;
|
||||
use cc;
|
||||
use tempdir::TempDir;
|
||||
|
||||
pub struct Test {
|
||||
@ -36,7 +36,7 @@ impl Test {
|
||||
|
||||
pub fn gnu() -> Test {
|
||||
let t = Test::new();
|
||||
t.shim("cc").shim("ar");
|
||||
t.shim("cc").shim("c++").shim("ar");
|
||||
t
|
||||
}
|
||||
|
||||
@ -55,8 +55,8 @@ impl Test {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn gcc(&self) -> gcc::Config {
|
||||
let mut cfg = gcc::Config::new();
|
||||
pub fn gcc(&self) -> cc::Build {
|
||||
let mut cfg = cc::Build::new();
|
||||
let mut path = env::split_paths(&env::var_os("PATH").unwrap()).collect::<Vec<_>>();
|
||||
path.insert(0, self.td.path().to_owned());
|
||||
let target = if self.msvc {
|
||||
@ -109,4 +109,14 @@ impl Execution {
|
||||
pub fn has(&self, p: &OsStr) -> bool {
|
||||
self.args.iter().any(|arg| OsStr::new(arg) == p)
|
||||
}
|
||||
|
||||
pub fn must_have_in_order(&self, before: &str, after: &str) -> &Execution {
|
||||
let before_position = self.args.iter().rposition(|x| OsStr::new(x) == OsStr::new(before));
|
||||
let after_position = self.args.iter().rposition(|x| OsStr::new(x) == OsStr::new(after));
|
||||
match (before_position, after_position) {
|
||||
(Some(b), Some(a)) if b < a => {},
|
||||
(b, a) => { panic!("{:?} (last position: {:?}) did not appear before {:?} (last position: {:?})", before, b, after, a) },
|
||||
};
|
||||
self
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
extern crate gcc;
|
||||
extern crate cc;
|
||||
extern crate tempdir;
|
||||
|
||||
use support::Test;
|
||||
@ -10,7 +10,7 @@ fn gnu_smoke() {
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.file("foo.c")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0)
|
||||
.must_have("-O2")
|
||||
@ -28,7 +28,7 @@ fn gnu_opt_level_1() {
|
||||
test.gcc()
|
||||
.opt_level(1)
|
||||
.file("foo.c")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0)
|
||||
.must_have("-O1")
|
||||
@ -41,7 +41,7 @@ fn gnu_opt_level_s() {
|
||||
test.gcc()
|
||||
.opt_level_str("s")
|
||||
.file("foo.c")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0)
|
||||
.must_have("-Os")
|
||||
@ -57,10 +57,46 @@ fn gnu_debug() {
|
||||
test.gcc()
|
||||
.debug(true)
|
||||
.file("foo.c")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
test.cmd(0).must_have("-g");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_warnings_into_errors() {
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.warnings_into_errors(true)
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-Werror");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_warnings() {
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.warnings(true)
|
||||
.flag("-Wno-missing-field-initializers")
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-Wall")
|
||||
.must_have("-Wextra");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_warnings_overridable() {
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.warnings(true)
|
||||
.flag("-Wno-missing-field-initializers")
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have_in_order("-Wall", "-Wno-missing-field-initializers");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_x86_64() {
|
||||
for vendor in &["unknown-linux-gnu", "apple-darwin"] {
|
||||
@ -70,7 +106,7 @@ fn gnu_x86_64() {
|
||||
.target(&target)
|
||||
.host(&target)
|
||||
.file("foo.c")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0)
|
||||
.must_have("-fPIC")
|
||||
@ -88,7 +124,7 @@ fn gnu_x86_64_no_pic() {
|
||||
.target(&target)
|
||||
.host(&target)
|
||||
.file("foo.c")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_not_have("-fPIC");
|
||||
}
|
||||
@ -103,10 +139,9 @@ fn gnu_i686() {
|
||||
.target(&target)
|
||||
.host(&target)
|
||||
.file("foo.c")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0)
|
||||
.must_not_have("-fPIC")
|
||||
.must_have("-m32");
|
||||
}
|
||||
}
|
||||
@ -121,7 +156,7 @@ fn gnu_i686_pic() {
|
||||
.target(&target)
|
||||
.host(&target)
|
||||
.file("foo.c")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-fPIC");
|
||||
}
|
||||
@ -133,7 +168,7 @@ fn gnu_set_stdlib() {
|
||||
test.gcc()
|
||||
.cpp_set_stdlib(Some("foo"))
|
||||
.file("foo.c")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_not_have("-stdlib=foo");
|
||||
}
|
||||
@ -144,7 +179,7 @@ fn gnu_include() {
|
||||
test.gcc()
|
||||
.include("foo/bar")
|
||||
.file("foo.c")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-I").must_have("foo/bar");
|
||||
}
|
||||
@ -153,10 +188,10 @@ fn gnu_include() {
|
||||
fn gnu_define() {
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.define("FOO", Some("bar"))
|
||||
.define("FOO", "bar")
|
||||
.define("BAR", None)
|
||||
.file("foo.c")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("-DFOO=bar").must_have("-DBAR");
|
||||
}
|
||||
@ -166,22 +201,86 @@ fn gnu_compile_assembly() {
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.file("foo.S")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
test.cmd(0).must_have("foo.S");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_shared() {
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.file("foo.c")
|
||||
.shared_flag(true)
|
||||
.static_flag(false)
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0)
|
||||
.must_have("-shared")
|
||||
.must_not_have("-static");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_flag_if_supported() {
|
||||
if cfg!(windows) {
|
||||
return
|
||||
}
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.file("foo.c")
|
||||
.flag_if_supported("-Wall")
|
||||
.flag_if_supported("-Wflag-does-not-exist")
|
||||
.flag_if_supported("-std=c++11")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0)
|
||||
.must_have("-Wall")
|
||||
.must_not_have("-Wflag-does-not-exist")
|
||||
.must_not_have("-std=c++11");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_flag_if_supported_cpp() {
|
||||
if cfg!(windows) {
|
||||
return
|
||||
}
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.cpp(true)
|
||||
.file("foo.cpp")
|
||||
.flag_if_supported("-std=c++11")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0)
|
||||
.must_have("-std=c++11");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gnu_static() {
|
||||
let test = Test::gnu();
|
||||
test.gcc()
|
||||
.file("foo.c")
|
||||
.shared_flag(false)
|
||||
.static_flag(true)
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0)
|
||||
.must_have("-static")
|
||||
.must_not_have("-shared");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn msvc_smoke() {
|
||||
let test = Test::msvc();
|
||||
test.gcc()
|
||||
.file("foo.c")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0)
|
||||
.must_have("/O2")
|
||||
.must_have("foo.c")
|
||||
.must_not_have("/Z7")
|
||||
.must_have("/c");
|
||||
.must_have("/c")
|
||||
.must_have("/MD");
|
||||
test.cmd(1).must_have(test.td.path().join("foo.o"));
|
||||
}
|
||||
|
||||
@ -191,7 +290,7 @@ fn msvc_opt_level_0() {
|
||||
test.gcc()
|
||||
.opt_level(0)
|
||||
.file("foo.c")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_not_have("/O2");
|
||||
}
|
||||
@ -202,7 +301,7 @@ fn msvc_debug() {
|
||||
test.gcc()
|
||||
.debug(true)
|
||||
.file("foo.c")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
test.cmd(0).must_have("/Z7");
|
||||
}
|
||||
|
||||
@ -212,7 +311,7 @@ fn msvc_include() {
|
||||
test.gcc()
|
||||
.include("foo/bar")
|
||||
.file("foo.c")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("/I").must_have("foo/bar");
|
||||
}
|
||||
@ -221,10 +320,32 @@ fn msvc_include() {
|
||||
fn msvc_define() {
|
||||
let test = Test::msvc();
|
||||
test.gcc()
|
||||
.define("FOO", Some("bar"))
|
||||
.define("FOO", "bar")
|
||||
.define("BAR", None)
|
||||
.file("foo.c")
|
||||
.compile("libfoo.a");
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("/DFOO=bar").must_have("/DBAR");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn msvc_static_crt() {
|
||||
let test = Test::msvc();
|
||||
test.gcc()
|
||||
.static_crt(true)
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("/MT");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn msvc_no_static_crt() {
|
||||
let test = Test::msvc();
|
||||
test.gcc()
|
||||
.static_crt(false)
|
||||
.file("foo.c")
|
||||
.compile("foo");
|
||||
|
||||
test.cmd(0).must_have("/MD");
|
||||
}
|
@ -1 +0,0 @@
|
||||
{"files":{".clog.toml":"f691701bd51b5f311931d0d8f05fa3d78c00dda8d60f3313e21011309c736ff1",".github/CONTRIBUTING.md":"f7eff737f3aa25294802fefb233e3758a64b248781dbbf3262532d693f340a87",".github/ISSUE_TEMPLATE.md":"681afbd64b3603e3e82789ceb6841d851eaa7333caec5769173462bab1b5d82b",".travis.yml":"2975b3159624d4ecc4dd29577f378e9d4fa27f1991bfd5042ac3c267fb2cdd38","CHANGELOG.md":"82b23419a6964c8f80993b399c9dded5b7fd809ba51f5f806c2a139d3c6270a4","CONTRIBUTORS.md":"5d7dbafaff6879bbfbb01b22cca299953ec163872d8d624bbf99e20851ca0165","Cargo.toml":"94e3789815bfd001abf96cb0d10fa95a4b4576bc679539e79a531d0010e2ccdd","LICENSE-MIT":"6725d1437fc6c77301f2ff0e7d52914cf4f9509213e1078dc77d9356dbe6eac5","README.md":"031031971829f165ed7ffd8375c2249ce96336a9ed7f207d4722df05563d2d7e","appveyor.yml":"303c64c2cc84c24b3c9ac0b4cd66b98d6bb25dec7d030ed53e5cb6ab3f13ebd1","clap-test.rs":"a0b0d9ca9106a52bf9dc41cf52b0b87c98209dca3490caa6ec1452bd1fec5c4c","index.html":"36f9ce4465266f3af9a259444b01c4239200473cabfc848f789f75b322a3ea8f","justfile":"811b2dec57aec46e570aeeb9945018cf87fe65f6d5b27cdb9ffca79d906910f6","rustfmt.toml":"8fd2d63119df515fd5f44e530c709b19d66b09fbc2e22a640bf4b64c57e7d6b3","src/app/help.rs":"da53217886fb1ea289b9057d4b5e94dce74ce81a7b7006d216370aad709bff77","src/app/macros.rs":"0205c461041d917aecb4a15212f89908e72902b961f47014a645f2b061de5998","src/app/meta.rs":"a56d28bb466a8ba68155b3f2883e85228b4b74cf25658f62fc050e07cff2dc85","src/app/mod.rs":"d0e1843ae1f77c1da4179cebdd8fb1ea55803002fb1ae96087de3a8cdcedf6fc","src/app/parser.rs":"66b08057b7bc19f6c2c94671de7fc20ec623368e04f92d2a6775991d37430fc2","src/app/settings.rs":"cf9f4a1a9d3799ac30d1d98cf23987cc884435ad912a0dfd853b101ce86c97cc","src/app/usage.rs":"ecaeab6c7980544e9a2d35cc41f2797df8bc9c09f5da67e96286631a116c0ccc","src/app/validator.rs":"f19d876ac673019ed5fdd4b9f76ba598fa790aa5e64d482696ca1e45dce5f28b","src/args/any_arg.rs":"b082385eeff2505ced7b747bd44d20a3fb6fd9d4bd14be9e99870699c43ea072","src/args/arg.rs":"673de3f1957eccb1b116255bac9638fe24c0da54ccb358d958446c8ed54c9621","src/args/arg_builder/base.rs":"8b99a9ab811df3e0bdcfba8c0994042b0bcd06d8ddf794ab559baaf9a490ba59","src/args/arg_builder/flag.rs":"4007a950869789b1f4d5f953107aee228477e2d5fe82515d3b895286c65522c6","src/args/arg_builder/mod.rs":"7a32c8fd85b48f7b60e5f2c13dc70fa9100aa65cd933ba419300d28d682bf722","src/args/arg_builder/option.rs":"d5e5243e3a72d2c820c8fad4e1efc4b985881c6f60f3a72757b33a9054a87e99","src/args/arg_builder/positional.rs":"39615d22b586e744a0bdeb8490dbe43df7df66ed793abf8f50ed2037ec0fb90c","src/args/arg_builder/switched.rs":"61f5121b0ec746461215a47e1b7a4d699a37a3f181172820e0615f68d5f6f0ef","src/args/arg_builder/valued.rs":"19368a03e046d6b63451c3d04dff6e51d49f140ed45330f82879539c6d1b28dd","src/args/arg_matcher.rs":"27829739ae12ac7800a26109e751ce9f8c3d26e262d41de161a38baf5c421167","src/args/arg_matches.rs":"9d72a388053ef0c31fe2516df9ea791a4d0f6c0b5e9758eb61886f1ac8df89ab","src/args/group.rs":"3f72a6ecc6ff71c96dd9cd8098e4fb6f7c4e6207e9bd0b67a50b104f5dfdb23d","src/args/macros.rs":"0dd7ae4c6e26ed78044c3ef90e21259816e544f724dcb09e6a0d92d4fcbc4b1a","src/args/matched_arg.rs":"1ed8d338869ecc3b5fa426ef4cf42f4c9c3b1dd538cdea1fe0489169345536f7","src/args/mod.rs":"c155cd989fa4ca1f8de6a79115afbf5086f092adcb854ff9698b9100f45fc323","src/args/settings.rs":"e6bbfb49c2e38fcedb67481bcbf0eb887ee510031639be8134411121a9363f7e","src/args/subcommand.rs":"e1ad9638c33785f1301675de1795b0a4f4b079452aa11f7526d263c2a1179432","src/completions/bash.rs":"116c6830ee2b6310f299a69924f5b1e39b05ebec2b5f7b0ffe3b6938b7fa5514","src/completions/fish.rs":"63975f8beea9af6bef66c7dd7938bfa61c6f871995a74dbc1545daa9fbc1f2d0","src/completions/macros.rs":"ebad5037e6e63401b1a54498e09d3bd93d1a3a06f045c2990902d47eb9a73774","src/completions/mod.rs":"5d4a734df6a21e6c1e0831a2f7be50a45d2e7bdaf7475589ea78b978643229cd","src/completions/powershell.rs":"4267818aaa60583c055d7a276a7535309e5162c94467f3003799b6a8a7f6d6b0","src/completions/shell.rs":"c7995ca229fd0d8671761da0aca0513c4f740165f02d06cd97aa0ae881c22cd4","src/completions/zsh.rs":"8ac4576e1cb3b1403dbb35ce146159aa8b29864e1d8201776200d999052b422d","src/errors.rs":"5d0ab536ea62614a6cf88d175a5b5e9c2777a35958e1d4598ac1ec4a6f451593","src/fmt.rs":"42459e7f42f5495c005d2de3eaf8d7b5619bf4b8d245ecb76e583f08ecaa3869","src/lib.rs":"3471c5b046df081afecb4e541d4e55dc7afa34bf7fe8f369f301f6471887e930","src/macros.rs":"c1d40220947c62b0364eedd2c40ca2c414daccc334a1e04e029a884e782bf2b0","src/osstringext.rs":"a87a5a0685dd8310f6329d5f8e8f54c0fac68eb75595a835aeb1c36208efd5f9","src/strext.rs":"d4418d396069e9c05804f92c042ba7192a4244e46059e2edc98670b45cd2daee","src/suggestions.rs":"ca352c62cdcc1b6071c50e39f39e8f5f6cd11c318229cc6cf16511dfde43c5c7","src/usage_parser.rs":"a04143bba42a6506746091a3f898c38e2c7409bacefed21fa8194c90961ca390"},"package":"6b8f69e518f967224e628896b54e41ff6acfb4dcfefc5076325c36525dac900f"}
|
83
third_party/rust/clap-2.24.2/Cargo.toml
vendored
83
third_party/rust/clap-2.24.2/Cargo.toml
vendored
@ -1,83 +0,0 @@
|
||||
[package]
|
||||
|
||||
name = "clap"
|
||||
version = "2.24.2"
|
||||
authors = ["Kevin K. <kbknapp@gmail.com>"]
|
||||
exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
|
||||
repository = "https://github.com/kbknapp/clap-rs.git"
|
||||
documentation = "https://docs.rs/clap/"
|
||||
homepage = "https://clap.rs/"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
keywords = ["argument", "command", "arg", "parser", "parse"]
|
||||
categories = ["command-line-interface"]
|
||||
description = """
|
||||
A simple to use, efficient, and full featured Command Line Argument Parser
|
||||
"""
|
||||
|
||||
[dependencies]
|
||||
bitflags = "0.8.0"
|
||||
vec_map = "0.8"
|
||||
unicode-width = "0.1.4"
|
||||
unicode-segmentation = "1.0.1"
|
||||
strsim = { version = "0.6.0", optional = true }
|
||||
ansi_term = { version = "0.9.0", optional = true }
|
||||
term_size = { version = "0.3.0", optional = true }
|
||||
yaml-rust = { version = "0.3.5", optional = true }
|
||||
clippy = { version = "~0.0.131", optional = true }
|
||||
atty = { version = "0.2.2", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
regex = "0.2"
|
||||
lazy_static = "0.2"
|
||||
|
||||
[features]
|
||||
default = ["suggestions", "color", "wrap_help"]
|
||||
suggestions = ["strsim"]
|
||||
color = ["ansi_term", "atty"]
|
||||
wrap_help = ["term_size"]
|
||||
yaml = ["yaml-rust"]
|
||||
unstable = [] # for building with unstable clap features (doesn't require nightly Rust) (currently none)
|
||||
nightly = [] # for building with unstable Rust features (currently none)
|
||||
lints = ["clippy"] # Requires nightly Rust
|
||||
debug = [] # Enables debug messages
|
||||
no_cargo = [] # Enable if you're not using Cargo, disables Cargo-env-var-dependent macros
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
debug = false
|
||||
rpath = false
|
||||
lto = true
|
||||
debug-assertions = false
|
||||
# codegen-units ignored with lto=true
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
debug = true
|
||||
rpath = false
|
||||
lto = false
|
||||
debug-assertions = true
|
||||
codegen-units = 4
|
||||
|
||||
[profile.test]
|
||||
opt-level = 1
|
||||
debug = true
|
||||
rpath = false
|
||||
lto = false
|
||||
debug-assertions = true
|
||||
codegen-units = 4
|
||||
|
||||
[profile.bench]
|
||||
opt-level = 3
|
||||
debug = false
|
||||
rpath = false
|
||||
lto = true
|
||||
debug-assertions = false
|
||||
|
||||
[profile.doc]
|
||||
opt-level = 0
|
||||
debug = true
|
||||
rpath = false
|
||||
lto = false
|
||||
debug-assertions = true
|
||||
codegen-units = 4
|
12
third_party/rust/clap-2.24.2/appveyor.yml
vendored
12
third_party/rust/clap-2.24.2/appveyor.yml
vendored
@ -1,12 +0,0 @@
|
||||
install:
|
||||
- ps: Start-FileDownload 'https://static.rust-lang.org/dist/rust-nightly-i686-pc-windows-gnu.exe'
|
||||
- rust-nightly-i686-pc-windows-gnu.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
|
||||
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
|
||||
- rustc -V
|
||||
- cargo -V
|
||||
|
||||
build: false
|
||||
|
||||
test_script:
|
||||
- cargo build --features yaml
|
||||
- cargo test --features yaml
|
17
third_party/rust/clap-2.25.0/.appveyor.yml
vendored
Normal file
17
third_party/rust/clap-2.25.0/.appveyor.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
environment:
|
||||
matrix:
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
- TARGET: x86_64-pc-windows-gnu
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
RUST_BACKTRACE: full
|
||||
install:
|
||||
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
|
||||
- rustup-init.exe -y --default-host %TARGET%
|
||||
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
|
||||
- rustc -vV
|
||||
- cargo -vV
|
||||
build: false
|
||||
test_script:
|
||||
- cargo build --verbose --features yaml
|
||||
- cargo test --verbose --features yaml
|
1
third_party/rust/clap-2.25.0/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/clap-2.25.0/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"files":{".appveyor.yml":"38fb7e583271029caad727c9123a2b2679b7c59971de418f16dc5136dbebaeb5",".clog.toml":"f691701bd51b5f311931d0d8f05fa3d78c00dda8d60f3313e21011309c736ff1",".github/CONTRIBUTING.md":"f7eff737f3aa25294802fefb233e3758a64b248781dbbf3262532d693f340a87",".github/ISSUE_TEMPLATE.md":"681afbd64b3603e3e82789ceb6841d851eaa7333caec5769173462bab1b5d82b",".mention-bot":"51790ab49f43ed86a4a7c3d2e468aa5fa526ca5e2ac6af20432a2cb5b2fdbe84",".travis.yml":"2975b3159624d4ecc4dd29577f378e9d4fa27f1991bfd5042ac3c267fb2cdd38","CHANGELOG.md":"89936cd672f43681351e1b76622cc44d11c69f60440dd101f7b9db1cf2f184f7","CONTRIBUTORS.md":"5d7dbafaff6879bbfbb01b22cca299953ec163872d8d624bbf99e20851ca0165","Cargo.toml":"f12c622fae3f6582168616219b6e07e2ec99943e9515b76f97974e75227b9aa0","LICENSE-MIT":"6725d1437fc6c77301f2ff0e7d52914cf4f9509213e1078dc77d9356dbe6eac5","README.md":"bce567fb1e3e57129f3d0f58f5a1e9e07dc7414731644a47939c50b76f9976bb","clap-test.rs":"995a9d41ef372a814616113f4a58c1e580043678e54527afc2ebee7e8e1d3ef5","index.html":"36f9ce4465266f3af9a259444b01c4239200473cabfc848f789f75b322a3ea8f","justfile":"811b2dec57aec46e570aeeb9945018cf87fe65f6d5b27cdb9ffca79d906910f6","rustfmt.toml":"8fd2d63119df515fd5f44e530c709b19d66b09fbc2e22a640bf4b64c57e7d6b3","src/app/help.rs":"515f3ec638e3df8323b44c906073c07657122ec1b34bdadbdc47661c5d97ad1d","src/app/macros.rs":"44610b6522cedbcb140670aac27c796379f562ce77fcf5e8d104b038aadf52ec","src/app/meta.rs":"a56d28bb466a8ba68155b3f2883e85228b4b74cf25658f62fc050e07cff2dc85","src/app/mod.rs":"d0e1843ae1f77c1da4179cebdd8fb1ea55803002fb1ae96087de3a8cdcedf6fc","src/app/parser.rs":"1bae4cecf4fc798efdc2ad8d237f17536dafd7524e2d9a366f30f72a8a275846","src/app/settings.rs":"c6b87d4da01891123edddee9e28b048cba0c19d8c1db34ad5ad3e85b657c6b97","src/app/usage.rs":"703cec975c53e7f01b14b4593de41c518910ab347bc4c54efe79367a704ffc4c","src/app/validator.rs":"bc2291f6231a63456acab9e7743d1f881f1d5dfc17955394fa856703a8e80086","src/args/any_arg.rs":"b082385eeff2505ced7b747bd44d20a3fb6fd9d4bd14be9e99870699c43ea072","src/args/arg.rs":"673de3f1957eccb1b116255bac9638fe24c0da54ccb358d958446c8ed54c9621","src/args/arg_builder/base.rs":"8b99a9ab811df3e0bdcfba8c0994042b0bcd06d8ddf794ab559baaf9a490ba59","src/args/arg_builder/flag.rs":"4007a950869789b1f4d5f953107aee228477e2d5fe82515d3b895286c65522c6","src/args/arg_builder/mod.rs":"7a32c8fd85b48f7b60e5f2c13dc70fa9100aa65cd933ba419300d28d682bf722","src/args/arg_builder/option.rs":"d5e5243e3a72d2c820c8fad4e1efc4b985881c6f60f3a72757b33a9054a87e99","src/args/arg_builder/positional.rs":"f103a22803d9fb7f7c8f37f705fe214fdaad46903439964fc13740ec6f647eb8","src/args/arg_builder/switched.rs":"61f5121b0ec746461215a47e1b7a4d699a37a3f181172820e0615f68d5f6f0ef","src/args/arg_builder/valued.rs":"19368a03e046d6b63451c3d04dff6e51d49f140ed45330f82879539c6d1b28dd","src/args/arg_matcher.rs":"27829739ae12ac7800a26109e751ce9f8c3d26e262d41de161a38baf5c421167","src/args/arg_matches.rs":"9d72a388053ef0c31fe2516df9ea791a4d0f6c0b5e9758eb61886f1ac8df89ab","src/args/group.rs":"7fe5e2f0dd24faf1765410a9336d85976875e964d7f246e1fa216c4808d88dde","src/args/macros.rs":"57f248e2694f9413cbbaf9087813ed4f27064f5f8e29eaf4ec41ec2b274ae806","src/args/matched_arg.rs":"1ed8d338869ecc3b5fa426ef4cf42f4c9c3b1dd538cdea1fe0489169345536f7","src/args/mod.rs":"c155cd989fa4ca1f8de6a79115afbf5086f092adcb854ff9698b9100f45fc323","src/args/settings.rs":"2753ff50046def9ccb7f601b3d9f565348da1ef0253af24ccee94616a2e5c470","src/args/subcommand.rs":"e1ad9638c33785f1301675de1795b0a4f4b079452aa11f7526d263c2a1179432","src/completions/bash.rs":"116c6830ee2b6310f299a69924f5b1e39b05ebec2b5f7b0ffe3b6938b7fa5514","src/completions/fish.rs":"63975f8beea9af6bef66c7dd7938bfa61c6f871995a74dbc1545daa9fbc1f2d0","src/completions/macros.rs":"ebad5037e6e63401b1a54498e09d3bd93d1a3a06f045c2990902d47eb9a73774","src/completions/mod.rs":"5d4a734df6a21e6c1e0831a2f7be50a45d2e7bdaf7475589ea78b978643229cd","src/completions/powershell.rs":"866409e5d0a9b2551d739f86c0e4faf86911e9e7c656fb74b38e6960844233b5","src/completions/shell.rs":"c7995ca229fd0d8671761da0aca0513c4f740165f02d06cd97aa0ae881c22cd4","src/completions/zsh.rs":"8ac4576e1cb3b1403dbb35ce146159aa8b29864e1d8201776200d999052b422d","src/errors.rs":"3c46a4d79d9304ffb152a190528ec9db0cb6c05799bb5211e6df9f7d7abab814","src/fmt.rs":"f205f784268572544ff7e84a89f416c898255404275d4ab1f8fea7e89695daa9","src/lib.rs":"87b3ee49c6389cdbaa23e705732bcc68e7235bb16ff469321c92a89258c21beb","src/macros.rs":"2317a90223c80d8688fea5334b09b783c8aca8894e6c22ec2fd400ce941d301b","src/osstringext.rs":"a87a5a0685dd8310f6329d5f8e8f54c0fac68eb75595a835aeb1c36208efd5f9","src/strext.rs":"d4418d396069e9c05804f92c042ba7192a4244e46059e2edc98670b45cd2daee","src/suggestions.rs":"ad1165a9896382a0f09f73c0f6bf468454c19da207f28c3973e02879f453ad68","src/usage_parser.rs":"a04143bba42a6506746091a3f898c38e2c7409bacefed21fa8194c90961ca390"},"package":"867a885995b4184be051b70a592d4d70e32d7a188db6e8dff626af286a962771"}
|
9
third_party/rust/clap-2.25.0/.mention-bot
vendored
Normal file
9
third_party/rust/clap-2.25.0/.mention-bot
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"findPotentialReviewers": false,
|
||||
"alwaysNotifyForPaths": [
|
||||
{
|
||||
"name": "kbknapp",
|
||||
"files": ["**/*.rs", "**/*.md", "*"]
|
||||
}
|
||||
]
|
||||
}
|
@ -1,3 +1,31 @@
|
||||
<a name="v2.24.2"></a>
|
||||
### v2.25.0 (2017-06-20)
|
||||
|
||||
|
||||
#### Features
|
||||
|
||||
* use textwrap crate for wrapping help texts ([b93870c1](https://github.com/kbknapp/clap-rs/commit/b93870c10ae3bd90d233c586a33e086803117285))
|
||||
|
||||
#### Improvements
|
||||
|
||||
* **Suggestions:** suggests to use flag after subcommand when applicable ([2671ca72](https://github.com/kbknapp/clap-rs/commit/2671ca7260119d4311d21c4075466aafdd9da734))
|
||||
* Bumps bitflags crate to v0.9
|
||||
|
||||
#### Documentation
|
||||
|
||||
* Change `who's` -> `whose` ([53c1ffe8](https://github.com/kbknapp/clap-rs/commit/53c1ffe87f38b05d8804a0f7832412a952845349))
|
||||
|
||||
#### Documentation
|
||||
|
||||
* **App::template:** adds details about the necessity to use AppSettings::UnifiedHelpMessage when using {unified} tags in the help template ([cbea3d5a](https://github.com/kbknapp/clap-rs/commit/cbea3d5acf3271a7a734498c4d99c709941c331e), closes [#949](https://github.com/kbknapp/clap-rs/issues/949))
|
||||
* **Arg::allow_hyphen_values:** updates the docs to include warnings for allow_hyphen_values and multiple(true) used together ([f9b0d657](https://github.com/kbknapp/clap-rs/commit/f9b0d657835d3f517f313d70962177dc30acf4a7))
|
||||
* **README.md:**
|
||||
* added a warning about using ~ deps ([821929b5](https://github.com/kbknapp/clap-rs/commit/821929b51bd60213955705900a436c9a64fcb79f), closes [#964](https://github.com/kbknapp/clap-rs/issues/964))
|
||||
* added a warning about using ~ deps ([667697b0](https://github.com/kbknapp/clap-rs/commit/667697b0018369b71da41d02d567ab57df0f4887))
|
||||
* **clap_app!:** adds using the @group specifier to the macro docs ([826048cb](https://github.com/kbknapp/clap-rs/commit/826048cb3cbc0280169303f1498ff0a2b7395883), closes [#932](https://github.com/kbknapp/clap-rs/issues/932))
|
||||
|
||||
|
||||
|
||||
<a name="v2.24.2"></a>
|
||||
### v2.24.2 (2017-05-15)
|
||||
|
117
third_party/rust/clap-2.25.0/Cargo.toml
vendored
Normal file
117
third_party/rust/clap-2.25.0/Cargo.toml
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
# 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 believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "clap"
|
||||
version = "2.25.0"
|
||||
authors = ["Kevin K. <kbknapp@gmail.com>"]
|
||||
exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
|
||||
description = "A simple to use, efficient, and full featured Command Line Argument Parser\n"
|
||||
homepage = "https://clap.rs/"
|
||||
documentation = "https://docs.rs/clap/"
|
||||
readme = "README.md"
|
||||
keywords = ["argument", "command", "arg", "parser", "parse"]
|
||||
categories = ["command-line-interface"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/kbknapp/clap-rs.git"
|
||||
[profile.test]
|
||||
opt-level = 1
|
||||
lto = false
|
||||
codegen-units = 4
|
||||
debug = true
|
||||
debug-assertions = true
|
||||
rpath = false
|
||||
|
||||
[profile.doc]
|
||||
opt-level = 0
|
||||
lto = false
|
||||
codegen-units = 4
|
||||
debug = true
|
||||
debug-assertions = true
|
||||
rpath = false
|
||||
|
||||
[profile.bench]
|
||||
opt-level = 3
|
||||
lto = true
|
||||
debug = false
|
||||
debug-assertions = false
|
||||
rpath = false
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
lto = false
|
||||
codegen-units = 4
|
||||
debug = true
|
||||
debug-assertions = true
|
||||
rpath = false
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
lto = true
|
||||
debug = false
|
||||
debug-assertions = false
|
||||
rpath = false
|
||||
[dependencies.ansi_term]
|
||||
version = "0.9.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.term_size]
|
||||
version = "0.3.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.textwrap]
|
||||
version = "0.6.0"
|
||||
|
||||
[dependencies.yaml-rust]
|
||||
version = "0.3.5"
|
||||
optional = true
|
||||
|
||||
[dependencies.unicode-width]
|
||||
version = "0.1.4"
|
||||
|
||||
[dependencies.atty]
|
||||
version = "0.2.2"
|
||||
optional = true
|
||||
|
||||
[dependencies.vec_map]
|
||||
version = "0.8"
|
||||
|
||||
[dependencies.clippy]
|
||||
version = "~0.0.131"
|
||||
optional = true
|
||||
|
||||
[dependencies.unicode-segmentation]
|
||||
version = "~1.1.0"
|
||||
|
||||
[dependencies.bitflags]
|
||||
version = "0.9"
|
||||
|
||||
[dependencies.strsim]
|
||||
version = "0.6.0"
|
||||
optional = true
|
||||
[dev-dependencies.regex]
|
||||
version = "0.2"
|
||||
|
||||
[dev-dependencies.lazy_static]
|
||||
version = "0.2"
|
||||
|
||||
[features]
|
||||
unstable = []
|
||||
default = ["suggestions", "color", "wrap_help"]
|
||||
color = ["ansi_term", "atty"]
|
||||
yaml = ["yaml-rust"]
|
||||
no_cargo = []
|
||||
wrap_help = ["term_size"]
|
||||
suggestions = ["strsim"]
|
||||
nightly = []
|
||||
debug = []
|
||||
lints = ["clippy"]
|
@ -45,7 +45,13 @@ Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)
|
||||
|
||||
## What's New
|
||||
|
||||
Here's the highlights for v2.24.2
|
||||
Here's the highlights for v2.25.0
|
||||
|
||||
* use textwrap crate for wrapping help texts
|
||||
* suggests to use flag after subcommand when applicable
|
||||
* Bumps bitflags crate to v0.9
|
||||
|
||||
Here's the highlights for v2.21.0 to v2.24.2
|
||||
|
||||
* fixes a bug where args that allow values to start with a hyphen couldnt contain a double hyphen -- as a value
|
||||
* fixes a bug where positional argument help text is misaligned
|
||||
@ -53,9 +59,6 @@ Here's the highlights for v2.24.2
|
||||
* **Arg::allow_hyphen_values docs:** updates the docs to include warnings for allow_hyphen_values and multiple(true) used together
|
||||
* **clap_app! docs:** adds using the @group specifier to the macro docs
|
||||
* adds a debug assertion to ensure all args added to groups actually exist
|
||||
|
||||
Here's the highlights for v2.21.0 to v2.24.1
|
||||
|
||||
* fixes a bug where args with last(true) and required(true) set were not being printed in the usage string
|
||||
* fixes a bug that was printing the arg name, instead of value name when Arg::last(true) was used
|
||||
* fixes a bug where flags were parsed as flags AND positional values when specific combinations of settings were used
|
||||
@ -618,6 +621,28 @@ clap = "~2.19.0"
|
||||
|
||||
This will cause *only* the patch version to be updated upon a `cargo update` call, and therefore cannot break due to new features, or bumped minimum versions of Rust.
|
||||
|
||||
#### Warning about '~' Dependencies
|
||||
|
||||
Using `~` can cause issues in certain circumstances.
|
||||
|
||||
From @alexcrichton:
|
||||
|
||||
Right now Cargo's version resolution is pretty naive, it's just a brute-force search of the solution space, returning the first resolvable graph. This also means that it currently won't terminate until it proves there is not possible resolvable graph. This leads to situations where workspaces with multiple binaries, for example, have two different dependencies such as:
|
||||
|
||||
```toml
|
||||
|
||||
# In one Cargo.toml
|
||||
[dependencies]
|
||||
clap = "~2.19.0"
|
||||
|
||||
# In another Cargo.toml
|
||||
[dependencies]
|
||||
clap = "2.22"
|
||||
|
||||
```
|
||||
|
||||
This is inherently an unresolvable crate graph in Cargo right now. Cargo requires there's only one major version of a crate, and being in the same workspace these two crates must share a version. This is impossible in this location, though, as these version constraints cannot be met.
|
||||
|
||||
#### Minimum Version of Rust
|
||||
|
||||
`clap` will officially support current stable Rust, minus two releases, but may work with prior releases as well. For example, current stable Rust at the time of this writing is 1.13.0, meaning `clap` is guaranteed to compile with 1.11.0 and beyond.
|
@ -70,6 +70,7 @@ mod test {
|
||||
.version("0.1")
|
||||
.author("Kevin K. <kbknapp@gmail.com>")
|
||||
.arg_from_usage("-o --option [scoption]... 'tests options'")
|
||||
.arg_from_usage("-s --subcmdarg [subcmdarg] 'tests other args'")
|
||||
.arg_from_usage("[scpositional] 'tests positionals'"))
|
||||
}
|
||||
}
|
@ -10,14 +10,14 @@ use app::{App, AppSettings};
|
||||
use app::parser::Parser;
|
||||
use args::{AnyArg, ArgSettings, DispOrder};
|
||||
use errors::{Error, Result as ClapResult};
|
||||
use fmt::{Format, Colorizer};
|
||||
use fmt::{Format, Colorizer, ColorizerOption};
|
||||
use app::usage;
|
||||
|
||||
// Third Party
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
#[cfg(feature = "wrap_help")]
|
||||
use term_size;
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
use textwrap;
|
||||
use vec_map::VecMap;
|
||||
|
||||
#[cfg(not(feature = "wrap_help"))]
|
||||
@ -25,18 +25,6 @@ mod term_size {
|
||||
pub fn dimensions() -> Option<(usize, usize)> { None }
|
||||
}
|
||||
|
||||
macro_rules! find_longest {
|
||||
($help:expr) => {{
|
||||
let mut lw = 0;
|
||||
for l in $help.split(' ').map(|s| str_width(s)) {
|
||||
if l > lw {
|
||||
lw = l;
|
||||
}
|
||||
}
|
||||
lw
|
||||
}};
|
||||
}
|
||||
|
||||
fn str_width(s: &str) -> usize { UnicodeWidthStr::width(s) }
|
||||
|
||||
const TAB: &'static str = " ";
|
||||
@ -95,6 +83,7 @@ pub struct Help<'a> {
|
||||
// Public Functions
|
||||
impl<'a> Help<'a> {
|
||||
/// Create a new `Help` instance.
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
||||
pub fn new(w: &'a mut Write,
|
||||
next_line_help: bool,
|
||||
hide_pv: bool,
|
||||
@ -155,10 +144,10 @@ impl<'a> Help<'a> {
|
||||
let nlh = parser.is_set(AppSettings::NextLineHelp);
|
||||
let hide_v = parser.is_set(AppSettings::HidePossibleValuesInHelp);
|
||||
let color = parser.is_set(AppSettings::ColoredHelp);
|
||||
let cizer = Colorizer {
|
||||
let cizer = Colorizer::new(ColorizerOption {
|
||||
use_stderr: stderr,
|
||||
when: parser.color(),
|
||||
};
|
||||
});
|
||||
Self::new(w,
|
||||
nlh,
|
||||
hide_v,
|
||||
@ -176,9 +165,9 @@ impl<'a> Help<'a> {
|
||||
if let Some(h) = parser.meta.help_str {
|
||||
try!(write!(self.writer, "{}", h).map_err(Error::from));
|
||||
} else if let Some(tmpl) = parser.meta.template {
|
||||
try!(self.write_templated_help(&parser, tmpl));
|
||||
try!(self.write_templated_help(parser, tmpl));
|
||||
} else {
|
||||
try!(self.write_default_help(&parser));
|
||||
try!(self.write_default_help(parser));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -199,7 +188,7 @@ impl<'a> Help<'a> {
|
||||
arg.is_set(ArgSettings::NextLineHelp)
|
||||
}) {
|
||||
if arg.longest_filter() {
|
||||
self.longest = cmp::max(self.longest, arg.to_string().len());
|
||||
self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str()));
|
||||
}
|
||||
arg_v.push(arg)
|
||||
}
|
||||
@ -232,7 +221,7 @@ impl<'a> Help<'a> {
|
||||
}) {
|
||||
if arg.longest_filter() {
|
||||
debugln!("Help::write_args: Current Longest...{}", self.longest);
|
||||
self.longest = cmp::max(self.longest, arg.to_string().len());
|
||||
self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str()));
|
||||
debugln!("Help::write_args: New Longest...{}", self.longest);
|
||||
}
|
||||
let btm = ord_m.entry(arg.disp_ord()).or_insert(BTreeMap::new());
|
||||
@ -364,7 +353,7 @@ impl<'a> Help<'a> {
|
||||
debug!("Help::val: next_line...");
|
||||
if !(nlh || self.force_next_line) {
|
||||
sdebugln!("No");
|
||||
let self_len = arg.to_string().len();
|
||||
let self_len = str_width(arg.to_string().as_str());
|
||||
// subtract ourself
|
||||
let mut spcs = self.longest - self_len;
|
||||
// Since we're writing spaces from the tab point we first need to know if we
|
||||
@ -383,7 +372,7 @@ impl<'a> Help<'a> {
|
||||
}
|
||||
} else if !(nlh || self.force_next_line) {
|
||||
sdebugln!("No, and not next_line");
|
||||
write_nspaces!(self.writer, self.longest + 4 - (arg.to_string().len()));
|
||||
write_nspaces!(self.writer, self.longest + 4 - (str_width(arg.to_string().as_str())));
|
||||
} else {
|
||||
sdebugln!("No");
|
||||
}
|
||||
@ -392,7 +381,7 @@ impl<'a> Help<'a> {
|
||||
|
||||
fn write_before_after_help(&mut self, h: &str) -> io::Result<()> {
|
||||
debugln!("Help::write_before_after_help;");
|
||||
let mut help = String::new();
|
||||
let mut help = String::from(h);
|
||||
// determine if our help fits or needs to wrap
|
||||
debugln!("Help::write_before_after_help: Term width...{}",
|
||||
self.term_w);
|
||||
@ -401,47 +390,29 @@ impl<'a> Help<'a> {
|
||||
debug!("Help::write_before_after_help: Too long...");
|
||||
if too_long || h.contains("{n}") {
|
||||
sdebugln!("Yes");
|
||||
help.push_str(h);
|
||||
debugln!("Help::write_before_after_help: help: {}", help);
|
||||
debugln!("Help::write_before_after_help: help width: {}",
|
||||
str_width(&*help));
|
||||
// Determine how many newlines we need to insert
|
||||
debugln!("Help::write_before_after_help: Usable space: {}",
|
||||
self.term_w);
|
||||
let longest_w = find_longest!(help);
|
||||
help = help.replace("{n}", "\n");
|
||||
wrap_help(&mut help, longest_w, self.term_w);
|
||||
help = wrap_help(&help.replace("{n}", "\n"), self.term_w);
|
||||
} else {
|
||||
sdebugln!("No");
|
||||
}
|
||||
let help = if !help.is_empty() {
|
||||
&*help
|
||||
} else {
|
||||
help.push_str(h);
|
||||
&*help
|
||||
};
|
||||
if help.contains('\n') {
|
||||
if let Some(part) = help.lines().next() {
|
||||
try!(write!(self.writer, "{}", part));
|
||||
}
|
||||
for part in help.lines().skip(1) {
|
||||
try!(write!(self.writer, "\n{}", part));
|
||||
}
|
||||
} else {
|
||||
try!(write!(self.writer, "{}", help));
|
||||
}
|
||||
try!(write!(self.writer, "{}", help));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Writes argument's help to the wrapped stream.
|
||||
fn help<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>, spec_vals: &str) -> io::Result<()> {
|
||||
debugln!("Help::help;");
|
||||
let mut help = String::new();
|
||||
let h = if self.use_long {
|
||||
arg.long_help().unwrap_or(arg.help().unwrap_or(""))
|
||||
arg.long_help().unwrap_or_else(|| arg.help().unwrap_or(""))
|
||||
} else {
|
||||
arg.help().unwrap_or(arg.long_help().unwrap_or(""))
|
||||
arg.help().unwrap_or_else(|| arg.long_help().unwrap_or(""))
|
||||
};
|
||||
let mut help = String::from(h) + spec_vals;
|
||||
let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) || self.use_long;
|
||||
debugln!("Help::help: Next Line...{:?}", nlh);
|
||||
|
||||
@ -461,48 +432,31 @@ impl<'a> Help<'a> {
|
||||
debug!("Help::help: Too long...");
|
||||
if too_long && spcs <= self.term_w || h.contains("{n}") {
|
||||
sdebugln!("Yes");
|
||||
help.push_str(h);
|
||||
help.push_str(&*spec_vals);
|
||||
debugln!("Help::help: help...{}", help);
|
||||
debugln!("Help::help: help width...{}", str_width(&*help));
|
||||
// Determine how many newlines we need to insert
|
||||
let avail_chars = self.term_w - spcs;
|
||||
debugln!("Help::help: Usable space...{}", avail_chars);
|
||||
let longest_w = find_longest!(help);
|
||||
help = help.replace("{n}", "\n");
|
||||
wrap_help(&mut help, longest_w, avail_chars);
|
||||
help = wrap_help(&help.replace("{n}", "\n"), avail_chars);
|
||||
} else {
|
||||
sdebugln!("No");
|
||||
}
|
||||
let help = if !help.is_empty() {
|
||||
&*help
|
||||
} else if spec_vals.is_empty() {
|
||||
h
|
||||
} else {
|
||||
help.push_str(h);
|
||||
help.push_str(&*spec_vals);
|
||||
&*help
|
||||
};
|
||||
if help.contains('\n') {
|
||||
if let Some(part) = help.lines().next() {
|
||||
try!(write!(self.writer, "{}", part));
|
||||
}
|
||||
for part in help.lines().skip(1) {
|
||||
try!(write!(self.writer, "\n"));
|
||||
if nlh || self.force_next_line {
|
||||
try!(write!(self.writer, "{}{}{}", TAB, TAB, TAB));
|
||||
} else if arg.has_switch() {
|
||||
write_nspaces!(self.writer, self.longest + 12);
|
||||
} else {
|
||||
write_nspaces!(self.writer, self.longest + 8);
|
||||
}
|
||||
try!(write!(self.writer, "{}", part));
|
||||
}
|
||||
} else if nlh || self.force_next_line {
|
||||
try!(write!(self.writer, "{}", help));
|
||||
if let Some(part) = help.lines().next() {
|
||||
try!(write!(self.writer, "{}", part));
|
||||
}
|
||||
for part in help.lines().skip(1) {
|
||||
try!(write!(self.writer, "\n"));
|
||||
if nlh || self.force_next_line {
|
||||
try!(write!(self.writer, "{}{}{}", TAB, TAB, TAB));
|
||||
} else if arg.has_switch() {
|
||||
write_nspaces!(self.writer, self.longest + 12);
|
||||
} else {
|
||||
write_nspaces!(self.writer, self.longest + 8);
|
||||
}
|
||||
try!(write!(self.writer, "{}", part));
|
||||
}
|
||||
if !help.contains('\n') && (nlh || self.force_next_line) {
|
||||
try!(write!(self.writer, "\n"));
|
||||
} else {
|
||||
try!(write!(self.writer, "{}", help));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -558,6 +512,7 @@ impl<'a> Help<'a> {
|
||||
/// Writes help for all arguments (options, flags, args, subcommands)
|
||||
/// including titles of a Parser Object to the wrapped stream.
|
||||
#[cfg_attr(feature = "lints", allow(useless_let_if_seq))]
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(useless_let_if_seq))]
|
||||
pub fn write_all_args(&mut self, parser: &Parser) -> ClapResult<()> {
|
||||
debugln!("Help::write_all_args;");
|
||||
let flags = parser.has_flags();
|
||||
@ -610,7 +565,7 @@ impl<'a> Help<'a> {
|
||||
try!(self.writer.write_all(b"\n\n"));
|
||||
}
|
||||
try!(color!(self, "SUBCOMMANDS:\n", warning));
|
||||
try!(self.write_subcommands(&parser));
|
||||
try!(self.write_subcommands(parser));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -629,7 +584,8 @@ impl<'a> Help<'a> {
|
||||
let btm = ord_m
|
||||
.entry(sc.p.meta.disp_ord)
|
||||
.or_insert(BTreeMap::new());
|
||||
self.longest = cmp::max(self.longest, sc.p.meta.name.len());
|
||||
self.longest = cmp::max(self.longest, str_width(sc.p.meta.name.as_str()));
|
||||
//self.longest = cmp::max(self.longest, sc.p.meta.name.len());
|
||||
btm.insert(sc.p.meta.name.clone(), sc.clone());
|
||||
}
|
||||
|
||||
@ -650,7 +606,7 @@ impl<'a> Help<'a> {
|
||||
/// Writes version of a Parser Object to the wrapped stream.
|
||||
fn write_version(&mut self, parser: &Parser) -> io::Result<()> {
|
||||
debugln!("Help::write_version;");
|
||||
try!(write!(self.writer, "{}", parser.meta.version.unwrap_or("".into())));
|
||||
try!(write!(self.writer, "{}", parser.meta.version.unwrap_or("")));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -660,10 +616,8 @@ impl<'a> Help<'a> {
|
||||
macro_rules! write_name {
|
||||
() => {{
|
||||
let mut name = parser.meta.name.clone();
|
||||
let longest_w = find_longest!(name);
|
||||
name = name.replace("{n}", "\n");
|
||||
wrap_help(&mut name, longest_w, self.term_w);
|
||||
try!(color!(self, &*name, good));
|
||||
try!(color!(self, wrap_help(&name, self.term_w), good));
|
||||
}};
|
||||
}
|
||||
if let Some(bn) = parser.meta.bin_name.as_ref() {
|
||||
@ -690,16 +644,15 @@ impl<'a> Help<'a> {
|
||||
macro_rules! write_thing {
|
||||
($thing:expr) => {{
|
||||
let mut owned_thing = $thing.to_owned();
|
||||
let longest_w = find_longest!(owned_thing);
|
||||
owned_thing = owned_thing.replace("{n}", "\n");
|
||||
wrap_help(&mut owned_thing, longest_w, self.term_w);
|
||||
try!(write!(self.writer, "{}\n", &*owned_thing))
|
||||
try!(write!(self.writer, "{}\n",
|
||||
wrap_help(&owned_thing, self.term_w)))
|
||||
}};
|
||||
}
|
||||
// Print the version
|
||||
try!(self.write_bin_name(&parser));
|
||||
try!(self.write_bin_name(parser));
|
||||
try!(self.writer.write_all(b" "));
|
||||
try!(self.write_version(&parser));
|
||||
try!(self.write_version(parser));
|
||||
try!(self.writer.write_all(b"\n"));
|
||||
if let Some(author) = parser.meta.author {
|
||||
write_thing!(author)
|
||||
@ -720,7 +673,7 @@ impl<'a> Help<'a> {
|
||||
let subcmds = parser.has_subcommands();
|
||||
|
||||
if flags || opts || pos || subcmds {
|
||||
try!(self.write_all_args(&parser));
|
||||
try!(self.write_all_args(parser));
|
||||
}
|
||||
|
||||
if let Some(h) = parser.meta.more_help {
|
||||
@ -775,9 +728,9 @@ fn copy_until<R: Read, W: Write>(r: &mut R, w: &mut W, delimiter_byte: u8) -> Co
|
||||
/// Copies the contents of a reader into a writer until a {tag} is found,
|
||||
/// copying the tag content to a buffer and returning its size.
|
||||
/// In addition to errors, there are three possible outputs:
|
||||
/// - None: The reader was consumed.
|
||||
/// - Some(Ok(0)): No tag was captured but the reader still contains data.
|
||||
/// - Some(Ok(length>0)): a tag with `length` was captured to the tag_buffer.
|
||||
/// - `None`: The reader was consumed.
|
||||
/// - `Some(Ok(0))`: No tag was captured but the reader still contains data.
|
||||
/// - `Some(Ok(length>0))`: a tag with `length` was captured to the `tag_buffer`.
|
||||
fn copy_and_capture<R: Read, W: Write>(r: &mut R,
|
||||
w: &mut W,
|
||||
tag_buffer: &mut Cursor<Vec<u8>>)
|
||||
@ -891,7 +844,7 @@ impl<'a> Help<'a> {
|
||||
try!(self.writer.write_all(b"Could not decode tag name"));
|
||||
}
|
||||
b"bin" => {
|
||||
try!(self.write_bin_name(&parser));
|
||||
try!(self.write_bin_name(parser));
|
||||
}
|
||||
b"version" => {
|
||||
try!(write!(self.writer,
|
||||
@ -912,7 +865,7 @@ impl<'a> Help<'a> {
|
||||
try!(write!(self.writer, "{}", usage::create_usage_no_title(parser, &[])));
|
||||
}
|
||||
b"all-args" => {
|
||||
try!(self.write_all_args(&parser));
|
||||
try!(self.write_all_args(parser));
|
||||
}
|
||||
b"unified" => {
|
||||
let opts_flags = parser
|
||||
@ -931,7 +884,7 @@ impl<'a> Help<'a> {
|
||||
try!(self.write_args(parser.positionals().map(as_arg_trait)));
|
||||
}
|
||||
b"subcommands" => {
|
||||
try!(self.write_subcommands(&parser));
|
||||
try!(self.write_subcommands(parser));
|
||||
}
|
||||
b"after-help" => {
|
||||
try!(write!(self.writer,
|
||||
@ -954,47 +907,12 @@ impl<'a> Help<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn wrap_help(help: &mut String, longest_w: usize, avail_chars: usize) {
|
||||
debugln!("Help::wrap_help: longest_w={}, avail_chars={}",
|
||||
longest_w,
|
||||
avail_chars);
|
||||
debug!("Help::wrap_help: Enough space to wrap...");
|
||||
if longest_w < avail_chars {
|
||||
sdebugln!("Yes");
|
||||
let mut prev_space = 0;
|
||||
let mut j = 0;
|
||||
for (idx, g) in (&*help.clone()).grapheme_indices(true) {
|
||||
debugln!("Help::wrap_help:iter: idx={}, g={}", idx, g);
|
||||
if g == "\n" {
|
||||
debugln!("Help::wrap_help:iter: Newline found...");
|
||||
debugln!("Help::wrap_help:iter: Still space...{:?}",
|
||||
str_width(&help[j..idx]) < avail_chars);
|
||||
if str_width(&help[j..idx]) < avail_chars {
|
||||
j = idx;
|
||||
continue;
|
||||
}
|
||||
} else if g != " " {
|
||||
if idx != help.len() - 1 || str_width(&help[j..idx]) < avail_chars {
|
||||
continue;
|
||||
}
|
||||
debugln!("Help::wrap_help:iter: Reached the end of the line and we're over...");
|
||||
} else if str_width(&help[j..idx]) <= avail_chars {
|
||||
debugln!("Help::wrap_help:iter: Space found with room...");
|
||||
prev_space = idx;
|
||||
continue;
|
||||
}
|
||||
debugln!("Help::wrap_help:iter: Adding Newline...");
|
||||
j = prev_space;
|
||||
debugln!("Help::wrap_help:iter: prev_space={}, j={}", prev_space, j);
|
||||
debugln!("Help::wrap_help:iter: Removing...{}", j);
|
||||
debugln!("Help::wrap_help:iter: Char at {}: {:?}", j, &help[j..j + 1]);
|
||||
help.remove(j);
|
||||
help.insert(j, '\n');
|
||||
prev_space = idx;
|
||||
}
|
||||
} else {
|
||||
sdebugln!("No");
|
||||
}
|
||||
fn wrap_help(help: &str, avail_chars: usize) -> String {
|
||||
let wrapper = textwrap::Wrapper::new(avail_chars).break_words(false);
|
||||
help.lines()
|
||||
.map(|line| wrapper.fill(line))
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -1003,8 +921,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn wrap_help_last_word() {
|
||||
let mut help = String::from("foo bar baz");
|
||||
wrap_help(&mut help, 3, 5);
|
||||
assert_eq!(help, "foo\nbar\nbaz");
|
||||
let help = String::from("foo bar baz");
|
||||
assert_eq!(wrap_help(&help, 5), "foo\nbar\nbaz");
|
||||
}
|
||||
}
|
@ -98,9 +98,8 @@ macro_rules! _handle_group_reqs{
|
||||
($me:ident, $arg:ident) => ({
|
||||
use args::AnyArg;
|
||||
debugln!("_handle_group_reqs!;");
|
||||
for grp in $me.groups.iter() {
|
||||
for grp in &$me.groups {
|
||||
let found = if grp.args.contains(&$arg.name()) {
|
||||
// vec_remove!($me.required, &$arg.name());
|
||||
if let Some(ref reqs) = grp.requires {
|
||||
debugln!("_handle_group_reqs!: Adding {:?} to the required list", reqs);
|
||||
$me.required.extend(reqs);
|
||||
@ -121,7 +120,11 @@ macro_rules! _handle_group_reqs{
|
||||
debugln!("_handle_group_reqs!:iter: Adding args from group to blacklist...{:?}", grp.args);
|
||||
if !grp.multiple {
|
||||
$me.blacklist.extend(&grp.args);
|
||||
vec_remove!($me.blacklist, &$arg.name());
|
||||
debugln!("_handle_group_reqs!: removing {:?} from blacklist", $arg.name());
|
||||
for i in (0 .. $me.blacklist.len()).rev() {
|
||||
let should_remove = $me.blacklist[i] == $arg.name();
|
||||
if should_remove { $me.blacklist.swap_remove(i); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -305,11 +305,11 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||
}
|
||||
// actually adds the arguments but from a borrow (which means we have to do some clonine)
|
||||
pub fn add_arg_ref(&mut self, a: &Arg<'a, 'b>) {
|
||||
debug_assert!(self.debug_asserts(&a));
|
||||
debug_assert!(self.debug_asserts(a));
|
||||
self.add_conditional_reqs(a);
|
||||
self.add_arg_groups(a);
|
||||
self.add_reqs(a);
|
||||
self.implied_settings(&a);
|
||||
self.implied_settings(a);
|
||||
if a.index.is_some() || (a.s.short.is_none() && a.s.long.is_none()) {
|
||||
let i = if a.index.is_none() {
|
||||
(self.positionals.len() + 1)
|
||||
@ -500,7 +500,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||
// but no 2)
|
||||
if let Some((idx, p)) = self.positionals.iter().rev().next() {
|
||||
assert!(!(idx != self.positionals.len()),
|
||||
"Found positional argument \"{}\" who's index is {} but there \
|
||||
"Found positional argument \"{}\" whose index is {} but there \
|
||||
are only {} positional arguments defined",
|
||||
p.b.name,
|
||||
idx,
|
||||
@ -702,7 +702,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||
} else if let Some(c) = sc.subcommands
|
||||
.iter()
|
||||
.find(|s| if let Some(ref als) = s.p.meta.aliases {
|
||||
als.iter().any(|&(a, _)| &a == &&*cmd.to_string_lossy())
|
||||
als.iter().any(|&(a, _)| a == &*cmd.to_string_lossy())
|
||||
} else {
|
||||
false
|
||||
})
|
||||
@ -868,8 +868,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||
}
|
||||
|
||||
if !starts_new_arg {
|
||||
match needs_val_of {
|
||||
ParseResult::Opt(name) => {
|
||||
if let ParseResult::Opt(name) = needs_val_of {
|
||||
// Check to see if parsing a value from a previous arg
|
||||
let arg = self.opts
|
||||
.iter()
|
||||
@ -879,43 +878,39 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||
needs_val_of = try!(self.add_val_to_arg(arg, &arg_os, matcher));
|
||||
// get the next value from the iterator
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if arg_os.starts_with(b"--") {
|
||||
needs_val_of = try!(self.parse_long_arg(matcher, &arg_os));
|
||||
debugln!("Parser:get_matches_with: After parse_long_arg {:?}",
|
||||
needs_val_of);
|
||||
match needs_val_of {
|
||||
ParseResult::Flag |
|
||||
ParseResult::Opt(..) |
|
||||
ParseResult::ValuesDone => continue,
|
||||
_ => (),
|
||||
}
|
||||
} else {
|
||||
if arg_os.starts_with(b"--") {
|
||||
needs_val_of = try!(self.parse_long_arg(matcher, &arg_os));
|
||||
debugln!("Parser:get_matches_with: After parse_long_arg {:?}",
|
||||
needs_val_of);
|
||||
match needs_val_of {
|
||||
ParseResult::Flag |
|
||||
ParseResult::Opt(..) |
|
||||
ParseResult::ValuesDone => continue,
|
||||
_ => (),
|
||||
}
|
||||
} else if arg_os.starts_with(b"-") && arg_os.len_() != 1 {
|
||||
// Try to parse short args like normal, if AllowLeadingHyphen or
|
||||
// AllowNegativeNumbers is set, parse_short_arg will *not* throw
|
||||
// an error, and instead return Ok(None)
|
||||
needs_val_of = try!(self.parse_short_arg(matcher, &arg_os));
|
||||
// If it's None, we then check if one of those two AppSettings was set
|
||||
debugln!("Parser:get_matches_with: After parse_short_arg {:?}",
|
||||
needs_val_of);
|
||||
match needs_val_of {
|
||||
ParseResult::MaybeNegNum => {
|
||||
if !(arg_os.to_string_lossy().parse::<i64>().is_ok() ||
|
||||
arg_os.to_string_lossy().parse::<f64>().is_ok()) {
|
||||
return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
|
||||
"",
|
||||
&*usage::create_error_usage(self, matcher, None),
|
||||
self.color()));
|
||||
}
|
||||
} else if arg_os.starts_with(b"-") && arg_os.len_() != 1 {
|
||||
// Try to parse short args like normal, if AllowLeadingHyphen or
|
||||
// AllowNegativeNumbers is set, parse_short_arg will *not* throw
|
||||
// an error, and instead return Ok(None)
|
||||
needs_val_of = try!(self.parse_short_arg(matcher, &arg_os));
|
||||
// If it's None, we then check if one of those two AppSettings was set
|
||||
debugln!("Parser:get_matches_with: After parse_short_arg {:?}",
|
||||
needs_val_of);
|
||||
match needs_val_of {
|
||||
ParseResult::MaybeNegNum => {
|
||||
if !(arg_os.to_string_lossy().parse::<i64>().is_ok() ||
|
||||
arg_os.to_string_lossy().parse::<f64>().is_ok()) {
|
||||
return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
|
||||
"",
|
||||
&*usage::create_error_usage(self, matcher, None),
|
||||
self.color()));
|
||||
}
|
||||
ParseResult::Opt(..) |
|
||||
}
|
||||
ParseResult::Opt(..) |
|
||||
ParseResult::Flag |
|
||||
ParseResult::ValuesDone => continue,
|
||||
_ => (),
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1148,7 +1143,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||
mid_string.push_str(" ");
|
||||
if let Some(ref mut sc) = self.subcommands
|
||||
.iter_mut()
|
||||
.find(|s| &s.p.meta.name == &sc_name) {
|
||||
.find(|s| s.p.meta.name == sc_name) {
|
||||
let mut sc_matcher = ArgMatcher::new();
|
||||
// bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by
|
||||
// a space
|
||||
@ -1241,13 +1236,11 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||
.find(|g| g.name == group)
|
||||
.expect(INTERNAL_ERROR_MSG)
|
||||
.args {
|
||||
if self.groups.iter().any(|g| &g.name == &*n) {
|
||||
if self.groups.iter().any(|g| g.name == *n) {
|
||||
args.extend(self.arg_names_in_group(n));
|
||||
g_vec.push(*n);
|
||||
} else {
|
||||
if !args.contains(n) {
|
||||
args.push(*n);
|
||||
}
|
||||
} else if !args.contains(n) {
|
||||
args.push(*n);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1344,6 +1337,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(let_and_return))]
|
||||
fn use_long_help(&self) -> bool {
|
||||
let ul = self.flags.iter().any(|f| f.b.long_help.is_some()) ||
|
||||
self.opts.iter().any(|o| o.b.long_help.is_some()) ||
|
||||
@ -1360,13 +1354,12 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||
use_long = use_long && self.use_long_help();
|
||||
let mut buf = vec![];
|
||||
match Help::write_parser_help(&mut buf, self, use_long) {
|
||||
Err(e) => return e,
|
||||
_ => (),
|
||||
}
|
||||
Error {
|
||||
message: unsafe { String::from_utf8_unchecked(buf) },
|
||||
kind: ErrorKind::HelpDisplayed,
|
||||
info: None,
|
||||
Err(e) => e,
|
||||
_ => Error {
|
||||
message: unsafe { String::from_utf8_unchecked(buf) },
|
||||
kind: ErrorKind::HelpDisplayed,
|
||||
info: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1375,13 +1368,12 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||
let out = io::stdout();
|
||||
let mut buf_w = BufWriter::new(out.lock());
|
||||
match self.print_version(&mut buf_w, use_long) {
|
||||
Err(e) => return e,
|
||||
_ => (),
|
||||
}
|
||||
Error {
|
||||
message: String::new(),
|
||||
kind: ErrorKind::VersionDisplayed,
|
||||
info: None,
|
||||
Err(e) => e,
|
||||
_ => Error {
|
||||
message: String::new(),
|
||||
kind: ErrorKind::VersionDisplayed,
|
||||
info: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1403,7 +1395,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||
full_arg.trim_left_matches(b'-')
|
||||
};
|
||||
|
||||
if let Some(opt) = find_opt_by_long!(@os self, &arg) {
|
||||
if let Some(opt) = find_opt_by_long!(@os self, arg) {
|
||||
debugln!("Parser::parse_long_arg: Found valid opt '{}'",
|
||||
opt.to_string());
|
||||
self.settings.set(AS::ValidArgFound);
|
||||
@ -1414,7 +1406,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||
}
|
||||
|
||||
return Ok(ret);
|
||||
} else if let Some(flag) = find_flag_by_long!(@os self, &arg) {
|
||||
} else if let Some(flag) = find_flag_by_long!(@os self, arg) {
|
||||
debugln!("Parser::parse_long_arg: Found valid flag '{}'",
|
||||
flag.to_string());
|
||||
self.settings.set(AS::ValidArgFound);
|
||||
@ -1588,33 +1580,31 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||
where A: AnyArg<'a, 'b> + Display
|
||||
{
|
||||
debugln!("Parser::add_val_to_arg; arg={}, val={:?}", arg.name(), val);
|
||||
let ret;
|
||||
debugln!("Parser::add_val_to_arg; trailing_vals={:?}, DontDelimTrailingVals={:?}",
|
||||
self.is_set(AS::TrailingValues),
|
||||
self.is_set(AS::DontDelimitTrailingValues));
|
||||
if !(self.is_set(AS::TrailingValues) && self.is_set(AS::DontDelimitTrailingValues)) {
|
||||
if let Some(delim) = arg.val_delim() {
|
||||
let mut iret = ParseResult::ValuesDone;
|
||||
if val.is_empty_() {
|
||||
iret = try!(self.add_single_val_to_arg(arg, val, matcher));
|
||||
Ok(try!(self.add_single_val_to_arg(arg, val, matcher)))
|
||||
} else {
|
||||
let mut iret = ParseResult::ValuesDone;
|
||||
for v in val.split(delim as u32 as u8) {
|
||||
iret = try!(self.add_single_val_to_arg(arg, v, matcher));
|
||||
}
|
||||
// If there was a delimiter used, we're not looking for more values
|
||||
if val.contains_byte(delim as u32 as u8) ||
|
||||
arg.is_set(ArgSettings::RequireDelimiter) {
|
||||
iret = ParseResult::ValuesDone;
|
||||
}
|
||||
arg.is_set(ArgSettings::RequireDelimiter) {
|
||||
iret = ParseResult::ValuesDone;
|
||||
}
|
||||
Ok(iret)
|
||||
}
|
||||
ret = Ok(iret);
|
||||
} else {
|
||||
ret = self.add_single_val_to_arg(arg, val, matcher);
|
||||
self.add_single_val_to_arg(arg, val, matcher)
|
||||
}
|
||||
} else {
|
||||
ret = self.add_single_val_to_arg(arg, val, matcher);
|
||||
self.add_single_val_to_arg(arg, val, matcher)
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
fn add_single_val_to_arg<A>(&self,
|
||||
@ -1662,19 +1652,18 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||
}
|
||||
|
||||
fn did_you_mean_error(&self, arg: &str, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
|
||||
// Didn't match a flag or option...maybe it was a typo and close to one
|
||||
|
||||
// Didn't match a flag or option
|
||||
let suffix =
|
||||
suggestions::did_you_mean_suffix(arg,
|
||||
longs!(self),
|
||||
suggestions::DidYouMeanMessageStyle::LongFlag);
|
||||
suggestions::did_you_mean_flag_suffix(arg, longs!(self), &self.subcommands);
|
||||
|
||||
// Add the arg to the matches to build a proper usage string
|
||||
if let Some(name) = suffix.1 {
|
||||
if let Some(opt) = find_opt_by_long!(self, &name) {
|
||||
if let Some(opt) = find_opt_by_long!(self, name) {
|
||||
self.groups_for_arg(&*opt.b.name)
|
||||
.and_then(|grps| Some(matcher.inc_occurrences_of(&*grps)));
|
||||
matcher.insert(&*opt.b.name);
|
||||
} else if let Some(flg) = find_flag_by_long!(self, &name) {
|
||||
} else if let Some(flg) = find_flag_by_long!(self, name) {
|
||||
self.groups_for_arg(&*flg.b.name)
|
||||
.and_then(|grps| Some(matcher.inc_occurrences_of(&*grps)));
|
||||
matcher.insert(&*flg.b.name);
|
||||
@ -1698,11 +1687,11 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||
let ver = if use_long {
|
||||
self.meta
|
||||
.long_version
|
||||
.unwrap_or(self.meta.version.unwrap_or("".into()))
|
||||
.unwrap_or_else(|| self.meta.version.unwrap_or(""))
|
||||
} else {
|
||||
self.meta
|
||||
.version
|
||||
.unwrap_or(self.meta.long_version.unwrap_or("".into()))
|
||||
.unwrap_or_else(|| self.meta.long_version.unwrap_or(""))
|
||||
};
|
||||
if let Some(bn) = self.meta.bin_name.as_ref() {
|
||||
if bn.contains(' ') {
|
||||
@ -1817,38 +1806,58 @@ impl<'a, 'b> Parser<'a, 'b>
|
||||
}
|
||||
|
||||
pub fn find_any_arg(&self, name: &str) -> Option<&AnyArg> {
|
||||
if let Some(f) = find_by_name!(self, &name, flags, iter) {
|
||||
if let Some(f) = find_by_name!(self, name, flags, iter) {
|
||||
return Some(f);
|
||||
}
|
||||
if let Some(o) = find_by_name!(self, &name, opts, iter) {
|
||||
if let Some(o) = find_by_name!(self, name, opts, iter) {
|
||||
return Some(o);
|
||||
}
|
||||
if let Some(p) = find_by_name!(self, &name, positionals, values) {
|
||||
if let Some(p) = find_by_name!(self, name, positionals, values) {
|
||||
return Some(p);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Check is a given string matches the binary name for this parser
|
||||
fn is_bin_name(&self, value: &str) -> bool {
|
||||
self.meta.bin_name
|
||||
.as_ref()
|
||||
.and_then(|name| Some(value == name))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Check is a given string is an alias for this parser
|
||||
fn is_alias(&self, value: &str) -> bool {
|
||||
self.meta.aliases
|
||||
.as_ref()
|
||||
.and_then(|aliases| {
|
||||
for alias in aliases {
|
||||
if alias.0 == value {
|
||||
return Some(true);
|
||||
}
|
||||
}
|
||||
Some(false)
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
// Only used for completion scripts due to bin_name messiness
|
||||
#[cfg_attr(feature = "lints", allow(block_in_if_condition_stmt))]
|
||||
pub fn find_subcommand(&'b self, sc: &str) -> Option<&'b App<'a, 'b>> {
|
||||
debugln!("Parser::find_subcommand: sc={}", sc);
|
||||
debugln!("Parser::find_subcommand: Currently in Parser...{}",
|
||||
self.meta.bin_name.as_ref().unwrap());
|
||||
for s in self.subcommands.iter() {
|
||||
if s.p.meta.bin_name.as_ref().unwrap_or(&String::new()) == sc ||
|
||||
(s.p.meta.aliases.is_some() &&
|
||||
s.p
|
||||
.meta
|
||||
.aliases
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|&(s, _)| {
|
||||
s == sc.split(' ').rev().next().expect(INTERNAL_ERROR_MSG)
|
||||
})) {
|
||||
for s in &self.subcommands {
|
||||
if s.p.is_bin_name(sc) {
|
||||
return Some(s);
|
||||
}
|
||||
// XXX: why do we split here?
|
||||
// isn't `sc` supposed to be single word already?
|
||||
let last = sc.split(' ').rev().next().expect(INTERNAL_ERROR_MSG);
|
||||
if s.p.is_alias(last) {
|
||||
return Some(s);
|
||||
}
|
||||
|
||||
if let Some(app) = s.p.find_subcommand(sc) {
|
||||
return Some(app);
|
||||
}
|
@ -4,47 +4,47 @@ use std::str::FromStr;
|
||||
use std::ops::BitOr;
|
||||
|
||||
bitflags! {
|
||||
flags Flags: u64 {
|
||||
const SC_NEGATE_REQS = 1 << 0,
|
||||
const SC_REQUIRED = 1 << 1,
|
||||
const A_REQUIRED_ELSE_HELP = 1 << 2,
|
||||
const GLOBAL_VERSION = 1 << 3,
|
||||
const VERSIONLESS_SC = 1 << 4,
|
||||
const UNIFIED_HELP = 1 << 5,
|
||||
const WAIT_ON_ERROR = 1 << 6,
|
||||
const SC_REQUIRED_ELSE_HELP= 1 << 7,
|
||||
const NEEDS_LONG_HELP = 1 << 8,
|
||||
const NEEDS_LONG_VERSION = 1 << 9,
|
||||
const NEEDS_SC_HELP = 1 << 10,
|
||||
const DISABLE_VERSION = 1 << 11,
|
||||
const HIDDEN = 1 << 12,
|
||||
const TRAILING_VARARG = 1 << 13,
|
||||
const NO_BIN_NAME = 1 << 14,
|
||||
const ALLOW_UNK_SC = 1 << 15,
|
||||
const UTF8_STRICT = 1 << 16,
|
||||
const UTF8_NONE = 1 << 17,
|
||||
const LEADING_HYPHEN = 1 << 18,
|
||||
const NO_POS_VALUES = 1 << 19,
|
||||
const NEXT_LINE_HELP = 1 << 20,
|
||||
const DERIVE_DISP_ORDER = 1 << 21,
|
||||
const COLORED_HELP = 1 << 22,
|
||||
const COLOR_ALWAYS = 1 << 23,
|
||||
const COLOR_AUTO = 1 << 24,
|
||||
const COLOR_NEVER = 1 << 25,
|
||||
const DONT_DELIM_TRAIL = 1 << 26,
|
||||
const ALLOW_NEG_NUMS = 1 << 27,
|
||||
const LOW_INDEX_MUL_POS = 1 << 28,
|
||||
const DISABLE_HELP_SC = 1 << 29,
|
||||
const DONT_COLLAPSE_ARGS = 1 << 30,
|
||||
const ARGS_NEGATE_SCS = 1 << 31,
|
||||
const PROPAGATE_VALS_DOWN = 1 << 32,
|
||||
const ALLOW_MISSING_POS = 1 << 33,
|
||||
const TRAILING_VALUES = 1 << 34,
|
||||
const VALID_NEG_NUM_FOUND = 1 << 35,
|
||||
const PROPOGATED = 1 << 36,
|
||||
const VALID_ARG_FOUND = 1 << 37,
|
||||
const INFER_SUBCOMMANDS = 1 << 38,
|
||||
const CONTAINS_LAST = 1 << 39,
|
||||
struct Flags: u64 {
|
||||
const SC_NEGATE_REQS = 1;
|
||||
const SC_REQUIRED = 1 << 1;
|
||||
const A_REQUIRED_ELSE_HELP = 1 << 2;
|
||||
const GLOBAL_VERSION = 1 << 3;
|
||||
const VERSIONLESS_SC = 1 << 4;
|
||||
const UNIFIED_HELP = 1 << 5;
|
||||
const WAIT_ON_ERROR = 1 << 6;
|
||||
const SC_REQUIRED_ELSE_HELP= 1 << 7;
|
||||
const NEEDS_LONG_HELP = 1 << 8;
|
||||
const NEEDS_LONG_VERSION = 1 << 9;
|
||||
const NEEDS_SC_HELP = 1 << 10;
|
||||
const DISABLE_VERSION = 1 << 11;
|
||||
const HIDDEN = 1 << 12;
|
||||
const TRAILING_VARARG = 1 << 13;
|
||||
const NO_BIN_NAME = 1 << 14;
|
||||
const ALLOW_UNK_SC = 1 << 15;
|
||||
const UTF8_STRICT = 1 << 16;
|
||||
const UTF8_NONE = 1 << 17;
|
||||
const LEADING_HYPHEN = 1 << 18;
|
||||
const NO_POS_VALUES = 1 << 19;
|
||||
const NEXT_LINE_HELP = 1 << 20;
|
||||
const DERIVE_DISP_ORDER = 1 << 21;
|
||||
const COLORED_HELP = 1 << 22;
|
||||
const COLOR_ALWAYS = 1 << 23;
|
||||
const COLOR_AUTO = 1 << 24;
|
||||
const COLOR_NEVER = 1 << 25;
|
||||
const DONT_DELIM_TRAIL = 1 << 26;
|
||||
const ALLOW_NEG_NUMS = 1 << 27;
|
||||
const LOW_INDEX_MUL_POS = 1 << 28;
|
||||
const DISABLE_HELP_SC = 1 << 29;
|
||||
const DONT_COLLAPSE_ARGS = 1 << 30;
|
||||
const ARGS_NEGATE_SCS = 1 << 31;
|
||||
const PROPAGATE_VALS_DOWN = 1 << 32;
|
||||
const ALLOW_MISSING_POS = 1 << 33;
|
||||
const TRAILING_VALUES = 1 << 34;
|
||||
const VALID_NEG_NUM_FOUND = 1 << 35;
|
||||
const PROPOGATED = 1 << 36;
|
||||
const VALID_ARG_FOUND = 1 << 37;
|
||||
const INFER_SUBCOMMANDS = 1 << 38;
|
||||
const CONTAINS_LAST = 1 << 39;
|
||||
}
|
||||
}
|
||||
|
||||
@ -528,7 +528,7 @@ pub enum AppSettings {
|
||||
/// This can be useful if there are many values, or they are explained elsewhere.
|
||||
HidePossibleValuesInHelp,
|
||||
|
||||
/// Tries to match unknown args to partial [`subcommands`] or their [aliases]. For example to
|
||||
/// Tries to match unknown args to partial [`subcommands`] or their [aliases]. For example to
|
||||
/// match a subcommand named `test`, one could use `t`, `te`, `tes`, and `test`.
|
||||
///
|
||||
/// **NOTE:** The match *must not* be ambiguous at all in order to succeed. i.e. to match `te`
|
||||
@ -536,7 +536,7 @@ pub enum AppSettings {
|
||||
///
|
||||
/// **CAUTION:** This setting can interfere with [positional/free arguments], take care when
|
||||
/// designing CLIs which allow inferred subcommands and have potential positional/free
|
||||
/// arguments who's values could start with the same characters as subcommands. If this is the
|
||||
/// arguments whose values could start with the same characters as subcommands. If this is the
|
||||
/// case, it's recommended to use settings such as [`AppSeettings::ArgsNegateSubcommands`] in
|
||||
/// conjuction with this setting.
|
||||
///
|
@ -26,9 +26,9 @@ pub fn create_error_usage<'a, 'b>(p: &Parser<'a, 'b>,
|
||||
let mut args: Vec<_> = matcher.arg_names()
|
||||
.iter()
|
||||
.filter(|n| {
|
||||
if let Some(o) = find_by_name!(p, *n, opts, iter) {
|
||||
if let Some(o) = find_by_name!(p, **n, opts, iter) {
|
||||
!o.b.is_set(ArgSettings::Required) && !o.b.is_set(ArgSettings::Hidden)
|
||||
} else if let Some(p) = find_by_name!(p, *n, positionals, values) {
|
||||
} else if let Some(p) = find_by_name!(p, **n, positionals, values) {
|
||||
!p.b.is_set(ArgSettings::Required) && p.b.is_set(ArgSettings::Hidden)
|
||||
} else {
|
||||
true // flags can't be required, so they're always true
|
||||
@ -244,7 +244,7 @@ fn get_args_tag(p: &Parser, incl_reqs: bool) -> Option<String> {
|
||||
None
|
||||
})
|
||||
.max()
|
||||
.unwrap_or(p.positionals.len());
|
||||
.unwrap_or_else(|| p.positionals.len());
|
||||
return Some(p.positionals
|
||||
.iter()
|
||||
.filter_map(|(idx, pos)| if idx <= highest_req_pos {
|
||||
@ -379,10 +379,10 @@ pub fn get_required_usage_from<'a, 'b>(p: &Parser<'a, 'b>,
|
||||
let args_in_groups = p.groups
|
||||
.iter()
|
||||
.filter(|gn| desc_reqs.contains(&gn.name))
|
||||
.flat_map(|g| p.arg_names_in_group(&g.name))
|
||||
.flat_map(|g| p.arg_names_in_group(g.name))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let pmap = if let Some(ref m) = matcher {
|
||||
let pmap = if let Some(m) = matcher {
|
||||
desc_reqs.iter()
|
||||
.filter(|a| p.positionals.values().any(|p| &&p.b.name == a))
|
||||
.filter(|&pos| !m.contains(pos))
|
||||
@ -414,10 +414,10 @@ pub fn get_required_usage_from<'a, 'b>(p: &Parser<'a, 'b>,
|
||||
.filter(|name| !args_in_groups.contains(name))
|
||||
.filter(|name| !(matcher.is_some() && matcher.as_ref().unwrap().contains(name))) {
|
||||
debugln!("usage::get_required_usage_from:iter:{}:", a);
|
||||
let arg = find_by_name!(p, a, flags, iter)
|
||||
let arg = find_by_name!(p, *a, flags, iter)
|
||||
.map(|f| f.to_string())
|
||||
.unwrap_or_else(|| {
|
||||
find_by_name!(p, a, opts, iter)
|
||||
find_by_name!(p, *a, opts, iter)
|
||||
.map(|o| o.to_string())
|
||||
.expect(INTERNAL_ERROR_MSG)
|
||||
});
|
@ -11,7 +11,7 @@ use errors::Result as ClapResult;
|
||||
use osstringext::OsStrExt2;
|
||||
use app::settings::AppSettings as AS;
|
||||
use app::parser::{Parser, ParseResult};
|
||||
use fmt::Colorizer;
|
||||
use fmt::{Colorizer, ColorizerOption};
|
||||
use app::usage;
|
||||
|
||||
pub struct Validator<'a, 'b, 'z>(&'z mut Parser<'a, 'b>)
|
||||
@ -135,16 +135,16 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||
macro_rules! build_err {
|
||||
($p:expr, $name:expr, $matcher:ident) => ({
|
||||
debugln!("build_err!: name={}", $name);
|
||||
let mut c_with = find_from!($p, $name, blacklist, &$matcher);
|
||||
let mut c_with = find_from!($p, &$name, blacklist, &$matcher);
|
||||
c_with = c_with.or(
|
||||
$p.find_any_arg($name).map_or(None, |aa| aa.blacklist())
|
||||
$p.find_any_arg(&$name).map_or(None, |aa| aa.blacklist())
|
||||
.map_or(None,
|
||||
|bl| bl.iter().find(|arg| $matcher.contains(arg)))
|
||||
.map_or(None, |an| $p.find_any_arg(an))
|
||||
.map_or(None, |aa| Some(format!("{}", aa)))
|
||||
);
|
||||
debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, $name);
|
||||
$matcher.remove($name);
|
||||
debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &$name);
|
||||
$matcher.remove(&$name);
|
||||
let usg = usage::create_error_usage($p, $matcher, None);
|
||||
if let Some(f) = find_by_name!($p, $name, flags, iter) {
|
||||
debugln!("build_err!: It was a flag...");
|
||||
@ -174,12 +174,12 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||
n);
|
||||
if matcher.contains(n) {
|
||||
debugln!("Validator::validate_blacklist:iter:iter: matcher contains it...");
|
||||
return Err(build_err!(self.0, &n, matcher));
|
||||
return Err(build_err!(self.0, n, matcher));
|
||||
}
|
||||
}
|
||||
} else if matcher.contains(name) {
|
||||
debugln!("Validator::validate_blacklist:iter: matcher contains it...");
|
||||
return Err(build_err!(self.0, name, matcher));
|
||||
return Err(build_err!(self.0, *name, matcher));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@ -191,15 +191,15 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||
debugln!("Validator::validate_matched_args:iter:{}: vals={:#?}",
|
||||
name,
|
||||
ma.vals);
|
||||
if let Some(opt) = find_by_name!(self.0, name, opts, iter) {
|
||||
if let Some(opt) = find_by_name!(self.0, *name, opts, iter) {
|
||||
try!(self.validate_arg_num_vals(opt, ma, matcher));
|
||||
try!(self.validate_values(opt, ma, matcher));
|
||||
try!(self.validate_arg_requires(opt, ma, matcher));
|
||||
try!(self.validate_arg_num_occurs(opt, ma, matcher));
|
||||
} else if let Some(flag) = find_by_name!(self.0, name, flags, iter) {
|
||||
} else if let Some(flag) = find_by_name!(self.0, *name, flags, iter) {
|
||||
try!(self.validate_arg_requires(flag, ma, matcher));
|
||||
try!(self.validate_arg_num_occurs(flag, ma, matcher));
|
||||
} else if let Some(pos) = find_by_name!(self.0, name, positionals, values) {
|
||||
} else if let Some(pos) = find_by_name!(self.0, *name, positionals, values) {
|
||||
try!(self.validate_arg_num_vals(pos, ma, matcher));
|
||||
try!(self.validate_arg_num_occurs(pos, ma, matcher));
|
||||
try!(self.validate_values(pos, ma, matcher));
|
||||
@ -344,15 +344,15 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||
if matcher.contains(name) {
|
||||
continue 'outer;
|
||||
}
|
||||
if let Some(a) = find_by_name!(self.0, name, flags, iter) {
|
||||
if let Some(a) = find_by_name!(self.0, *name, flags, iter) {
|
||||
if self.is_missing_required_ok(a, matcher) {
|
||||
continue 'outer;
|
||||
}
|
||||
} else if let Some(a) = find_by_name!(self.0, name, opts, iter) {
|
||||
} else if let Some(a) = find_by_name!(self.0, *name, opts, iter) {
|
||||
if self.is_missing_required_ok(a, matcher) {
|
||||
continue 'outer;
|
||||
}
|
||||
} else if let Some(a) = find_by_name!(self.0, name, positionals, values) {
|
||||
} else if let Some(a) = find_by_name!(self.0, *name, positionals, values) {
|
||||
if self.is_missing_required_ok(a, matcher) {
|
||||
continue 'outer;
|
||||
}
|
||||
@ -417,10 +417,10 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||
|
||||
fn missing_required_error(&self, matcher: &ArgMatcher, extra: Option<&str>) -> ClapResult<()> {
|
||||
debugln!("Validator::missing_required_error: extra={:?}", extra);
|
||||
let c = Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: self.0.color(),
|
||||
};
|
||||
});
|
||||
let mut reqs = self.0
|
||||
.required
|
||||
.iter()
|
||||
@ -453,4 +453,4 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
|
||||
self.validate_required_unless(a, matcher)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
}
|
@ -63,7 +63,7 @@ impl<'n, 'e> PosBuilder<'n, 'e> {
|
||||
let mult_vals = self.v
|
||||
.val_names
|
||||
.as_ref()
|
||||
.map_or(true, |ref names| names.len() < 2);
|
||||
.map_or(true, |names| names.len() < 2);
|
||||
if self.is_set(ArgSettings::Multiple) && mult_vals {
|
||||
"..."
|
||||
} else {
|
@ -472,7 +472,7 @@ impl<'a> From<&'a BTreeMap<Yaml, Yaml>> for ArgGroup<'a> {
|
||||
b
|
||||
};
|
||||
|
||||
for (k, v) in group_settings.iter() {
|
||||
for (k, v) in group_settings {
|
||||
a = match k.as_str().unwrap() {
|
||||
"required" => a.required(v.as_bool().unwrap()),
|
||||
"multiple" => a.multiple(v.as_bool().unwrap()),
|
@ -1,4 +1,4 @@
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
macro_rules! yaml_tuple2 {
|
||||
($a:ident, $v:ident, $c:ident) => {{
|
||||
if let Some(vec) = $v.as_vec() {
|
||||
@ -18,6 +18,7 @@ macro_rules! yaml_tuple2 {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
macro_rules! yaml_tuple3 {
|
||||
($a:ident, $v:ident, $c:ident) => {{
|
||||
if let Some(vec) = $v.as_vec() {
|
||||
@ -37,6 +38,7 @@ macro_rules! yaml_tuple3 {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
macro_rules! yaml_vec_or_str {
|
||||
($v:ident, $a:ident, $c:ident) => {{
|
||||
let maybe_vec = $v.as_vec();
|
||||
@ -60,6 +62,7 @@ macro_rules! yaml_vec_or_str {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
macro_rules! yaml_opt_str {
|
||||
($v:expr) => {{
|
||||
if $v.is_null() {
|
||||
@ -70,31 +73,35 @@ macro_rules! yaml_opt_str {
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
macro_rules! yaml_str {
|
||||
($v:expr) => {{
|
||||
$v.as_str().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v))
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
macro_rules! yaml_to_str {
|
||||
($a:ident, $v:ident, $c:ident) => {{
|
||||
$a.$c(yaml_str!($v))
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
macro_rules! yaml_to_bool {
|
||||
($a:ident, $v:ident, $c:ident) => {{
|
||||
$a.$c($v.as_bool().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)))
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
macro_rules! yaml_to_u64 {
|
||||
($a:ident, $v:ident, $c:ident) => {{
|
||||
$a.$c($v.as_i64().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)) as u64)
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
macro_rules! yaml_to_usize {
|
||||
($a:ident, $v:ident, $c:ident) => {{
|
||||
$a.$c($v.as_i64().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)) as usize)
|
@ -3,23 +3,23 @@ use std::ascii::AsciiExt;
|
||||
use std::str::FromStr;
|
||||
|
||||
bitflags! {
|
||||
flags Flags: u16 {
|
||||
const REQUIRED = 1 << 0,
|
||||
const MULTIPLE = 1 << 1,
|
||||
const EMPTY_VALS = 1 << 2,
|
||||
const GLOBAL = 1 << 3,
|
||||
const HIDDEN = 1 << 4,
|
||||
const TAKES_VAL = 1 << 5,
|
||||
const USE_DELIM = 1 << 6,
|
||||
const NEXT_LINE_HELP = 1 << 7,
|
||||
const R_UNLESS_ALL = 1 << 8,
|
||||
const REQ_DELIM = 1 << 9,
|
||||
const DELIM_NOT_SET = 1 << 10,
|
||||
const HIDE_POS_VALS = 1 << 11,
|
||||
const ALLOW_TAC_VALS = 1 << 12,
|
||||
const REQUIRE_EQUALS = 1 << 13,
|
||||
const LAST = 1 << 14,
|
||||
const HIDE_DEFAULT_VAL = 1 << 15,
|
||||
struct Flags: u16 {
|
||||
const REQUIRED = 1;
|
||||
const MULTIPLE = 1 << 1;
|
||||
const EMPTY_VALS = 1 << 2;
|
||||
const GLOBAL = 1 << 3;
|
||||
const HIDDEN = 1 << 4;
|
||||
const TAKES_VAL = 1 << 5;
|
||||
const USE_DELIM = 1 << 6;
|
||||
const NEXT_LINE_HELP = 1 << 7;
|
||||
const R_UNLESS_ALL = 1 << 8;
|
||||
const REQ_DELIM = 1 << 9;
|
||||
const DELIM_NOT_SET = 1 << 10;
|
||||
const HIDE_POS_VALS = 1 << 11;
|
||||
const ALLOW_TAC_VALS = 1 << 12;
|
||||
const REQUIRE_EQUALS = 1 << 13;
|
||||
const LAST = 1 << 14;
|
||||
const HIDE_DEFAULT_VAL = 1 << 15;
|
||||
}
|
||||
}
|
||||
|
@ -82,10 +82,8 @@ fn generate_inner<'a, 'b, 'p>(p: &'p Parser<'a, 'b>, previous_command_name: &str
|
||||
format!("{}_{}", previous_command_name, &p.meta.name)
|
||||
};
|
||||
|
||||
let mut subcommands_detection_cases = if previous_command_name.is_empty() {
|
||||
String::new()
|
||||
} else if !names.contains(&&*p.meta.name) {
|
||||
names.push(&&*p.meta.name);
|
||||
let mut subcommands_detection_cases = if !names.contains(&&*p.meta.name) {
|
||||
names.push(&*p.meta.name);
|
||||
format!(r"
|
||||
'{0}' {{
|
||||
$command += '_{0}'
|
@ -9,7 +9,7 @@ use std::result::Result as StdResult;
|
||||
|
||||
// Internal
|
||||
use args::{FlagBuilder, AnyArg};
|
||||
use fmt;
|
||||
use fmt::{Colorizer, ColorizerOption, ColorWhen};
|
||||
use suggestions;
|
||||
|
||||
/// Short hand for [`Result`] type
|
||||
@ -408,17 +408,17 @@ impl Error {
|
||||
pub fn argument_conflict<'a, 'b, A, O, U>(arg: &A,
|
||||
other: Option<O>,
|
||||
usage: U,
|
||||
color: fmt::ColorWhen)
|
||||
color: ColorWhen)
|
||||
-> Self
|
||||
where A: AnyArg<'a, 'b> + Display,
|
||||
O: Into<String>,
|
||||
U: Display
|
||||
{
|
||||
let mut v = vec![arg.name().to_owned()];
|
||||
let c = fmt::Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
};
|
||||
});
|
||||
Error {
|
||||
message: format!("{} The argument '{}' cannot be used with {}\n\n\
|
||||
{}\n\n\
|
||||
@ -444,14 +444,14 @@ impl Error {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn empty_value<'a, 'b, A, U>(arg: &A, usage: U, color: fmt::ColorWhen) -> Self
|
||||
pub fn empty_value<'a, 'b, A, U>(arg: &A, usage: U, color: ColorWhen) -> Self
|
||||
where A: AnyArg<'a, 'b> + Display,
|
||||
U: Display
|
||||
{
|
||||
let c = fmt::Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
};
|
||||
});
|
||||
Error {
|
||||
message: format!("{} The argument '{}' requires a value but none was supplied\
|
||||
\n\n\
|
||||
@ -471,21 +471,21 @@ impl Error {
|
||||
good_vals: &[G],
|
||||
arg: &A,
|
||||
usage: U,
|
||||
color: fmt::ColorWhen)
|
||||
color: ColorWhen)
|
||||
-> Self
|
||||
where B: AsRef<str>,
|
||||
G: AsRef<str> + Display,
|
||||
A: AnyArg<'a, 'b> + Display,
|
||||
U: Display
|
||||
{
|
||||
let c = fmt::Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
};
|
||||
});
|
||||
let suffix =
|
||||
suggestions::did_you_mean_suffix(bad_val.as_ref(),
|
||||
good_vals.iter(),
|
||||
suggestions::DidYouMeanMessageStyle::EnumValue);
|
||||
suggestions::did_you_mean_value_suffix(
|
||||
bad_val.as_ref(),
|
||||
good_vals.iter());
|
||||
|
||||
let mut sorted = vec![];
|
||||
for v in good_vals {
|
||||
@ -517,7 +517,7 @@ impl Error {
|
||||
did_you_mean: D,
|
||||
name: N,
|
||||
usage: U,
|
||||
color: fmt::ColorWhen)
|
||||
color: ColorWhen)
|
||||
-> Self
|
||||
where S: Into<String>,
|
||||
D: AsRef<str> + Display,
|
||||
@ -525,10 +525,10 @@ impl Error {
|
||||
U: Display
|
||||
{
|
||||
let s = subcmd.into();
|
||||
let c = fmt::Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
};
|
||||
});
|
||||
Error {
|
||||
message: format!("{} The subcommand '{}' wasn't recognized\n\t\
|
||||
Did you mean '{}'?\n\n\
|
||||
@ -550,15 +550,15 @@ impl Error {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn unrecognized_subcommand<S, N>(subcmd: S, name: N, color: fmt::ColorWhen) -> Self
|
||||
pub fn unrecognized_subcommand<S, N>(subcmd: S, name: N, color: ColorWhen) -> Self
|
||||
where S: Into<String>,
|
||||
N: Display
|
||||
{
|
||||
let s = subcmd.into();
|
||||
let c = fmt::Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
};
|
||||
});
|
||||
Error {
|
||||
message: format!("{} The subcommand '{}' wasn't recognized\n\n\
|
||||
{}\n\t\
|
||||
@ -575,14 +575,14 @@ impl Error {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn missing_required_argument<R, U>(required: R, usage: U, color: fmt::ColorWhen) -> Self
|
||||
pub fn missing_required_argument<R, U>(required: R, usage: U, color: ColorWhen) -> Self
|
||||
where R: Display,
|
||||
U: Display
|
||||
{
|
||||
let c = fmt::Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
};
|
||||
});
|
||||
Error {
|
||||
message: format!("{} The following required arguments were not provided:{}\n\n\
|
||||
{}\n\n\
|
||||
@ -597,14 +597,14 @@ impl Error {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn missing_subcommand<N, U>(name: N, usage: U, color: fmt::ColorWhen) -> Self
|
||||
pub fn missing_subcommand<N, U>(name: N, usage: U, color: ColorWhen) -> Self
|
||||
where N: AsRef<str> + Display,
|
||||
U: Display
|
||||
{
|
||||
let c = fmt::Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
};
|
||||
});
|
||||
Error {
|
||||
message: format!("{} '{}' requires a subcommand, but one was not provided\n\n\
|
||||
{}\n\n\
|
||||
@ -620,13 +620,13 @@ impl Error {
|
||||
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn invalid_utf8<U>(usage: U, color: fmt::ColorWhen) -> Self
|
||||
pub fn invalid_utf8<U>(usage: U, color: ColorWhen) -> Self
|
||||
where U: Display
|
||||
{
|
||||
let c = fmt::Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
};
|
||||
});
|
||||
Error {
|
||||
message: format!("{} Invalid UTF-8 was detected in one or more arguments\n\n\
|
||||
{}\n\n\
|
||||
@ -643,17 +643,17 @@ impl Error {
|
||||
pub fn too_many_values<'a, 'b, V, A, U>(val: V,
|
||||
arg: &A,
|
||||
usage: U,
|
||||
color: fmt::ColorWhen)
|
||||
color: ColorWhen)
|
||||
-> Self
|
||||
where V: AsRef<str> + Display + ToOwned,
|
||||
A: AnyArg<'a, 'b> + Display,
|
||||
U: Display
|
||||
{
|
||||
let v = val.as_ref();
|
||||
let c = fmt::Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
};
|
||||
});
|
||||
Error {
|
||||
message: format!("{} The value '{}' was provided to '{}', but it wasn't expecting \
|
||||
any more values\n\n\
|
||||
@ -674,15 +674,15 @@ impl Error {
|
||||
min_vals: u64,
|
||||
curr_vals: usize,
|
||||
usage: U,
|
||||
color: fmt::ColorWhen)
|
||||
color: ColorWhen)
|
||||
-> Self
|
||||
where A: AnyArg<'a, 'b> + Display,
|
||||
U: Display
|
||||
{
|
||||
let c = fmt::Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
};
|
||||
});
|
||||
Error {
|
||||
message: format!("{} The argument '{}' requires at least {} values, but only {} w{} \
|
||||
provided\n\n\
|
||||
@ -701,13 +701,13 @@ impl Error {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn value_validation<'a, 'b, A>(arg: Option<&A>, err: String, color: fmt::ColorWhen) -> Self
|
||||
pub fn value_validation<'a, 'b, A>(arg: Option<&A>, err: String, color: ColorWhen) -> Self
|
||||
where A: AnyArg<'a, 'b> + Display
|
||||
{
|
||||
let c = fmt::Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
};
|
||||
});
|
||||
Error {
|
||||
message: format!("{} Invalid value{}: {}",
|
||||
c.error("error:"),
|
||||
@ -725,7 +725,7 @@ impl Error {
|
||||
#[doc(hidden)]
|
||||
pub fn value_validation_auto(err: String) -> Self {
|
||||
let n: Option<&FlagBuilder> = None;
|
||||
Error::value_validation(n, err, fmt::ColorWhen::Auto)
|
||||
Error::value_validation(n, err, ColorWhen::Auto)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
@ -734,16 +734,16 @@ impl Error {
|
||||
curr_vals: usize,
|
||||
suffix: S,
|
||||
usage: U,
|
||||
color: fmt::ColorWhen)
|
||||
color: ColorWhen)
|
||||
-> Self
|
||||
where A: AnyArg<'a, 'b> + Display,
|
||||
S: Display,
|
||||
U: Display
|
||||
{
|
||||
let c = fmt::Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
};
|
||||
});
|
||||
Error {
|
||||
message: format!("{} The argument '{}' requires {} values, but {} w{} \
|
||||
provided\n\n\
|
||||
@ -762,14 +762,14 @@ impl Error {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn unexpected_multiple_usage<'a, 'b, A, U>(arg: &A, usage: U, color: fmt::ColorWhen) -> Self
|
||||
pub fn unexpected_multiple_usage<'a, 'b, A, U>(arg: &A, usage: U, color: ColorWhen) -> Self
|
||||
where A: AnyArg<'a, 'b> + Display,
|
||||
U: Display
|
||||
{
|
||||
let c = fmt::Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
};
|
||||
});
|
||||
Error {
|
||||
message: format!("{} The argument '{}' was provided more than once, but cannot \
|
||||
be used multiple times\n\n\
|
||||
@ -788,16 +788,16 @@ impl Error {
|
||||
pub fn unknown_argument<A, U>(arg: A,
|
||||
did_you_mean: &str,
|
||||
usage: U,
|
||||
color: fmt::ColorWhen)
|
||||
color: ColorWhen)
|
||||
-> Self
|
||||
where A: Into<String>,
|
||||
U: Display
|
||||
{
|
||||
let a = arg.into();
|
||||
let c = fmt::Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
};
|
||||
});
|
||||
Error {
|
||||
message: format!("{} Found argument '{}' which wasn't expected, or isn't valid in \
|
||||
this context{}\n\
|
||||
@ -818,11 +818,11 @@ impl Error {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn io_error(e: &Error, color: fmt::ColorWhen) -> Self {
|
||||
let c = fmt::Colorizer {
|
||||
pub fn io_error(e: &Error, color: ColorWhen) -> Self {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
};
|
||||
});
|
||||
Error {
|
||||
message: format!("{} {}", c.error("error:"), e.description()),
|
||||
kind: ErrorKind::Io,
|
||||
@ -835,10 +835,10 @@ impl Error {
|
||||
where A: Into<String>
|
||||
{
|
||||
let a = arg.into();
|
||||
let c = fmt::Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: fmt::ColorWhen::Auto,
|
||||
};
|
||||
when: ColorWhen::Auto,
|
||||
});
|
||||
Error {
|
||||
message: format!("{} The argument '{}' wasn't found",
|
||||
c.error("error:"),
|
||||
@ -853,10 +853,10 @@ impl Error {
|
||||
/// This can be used in combination with `Error::exit` to exit your program
|
||||
/// with a custom error message.
|
||||
pub fn with_description(description: &str, kind: ErrorKind) -> Self {
|
||||
let c = fmt::Colorizer {
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: fmt::ColorWhen::Auto,
|
||||
};
|
||||
when: ColorWhen::Auto,
|
||||
});
|
||||
Error {
|
||||
message: format!("{} {}", c.error("error:"), description),
|
||||
kind: kind,
|
@ -7,6 +7,7 @@ use ansi_term::Colour::{Green, Red, Yellow};
|
||||
#[cfg(feature = "color")]
|
||||
use atty;
|
||||
use std::fmt;
|
||||
use std::env;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
@ -33,20 +34,23 @@ pub fn is_a_tty(_: bool) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn is_term_dumb() -> bool { env::var("TERM").ok() == Some(String::from("dumb")) }
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct Colorizer {
|
||||
pub struct ColorizerOption {
|
||||
pub use_stderr: bool,
|
||||
pub when: ColorWhen,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct Colorizer {
|
||||
when: ColorWhen,
|
||||
}
|
||||
|
||||
macro_rules! color {
|
||||
($_self:ident, $c:ident, $m:expr) => {
|
||||
match $_self.when {
|
||||
ColorWhen::Auto => if is_a_tty($_self.use_stderr) {
|
||||
Format::$c($m)
|
||||
} else {
|
||||
Format::None($m)
|
||||
},
|
||||
ColorWhen::Auto => Format::$c($m),
|
||||
ColorWhen::Always => Format::$c($m),
|
||||
ColorWhen::Never => Format::None($m),
|
||||
}
|
||||
@ -54,6 +58,18 @@ macro_rules! color {
|
||||
}
|
||||
|
||||
impl Colorizer {
|
||||
pub fn new(option: ColorizerOption) -> Colorizer {
|
||||
let is_a_tty = is_a_tty(option.use_stderr);
|
||||
let is_term_dumb = is_term_dumb();
|
||||
Colorizer {
|
||||
when: if is_a_tty && !is_term_dumb {
|
||||
option.when
|
||||
} else {
|
||||
ColorWhen::Never
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn good<T>(&self, msg: T) -> Format<T>
|
||||
where T: fmt::Display + AsRef<str>
|
||||
{
|
||||
@ -85,10 +101,10 @@ impl Colorizer {
|
||||
|
||||
impl Default for Colorizer {
|
||||
fn default() -> Self {
|
||||
Colorizer {
|
||||
Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: ColorWhen::Auto,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user