added rust vendor
This commit is contained in:
parent
63e90f94a8
commit
7da03ad9a2
33211 changed files with 12523284 additions and 0 deletions
1
.gear/predownloaded-development/vendor/Inflector/.cargo-checksum.json
vendored
Normal file
1
.gear/predownloaded-development/vendor/Inflector/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{".cargo_vcs_info.json":"882e6524f5b956dd8a55b2f09c07b0128139240d7a2290bfca5e09e6b33eab21","Cargo.toml":"8fb633b01ea17947fd1f76e0a447b027ddf48c019671f09e39c1338ab715605d","Cargo.toml.orig":"e048a47a1760e78ea145327d8de218d792ce23f0da8665b7a75ddf56f2bfb92c","README.md":"3c7136fc446143eecf9668e6daf7f096eb5eb3a3e312cc674571719cb4c83bcc","src/cases/camelcase/mod.rs":"8e65fca78ea88acb32c0f214cafde39b849aef253253c3681e316f2559b26977","src/cases/case/mod.rs":"16323191c983d316debd50af11f94f4c525bb70d4d1a02db06a9aed67d4ba2a9","src/cases/classcase/mod.rs":"5b6b74530a2a693bf1ac89342f1b25f58f39336b1ee3242547c3d6ef468a878f","src/cases/kebabcase/mod.rs":"b317ebd42f22daab4b23bb4b83ce85f053d7088680d3a32eecbd13bd5331587a","src/cases/mod.rs":"e272853bcc1c5f6eb02594038febb9dcebb6eca8eac744d6e503db5082e585c6","src/cases/pascalcase/mod.rs":"a44feed6d8877fd8a31160076befe826960aa001d859587aef2dddc1aedc397b","src/cases/screamingsnakecase/mod.rs":"21582eb1ec2170d379bf3536c6ffb39b8bdc096efe2d493674458ee27b86e985","src/cases/sentencecase/mod.rs":"eb21d7d5bf0b23e1325d429dfdc149081d233a8b950c1fdfe04b4bebcc2c0ddb","src/cases/snakecase/mod.rs":"369739e37e700c028022f308aa78504873c10a5e88768f05249c1c8481b30c9d","src/cases/tablecase/mod.rs":"a6a50a397059d775a517d5dce6ba612b107919e209a9eb56871a5c1d42314664","src/cases/titlecase/mod.rs":"3f0dac5e5b434da9234d6c389f67bb2d3c8f138dc521fa29dbe3791f8eaf5341","src/cases/traincase/mod.rs":"4e2493d6594d3c505de293c69390b3f672c0fd4d35603ae1a1aae48166bc18c2","src/lib.rs":"6c5cf60f5c2f8778a3ad7638f37064527b8a86f164117d867b8b6532e2cc655e","src/numbers/deordinalize/mod.rs":"a3930b0315d20d2d86747bc4ae653a0fb7f7d80de497b0aaa9873aadd1459d18","src/numbers/mod.rs":"fed4e090f8b64a34ae64ddcb68d899cfa4dd8e8422a060be01a70dbdb71b85e0","src/numbers/ordinalize/mod.rs":"ce0d88977efaa50792e7311c0e0a73a3115928f9f7be77f914824c3d80eab66c","src/string/constants/mod.rs":"38de3d5060a5d224d28d184eab8af02203c65d74c1d380720c3260ea205f3e05","src/string/deconstantize/mod.rs":"c79f2170dc41bd6abb89a6e74fbdd87bf011f62cfe1f34d8886fda0724ade6fa","src/string/demodulize/mod.rs":"bbcb5314473e4ca02feee4903e31a332caaa912ed2cbca0f49c2fe411a826215","src/string/mod.rs":"570f7ea4dd646f2d633ddd67079db922cc2cadf916719fa19c2f59b4d522ee89","src/string/pluralize/mod.rs":"5f07fab8b5f4e7af546f1e907426724714b9b27af1ecb59a91e57dccd0833a6e","src/string/singularize/mod.rs":"9c2d833cbcdc1489013642de22578d51f558a31e8d2fea4536a27f8fa1114169","src/suffix/foreignkey/mod.rs":"e7ad9a9a0a21fcb53becb36306a15eedf67958e2da18ae928ae592177e70e7a3","src/suffix/mod.rs":"f6f99ce6fc8794d5411d91533b67be5d4a2bc5994317d32f405b2fa3c5ec660d","tests/lib.rs":"e1cfcea8a146291396ff72b0a2e84c2b9ddaa0103717442c4921c165a2ab470d"},"package":"fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"}
|
||||
5
.gear/predownloaded-development/vendor/Inflector/.cargo_vcs_info.json
vendored
Normal file
5
.gear/predownloaded-development/vendor/Inflector/.cargo_vcs_info.json
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"git": {
|
||||
"sha1": "a4a95eac75043f4bffb127c7c8ec886b5b106053"
|
||||
}
|
||||
}
|
||||
42
.gear/predownloaded-development/vendor/Inflector/Cargo.toml
vendored
Normal file
42
.gear/predownloaded-development/vendor/Inflector/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# 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 = "Inflector"
|
||||
version = "0.11.4"
|
||||
authors = ["Josh Teeter<joshteeter@gmail.com>"]
|
||||
include = ["**/*.rs", "Cargo.toml", "README.md"]
|
||||
description = "Adds String based inflections for Rust. Snake, kebab, camel, sentence, class, title and table cases as well as ordinalize, deordinalize, demodulize, foreign key, and pluralize/singularize are supported as both traits and pure functions acting on String types.\n"
|
||||
homepage = "https://github.com/whatisinternet/inflector"
|
||||
documentation = "https://docs.rs/Inflector"
|
||||
readme = "README.md"
|
||||
keywords = ["pluralize", "Inflector", "camel", "snake", "inflection"]
|
||||
categories = ["text-processing", "value-formatting"]
|
||||
license = "BSD-2-Clause"
|
||||
repository = "https://github.com/whatisinternet/inflector"
|
||||
|
||||
[lib]
|
||||
name = "inflector"
|
||||
[dependencies.lazy_static]
|
||||
version = "1.2.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.regex]
|
||||
version = "1.1"
|
||||
optional = true
|
||||
|
||||
[features]
|
||||
default = ["heavyweight"]
|
||||
heavyweight = ["regex", "lazy_static"]
|
||||
unstable = []
|
||||
[badges.travis-ci]
|
||||
repository = "whatisinternet/Inflector"
|
||||
34
.gear/predownloaded-development/vendor/Inflector/Cargo.toml.orig
generated
vendored
Normal file
34
.gear/predownloaded-development/vendor/Inflector/Cargo.toml.orig
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
[package]
|
||||
name = "Inflector"
|
||||
version = "0.11.4"
|
||||
authors = ["Josh Teeter<joshteeter@gmail.com>"]
|
||||
include = [
|
||||
"**/*.rs",
|
||||
"Cargo.toml",
|
||||
"README.md"
|
||||
]
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/whatisinternet/inflector"
|
||||
documentation = "https://docs.rs/Inflector"
|
||||
homepage = "https://github.com/whatisinternet/inflector"
|
||||
license="BSD-2-Clause"
|
||||
description = """
|
||||
Adds String based inflections for Rust. Snake, kebab, camel, sentence, class, title and table cases as well as ordinalize, deordinalize, demodulize, foreign key, and pluralize/singularize are supported as both traits and pure functions acting on String types.
|
||||
"""
|
||||
keywords = ["pluralize", "Inflector", "camel", "snake", "inflection"]
|
||||
categories = ["text-processing", "value-formatting"]
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "whatisinternet/Inflector" }
|
||||
|
||||
[features]
|
||||
default = ['heavyweight']
|
||||
unstable = []
|
||||
heavyweight = ['regex', 'lazy_static']
|
||||
|
||||
[lib]
|
||||
name = "inflector"
|
||||
|
||||
[dependencies]
|
||||
regex = {version = "1.1", optional = true}
|
||||
lazy_static = {version = "1.2.0", optional = true}
|
||||
136
.gear/predownloaded-development/vendor/Inflector/README.md
vendored
Normal file
136
.gear/predownloaded-development/vendor/Inflector/README.md
vendored
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
# Rust Inflector
|
||||
|
||||
|
||||
[](https://travis-ci.org/whatisinternet/Inflector) [](https://crates.io/crates/inflector)[](https://crates.io/crates/inflector)
|
||||
|
||||
|
||||
Adds String based inflections for Rust. Snake, kebab, train, camel,
|
||||
sentence, class, and title cases as well as ordinalize,
|
||||
deordinalize, demodulize, deconstantize, foreign key, table case, and pluralize/singularize are supported as both traits and pure functions
|
||||
acting on &str and String types.
|
||||
|
||||
-----
|
||||
## Documentation:
|
||||
|
||||
Documentation can be found here at the README or via rust docs below.
|
||||
|
||||
[Rust docs with examples](https://docs.rs/Inflector)
|
||||
|
||||
-----
|
||||
|
||||
## Installation:
|
||||
|
||||
### As a [crate](http://crates.io)
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
Inflector = "*"
|
||||
```
|
||||
|
||||
### Compile yourself:
|
||||
|
||||
1. Install [Rust and cargo](http://doc.crates.io/)
|
||||
2. git clone https://github.com/whatisinternet/Inflector
|
||||
3. Library: cd inflector && cargo build --release --lib
|
||||
4. You can find the library in target/release
|
||||
|
||||
## Usage / Example:
|
||||
|
||||
```rust
|
||||
...
|
||||
// to use methods like String.to_lower_case();
|
||||
extern crate inflector;
|
||||
use inflector::Inflector;
|
||||
...
|
||||
fn main() {
|
||||
...
|
||||
let camel_case_string: String = "some_string".to_camel_case();
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Or
|
||||
|
||||
```rust
|
||||
...
|
||||
// to use methods like to_snake_case(&str);
|
||||
extern crate inflector;
|
||||
|
||||
// use inflector::cases::classcase::to_class_case;
|
||||
// use inflector::cases::classcase::is_class_case;
|
||||
|
||||
// use inflector::cases::camelcase::to_camel_case;
|
||||
// use inflector::cases::camelcase::is_camel_case;
|
||||
|
||||
// use inflector::cases::pascalcase::to_pascal_case;
|
||||
// use inflector::cases::pascalcase::is_pascal_case;
|
||||
|
||||
// use inflector::cases::screamingsnakecase::to_screamingsnake_case;
|
||||
// use inflector::cases::screamingsnakecase::is_screamingsnake_case;
|
||||
|
||||
// use inflector::cases::snakecase::to_snake_case;
|
||||
// use inflector::cases::snakecase::is_snake_case;
|
||||
|
||||
// use inflector::cases::kebabcase::to_kebab_case;
|
||||
// use inflector::cases::kebabcase::is_kebab_case;
|
||||
|
||||
// use inflector::cases::traincase::to_train_case;
|
||||
// use inflector::cases::traincase::is_train_case;
|
||||
|
||||
// use inflector::cases::sentencecase::to_sentence_case;
|
||||
// use inflector::cases::sentencecase::is_sentence_case;
|
||||
|
||||
// use inflector::cases::titlecase::to_title_case;
|
||||
// use inflector::cases::titlecase::is_title_case;
|
||||
|
||||
// use inflector::cases::tablecase::to_table_case;
|
||||
// use inflector::cases::tablecase::is_table_case;
|
||||
|
||||
// use inflector::numbers::ordinalize::ordinalize;
|
||||
// use inflector::numbers::deordinalize::deordinalize;
|
||||
|
||||
// use inflector::suffix::foreignkey::to_foreign_key;
|
||||
// use inflector::suffix::foreignkey::is_foreign_key;
|
||||
|
||||
// use inflector::string::demodulize::demodulize;
|
||||
// use inflector::string::deconstantize::deconstantize;
|
||||
|
||||
// use inflector::string::pluralize::to_plural;
|
||||
// use inflector::string::singularize::to_singular;
|
||||
...
|
||||
fn main() {
|
||||
...
|
||||
let camel_case_string: String = to_camel_case("some_string");
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Advanced installation and usage:
|
||||
|
||||
If the project doesn't require singularize, pluralize, class, table, demodulize,
|
||||
deconstantize. Then in your `cargo.toml` you may wish to specify:
|
||||
|
||||
```toml
|
||||
[dependencies.Inflector]
|
||||
version = "*"
|
||||
default-features = false
|
||||
```
|
||||
|
||||
Or
|
||||
|
||||
```toml
|
||||
Inflector = {version="*", default-features=false}
|
||||
|
||||
```
|
||||
|
||||
To test this crate locally with features off try:
|
||||
|
||||
```shell
|
||||
cargo test --no-default-features
|
||||
```
|
||||
|
||||
## [Contributing](CONTRIBUTING.md)
|
||||
|
||||
This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
||||
370
.gear/predownloaded-development/vendor/Inflector/src/cases/camelcase/mod.rs
vendored
Normal file
370
.gear/predownloaded-development/vendor/Inflector/src/cases/camelcase/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
#![deny(warnings)]
|
||||
use cases::case::*;
|
||||
|
||||
/// Converts a `&str` to camelCase `String`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::to_camel_case;
|
||||
/// let mock_string: &str = "fooBar";
|
||||
/// let expected_string: String = "fooBar".to_string();
|
||||
/// let asserted_string: String = to_camel_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::to_camel_case;
|
||||
/// let mock_string: &str = "FOO_BAR";
|
||||
/// let expected_string: String = "fooBar".to_string();
|
||||
/// let asserted_string: String = to_camel_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::to_camel_case;
|
||||
/// let mock_string: &str = "Foo Bar";
|
||||
/// let expected_string: String = "fooBar".to_string();
|
||||
/// let asserted_string: String = to_camel_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::to_camel_case;
|
||||
/// let mock_string: &str = "foo_bar";
|
||||
/// let expected_string: String = "fooBar".to_string();
|
||||
/// let asserted_string: String = to_camel_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::to_camel_case;
|
||||
/// let mock_string: &str = "Foo bar";
|
||||
/// let expected_string: String = "fooBar".to_string();
|
||||
/// let asserted_string: String = to_camel_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::to_camel_case;
|
||||
/// let mock_string: &str = "foo-bar";
|
||||
/// let expected_string: String = "fooBar".to_string();
|
||||
/// let asserted_string: String = to_camel_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::to_camel_case;
|
||||
/// let mock_string: &str = "FooBar";
|
||||
/// let expected_string: String = "fooBar".to_string();
|
||||
/// let asserted_string: String = to_camel_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::to_camel_case;
|
||||
/// let mock_string: &str = "FooBar3";
|
||||
/// let expected_string: String = "fooBar3".to_string();
|
||||
/// let asserted_string: String = to_camel_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::to_camel_case;
|
||||
/// let mock_string: &str = "Foo-Bar";
|
||||
/// let expected_string: String = "fooBar".to_string();
|
||||
/// let asserted_string: String = to_camel_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
pub fn to_camel_case(non_camelized_string: &str) -> String {
|
||||
let options = CamelOptions {
|
||||
new_word: false,
|
||||
last_char: ' ',
|
||||
first_word: false,
|
||||
injectable_char: ' ',
|
||||
has_seperator: false,
|
||||
inverted: false,
|
||||
};
|
||||
to_case_camel_like(&non_camelized_string, options)
|
||||
}
|
||||
|
||||
/// Determines if a `&str` is camelCase bool``
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::is_camel_case;
|
||||
/// let mock_string: &str = "Foo";
|
||||
/// let asserted_bool: bool = is_camel_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::is_camel_case;
|
||||
/// let mock_string: &str = "foo";
|
||||
/// let asserted_bool: bool = is_camel_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::is_camel_case;
|
||||
/// let mock_string: &str = "foo-bar-string-that-is-really-really-long";
|
||||
/// let asserted_bool: bool = is_camel_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::is_camel_case;
|
||||
/// let mock_string: &str = "FooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_camel_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::is_camel_case;
|
||||
/// let mock_string: &str = "fooBarIsAReallyReally3LongString";
|
||||
/// let asserted_bool: bool = is_camel_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::is_camel_case;
|
||||
/// let mock_string: &str = "fooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_camel_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::is_camel_case;
|
||||
/// let mock_string: &str = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG";
|
||||
/// let asserted_bool: bool = is_camel_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::is_camel_case;
|
||||
/// let mock_string: &str = "foo_bar_string_that_is_really_really_long";
|
||||
/// let asserted_bool: bool = is_camel_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::is_camel_case;
|
||||
/// let mock_string: &str = "Foo bar string that is really really long";
|
||||
/// let asserted_bool: bool = is_camel_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::camelcase::is_camel_case;
|
||||
/// let mock_string: &str = "Foo Bar Is A Really Really Long String";
|
||||
/// let asserted_bool: bool = is_camel_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
/// ```
|
||||
pub fn is_camel_case(test_string: &str) -> bool {
|
||||
to_camel_case(&test_string.clone()) == test_string
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "unstable", test))]
|
||||
mod benchmarks {
|
||||
extern crate test;
|
||||
use self::test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_camel0(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let test_string = "Foo bar";
|
||||
super::to_camel_case(test_string)
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_camel1(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let test_string = "foo_bar";
|
||||
super::to_camel_case(test_string)
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_camel2(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let test_string = "fooBar";
|
||||
super::to_camel_case(test_string)
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_is_camel(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let test_string: &str = "Foo bar";
|
||||
super::is_camel_case(test_string)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ::to_camel_case;
|
||||
use ::is_camel_case;
|
||||
|
||||
#[test]
|
||||
fn from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
let expected: String = "fooBar".to_owned();
|
||||
assert_eq!(to_camel_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
let expected: String = "fooBar".to_owned();
|
||||
assert_eq!(to_camel_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
let expected: String = "fooBar".to_owned();
|
||||
assert_eq!(to_camel_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
let expected: String = "fooBar".to_owned();
|
||||
assert_eq!(to_camel_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
let expected: String = "fooBar".to_owned();
|
||||
assert_eq!(to_camel_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
let expected: String = "fooBar".to_owned();
|
||||
assert_eq!(to_camel_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
let expected: String = "fooBar".to_owned();
|
||||
assert_eq!(to_camel_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
let expected: String = "fooBar".to_owned();
|
||||
assert_eq!(to_camel_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_case_with_loads_of_space() {
|
||||
let convertable_string: String = "foo bar".to_owned();
|
||||
let expected: String = "fooBar".to_owned();
|
||||
assert_eq!(to_camel_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_name_with_a_dot() {
|
||||
let convertable_string: String = "Robert C. Martin".to_owned();
|
||||
let expected: String = "robertCMartin".to_owned();
|
||||
assert_eq!(to_camel_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_text_with_bad_chars() {
|
||||
let convertable_string: String = "Random text with *(bad) chars".to_owned();
|
||||
let expected: String = "randomTextWithBadChars".to_owned();
|
||||
assert_eq!(to_camel_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_bad_chars() {
|
||||
let convertable_string: String = "trailing bad_chars*(()())".to_owned();
|
||||
let expected: String = "trailingBadChars".to_owned();
|
||||
assert_eq!(to_camel_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leading_bad_chars() {
|
||||
let convertable_string: String = "-!#$%leading bad chars".to_owned();
|
||||
let expected: String = "leadingBadChars".to_owned();
|
||||
assert_eq!(to_camel_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapped_in_bad_chars() {
|
||||
let convertable_string: String = "-!#$%wrapped in bad chars&*^*&(&*^&(<><?>><?><>))".to_owned();
|
||||
let expected: String = "wrappedInBadChars".to_owned();
|
||||
assert_eq!(to_camel_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn has_a_sign() {
|
||||
let convertable_string: String = "has a + sign".to_owned();
|
||||
let expected: String = "hasASign".to_owned();
|
||||
assert_eq!(to_camel_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
assert_eq!(is_camel_case(&convertable_string), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
assert_eq!(is_camel_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
assert_eq!(is_camel_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
assert_eq!(is_camel_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
assert_eq!(is_camel_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(is_camel_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(is_camel_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
assert_eq!(is_camel_case(&convertable_string), false)
|
||||
}
|
||||
}
|
||||
|
||||
303
.gear/predownloaded-development/vendor/Inflector/src/cases/case/mod.rs
vendored
Normal file
303
.gear/predownloaded-development/vendor/Inflector/src/cases/case/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
#![deny(warnings)]
|
||||
#[allow(unknown_lints)]
|
||||
#[allow(unused_imports)]
|
||||
use std::ascii::*;
|
||||
|
||||
pub struct CamelOptions {
|
||||
pub new_word: bool,
|
||||
pub last_char: char,
|
||||
pub first_word: bool,
|
||||
pub injectable_char: char,
|
||||
pub has_seperator: bool,
|
||||
pub inverted: bool,
|
||||
}
|
||||
|
||||
pub fn to_case_snake_like(convertable_string: &str, replace_with: &str, case: &str) -> String {
|
||||
let mut first_character: bool = true;
|
||||
let mut result: String = String::with_capacity(convertable_string.len() * 2);
|
||||
for char_with_index in trim_right(convertable_string).char_indices() {
|
||||
if char_is_seperator(&char_with_index.1) {
|
||||
if !first_character {
|
||||
first_character = true;
|
||||
result.push(replace_with.chars().nth(0).unwrap_or('_'));
|
||||
}
|
||||
} else if requires_seperator(char_with_index, first_character, &convertable_string) {
|
||||
first_character = false;
|
||||
result = snake_like_with_seperator(result, replace_with, &char_with_index.1, case)
|
||||
} else {
|
||||
first_character = false;
|
||||
result = snake_like_no_seperator(result, &char_with_index.1, case)
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn to_case_camel_like(convertable_string: &str, camel_options: CamelOptions) -> String {
|
||||
let mut new_word: bool = camel_options.new_word;
|
||||
let mut first_word: bool = camel_options.first_word;
|
||||
let mut last_char: char = camel_options.last_char;
|
||||
let mut found_real_char: bool = false;
|
||||
let mut result: String = String::with_capacity(convertable_string.len() * 2);
|
||||
for character in trim_right(convertable_string).chars() {
|
||||
if char_is_seperator(&character) && found_real_char {
|
||||
new_word = true;
|
||||
} else if !found_real_char && is_not_alphanumeric(character) {
|
||||
continue;
|
||||
} else if character.is_numeric() {
|
||||
found_real_char = true;
|
||||
new_word = true;
|
||||
result.push(character);
|
||||
} else if last_char_lower_current_is_upper_or_new_word(new_word, last_char, character) {
|
||||
found_real_char = true;
|
||||
new_word = false;
|
||||
result = append_on_new_word(result, first_word, character, &camel_options);
|
||||
first_word = false;
|
||||
} else {
|
||||
found_real_char = true;
|
||||
last_char = character;
|
||||
result.push(character.to_ascii_lowercase());
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn append_on_new_word(mut result: String, first_word: bool, character: char, camel_options: &CamelOptions) -> String {
|
||||
if not_first_word_and_has_seperator(first_word, camel_options.has_seperator) {
|
||||
result.push(camel_options.injectable_char);
|
||||
}
|
||||
if first_word_or_not_inverted(first_word, camel_options.inverted) {
|
||||
result.push(character.to_ascii_uppercase());
|
||||
} else {
|
||||
result.push(character.to_ascii_lowercase());
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn not_first_word_and_has_seperator(first_word: bool, has_seperator: bool) -> bool {
|
||||
has_seperator && !first_word
|
||||
}
|
||||
|
||||
fn first_word_or_not_inverted(first_word: bool, inverted: bool) -> bool {
|
||||
!inverted || first_word
|
||||
}
|
||||
|
||||
|
||||
fn last_char_lower_current_is_upper_or_new_word(new_word: bool, last_char: char, character: char) -> bool{
|
||||
new_word ||
|
||||
((last_char.is_lowercase() && character.is_uppercase()) &&
|
||||
(last_char != ' '))
|
||||
}
|
||||
|
||||
fn char_is_seperator(character: &char) -> bool {
|
||||
is_not_alphanumeric(*character)
|
||||
}
|
||||
|
||||
fn trim_right(convertable_string: &str) -> &str {
|
||||
convertable_string.trim_end_matches(is_not_alphanumeric)
|
||||
}
|
||||
|
||||
fn is_not_alphanumeric(character: char) -> bool {
|
||||
!character.is_alphanumeric()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn requires_seperator(char_with_index: (usize, char), first_character: bool, convertable_string: &str) -> bool {
|
||||
!first_character &&
|
||||
char_is_uppercase(char_with_index.1) &&
|
||||
next_or_previous_char_is_lowercase(convertable_string, char_with_index.0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn snake_like_no_seperator(mut accumlator: String, current_char: &char, case: &str) -> String {
|
||||
if case == "lower" {
|
||||
accumlator.push(current_char.to_ascii_lowercase());
|
||||
accumlator
|
||||
} else {
|
||||
accumlator.push(current_char.to_ascii_uppercase());
|
||||
accumlator
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn snake_like_with_seperator(mut accumlator: String, replace_with: &str, current_char: &char, case: &str) -> String {
|
||||
if case == "lower" {
|
||||
accumlator.push(replace_with.chars().nth(0).unwrap_or('_'));
|
||||
accumlator.push(current_char.to_ascii_lowercase());
|
||||
accumlator
|
||||
} else {
|
||||
accumlator.push(replace_with.chars().nth(0).unwrap_or('_'));
|
||||
accumlator.push(current_char.to_ascii_uppercase());
|
||||
accumlator
|
||||
}
|
||||
}
|
||||
|
||||
fn next_or_previous_char_is_lowercase(convertable_string: &str, char_with_index: usize) -> bool {
|
||||
convertable_string.chars().nth(char_with_index + 1).unwrap_or('A').is_lowercase() ||
|
||||
convertable_string.chars().nth(char_with_index - 1).unwrap_or('A').is_lowercase()
|
||||
}
|
||||
|
||||
fn char_is_uppercase(test_char: char) -> bool {
|
||||
test_char == test_char.to_ascii_uppercase()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trim_bad_chars() {
|
||||
assert_eq!("abc", trim_right("abc----^"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trim_bad_chars_when_none_are_bad() {
|
||||
assert_eq!("abc", trim_right("abc"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_not_alphanumeric_on_is_alphanumeric() {
|
||||
assert!(!is_not_alphanumeric('a'))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_not_alphanumeric_on_is_not_alphanumeric() {
|
||||
assert!(is_not_alphanumeric('_'))
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_char_is_uppercase_when_it_is() {
|
||||
assert_eq!(char_is_uppercase('A'), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_char_is_uppercase_when_it_is_not() {
|
||||
assert_eq!(char_is_uppercase('a'), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_next_or_previous_char_is_lowercase_true() {
|
||||
assert_eq!(next_or_previous_char_is_lowercase("TestWWW", 3), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_next_or_previous_char_is_lowercase_false() {
|
||||
assert_eq!(next_or_previous_char_is_lowercase("TestWWW", 5), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snake_like_with_seperator_lowers() {
|
||||
assert_eq!(snake_like_with_seperator("".to_owned(), "^", &'c', "lower"), "^c".to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snake_like_with_seperator_upper() {
|
||||
assert_eq!(snake_like_with_seperator("".to_owned(), "^", &'c', "upper"), "^C".to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snake_like_no_seperator_lower() {
|
||||
assert_eq!(snake_like_no_seperator("".to_owned(), &'C', "lower"), "c".to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snake_like_no_seperator_upper() {
|
||||
assert_eq!(snake_like_no_seperator("".to_owned(), &'c', "upper"), "C".to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn requires_seperator_upper_not_first_wrap_is_safe_current_upper() {
|
||||
assert_eq!(requires_seperator((2, 'C'), false, "test"), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn requires_seperator_upper_not_first_wrap_is_safe_current_lower() {
|
||||
assert_eq!(requires_seperator((2, 'c'), false, "test"), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn requires_seperator_upper_first_wrap_is_safe_current_upper() {
|
||||
assert_eq!(requires_seperator((0, 'T'), true, "Test"), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn requires_seperator_upper_first_wrap_is_safe_current_lower() {
|
||||
assert_eq!(requires_seperator((0, 't'), true, "Test"), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn requires_seperator_upper_first_wrap_is_safe_current_lower_next_is_too() {
|
||||
assert_eq!(requires_seperator((0, 't'), true, "test"), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_char_is_seperator_dash() {
|
||||
assert_eq!(char_is_seperator(&'-'), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_char_is_seperator_underscore() {
|
||||
assert_eq!(char_is_seperator(&'_'), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_char_is_seperator_space() {
|
||||
assert_eq!(char_is_seperator(&' '), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_char_is_seperator_when_not() {
|
||||
assert_eq!(char_is_seperator(&'A'), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_last_char_lower_current_is_upper_or_new_word_with_new_word() {
|
||||
assert_eq!(last_char_lower_current_is_upper_or_new_word(true, ' ', '-'), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_last_char_lower_current_is_upper_or_new_word_last_char_space() {
|
||||
assert_eq!(last_char_lower_current_is_upper_or_new_word(false, ' ', '-'), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_last_char_lower_current_is_upper_or_new_word_last_char_lower_current_upper() {
|
||||
assert_eq!(last_char_lower_current_is_upper_or_new_word(false, 'a', 'A'), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_last_char_lower_current_is_upper_or_new_word_last_char_upper_current_upper() {
|
||||
assert_eq!(last_char_lower_current_is_upper_or_new_word(false, 'A', 'A'), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_last_char_lower_current_is_upper_or_new_word_last_char_upper_current_lower() {
|
||||
assert_eq!(last_char_lower_current_is_upper_or_new_word(false, 'A', 'a'), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_first_word_or_not_inverted_with_first_word() {
|
||||
assert_eq!(first_word_or_not_inverted(true, false), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_first_word_or_not_inverted_not_first_word_not_inverted() {
|
||||
assert_eq!(first_word_or_not_inverted(false, false), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_first_word_or_not_inverted_not_first_word_is_inverted() {
|
||||
assert_eq!(first_word_or_not_inverted(false, true), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_not_first_word_and_has_seperator_is_first_and_not_seperator() {
|
||||
assert_eq!(not_first_word_and_has_seperator(true, false), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_not_first_word_and_has_seperator_not_first_and_not_seperator() {
|
||||
assert_eq!(not_first_word_and_has_seperator(false, false), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_not_first_word_and_has_seperator_not_first_and_has_seperator() {
|
||||
assert_eq!(not_first_word_and_has_seperator(false, true), true)
|
||||
}
|
||||
393
.gear/predownloaded-development/vendor/Inflector/src/cases/classcase/mod.rs
vendored
Normal file
393
.gear/predownloaded-development/vendor/Inflector/src/cases/classcase/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
#![deny(warnings)]
|
||||
use cases::case::*;
|
||||
#[cfg(feature = "heavyweight")]
|
||||
use string::singularize::to_singular;
|
||||
#[cfg(feature = "heavyweight")]
|
||||
/// Converts a `&str` to `ClassCase` `String`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::to_class_case;
|
||||
/// let mock_string: &str = "FooBar";
|
||||
/// let expected_string: String = "FooBar".to_string();
|
||||
/// let asserted_string: String = to_class_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::to_class_case;
|
||||
/// let mock_string: &str = "FooBars";
|
||||
/// let expected_string: String = "FooBar".to_string();
|
||||
/// let asserted_string: String = to_class_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::to_class_case;
|
||||
/// let mock_string: &str = "Foo Bar";
|
||||
/// let expected_string: String = "FooBar".to_string();
|
||||
/// let asserted_string: String = to_class_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::to_class_case;
|
||||
/// let mock_string: &str = "foo-bar";
|
||||
/// let expected_string: String = "FooBar".to_string();
|
||||
/// let asserted_string: String = to_class_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::to_class_case;
|
||||
/// let mock_string: &str = "fooBar";
|
||||
/// let expected_string: String = "FooBar".to_string();
|
||||
/// let asserted_string: String = to_class_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::to_class_case;
|
||||
/// let mock_string: &str = "FOO_BAR";
|
||||
/// let expected_string: String = "FooBar".to_string();
|
||||
/// let asserted_string: String = to_class_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::to_class_case;
|
||||
/// let mock_string: &str = "foo_bar";
|
||||
/// let expected_string: String = "FooBar".to_string();
|
||||
/// let asserted_string: String = to_class_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::to_class_case;
|
||||
/// let mock_string: &str = "foo_bars";
|
||||
/// let expected_string: String = "FooBar".to_string();
|
||||
/// let asserted_string: String = to_class_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::to_class_case;
|
||||
/// let mock_string: &str = "Foo bar";
|
||||
/// let expected_string: String = "FooBar".to_string();
|
||||
/// let asserted_string: String = to_class_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
pub fn to_class_case(non_class_case_string: &str) -> String {
|
||||
let options = CamelOptions {
|
||||
new_word: true,
|
||||
last_char: ' ',
|
||||
first_word: false,
|
||||
injectable_char: ' ',
|
||||
has_seperator: false,
|
||||
inverted: false,
|
||||
};
|
||||
let class_plural = to_case_camel_like(non_class_case_string, options);
|
||||
let split: (&str, &str) =
|
||||
class_plural.split_at(class_plural.rfind(char::is_uppercase).unwrap_or(0));
|
||||
format!("{}{}", split.0, to_singular(split.1))
|
||||
}
|
||||
|
||||
#[cfg(feature = "heavyweight")]
|
||||
/// Determines if a `&str` is `ClassCase` `bool`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::is_class_case;
|
||||
/// let mock_string: &str = "Foo";
|
||||
/// let asserted_bool: bool = is_class_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::is_class_case;
|
||||
/// let mock_string: &str = "foo";
|
||||
/// let asserted_bool: bool = is_class_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::is_class_case;
|
||||
/// let mock_string: &str = "FooBarIsAReallyReallyLongStrings";
|
||||
/// let asserted_bool: bool = is_class_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::is_class_case;
|
||||
/// let mock_string: &str = "FooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_class_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::is_class_case;
|
||||
/// let mock_string: &str = "foo-bar-string-that-is-really-really-long";
|
||||
/// let asserted_bool: bool = is_class_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::is_class_case;
|
||||
/// let mock_string: &str = "foo_bar_is_a_really_really_long_strings";
|
||||
/// let asserted_bool: bool = is_class_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::is_class_case;
|
||||
/// let mock_string: &str = "fooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_class_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::is_class_case;
|
||||
/// let mock_string: &str = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG";
|
||||
/// let asserted_bool: bool = is_class_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::is_class_case;
|
||||
/// let mock_string: &str = "foo_bar_string_that_is_really_really_long";
|
||||
/// let asserted_bool: bool = is_class_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::is_class_case;
|
||||
/// let mock_string: &str = "Foo bar string that is really really long";
|
||||
/// let asserted_bool: bool = is_class_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::classcase::is_class_case;
|
||||
/// let mock_string: &str = "Foo Bar Is A Really Really Long String";
|
||||
/// let asserted_bool: bool = is_class_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
pub fn is_class_case(test_string: &str) -> bool {
|
||||
to_class_case(&test_string.clone()) == test_string
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "unstable", test))]
|
||||
#[cfg(feature = "heavyweight")]
|
||||
mod benchmarks {
|
||||
extern crate test;
|
||||
use self::test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_class_case(b: &mut Bencher) {
|
||||
b.iter(|| super::to_class_case("Foo bar"));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_is_class(b: &mut Bencher) {
|
||||
b.iter(|| super::is_class_case("Foo bar"));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_class_from_snake(b: &mut Bencher) {
|
||||
b.iter(|| super::to_class_case("foo_bar"));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "heavyweight")]
|
||||
mod tests {
|
||||
use ::to_class_case;
|
||||
use ::is_class_case;
|
||||
|
||||
#[test]
|
||||
fn from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_class_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_class_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_class_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_class_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_class_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_class_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_screaming_class_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_class_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_class_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_table_case() {
|
||||
let convertable_string: String = "foo_bars".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_class_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_case_with_loads_of_space() {
|
||||
let convertable_string: String = "foo bar".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_class_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_name_with_a_dot() {
|
||||
let convertable_string: String = "Robert C. Martin".to_owned();
|
||||
let expected: String = "RobertCMartin".to_owned();
|
||||
assert_eq!(to_class_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_text_with_bad_chars() {
|
||||
let convertable_string: String = "Random text with *(bad) chars".to_owned();
|
||||
let expected: String = "RandomTextWithBadChar".to_owned();
|
||||
assert_eq!(to_class_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_bad_chars() {
|
||||
let convertable_string: String = "trailing bad_chars*(()())".to_owned();
|
||||
let expected: String = "TrailingBadChar".to_owned();
|
||||
assert_eq!(to_class_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leading_bad_chars() {
|
||||
let convertable_string: String = "-!#$%leading bad chars".to_owned();
|
||||
let expected: String = "LeadingBadChar".to_owned();
|
||||
assert_eq!(to_class_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapped_in_bad_chars() {
|
||||
let convertable_string: String = "-!#$%wrapped in bad chars&*^*&(&*^&(<><?>><?><>))".to_owned();
|
||||
let expected: String = "WrappedInBadChar".to_owned();
|
||||
assert_eq!(to_class_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn has_a_sign() {
|
||||
let convertable_string: String = "has a + sign".to_owned();
|
||||
let expected: String = "HasASign".to_owned();
|
||||
assert_eq!(to_class_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_class_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
assert_eq!(is_class_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
assert_eq!(is_class_case(&convertable_string), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
assert_eq!(is_class_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
assert_eq!(is_class_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
assert_eq!(is_class_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(is_class_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(is_class_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
assert_eq!(is_class_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_table_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
assert_eq!(is_class_case(&convertable_string), true)
|
||||
}
|
||||
}
|
||||
|
||||
262
.gear/predownloaded-development/vendor/Inflector/src/cases/kebabcase/mod.rs
vendored
Normal file
262
.gear/predownloaded-development/vendor/Inflector/src/cases/kebabcase/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
#![deny(warnings)]
|
||||
use cases::case::*;
|
||||
/// Determines if a `&str` is `kebab-case`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::kebabcase::is_kebab_case;
|
||||
/// let mock_string: &str = "foo-bar-string-that-is-really-really-long";
|
||||
/// let asserted_bool: bool = is_kebab_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::kebabcase::is_kebab_case;
|
||||
/// let mock_string: &str = "FooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_kebab_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::kebabcase::is_kebab_case;
|
||||
/// let mock_string: &str = "fooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_kebab_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::kebabcase::is_kebab_case;
|
||||
/// let mock_string: &str = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG";
|
||||
/// let asserted_bool: bool = is_kebab_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::kebabcase::is_kebab_case;
|
||||
/// let mock_string: &str = "foo_bar_string_that_is_really_really_long";
|
||||
/// let asserted_bool: bool = is_kebab_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::kebabcase::is_kebab_case;
|
||||
/// let mock_string: &str = "Foo bar string that is really really long";
|
||||
/// let asserted_bool: bool = is_kebab_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::kebabcase::is_kebab_case;
|
||||
/// let mock_string: &str = "Foo Bar Is A Really Really Long String";
|
||||
/// let asserted_bool: bool = is_kebab_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
pub fn is_kebab_case(test_string: &str) -> bool {
|
||||
test_string == to_kebab_case(test_string.clone())
|
||||
}
|
||||
|
||||
/// Converts a `&str` to `kebab-case` `String`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::kebabcase::to_kebab_case;
|
||||
/// let mock_string: &str = "foo-bar";
|
||||
/// let expected_string: String = "foo-bar".to_string();
|
||||
/// let asserted_string: String = to_kebab_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::kebabcase::to_kebab_case;
|
||||
/// let mock_string: &str = "FOO_BAR";
|
||||
/// let expected_string: String = "foo-bar".to_string();
|
||||
/// let asserted_string: String = to_kebab_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::kebabcase::to_kebab_case;
|
||||
/// let mock_string: &str = "foo_bar";
|
||||
/// let expected_string: String = "foo-bar".to_string();
|
||||
/// let asserted_string: String = to_kebab_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::kebabcase::to_kebab_case;
|
||||
/// let mock_string: &str = "Foo Bar";
|
||||
/// let expected_string: String = "foo-bar".to_string();
|
||||
/// let asserted_string: String = to_kebab_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::kebabcase::to_kebab_case;
|
||||
/// let mock_string: &str = "Foo bar";
|
||||
/// let expected_string: String = "foo-bar".to_string();
|
||||
/// let asserted_string: String = to_kebab_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::kebabcase::to_kebab_case;
|
||||
/// let mock_string: &str = "FooBar";
|
||||
/// let expected_string: String = "foo-bar".to_string();
|
||||
/// let asserted_string: String = to_kebab_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::kebabcase::to_kebab_case;
|
||||
/// let mock_string: &str = "fooBar";
|
||||
/// let expected_string: String = "foo-bar".to_string();
|
||||
/// let asserted_string: String = to_kebab_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
pub fn to_kebab_case(non_kebab_case_string: &str) -> String {
|
||||
to_case_snake_like(non_kebab_case_string, "-", "lower")
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "unstable", test))]
|
||||
mod benchmarks {
|
||||
extern crate test;
|
||||
use self::test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_kebab(b: &mut Bencher) {
|
||||
b.iter(|| super::to_kebab_case("Foo bar"));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_is_kebab(b: &mut Bencher) {
|
||||
b.iter(|| super::is_kebab_case("Foo bar"));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_kebab_from_snake(b: &mut Bencher) {
|
||||
b.iter(|| super::to_kebab_case("test_test_test"));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ::to_kebab_case;
|
||||
use ::is_kebab_case;
|
||||
|
||||
#[test]
|
||||
fn from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
let expected: String = "foo-bar".to_owned();
|
||||
assert_eq!(to_kebab_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
let expected: String = "foo-bar".to_owned();
|
||||
assert_eq!(to_kebab_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
let expected: String = "foo-bar".to_owned();
|
||||
assert_eq!(to_kebab_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
let expected: String = "foo-bar".to_owned();
|
||||
assert_eq!(to_kebab_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
let expected: String = "foo-bar".to_owned();
|
||||
assert_eq!(to_kebab_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
let expected: String = "foo-bar".to_owned();
|
||||
assert_eq!(to_kebab_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
let expected: String = "foo-bar".to_owned();
|
||||
assert_eq!(to_kebab_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
let expected: String = "foo-bar".to_owned();
|
||||
assert_eq!(to_kebab_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
assert_eq!(is_kebab_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
assert_eq!(is_kebab_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
assert_eq!(is_kebab_case(&convertable_string), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
assert_eq!(is_kebab_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
assert_eq!(is_kebab_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(is_kebab_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(is_kebab_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
assert_eq!(is_kebab_case(&convertable_string), false)
|
||||
}
|
||||
}
|
||||
|
||||
52
.gear/predownloaded-development/vendor/Inflector/src/cases/mod.rs
vendored
Normal file
52
.gear/predownloaded-development/vendor/Inflector/src/cases/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
mod case;
|
||||
/// Provides conversion to and detection of class case strings.
|
||||
///
|
||||
/// This version singularizes strings.
|
||||
///
|
||||
/// Example string `ClassCase`
|
||||
pub mod classcase;
|
||||
|
||||
/// Provides conversion to and detection of camel case strings.
|
||||
///
|
||||
/// Example string `camelCase`
|
||||
pub mod camelcase;
|
||||
|
||||
/// Provides conversion to and detection of snake case strings.
|
||||
///
|
||||
/// Example string `snake_case`
|
||||
pub mod snakecase;
|
||||
|
||||
/// Provides conversion to and detection of screaming snake case strings.
|
||||
///
|
||||
/// Example string `SCREAMING_SNAKE_CASE`
|
||||
pub mod screamingsnakecase;
|
||||
|
||||
/// Provides conversion to and detection of kebab case strings.
|
||||
///
|
||||
/// Example string `kebab-case`
|
||||
pub mod kebabcase;
|
||||
|
||||
/// Provides conversion to and detection of train case strings.
|
||||
///
|
||||
/// Example string `Train-Case`
|
||||
pub mod traincase;
|
||||
|
||||
/// Provides conversion to and detection of sentence case strings.
|
||||
///
|
||||
/// Example string `Sentence case`
|
||||
pub mod sentencecase;
|
||||
|
||||
/// Provides conversion to and detection of title case strings.
|
||||
///
|
||||
/// Example string `Title Case`
|
||||
pub mod titlecase;
|
||||
|
||||
/// Provides conversion to and detection of table case strings.
|
||||
///
|
||||
/// Example string `table_cases`
|
||||
pub mod tablecase;
|
||||
|
||||
/// Provides conversion to pascal case strings.
|
||||
///
|
||||
/// Example string `PascalCase`
|
||||
pub mod pascalcase;
|
||||
360
.gear/predownloaded-development/vendor/Inflector/src/cases/pascalcase/mod.rs
vendored
Normal file
360
.gear/predownloaded-development/vendor/Inflector/src/cases/pascalcase/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
#![deny(warnings)]
|
||||
use cases::case::*;
|
||||
/// Converts a `&str` to pascalCase `String`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::to_pascal_case;
|
||||
/// let mock_string: &str = "fooBar";
|
||||
/// let expected_string: String = "FooBar".to_string();
|
||||
/// let asserted_string: String = to_pascal_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::to_pascal_case;
|
||||
/// let mock_string: &str = "FOO_BAR";
|
||||
/// let expected_string: String = "FooBar".to_string();
|
||||
/// let asserted_string: String = to_pascal_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::to_pascal_case;
|
||||
/// let mock_string: &str = "Foo Bar";
|
||||
/// let expected_string: String = "FooBar".to_string();
|
||||
/// let asserted_string: String = to_pascal_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::to_pascal_case;
|
||||
/// let mock_string: &str = "foo_bar";
|
||||
/// let expected_string: String = "FooBar".to_string();
|
||||
/// let asserted_string: String = to_pascal_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::to_pascal_case;
|
||||
/// let mock_string: &str = "Foo bar";
|
||||
/// let expected_string: String = "FooBar".to_string();
|
||||
/// let asserted_string: String = to_pascal_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::to_pascal_case;
|
||||
/// let mock_string: &str = "foo-bar";
|
||||
/// let expected_string: String = "FooBar".to_string();
|
||||
/// let asserted_string: String = to_pascal_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::to_pascal_case;
|
||||
/// let mock_string: &str = "FooBar";
|
||||
/// let expected_string: String = "FooBar".to_string();
|
||||
/// let asserted_string: String = to_pascal_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::to_pascal_case;
|
||||
/// let mock_string: &str = "FooBar3";
|
||||
/// let expected_string: String = "FooBar3".to_string();
|
||||
/// let asserted_string: String = to_pascal_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
pub fn to_pascal_case(non_pascalized_string: &str) -> String {
|
||||
let options = CamelOptions {
|
||||
new_word: true,
|
||||
last_char: ' ',
|
||||
first_word: false,
|
||||
injectable_char: ' ',
|
||||
has_seperator: false,
|
||||
inverted: false,
|
||||
};
|
||||
to_case_camel_like(non_pascalized_string, options)
|
||||
}
|
||||
|
||||
/// Determines if a `&str` is pascalCase bool``
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::is_pascal_case;
|
||||
/// let mock_string: &str = "Foo";
|
||||
/// let asserted_bool: bool = is_pascal_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::is_pascal_case;
|
||||
/// let mock_string: &str = "foo";
|
||||
/// let asserted_bool: bool = is_pascal_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::is_pascal_case;
|
||||
/// let mock_string: &str = "foo-bar-string-that-is-really-really-long";
|
||||
/// let asserted_bool: bool = is_pascal_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::is_pascal_case;
|
||||
/// let mock_string: &str = "FooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_pascal_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::is_pascal_case;
|
||||
/// let mock_string: &str = "FooBarIsAReallyReally3LongString";
|
||||
/// let asserted_bool: bool = is_pascal_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::is_pascal_case;
|
||||
/// let mock_string: &str = "FooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_pascal_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::is_pascal_case;
|
||||
/// let mock_string: &str = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG";
|
||||
/// let asserted_bool: bool = is_pascal_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::is_pascal_case;
|
||||
/// let mock_string: &str = "foo_bar_string_that_is_really_really_long";
|
||||
/// let asserted_bool: bool = is_pascal_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::is_pascal_case;
|
||||
/// let mock_string: &str = "Foo bar string that is really really long";
|
||||
/// let asserted_bool: bool = is_pascal_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::pascalcase::is_pascal_case;
|
||||
/// let mock_string: &str = "Foo Bar Is A Really Really Long String";
|
||||
/// let asserted_bool: bool = is_pascal_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
/// ```
|
||||
pub fn is_pascal_case(test_string: &str) -> bool {
|
||||
to_pascal_case(test_string.clone()) == test_string
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "unstable", test))]
|
||||
mod benchmarks {
|
||||
extern crate test;
|
||||
use self::test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_pascal0(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let test_string = "Foo bar";
|
||||
super::to_pascal_case(test_string)
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_pascal1(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let test_string = "foo_bar";
|
||||
super::to_pascal_case(test_string)
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_pascal2(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let test_string = "fooBar";
|
||||
super::to_pascal_case(test_string)
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_is_pascal(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let test_string: &str = "Foo bar";
|
||||
super::is_pascal_case(test_string)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ::to_pascal_case;
|
||||
use ::is_pascal_case;
|
||||
|
||||
#[test]
|
||||
fn from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_pascal_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_pascal_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_pascal_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_pascal_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_pascal_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_pascal_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_pascal_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_pascal_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_case_with_loads_of_space() {
|
||||
let convertable_string: String = "foo bar".to_owned();
|
||||
let expected: String = "FooBar".to_owned();
|
||||
assert_eq!(to_pascal_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_name_with_a_dot() {
|
||||
let convertable_string: String = "Robert C. Martin".to_owned();
|
||||
let expected: String = "RobertCMartin".to_owned();
|
||||
assert_eq!(to_pascal_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_text_with_bad_chars() {
|
||||
let convertable_string: String = "Random text with *(bad) chars".to_owned();
|
||||
let expected: String = "RandomTextWithBadChars".to_owned();
|
||||
assert_eq!(to_pascal_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_bad_chars() {
|
||||
let convertable_string: String = "trailing bad_chars*(()())".to_owned();
|
||||
let expected: String = "TrailingBadChars".to_owned();
|
||||
assert_eq!(to_pascal_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leading_bad_chars() {
|
||||
let convertable_string: String = "-!#$%leading bad chars".to_owned();
|
||||
let expected: String = "LeadingBadChars".to_owned();
|
||||
assert_eq!(to_pascal_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapped_in_bad_chars() {
|
||||
let convertable_string: String = "-!#$%wrapped in bad chars&*^*&(&*^&(<><?>><?><>))".to_owned();
|
||||
let expected: String = "WrappedInBadChars".to_owned();
|
||||
assert_eq!(to_pascal_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn has_a_sign() {
|
||||
let convertable_string: String = "has a + sign".to_owned();
|
||||
let expected: String = "HasASign".to_owned();
|
||||
assert_eq!(to_pascal_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
assert_eq!(is_pascal_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
assert_eq!(is_pascal_case(&convertable_string), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
assert_eq!(is_pascal_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
assert_eq!(is_pascal_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
assert_eq!(is_pascal_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(is_pascal_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(is_pascal_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
assert_eq!(is_pascal_case(&convertable_string), false)
|
||||
}
|
||||
}
|
||||
253
.gear/predownloaded-development/vendor/Inflector/src/cases/screamingsnakecase/mod.rs
vendored
Normal file
253
.gear/predownloaded-development/vendor/Inflector/src/cases/screamingsnakecase/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
#![deny(warnings)]
|
||||
use cases::case::*;
|
||||
/// Converts a `&str` to `SCREAMING_SNAKE_CASE` `String`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::screamingsnakecase::to_screaming_snake_case;
|
||||
/// let mock_string: &str = "foo_bar";
|
||||
/// let expected_string: String = "FOO_BAR".to_string();
|
||||
/// let asserted_string: String = to_screaming_snake_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::screamingsnakecase::to_screaming_snake_case;
|
||||
/// let mock_string: &str = "HTTP Foo bar";
|
||||
/// let expected_string: String = "HTTP_FOO_BAR".to_string();
|
||||
/// let asserted_string: String = to_screaming_snake_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::screamingsnakecase::to_screaming_snake_case;
|
||||
/// let mock_string: &str = "Foo bar";
|
||||
/// let expected_string: String = "FOO_BAR".to_string();
|
||||
/// let asserted_string: String = to_screaming_snake_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::screamingsnakecase::to_screaming_snake_case;
|
||||
/// let mock_string: &str = "Foo Bar";
|
||||
/// let expected_string: String = "FOO_BAR".to_string();
|
||||
/// let asserted_string: String = to_screaming_snake_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::screamingsnakecase::to_screaming_snake_case;
|
||||
/// let mock_string: &str = "FooBar";
|
||||
/// let expected_string: String = "FOO_BAR".to_string();
|
||||
/// let asserted_string: String = to_screaming_snake_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::screamingsnakecase::to_screaming_snake_case;
|
||||
/// let mock_string: &str = "fooBar";
|
||||
/// let expected_string: String = "FOO_BAR".to_string();
|
||||
/// let asserted_string: String = to_screaming_snake_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::screamingsnakecase::to_screaming_snake_case;
|
||||
/// let mock_string: &str = "fooBar3";
|
||||
/// let expected_string: String = "FOO_BAR_3".to_string();
|
||||
/// let asserted_string: String = to_screaming_snake_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
pub fn to_screaming_snake_case(non_snake_case_string: &str) -> String {
|
||||
to_case_snake_like(non_snake_case_string, "_", "upper")
|
||||
}
|
||||
|
||||
/// Determines of a `&str` is `SCREAMING_SNAKE_CASE`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::screamingsnakecase::is_screaming_snake_case;
|
||||
/// let mock_string: &str = "Foo bar string that is really really long";
|
||||
/// let asserted_bool: bool = is_screaming_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::screamingsnakecase::is_screaming_snake_case;
|
||||
/// let mock_string: &str = "foo-bar-string-that-is-really-really-long";
|
||||
/// let asserted_bool: bool = is_screaming_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::screamingsnakecase::is_screaming_snake_case;
|
||||
/// let mock_string: &str = "FooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_screaming_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::screamingsnakecase::is_screaming_snake_case;
|
||||
/// let mock_string: &str = "Foo Bar Is A Really Really Long String";
|
||||
/// let asserted_bool: bool = is_screaming_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::screamingsnakecase::is_screaming_snake_case;
|
||||
/// let mock_string: &str = "fooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_screaming_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::screamingsnakecase::is_screaming_snake_case;
|
||||
/// let mock_string: &str = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG";
|
||||
/// let asserted_bool: bool = is_screaming_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::screamingsnakecase::is_screaming_snake_case;
|
||||
/// let mock_string: &str = "FOO_BAR1_STRING_THAT_IS_REALLY_REALLY_LONG";
|
||||
/// let asserted_bool: bool = is_screaming_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::screamingsnakecase::is_screaming_snake_case;
|
||||
/// let mock_string: &str = "FOO_BAR_1_STRING_THAT_IS_REALLY_REALLY_LONG";
|
||||
/// let asserted_bool: bool = is_screaming_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
/// ```
|
||||
pub fn is_screaming_snake_case(test_string: &str) -> bool {
|
||||
test_string == to_screaming_snake_case(test_string.clone())
|
||||
}
|
||||
|
||||
|
||||
#[cfg(all(feature = "unstable", test))]
|
||||
mod benchmarks {
|
||||
extern crate test;
|
||||
use self::test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_screaming_snake(b: &mut Bencher) {
|
||||
b.iter(|| super::to_screaming_snake_case("Foo bar"));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_is_screaming_snake(b: &mut Bencher) {
|
||||
b.iter(|| super::is_screaming_snake_case("Foo bar"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ::to_screaming_snake_case;
|
||||
use ::is_screaming_snake_case;
|
||||
|
||||
#[test]
|
||||
fn from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
let expected: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(to_screaming_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
let expected: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(to_screaming_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
let expected: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(to_screaming_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
let expected: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(to_screaming_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
let expected: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(to_screaming_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
let expected: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(to_screaming_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_screaming_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
let expected: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(to_screaming_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
let expected: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(to_screaming_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
assert_eq!(is_screaming_snake_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
assert_eq!(is_screaming_snake_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
assert_eq!(is_screaming_snake_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
assert_eq!(is_screaming_snake_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
assert_eq!(is_screaming_snake_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(is_screaming_snake_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_screaming_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(is_screaming_snake_case(&convertable_string), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
assert_eq!(is_screaming_snake_case(&convertable_string), false)
|
||||
}
|
||||
}
|
||||
313
.gear/predownloaded-development/vendor/Inflector/src/cases/sentencecase/mod.rs
vendored
Normal file
313
.gear/predownloaded-development/vendor/Inflector/src/cases/sentencecase/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
#![deny(warnings)]
|
||||
use cases::case::*;
|
||||
/// Converts a `&str` to `Sentence case` `String`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::sentencecase::to_sentence_case;
|
||||
/// let mock_string: &str = "Foo bar";
|
||||
/// let expected_string: String = "Foo bar".to_string();
|
||||
/// let asserted_string: String = to_sentence_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::sentencecase::to_sentence_case;
|
||||
/// let mock_string: &str = "FooBar";
|
||||
/// let expected_string: String = "Foo bar".to_string();
|
||||
/// let asserted_string: String = to_sentence_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::sentencecase::to_sentence_case;
|
||||
/// let mock_string: &str = "fooBar";
|
||||
/// let expected_string: String = "Foo bar".to_string();
|
||||
/// let asserted_string: String = to_sentence_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::sentencecase::to_sentence_case;
|
||||
/// let mock_string: &str = "FOO_BAR";
|
||||
/// let expected_string: String = "Foo bar".to_string();
|
||||
/// let asserted_string: String = to_sentence_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::sentencecase::to_sentence_case;
|
||||
/// let mock_string: &str = "foo_bar";
|
||||
/// let expected_string: String = "Foo bar".to_string();
|
||||
/// let asserted_string: String = to_sentence_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::sentencecase::to_sentence_case;
|
||||
/// let mock_string: &str = "foo-bar";
|
||||
/// let expected_string: String = "Foo bar".to_string();
|
||||
/// let asserted_string: String = to_sentence_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
pub fn to_sentence_case(non_sentence_case_string: &str) -> String {
|
||||
let options = CamelOptions {
|
||||
new_word: true,
|
||||
last_char: ' ',
|
||||
first_word: true,
|
||||
injectable_char: ' ',
|
||||
has_seperator: true,
|
||||
inverted: true,
|
||||
};
|
||||
to_case_camel_like(non_sentence_case_string, options)
|
||||
}
|
||||
/// Determines of a `&str` is `Sentence case`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::sentencecase::is_sentence_case;
|
||||
/// let mock_string: &str = "foo-bar-string-that-is-really-really-long";
|
||||
/// let asserted_bool: bool = is_sentence_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::sentencecase::is_sentence_case;
|
||||
/// let mock_string: &str = "FooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_sentence_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::sentencecase::is_sentence_case;
|
||||
/// let mock_string: &str = "fooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_sentence_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::sentencecase::is_sentence_case;
|
||||
/// let mock_string: &str = "Foo Bar Is A Really Really Long String";
|
||||
/// let asserted_bool: bool = is_sentence_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::sentencecase::is_sentence_case;
|
||||
/// let mock_string: &str = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG";
|
||||
/// let asserted_bool: bool = is_sentence_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::sentencecase::is_sentence_case;
|
||||
/// let mock_string: &str = "foo_bar_string_that_is_really_really_long";
|
||||
/// let asserted_bool: bool = is_sentence_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::sentencecase::is_sentence_case;
|
||||
/// let mock_string: &str = "Foo";
|
||||
/// let asserted_bool: bool = is_sentence_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::sentencecase::is_sentence_case;
|
||||
/// let mock_string: &str = "foo";
|
||||
/// let asserted_bool: bool = is_sentence_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::sentencecase::is_sentence_case;
|
||||
/// let mock_string: &str = "Foo bar string that is really really long";
|
||||
/// let asserted_bool: bool = is_sentence_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
/// ```
|
||||
pub fn is_sentence_case(test_string: &str) -> bool {
|
||||
test_string == to_sentence_case(test_string.clone())
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "unstable", test))]
|
||||
mod benchmarks {
|
||||
extern crate test;
|
||||
use self::test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_sentence(b: &mut Bencher) {
|
||||
b.iter(|| super::to_sentence_case("Foo BAR"));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_is_sentence(b: &mut Bencher) {
|
||||
b.iter(|| super::is_sentence_case("Foo bar"));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_sentence_from_snake(b: &mut Bencher) {
|
||||
b.iter(|| super::to_sentence_case("foo_bar"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ::to_sentence_case;
|
||||
use ::is_sentence_case;
|
||||
|
||||
#[test]
|
||||
fn from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
let expected: String = "Foo bar".to_owned();
|
||||
assert_eq!(to_sentence_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
let expected: String = "Foo bar".to_owned();
|
||||
assert_eq!(to_sentence_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
let expected: String = "Foo bar".to_owned();
|
||||
assert_eq!(to_sentence_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
let expected: String = "Foo bar".to_owned();
|
||||
assert_eq!(to_sentence_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
let expected: String = "Foo bar".to_owned();
|
||||
assert_eq!(to_sentence_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
let expected: String = "Foo bar".to_owned();
|
||||
assert_eq!(to_sentence_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
let expected: String = "Foo bar".to_owned();
|
||||
assert_eq!(to_sentence_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
let expected: String = "Foo bar".to_owned();
|
||||
assert_eq!(to_sentence_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_case_with_loads_of_space() {
|
||||
let convertable_string: String = "foo bar".to_owned();
|
||||
let expected: String = "Foo bar".to_owned();
|
||||
assert_eq!(to_sentence_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_name_with_a_dot() {
|
||||
let convertable_string: String = "Robert C. Martin".to_owned();
|
||||
let expected: String = "Robert c martin".to_owned();
|
||||
assert_eq!(to_sentence_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_text_with_bad_chars() {
|
||||
let convertable_string: String = "Random text with *(bad) chars".to_owned();
|
||||
let expected: String = "Random text with bad chars".to_owned();
|
||||
assert_eq!(to_sentence_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_bad_chars() {
|
||||
let convertable_string: String = "trailing bad_chars*(()())".to_owned();
|
||||
let expected: String = "Trailing bad chars".to_owned();
|
||||
assert_eq!(to_sentence_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leading_bad_chars() {
|
||||
let convertable_string: String = "-!#$%leading bad chars".to_owned();
|
||||
let expected: String = "Leading bad chars".to_owned();
|
||||
assert_eq!(to_sentence_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapped_in_bad_chars() {
|
||||
let convertable_string: String = "-!#$%wrapped in bad chars&*^*&(&*^&(<><?>><?><>))".to_owned();
|
||||
let expected: String = "Wrapped in bad chars".to_owned();
|
||||
assert_eq!(to_sentence_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn has_a_sign() {
|
||||
let convertable_string: String = "has a + sign".to_owned();
|
||||
let expected: String = "Has a sign".to_owned();
|
||||
assert_eq!(to_sentence_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
assert_eq!(is_sentence_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
assert_eq!(is_sentence_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
assert_eq!(is_sentence_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
assert_eq!(is_sentence_case(&convertable_string), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
assert_eq!(is_sentence_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(is_sentence_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(is_sentence_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
assert_eq!(is_sentence_case(&convertable_string), false)
|
||||
}
|
||||
}
|
||||
334
.gear/predownloaded-development/vendor/Inflector/src/cases/snakecase/mod.rs
vendored
Normal file
334
.gear/predownloaded-development/vendor/Inflector/src/cases/snakecase/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
#![deny(warnings)]
|
||||
use cases::case::*;
|
||||
/// Converts a `&str` to `snake_case` `String`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::to_snake_case;
|
||||
/// let mock_string: &str = "foo_bar";
|
||||
/// let expected_string: String = "foo_bar".to_string();
|
||||
/// let asserted_string: String = to_snake_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::to_snake_case;
|
||||
/// let mock_string: &str = "HTTP Foo bar";
|
||||
/// let expected_string: String = "http_foo_bar".to_string();
|
||||
/// let asserted_string: String = to_snake_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::to_snake_case;
|
||||
/// let mock_string: &str = "HTTPFooBar";
|
||||
/// let expected_string: String = "http_foo_bar".to_string();
|
||||
/// let asserted_string: String = to_snake_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::to_snake_case;
|
||||
/// let mock_string: &str = "Foo bar";
|
||||
/// let expected_string: String = "foo_bar".to_string();
|
||||
/// let asserted_string: String = to_snake_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::to_snake_case;
|
||||
/// let mock_string: &str = "Foo Bar";
|
||||
/// let expected_string: String = "foo_bar".to_string();
|
||||
/// let asserted_string: String = to_snake_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::to_snake_case;
|
||||
/// let mock_string: &str = "FooBar";
|
||||
/// let expected_string: String = "foo_bar".to_string();
|
||||
/// let asserted_string: String = to_snake_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::to_snake_case;
|
||||
/// let mock_string: &str = "FOO_BAR";
|
||||
/// let expected_string: String = "foo_bar".to_string();
|
||||
/// let asserted_string: String = to_snake_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::to_snake_case;
|
||||
/// let mock_string: &str = "fooBar";
|
||||
/// let expected_string: String = "foo_bar".to_string();
|
||||
/// let asserted_string: String = to_snake_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::to_snake_case;
|
||||
/// let mock_string: &str = "fooBar3";
|
||||
/// let expected_string: String = "foo_bar_3".to_string();
|
||||
/// let asserted_string: String = to_snake_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
pub fn to_snake_case(non_snake_case_string: &str) -> String {
|
||||
to_case_snake_like(non_snake_case_string, "_", "lower")
|
||||
}
|
||||
|
||||
/// Determines of a `&str` is `snake_case`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::is_snake_case;
|
||||
/// let mock_string: &str = "Foo bar string that is really really long";
|
||||
/// let asserted_bool: bool = is_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::is_snake_case;
|
||||
/// let mock_string: &str = "foo-bar-string-that-is-really-really-long";
|
||||
/// let asserted_bool: bool = is_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::is_snake_case;
|
||||
/// let mock_string: &str = "FooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::is_snake_case;
|
||||
/// let mock_string: &str = "Foo Bar Is A Really Really Long String";
|
||||
/// let asserted_bool: bool = is_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::is_snake_case;
|
||||
/// let mock_string: &str = "FOO_BAR_IS_A_REALLY_REALLY_LONG_STRING";
|
||||
/// let asserted_bool: bool = is_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::is_snake_case;
|
||||
/// let mock_string: &str = "fooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::is_snake_case;
|
||||
/// let mock_string: &str = "foo_bar_string_that_is_really_really_long";
|
||||
/// let asserted_bool: bool = is_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::is_snake_case;
|
||||
/// let mock_string: &str = "foo_bar1_string_that_is_really_really_long";
|
||||
/// let asserted_bool: bool = is_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::snakecase::is_snake_case;
|
||||
/// let mock_string: &str = "foo_bar_1_string_that_is_really_really_long";
|
||||
/// let asserted_bool: bool = is_snake_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
/// ```
|
||||
pub fn is_snake_case(test_string: &str) -> bool {
|
||||
test_string == to_snake_case(test_string.clone())
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "unstable", test))]
|
||||
mod benchmarks {
|
||||
extern crate test;
|
||||
use self::test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_snake_from_title(b: &mut Bencher) {
|
||||
b.iter(|| super::to_snake_case("Foo bar"));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_snake_from_camel(b: &mut Bencher) {
|
||||
b.iter(|| super::to_snake_case("fooBar"));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_snake_from_snake(b: &mut Bencher) {
|
||||
b.iter(|| super::to_snake_case("foo_bar_bar_bar"));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_is_snake(b: &mut Bencher) {
|
||||
b.iter(|| super::is_snake_case("Foo bar"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ::to_snake_case;
|
||||
use ::is_snake_case;
|
||||
|
||||
#[test]
|
||||
fn from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
let expected: String = "foo_bar".to_owned();
|
||||
assert_eq!(to_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
let expected: String = "foo_bar".to_owned();
|
||||
assert_eq!(to_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
let expected: String = "foo_bar".to_owned();
|
||||
assert_eq!(to_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
let expected: String = "foo_bar".to_owned();
|
||||
assert_eq!(to_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
let expected: String = "foo_bar".to_owned();
|
||||
assert_eq!(to_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
let expected: String = "foo_bar".to_owned();
|
||||
assert_eq!(to_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
let expected: String = "foo_bar".to_owned();
|
||||
assert_eq!(to_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
let expected: String = "foo_bar".to_owned();
|
||||
assert_eq!(to_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_case_with_loads_of_space() {
|
||||
let convertable_string: String = "foo bar".to_owned();
|
||||
let expected: String = "foo_bar".to_owned();
|
||||
assert_eq!(to_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_name_with_a_dot() {
|
||||
let convertable_string: String = "Robert C. Martin".to_owned();
|
||||
let expected: String = "robert_c_martin".to_owned();
|
||||
assert_eq!(to_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_text_with_bad_chars() {
|
||||
let convertable_string: String = "Random text with *(bad) chars".to_owned();
|
||||
let expected: String = "random_text_with_bad_chars".to_owned();
|
||||
assert_eq!(to_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_bad_chars() {
|
||||
let convertable_string: String = "trailing bad_chars*(()())".to_owned();
|
||||
let expected: String = "trailing_bad_chars".to_owned();
|
||||
assert_eq!(to_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leading_bad_chars() {
|
||||
let convertable_string: String = "-!#$%leading bad chars".to_owned();
|
||||
let expected: String = "leading_bad_chars".to_owned();
|
||||
assert_eq!(to_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapped_in_bad_chars() {
|
||||
let convertable_string: String = "-!#$%wrapped in bad chars&*^*&(&*^&(<><?>><?><>))".to_owned();
|
||||
let expected: String = "wrapped_in_bad_chars".to_owned();
|
||||
assert_eq!(to_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn has_a_sign() {
|
||||
let convertable_string: String = "has a + sign".to_owned();
|
||||
let expected: String = "has_a_sign".to_owned();
|
||||
assert_eq!(to_snake_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
assert_eq!(is_snake_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
assert_eq!(is_snake_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
assert_eq!(is_snake_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
assert_eq!(is_snake_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
assert_eq!(is_snake_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(is_snake_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(is_snake_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
assert_eq!(is_snake_case(&convertable_string), true)
|
||||
}
|
||||
}
|
||||
271
.gear/predownloaded-development/vendor/Inflector/src/cases/tablecase/mod.rs
vendored
Normal file
271
.gear/predownloaded-development/vendor/Inflector/src/cases/tablecase/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
#![deny(warnings)]
|
||||
#[cfg(feature = "heavyweight")]
|
||||
use string::pluralize::to_plural;
|
||||
#[cfg(feature = "heavyweight")]
|
||||
use cases::case::*;
|
||||
#[cfg(feature = "heavyweight")]
|
||||
/// Converts a `&str` to `table-case` `String`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::tablecase::to_table_case;
|
||||
/// let mock_string: &str = "foo-bar";
|
||||
/// let expected_string: String = "foo_bars".to_string();
|
||||
/// let asserted_string: String = to_table_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::tablecase::to_table_case;
|
||||
/// let mock_string: &str = "FOO_BAR";
|
||||
/// let expected_string: String = "foo_bars".to_string();
|
||||
/// let asserted_string: String = to_table_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::tablecase::to_table_case;
|
||||
/// let mock_string: &str = "foo_bar";
|
||||
/// let expected_string: String = "foo_bars".to_string();
|
||||
/// let asserted_string: String = to_table_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::tablecase::to_table_case;
|
||||
/// let mock_string: &str = "Foo Bar";
|
||||
/// let expected_string: String = "foo_bars".to_string();
|
||||
/// let asserted_string: String = to_table_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::tablecase::to_table_case;
|
||||
/// let mock_string: &str = "Foo bar";
|
||||
/// let expected_string: String = "foo_bars".to_string();
|
||||
/// let asserted_string: String = to_table_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::tablecase::to_table_case;
|
||||
/// let mock_string: &str = "FooBar";
|
||||
/// let expected_string: String = "foo_bars".to_string();
|
||||
/// let asserted_string: String = to_table_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::tablecase::to_table_case;
|
||||
/// let mock_string: &str = "fooBar";
|
||||
/// let expected_string: String = "foo_bars".to_string();
|
||||
/// let asserted_string: String = to_table_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
/// ```
|
||||
pub fn to_table_case(non_table_case_string: &str) -> String {
|
||||
let snaked: String = to_case_snake_like(non_table_case_string, "_", "lower");
|
||||
let split: (&str, &str) = snaked.split_at(snaked.rfind('_').unwrap_or(0));
|
||||
format!("{}{}", split.0, to_plural(split.1))
|
||||
}
|
||||
|
||||
#[cfg(feature = "heavyweight")]
|
||||
/// Determines if a `&str` is `table-case`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::tablecase::is_table_case;
|
||||
/// let mock_string: &str = "foo_bar_strings";
|
||||
/// let asserted_bool: bool = is_table_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::tablecase::is_table_case;
|
||||
/// let mock_string: &str = "foo-bar-string-that-is-really-really-long";
|
||||
/// let asserted_bool: bool = is_table_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::tablecase::is_table_case;
|
||||
/// let mock_string: &str = "FooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_table_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::tablecase::is_table_case;
|
||||
/// let mock_string: &str = "fooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_table_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::tablecase::is_table_case;
|
||||
/// let mock_string: &str = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG";
|
||||
/// let asserted_bool: bool = is_table_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::tablecase::is_table_case;
|
||||
/// let mock_string: &str = "foo_bar_string_that_is_really_really_long";
|
||||
/// let asserted_bool: bool = is_table_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::tablecase::is_table_case;
|
||||
/// let mock_string: &str = "Foo bar string that is really really long";
|
||||
/// let asserted_bool: bool = is_table_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::tablecase::is_table_case;
|
||||
/// let mock_string: &str = "Foo Bar Is A Really Really Long String";
|
||||
/// let asserted_bool: bool = is_table_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
/// ```
|
||||
pub fn is_table_case(test_string: &str) -> bool {
|
||||
to_table_case(&test_string.clone()) == test_string
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "unstable", test))]
|
||||
#[cfg(feature = "heavyweight")]
|
||||
mod benchmarks {
|
||||
extern crate test;
|
||||
use self::test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_table_case(b: &mut Bencher) {
|
||||
b.iter(|| super::to_table_case("Foo bar"));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_is_table_case(b: &mut Bencher) {
|
||||
b.iter(|| super::is_table_case("Foo bar"));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "heavyweight")]
|
||||
mod tests {
|
||||
use ::to_table_case;
|
||||
use ::is_table_case;
|
||||
|
||||
#[test]
|
||||
fn from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
let expected: String = "foo_bars".to_owned();
|
||||
assert_eq!(to_table_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
let expected: String = "foo_bars".to_owned();
|
||||
assert_eq!(to_table_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
let expected: String = "foo_bars".to_owned();
|
||||
assert_eq!(to_table_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
let expected: String = "foo_bars".to_owned();
|
||||
assert_eq!(to_table_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
let expected: String = "foo_bars".to_owned();
|
||||
assert_eq!(to_table_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
let expected: String = "foo_bars".to_owned();
|
||||
assert_eq!(to_table_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
let expected: String = "foo_bars".to_owned();
|
||||
assert_eq!(to_table_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
let expected: String = "foo_bars".to_owned();
|
||||
assert_eq!(to_table_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_table_case() {
|
||||
let convertable_string: String = "foo_bars".to_owned();
|
||||
let expected: String = "foo_bars".to_owned();
|
||||
assert_eq!(to_table_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
assert_eq!(is_table_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
assert_eq!(is_table_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
assert_eq!(is_table_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
assert_eq!(is_table_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
assert_eq!(is_table_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(is_table_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(is_table_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
assert_eq!(is_table_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_table_case() {
|
||||
let convertable_string: String = "foo_bars".to_owned();
|
||||
assert_eq!(is_table_case(&convertable_string), true)
|
||||
}
|
||||
}
|
||||
308
.gear/predownloaded-development/vendor/Inflector/src/cases/titlecase/mod.rs
vendored
Normal file
308
.gear/predownloaded-development/vendor/Inflector/src/cases/titlecase/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
#![deny(warnings)]
|
||||
use cases::case::*;
|
||||
/// Converts a `&str` to `Title Case` `String`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::titlecase::to_title_case;
|
||||
/// let mock_string: &str = "Foo bar";
|
||||
/// let expected_string: String = "Foo Bar".to_string();
|
||||
/// let asserted_string: String = to_title_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::titlecase::to_title_case;
|
||||
/// let mock_string: &str = "FooBar";
|
||||
/// let expected_string: String = "Foo Bar".to_string();
|
||||
/// let asserted_string: String = to_title_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::titlecase::to_title_case;
|
||||
/// let mock_string: &str = "fooBar";
|
||||
/// let expected_string: String = "Foo Bar".to_string();
|
||||
/// let asserted_string: String = to_title_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::titlecase::to_title_case;
|
||||
/// let mock_string: &str = "FOO_BAR";
|
||||
/// let expected_string: String = "Foo Bar".to_string();
|
||||
/// let asserted_string: String = to_title_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::titlecase::to_title_case;
|
||||
/// let mock_string: &str = "foo_bar";
|
||||
/// let expected_string: String = "Foo Bar".to_string();
|
||||
/// let asserted_string: String = to_title_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::titlecase::to_title_case;
|
||||
/// let mock_string: &str = "foo-bar";
|
||||
/// let expected_string: String = "Foo Bar".to_string();
|
||||
/// let asserted_string: String = to_title_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
pub fn to_title_case(non_title_case_string: &str) -> String {
|
||||
let options = CamelOptions {
|
||||
new_word: true,
|
||||
last_char: ' ',
|
||||
first_word: true,
|
||||
injectable_char: ' ',
|
||||
has_seperator: true,
|
||||
inverted: false,
|
||||
};
|
||||
to_case_camel_like(non_title_case_string, options)
|
||||
}
|
||||
|
||||
/// Determines if a `&str` is `Title Case`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::titlecase::is_title_case;
|
||||
/// let mock_string: &str = "foo-bar-string-that-is-really-really-long";
|
||||
/// let asserted_bool: bool = is_title_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::titlecase::is_title_case;
|
||||
/// let mock_string: &str = "FooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_title_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::titlecase::is_title_case;
|
||||
/// let mock_string: &str = "fooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_title_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::titlecase::is_title_case;
|
||||
/// let mock_string: &str = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG";
|
||||
/// let asserted_bool: bool = is_title_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::titlecase::is_title_case;
|
||||
/// let mock_string: &str = "foo_bar_string_that_is_really_really_long";
|
||||
/// let asserted_bool: bool = is_title_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::titlecase::is_title_case;
|
||||
/// let mock_string: &str = "Foo bar string that is really really long";
|
||||
/// let asserted_bool: bool = is_title_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::titlecase::is_title_case;
|
||||
/// let mock_string: &str = "foo";
|
||||
/// let asserted_bool: bool = is_title_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::cases::titlecase::is_title_case;
|
||||
/// let mock_string: &str = "Foo Bar String That Is Really Really Long";
|
||||
/// let asserted_bool: bool = is_title_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
/// ```
|
||||
pub fn is_title_case(test_string: &str) -> bool {
|
||||
test_string == to_title_case(test_string.clone())
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "unstable", test))]
|
||||
mod benchmarks {
|
||||
extern crate test;
|
||||
use self::test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_title(b: &mut Bencher) {
|
||||
b.iter(|| super::to_title_case("Foo BAR"));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_is_title(b: &mut Bencher) {
|
||||
b.iter(|| super::is_title_case("Foo bar"));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_title_from_snake(b: &mut Bencher) {
|
||||
b.iter(|| super::to_title_case("foo_bar"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ::to_title_case;
|
||||
use ::is_title_case;
|
||||
|
||||
#[test]
|
||||
fn from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
let expected: String = "Foo Bar".to_owned();
|
||||
assert_eq!(to_title_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
let expected: String = "Foo Bar".to_owned();
|
||||
assert_eq!(to_title_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
let expected: String = "Foo Bar".to_owned();
|
||||
assert_eq!(to_title_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
let expected: String = "Foo Bar".to_owned();
|
||||
assert_eq!(to_title_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
let expected: String = "Foo Bar".to_owned();
|
||||
assert_eq!(to_title_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
let expected: String = "Foo Bar".to_owned();
|
||||
assert_eq!(to_title_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
let expected: String = "Foo Bar".to_owned();
|
||||
assert_eq!(to_title_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
let expected: String = "Foo Bar".to_owned();
|
||||
assert_eq!(to_title_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_case_with_loads_of_space() {
|
||||
let convertable_string: String = "foo bar".to_owned();
|
||||
let expected: String = "Foo Bar".to_owned();
|
||||
assert_eq!(to_title_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_name_with_a_dot() {
|
||||
let convertable_string: String = "Robert C. Martin".to_owned();
|
||||
let expected: String = "Robert C Martin".to_owned();
|
||||
assert_eq!(to_title_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_text_with_bad_chars() {
|
||||
let convertable_string: String = "Random text with *(bad) chars".to_owned();
|
||||
let expected: String = "Random Text With Bad Chars".to_owned();
|
||||
assert_eq!(to_title_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_bad_chars() {
|
||||
let convertable_string: String = "trailing bad_chars*(()())".to_owned();
|
||||
let expected: String = "Trailing Bad Chars".to_owned();
|
||||
assert_eq!(to_title_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leading_bad_chars() {
|
||||
let convertable_string: String = "-!#$%leading bad chars".to_owned();
|
||||
let expected: String = "Leading Bad Chars".to_owned();
|
||||
assert_eq!(to_title_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapped_in_bad_chars() {
|
||||
let convertable_string: String = "-!#$%wrapped in bad chars&*^*&(&*^&(<><?>><?><>))".to_owned();
|
||||
let expected: String = "Wrapped In Bad Chars".to_owned();
|
||||
assert_eq!(to_title_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn has_a_sign() {
|
||||
let convertable_string: String = "has a + sign".to_owned();
|
||||
let expected: String = "Has A Sign".to_owned();
|
||||
assert_eq!(to_title_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
assert_eq!(is_title_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
assert_eq!(is_title_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
assert_eq!(is_title_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
assert_eq!(is_title_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
assert_eq!(is_title_case(&convertable_string), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(is_title_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(is_title_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
assert_eq!(is_title_case(&convertable_string), false)
|
||||
}
|
||||
}
|
||||
|
||||
320
.gear/predownloaded-development/vendor/Inflector/src/cases/traincase/mod.rs
vendored
Normal file
320
.gear/predownloaded-development/vendor/Inflector/src/cases/traincase/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
#![deny(warnings)]
|
||||
use cases::case::*;
|
||||
/// Determines if a `&str` is `Train-Case`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::traincase::is_train_case;
|
||||
/// let mock_string: &str = "Foo-Bar-String-That-Is-Really-Really-Long";
|
||||
/// let asserted_bool: bool = is_train_case(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::traincase::is_train_case;
|
||||
/// let mock_string: &str = "foo-bar-string-that-is-really-really-long";
|
||||
/// let asserted_bool: bool = is_train_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::traincase::is_train_case;
|
||||
/// let mock_string: &str = "FooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_train_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::traincase::is_train_case;
|
||||
/// let mock_string: &str = "fooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_train_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::traincase::is_train_case;
|
||||
/// let mock_string: &str = "foo_bar_string_that_is_really_really_long";
|
||||
/// let asserted_bool: bool = is_train_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::traincase::is_train_case;
|
||||
/// let mock_string: &str = "Foo bar string that is really really long";
|
||||
/// let asserted_bool: bool = is_train_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::traincase::is_train_case;
|
||||
/// let mock_string: &str = "Foo Bar Is A Really Really Long String";
|
||||
/// let asserted_bool: bool = is_train_case(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
pub fn is_train_case(test_string: &str) -> bool {
|
||||
test_string == to_train_case(test_string.clone())
|
||||
}
|
||||
|
||||
|
||||
/// Converts a `&str` to `Train-Case` `String`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::traincase::to_train_case;
|
||||
/// let mock_string: &str = "foo-bar";
|
||||
/// let expected_string: String = "Foo-Bar".to_string();
|
||||
/// let asserted_string: String = to_train_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::traincase::to_train_case;
|
||||
/// let mock_string: &str = "FOO_BAR";
|
||||
/// let expected_string: String = "Foo-Bar".to_string();
|
||||
/// let asserted_string: String = to_train_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::traincase::to_train_case;
|
||||
/// let mock_string: &str = "foo_bar";
|
||||
/// let expected_string: String = "Foo-Bar".to_string();
|
||||
/// let asserted_string: String = to_train_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::traincase::to_train_case;
|
||||
/// let mock_string: &str = "Foo Bar";
|
||||
/// let expected_string: String = "Foo-Bar".to_string();
|
||||
/// let asserted_string: String = to_train_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::traincase::to_train_case;
|
||||
/// let mock_string: &str = "Foo bar";
|
||||
/// let expected_string: String = "Foo-Bar".to_string();
|
||||
/// let asserted_string: String = to_train_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::traincase::to_train_case;
|
||||
/// let mock_string: &str = "FooBar";
|
||||
/// let expected_string: String = "Foo-Bar".to_string();
|
||||
/// let asserted_string: String = to_train_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::cases::traincase::to_train_case;
|
||||
/// let mock_string: &str = "fooBar";
|
||||
/// let expected_string: String = "Foo-Bar".to_string();
|
||||
/// let asserted_string: String = to_train_case(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
pub fn to_train_case(non_train_case_string: &str) -> String {
|
||||
let options = CamelOptions {
|
||||
new_word: true,
|
||||
last_char: ' ',
|
||||
first_word: true,
|
||||
injectable_char: '-',
|
||||
has_seperator: true,
|
||||
inverted: false,
|
||||
};
|
||||
to_case_camel_like(non_train_case_string, options)
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "unstable", test))]
|
||||
mod benchmarks {
|
||||
extern crate test;
|
||||
use self::test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_train(b: &mut Bencher) {
|
||||
b.iter(|| super::to_train_case("Foo bar"));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_is_train(b: &mut Bencher) {
|
||||
b.iter(|| super::is_train_case("Foo bar"));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_train_from_snake(b: &mut Bencher) {
|
||||
b.iter(|| super::to_train_case("test_test_test"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ::to_train_case;
|
||||
use ::is_train_case;
|
||||
|
||||
#[test]
|
||||
fn from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
let expected: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(to_train_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
let expected: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(to_train_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
let expected: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(to_train_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
let expected: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(to_train_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
let expected: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(to_train_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
let expected: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(to_train_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
let expected: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(to_train_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
let expected: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(to_train_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_case_with_loads_of_space() {
|
||||
let convertable_string: String = "foo bar".to_owned();
|
||||
let expected: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(to_train_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_name_with_a_dot() {
|
||||
let convertable_string: String = "Robert C. Martin".to_owned();
|
||||
let expected: String = "Robert-C-Martin".to_owned();
|
||||
assert_eq!(to_train_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_text_with_bad_chars() {
|
||||
let convertable_string: String = "Random text with *(bad) chars".to_owned();
|
||||
let expected: String = "Random-Text-With-Bad-Chars".to_owned();
|
||||
assert_eq!(to_train_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_bad_chars() {
|
||||
let convertable_string: String = "trailing bad_chars*(()())".to_owned();
|
||||
let expected: String = "Trailing-Bad-Chars".to_owned();
|
||||
assert_eq!(to_train_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leading_bad_chars() {
|
||||
let convertable_string: String = "-!#$%leading bad chars".to_owned();
|
||||
let expected: String = "Leading-Bad-Chars".to_owned();
|
||||
assert_eq!(to_train_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapped_in_bad_chars() {
|
||||
let convertable_string: String = "-!#$%wrapped in bad chars&*^*&(&*^&(<><?>><?><>))".to_owned();
|
||||
let expected: String = "Wrapped-In-Bad-Chars".to_owned();
|
||||
assert_eq!(to_train_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn has_a_sign() {
|
||||
let convertable_string: String = "has a + sign".to_owned();
|
||||
let expected: String = "Has-A-Sign".to_owned();
|
||||
assert_eq!(to_train_case(&convertable_string), expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_camel_case() {
|
||||
let convertable_string: String = "fooBar".to_owned();
|
||||
assert_eq!(is_train_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_pascal_case() {
|
||||
let convertable_string: String = "FooBar".to_owned();
|
||||
assert_eq!(is_train_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_kebab_case() {
|
||||
let convertable_string: String = "foo-bar".to_owned();
|
||||
assert_eq!(is_train_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_sentence_case() {
|
||||
let convertable_string: String = "Foo bar".to_owned();
|
||||
assert_eq!(is_train_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_title_case() {
|
||||
let convertable_string: String = "Foo Bar".to_owned();
|
||||
assert_eq!(is_train_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_train_case() {
|
||||
let convertable_string: String = "Foo-Bar".to_owned();
|
||||
assert_eq!(is_train_case(&convertable_string), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_screaming_snake_case() {
|
||||
let convertable_string: String = "FOO_BAR".to_owned();
|
||||
assert_eq!(is_train_case(&convertable_string), false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_correct_from_snake_case() {
|
||||
let convertable_string: String = "foo_bar".to_owned();
|
||||
assert_eq!(is_train_case(&convertable_string), false)
|
||||
}
|
||||
}
|
||||
332
.gear/predownloaded-development/vendor/Inflector/src/lib.rs
vendored
Normal file
332
.gear/predownloaded-development/vendor/Inflector/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
#![deny(warnings, unused_variables, missing_docs, unsafe_code, unused_extern_crates)]
|
||||
#![cfg_attr(feature = "unstable", feature(test))]
|
||||
|
||||
//! Adds String based inflections for Rust. Snake, kebab, train, camel,
|
||||
//! sentence, class, and title cases as well as ordinalize,
|
||||
//! deordinalize, demodulize, deconstantize, and foreign key are supported as
|
||||
//! both traits and pure functions acting on String types.
|
||||
//! ```rust
|
||||
//! use inflector::Inflector;
|
||||
//! let camel_case_string: String = "some_string".to_camel_case();
|
||||
//! let is_camel_cased: bool= camel_case_string.is_camel_case();
|
||||
//! assert!(is_camel_cased == true);
|
||||
//! ```
|
||||
|
||||
#[cfg(feature = "heavyweight")]
|
||||
extern crate regex;
|
||||
|
||||
#[cfg(feature = "heavyweight")]
|
||||
#[macro_use] extern crate lazy_static;
|
||||
|
||||
/// Provides case inflections
|
||||
/// - Camel case
|
||||
/// - Class case
|
||||
/// - Kebab case
|
||||
/// - Train case
|
||||
/// - Screaming snake case
|
||||
/// - Table case
|
||||
/// - Sentence case
|
||||
/// - Snake case
|
||||
/// - Pascal case
|
||||
pub mod cases;
|
||||
/// Provides number inflections
|
||||
/// - Ordinalize
|
||||
/// - Deordinalize
|
||||
pub mod numbers;
|
||||
/// Provides suffix inflections
|
||||
/// - Foreign key
|
||||
pub mod suffix;
|
||||
/// Provides string inflections
|
||||
/// - Deconstantize
|
||||
/// - Demodulize
|
||||
/// - Pluralize
|
||||
/// - Singularize
|
||||
#[cfg(feature = "heavyweight")]
|
||||
pub mod string;
|
||||
|
||||
|
||||
#[cfg(feature = "heavyweight")]
|
||||
use cases::classcase::to_class_case;
|
||||
#[cfg(feature = "heavyweight")]
|
||||
use cases::classcase::is_class_case;
|
||||
|
||||
use cases::camelcase::to_camel_case;
|
||||
use cases::camelcase::is_camel_case;
|
||||
|
||||
use cases::pascalcase::to_pascal_case;
|
||||
use cases::pascalcase::is_pascal_case;
|
||||
|
||||
use cases::snakecase::to_snake_case;
|
||||
use cases::snakecase::is_snake_case;
|
||||
|
||||
use cases::screamingsnakecase::to_screaming_snake_case;
|
||||
use cases::screamingsnakecase::is_screaming_snake_case;
|
||||
|
||||
use cases::kebabcase::to_kebab_case;
|
||||
use cases::kebabcase::is_kebab_case;
|
||||
|
||||
use cases::traincase::to_train_case;
|
||||
use cases::traincase::is_train_case;
|
||||
|
||||
use cases::sentencecase::to_sentence_case;
|
||||
use cases::sentencecase::is_sentence_case;
|
||||
|
||||
use cases::titlecase::to_title_case;
|
||||
use cases::titlecase::is_title_case;
|
||||
|
||||
#[cfg(feature = "heavyweight")]
|
||||
use cases::tablecase::to_table_case;
|
||||
#[cfg(feature = "heavyweight")]
|
||||
use cases::tablecase::is_table_case;
|
||||
|
||||
use numbers::ordinalize::ordinalize;
|
||||
use numbers::deordinalize::deordinalize;
|
||||
|
||||
use suffix::foreignkey::to_foreign_key;
|
||||
use suffix::foreignkey::is_foreign_key;
|
||||
|
||||
#[cfg(feature = "heavyweight")]
|
||||
use string::demodulize::demodulize;
|
||||
#[cfg(feature = "heavyweight")]
|
||||
use string::deconstantize::deconstantize;
|
||||
|
||||
#[cfg(feature = "heavyweight")]
|
||||
use string::pluralize::to_plural;
|
||||
#[cfg(feature = "heavyweight")]
|
||||
use string::singularize::to_singular;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub trait Inflector {
|
||||
|
||||
fn to_camel_case(&self) -> String;
|
||||
fn is_camel_case(&self) -> bool;
|
||||
|
||||
fn to_pascal_case(&self) -> String;
|
||||
fn is_pascal_case(&self) -> bool;
|
||||
|
||||
fn to_snake_case(&self) -> String;
|
||||
fn is_snake_case(&self) -> bool;
|
||||
|
||||
fn to_screaming_snake_case(&self) -> String;
|
||||
fn is_screaming_snake_case(&self) -> bool;
|
||||
|
||||
fn to_kebab_case(&self) -> String;
|
||||
fn is_kebab_case(&self) -> bool;
|
||||
|
||||
fn to_train_case(&self) -> String;
|
||||
fn is_train_case(&self) -> bool;
|
||||
|
||||
fn to_sentence_case(&self) -> String;
|
||||
fn is_sentence_case(&self) -> bool;
|
||||
|
||||
fn to_title_case(&self) -> String;
|
||||
fn is_title_case(&self) -> bool;
|
||||
|
||||
fn ordinalize(&self) -> String;
|
||||
fn deordinalize(&self) -> String;
|
||||
|
||||
fn to_foreign_key(&self) -> String;
|
||||
fn is_foreign_key(&self) -> bool;
|
||||
|
||||
#[cfg(feature = "heavyweight")]
|
||||
fn demodulize(&self) -> String;
|
||||
#[cfg(feature = "heavyweight")]
|
||||
fn deconstantize(&self) -> String;
|
||||
|
||||
#[cfg(feature = "heavyweight")]
|
||||
fn to_class_case(&self) -> String;
|
||||
#[cfg(feature = "heavyweight")]
|
||||
fn is_class_case(&self) -> bool;
|
||||
|
||||
#[cfg(feature = "heavyweight")]
|
||||
fn to_table_case(&self) -> String;
|
||||
#[cfg(feature = "heavyweight")]
|
||||
fn is_table_case(&self) -> bool;
|
||||
#[cfg(feature = "heavyweight")]
|
||||
fn to_plural(&self) -> String;
|
||||
#[cfg(feature = "heavyweight")]
|
||||
fn to_singular(&self) -> String;
|
||||
}
|
||||
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub trait InflectorNumbers {
|
||||
fn ordinalize(&self) -> String;
|
||||
}
|
||||
|
||||
|
||||
macro_rules! define_implementations {
|
||||
( $slf:ident; $($imp_trait:ident => $typ:ident), *) => {
|
||||
$(
|
||||
#[inline]
|
||||
fn $imp_trait(&$slf) -> $typ {
|
||||
$imp_trait($slf)
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_number_implementations {
|
||||
( $slf:ident; $($imp_trait:ident => $typ:ident), *) => {
|
||||
$(
|
||||
#[inline]
|
||||
fn $imp_trait(&$slf) -> $typ {
|
||||
$imp_trait(&$slf.to_string())
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_gated_implementations {
|
||||
( $slf:ident; $($imp_trait:ident => $typ:ident), *) => {
|
||||
$(
|
||||
#[inline]
|
||||
#[cfg(feature = "heavyweight")]
|
||||
fn $imp_trait(&$slf) -> $typ {
|
||||
$imp_trait($slf)
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! implement_string_for {
|
||||
( $trt:ident; $($typ:ident), *) => {
|
||||
$(
|
||||
impl $trt for $typ {
|
||||
define_implementations![self;
|
||||
to_camel_case => String,
|
||||
is_camel_case => bool,
|
||||
to_pascal_case => String,
|
||||
is_pascal_case => bool,
|
||||
to_screaming_snake_case => String,
|
||||
is_screaming_snake_case => bool,
|
||||
to_snake_case => String,
|
||||
is_snake_case => bool,
|
||||
to_kebab_case => String,
|
||||
is_kebab_case => bool,
|
||||
to_train_case => String,
|
||||
is_train_case => bool,
|
||||
to_sentence_case => String,
|
||||
is_sentence_case => bool,
|
||||
to_title_case => String,
|
||||
is_title_case => bool,
|
||||
to_foreign_key => String,
|
||||
is_foreign_key => bool,
|
||||
ordinalize => String,
|
||||
deordinalize => String
|
||||
];
|
||||
define_gated_implementations![self;
|
||||
to_class_case => String,
|
||||
is_class_case => bool,
|
||||
to_table_case => String,
|
||||
is_table_case => bool,
|
||||
to_plural => String,
|
||||
to_singular => String,
|
||||
demodulize => String,
|
||||
deconstantize => String
|
||||
];
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! implement_number_for {
|
||||
( $trt:ident; $($typ:ident), *) => {
|
||||
$(
|
||||
impl $trt for $typ {
|
||||
define_number_implementations![self;
|
||||
ordinalize => String
|
||||
];
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
implement_string_for![
|
||||
Inflector;
|
||||
String, str
|
||||
];
|
||||
|
||||
implement_number_for![
|
||||
InflectorNumbers;
|
||||
i8, i16, i32, i64, u8, u16, u32, u64, isize, usize, f32, f64
|
||||
];
|
||||
|
||||
#[cfg(all(feature = "unstable", test))]
|
||||
mod benchmarks {
|
||||
extern crate test;
|
||||
use self::test::Bencher;
|
||||
use ::Inflector;
|
||||
|
||||
macro_rules! benchmarks {
|
||||
( $($test_name:ident => $imp_trait:ident => $to_cast:expr), *) => {
|
||||
$(
|
||||
#[bench]
|
||||
fn $test_name(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
$to_cast.$imp_trait()
|
||||
});
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
benchmarks![
|
||||
benchmark_str_to_camel => to_camel_case => "foo_bar",
|
||||
benchmark_str_is_camel => is_camel_case => "fooBar",
|
||||
benchmark_str_to_screaming_snake => to_screaming_snake_case => "fooBar",
|
||||
benchmark_str_is_screaming_snake => is_screaming_snake_case => "FOO_BAR",
|
||||
benchmark_str_to_snake => to_snake_case => "fooBar",
|
||||
benchmark_str_is_snake => is_snake_case => "foo_bar",
|
||||
benchmark_str_to_kebab => to_kebab_case => "fooBar",
|
||||
benchmark_str_is_kebab => is_kebab_case => "foo-bar",
|
||||
benchmark_str_to_train => to_train_case => "fooBar",
|
||||
benchmark_str_is_train => is_train_case => "Foo-Bar",
|
||||
benchmark_str_to_sentence => to_sentence_case => "fooBar",
|
||||
benchmark_str_is_sentence => is_sentence_case => "Foo bar",
|
||||
benchmark_str_to_title => to_title_case => "fooBar",
|
||||
benchmark_str_is_title => is_title_case => "Foo Bar",
|
||||
benchmark_str_ordinalize => ordinalize => "1",
|
||||
benchmark_str_deordinalize => deordinalize => "1st",
|
||||
benchmark_str_to_foreign_key => to_foreign_key => "Foo::Bar",
|
||||
benchmark_str_is_foreign_key => is_foreign_key => "bar_id",
|
||||
benchmark_string_to_camel => to_camel_case => "foo_bar".to_string(),
|
||||
benchmark_string_is_camel => is_camel_case => "fooBar".to_string(),
|
||||
benchmark_string_to_screaming_snake => to_screaming_snake_case => "fooBar".to_string(),
|
||||
benchmark_string_is_screaming_snake => is_screaming_snake_case => "FOO_BAR".to_string(),
|
||||
benchmark_string_to_snake => to_snake_case => "fooBar".to_string(),
|
||||
benchmark_string_is_snake => is_snake_case => "foo_bar".to_string(),
|
||||
benchmark_string_to_kebab => to_kebab_case => "fooBar".to_string(),
|
||||
benchmark_string_is_kebab => is_kebab_case => "foo-bar".to_string(),
|
||||
benchmark_string_to_train => to_train_case => "fooBar".to_string(),
|
||||
benchmark_string_is_train => is_train_case => "Foo-Bar".to_string(),
|
||||
benchmark_string_to_sentence => to_sentence_case => "fooBar".to_string(),
|
||||
benchmark_string_is_sentence => is_sentence_case => "Foo bar".to_string(),
|
||||
benchmark_string_to_title => to_title_case => "fooBar".to_string(),
|
||||
benchmark_string_is_title => is_title_case => "Foo Bar".to_string(),
|
||||
benchmark_string_ordinalize => ordinalize => "1".to_string(),
|
||||
benchmark_string_deordinalize => deordinalize => "1st".to_string(),
|
||||
benchmark_string_to_foreign_key => to_foreign_key => "Foo::Bar".to_string(),
|
||||
benchmark_string_is_foreign_key => is_foreign_key => "bar_id".to_string()
|
||||
];
|
||||
|
||||
#[cfg(feature = "heavyweight")]
|
||||
benchmarks![
|
||||
benchmark_str_to_class => to_class_case => "foo",
|
||||
benchmark_str_is_class => is_class_case => "Foo",
|
||||
benchmark_str_to_table => to_table_case => "fooBar",
|
||||
benchmark_str_is_table => is_table_case => "foo_bars",
|
||||
benchmark_str_pluralize => to_plural => "crate",
|
||||
benchmark_str_singular => to_singular => "crates",
|
||||
benchmark_string_to_class => to_class_case => "foo".to_string(),
|
||||
benchmark_string_is_class => is_class_case => "Foo".to_string(),
|
||||
benchmark_string_to_table => to_table_case => "fooBar".to_string(),
|
||||
benchmark_string_is_table => is_table_case => "foo_bars".to_string(),
|
||||
benchmark_string_pluralize => to_plural => "crate".to_string(),
|
||||
benchmark_string_singular => to_singular => "crates".to_string(),
|
||||
benchmark_string_demodulize => demodulize => "Foo::Bar".to_string(),
|
||||
benchmark_string_deconstantize => deconstantize => "Foo::Bar".to_string(),
|
||||
benchmark_str_demodulize => demodulize => "Foo::Bar",
|
||||
benchmark_str_deconstantize => deconstantize => "Foo::Bar"
|
||||
];
|
||||
}
|
||||
117
.gear/predownloaded-development/vendor/Inflector/src/numbers/deordinalize/mod.rs
vendored
Normal file
117
.gear/predownloaded-development/vendor/Inflector/src/numbers/deordinalize/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/// Deorginalizes a `&str`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::numbers::deordinalize::deordinalize;
|
||||
/// let mock_string: &str = "0.1";
|
||||
/// let expected_string: String = "0.1".to_owned();
|
||||
/// let asserted_string: String = deordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::deordinalize::deordinalize;
|
||||
/// let mock_string: &str = "-1st";
|
||||
/// let expected_string: String = "-1".to_owned();
|
||||
/// let asserted_string: String = deordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::deordinalize::deordinalize;
|
||||
/// let mock_string: &str = "0th";
|
||||
/// let expected_string: String = "0".to_owned();
|
||||
/// let asserted_string: String = deordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::deordinalize::deordinalize;
|
||||
/// let mock_string: &str = "1st";
|
||||
/// let expected_string: String = "1".to_owned();
|
||||
/// let asserted_string: String = deordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::deordinalize::deordinalize;
|
||||
/// let mock_string: &str = "2nd";
|
||||
/// let expected_string: String = "2".to_owned();
|
||||
/// let asserted_string: String = deordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::deordinalize::deordinalize;
|
||||
/// let mock_string: &str = "3rd";
|
||||
/// let expected_string: String = "3".to_owned();
|
||||
/// let asserted_string: String = deordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::deordinalize::deordinalize;
|
||||
/// let mock_string: &str = "9th";
|
||||
/// let expected_string: String = "9".to_owned();
|
||||
/// let asserted_string: String = deordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::deordinalize::deordinalize;
|
||||
/// let mock_string: &str = "12th";
|
||||
/// let expected_string: String = "12".to_owned();
|
||||
/// let asserted_string: String = deordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::deordinalize::deordinalize;
|
||||
/// let mock_string: &str = "12000th";
|
||||
/// let expected_string: String = "12000".to_owned();
|
||||
/// let asserted_string: String = deordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::deordinalize::deordinalize;
|
||||
/// let mock_string: &str = "12001th";
|
||||
/// let expected_string: String = "12001".to_owned();
|
||||
/// let asserted_string: String = deordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::deordinalize::deordinalize;
|
||||
/// let mock_string: &str = "12002nd";
|
||||
/// let expected_string: String = "12002".to_owned();
|
||||
/// let asserted_string: String = deordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::deordinalize::deordinalize;
|
||||
/// let mock_string: &str = "12003rd";
|
||||
/// let expected_string: String = "12003".to_owned();
|
||||
/// let asserted_string: String = deordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::deordinalize::deordinalize;
|
||||
/// let mock_string: &str = "12004th";
|
||||
/// let expected_string: String = "12004".to_owned();
|
||||
/// let asserted_string: String = deordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
pub fn deordinalize(non_ordinalized_string: &str) -> String {
|
||||
if non_ordinalized_string.contains('.') {
|
||||
non_ordinalized_string.to_owned()
|
||||
} else {
|
||||
non_ordinalized_string.trim_end_matches("st")
|
||||
.trim_end_matches("nd")
|
||||
.trim_end_matches("rd")
|
||||
.trim_end_matches("th")
|
||||
.to_owned()
|
||||
}
|
||||
}
|
||||
9
.gear/predownloaded-development/vendor/Inflector/src/numbers/mod.rs
vendored
Normal file
9
.gear/predownloaded-development/vendor/Inflector/src/numbers/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#![deny(warnings)]
|
||||
/// Provides ordinalization of a string.
|
||||
///
|
||||
/// Example string "1" becomes "1st"
|
||||
pub mod ordinalize;
|
||||
/// Provides deordinalization of a string.
|
||||
///
|
||||
/// Example string "1st" becomes "1"
|
||||
pub mod deordinalize;
|
||||
147
.gear/predownloaded-development/vendor/Inflector/src/numbers/ordinalize/mod.rs
vendored
Normal file
147
.gear/predownloaded-development/vendor/Inflector/src/numbers/ordinalize/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
/// Orginalizes a `&str`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::numbers::ordinalize::ordinalize;
|
||||
/// let mock_string: &str = "a";
|
||||
/// let expected_string: String = "a".to_owned();
|
||||
/// let asserted_string: String = ordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::ordinalize::ordinalize;
|
||||
/// let mock_string: &str = "0.1";
|
||||
/// let expected_string: String = "0.1".to_owned();
|
||||
/// let asserted_string: String = ordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::ordinalize::ordinalize;
|
||||
/// let mock_string: &str = "-1";
|
||||
/// let expected_string: String = "-1st".to_owned();
|
||||
/// let asserted_string: String = ordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::ordinalize::ordinalize;
|
||||
/// let mock_string: &str = "0";
|
||||
/// let expected_string: String = "0th".to_owned();
|
||||
/// let asserted_string: String = ordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::ordinalize::ordinalize;
|
||||
/// let mock_string: &str = "1";
|
||||
/// let expected_string: String = "1st".to_owned();
|
||||
/// let asserted_string: String = ordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::ordinalize::ordinalize;
|
||||
/// let mock_string: &str = "2";
|
||||
/// let expected_string: String = "2nd".to_owned();
|
||||
/// let asserted_string: String = ordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::ordinalize::ordinalize;
|
||||
/// let mock_string: &str = "3";
|
||||
/// let expected_string: String = "3rd".to_owned();
|
||||
/// let asserted_string: String = ordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::ordinalize::ordinalize;
|
||||
/// let mock_string: &str = "9";
|
||||
/// let expected_string: String = "9th".to_owned();
|
||||
/// let asserted_string: String = ordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::ordinalize::ordinalize;
|
||||
/// let mock_string: &str = "12";
|
||||
/// let expected_string: String = "12th".to_owned();
|
||||
/// let asserted_string: String = ordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::ordinalize::ordinalize;
|
||||
/// let mock_string: &str = "12000";
|
||||
/// let expected_string: String = "12000th".to_owned();
|
||||
/// let asserted_string: String = ordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::ordinalize::ordinalize;
|
||||
/// let mock_string: &str = "12001";
|
||||
/// let expected_string: String = "12001st".to_owned();
|
||||
/// let asserted_string: String = ordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::ordinalize::ordinalize;
|
||||
/// let mock_string: &str = "12002";
|
||||
/// let expected_string: String = "12002nd".to_owned();
|
||||
/// let asserted_string: String = ordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::ordinalize::ordinalize;
|
||||
/// let mock_string: &str = "12003";
|
||||
/// let expected_string: String = "12003rd".to_owned();
|
||||
/// let asserted_string: String = ordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::numbers::ordinalize::ordinalize;
|
||||
/// let mock_string: &str = "12004";
|
||||
/// let expected_string: String = "12004th".to_owned();
|
||||
/// let asserted_string: String = ordinalize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
pub fn ordinalize(non_ordinalized_string: &str) -> String {
|
||||
let chars: Vec<char> = non_ordinalized_string.clone().chars().collect();
|
||||
let last_number: char = chars[chars.len() - 1];
|
||||
if is_ordinalizable(last_number) {
|
||||
return non_ordinalized_string.to_owned();
|
||||
}
|
||||
if chars.len() > 1 {
|
||||
if second_last_number_is_one(chars) {
|
||||
return format!("{}{}", non_ordinalized_string, "th");
|
||||
} else if string_contains_decimal(non_ordinalized_string.to_owned()) {
|
||||
return non_ordinalized_string.to_owned();
|
||||
}
|
||||
}
|
||||
match last_number {
|
||||
'1' => format!("{}{}", non_ordinalized_string, "st"),
|
||||
'2' => format!("{}{}", non_ordinalized_string, "nd"),
|
||||
'3' => format!("{}{}", non_ordinalized_string, "rd"),
|
||||
_ => format!("{}{}", non_ordinalized_string, "th"),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_ordinalizable(last_number: char) -> bool {
|
||||
!last_number.is_numeric()
|
||||
}
|
||||
|
||||
fn second_last_number_is_one(chars: Vec<char>) -> bool {
|
||||
let second_last_number: char = chars[chars.len() - 2];
|
||||
second_last_number == '1'
|
||||
}
|
||||
|
||||
fn string_contains_decimal(non_ordinalized_string: String) -> bool {
|
||||
non_ordinalized_string.contains('.')
|
||||
}
|
||||
225
.gear/predownloaded-development/vendor/Inflector/src/string/constants/mod.rs
vendored
Normal file
225
.gear/predownloaded-development/vendor/Inflector/src/string/constants/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
pub const UNACCONTABLE_WORDS: [&'static str; 202] = ["accommodation",
|
||||
"adulthood",
|
||||
"advertising",
|
||||
"advice",
|
||||
"aggression",
|
||||
"aid",
|
||||
"air",
|
||||
"aircraft",
|
||||
"alcohol",
|
||||
"anger",
|
||||
"applause",
|
||||
"arithmetic",
|
||||
"assistance",
|
||||
"athletics",
|
||||
|
||||
"bacon",
|
||||
"baggage",
|
||||
"beef",
|
||||
"biology",
|
||||
"blood",
|
||||
"botany",
|
||||
"bread",
|
||||
"butter",
|
||||
|
||||
"carbon",
|
||||
"cardboard",
|
||||
"cash",
|
||||
"chalk",
|
||||
"chaos",
|
||||
"chess",
|
||||
"crossroads",
|
||||
"countryside",
|
||||
|
||||
"dancing",
|
||||
"deer",
|
||||
"dignity",
|
||||
"dirt",
|
||||
"dust",
|
||||
|
||||
"economics",
|
||||
"education",
|
||||
"electricity",
|
||||
"engineering",
|
||||
"enjoyment",
|
||||
"envy",
|
||||
"equipment",
|
||||
"ethics",
|
||||
"evidence",
|
||||
"evolution",
|
||||
|
||||
"fame",
|
||||
"fiction",
|
||||
"flour",
|
||||
"flu",
|
||||
"food",
|
||||
"fuel",
|
||||
"fun",
|
||||
"furniture",
|
||||
|
||||
"gallows",
|
||||
"garbage",
|
||||
"garlic",
|
||||
"genetics",
|
||||
"gold",
|
||||
"golf",
|
||||
"gossip",
|
||||
"grammar",
|
||||
"gratitude",
|
||||
"grief",
|
||||
"guilt",
|
||||
"gymnastics",
|
||||
|
||||
"happiness",
|
||||
"hardware",
|
||||
"harm",
|
||||
"hate",
|
||||
"hatred",
|
||||
"health",
|
||||
"heat",
|
||||
"help",
|
||||
"homework",
|
||||
"honesty",
|
||||
"honey",
|
||||
"hospitality",
|
||||
"housework",
|
||||
"humour",
|
||||
"hunger",
|
||||
"hydrogen",
|
||||
|
||||
"ice",
|
||||
"importance",
|
||||
"inflation",
|
||||
"information",
|
||||
"innocence",
|
||||
"iron",
|
||||
"irony",
|
||||
|
||||
"jam",
|
||||
"jewelry",
|
||||
"judo",
|
||||
|
||||
"karate",
|
||||
"knowledge",
|
||||
|
||||
"lack",
|
||||
"laughter",
|
||||
"lava",
|
||||
"leather",
|
||||
"leisure",
|
||||
"lightning",
|
||||
"linguine",
|
||||
"linguini",
|
||||
"linguistics",
|
||||
"literature",
|
||||
"litter",
|
||||
"livestock",
|
||||
"logic",
|
||||
"loneliness",
|
||||
"luck",
|
||||
"luggage",
|
||||
|
||||
"macaroni",
|
||||
"machinery",
|
||||
"magic",
|
||||
"management",
|
||||
"mankind",
|
||||
"marble",
|
||||
"mathematics",
|
||||
"mayonnaise",
|
||||
"measles",
|
||||
"methane",
|
||||
"milk",
|
||||
"money",
|
||||
"mud",
|
||||
"music",
|
||||
"mumps",
|
||||
|
||||
"nature",
|
||||
"news",
|
||||
"nitrogen",
|
||||
"nonsense",
|
||||
"nurture",
|
||||
"nutrition",
|
||||
|
||||
"obedience",
|
||||
"obesity",
|
||||
"oxygen",
|
||||
|
||||
"pasta",
|
||||
"patience",
|
||||
"physics",
|
||||
"poetry",
|
||||
"pollution",
|
||||
"poverty",
|
||||
"pride",
|
||||
"psychology",
|
||||
"publicity",
|
||||
"punctuation",
|
||||
|
||||
"quartz",
|
||||
|
||||
"racism",
|
||||
"relaxation",
|
||||
"reliability",
|
||||
"research",
|
||||
"respect",
|
||||
"revenge",
|
||||
"rice",
|
||||
"rubbish",
|
||||
"rum",
|
||||
|
||||
"safety",
|
||||
"scenery",
|
||||
"seafood",
|
||||
"seaside",
|
||||
"series",
|
||||
"shame",
|
||||
"sheep",
|
||||
"shopping",
|
||||
"sleep",
|
||||
"smoke",
|
||||
"smoking",
|
||||
"snow",
|
||||
"soap",
|
||||
"software",
|
||||
"soil",
|
||||
"spaghetti",
|
||||
"species",
|
||||
"steam",
|
||||
"stuff",
|
||||
"stupidity",
|
||||
"sunshine",
|
||||
"symmetry",
|
||||
|
||||
"tennis",
|
||||
"thirst",
|
||||
"thunder",
|
||||
"timber",
|
||||
"traffic",
|
||||
"transportation",
|
||||
"trust",
|
||||
|
||||
"underwear",
|
||||
"unemployment",
|
||||
"unity",
|
||||
|
||||
"validity",
|
||||
"veal",
|
||||
"vegetation",
|
||||
"vegetarianism",
|
||||
"vengeance",
|
||||
"violence",
|
||||
"vitality",
|
||||
|
||||
"warmth",
|
||||
"wealth",
|
||||
"weather",
|
||||
"welfare",
|
||||
"wheat",
|
||||
"wildlife",
|
||||
"wisdom",
|
||||
"yoga",
|
||||
|
||||
"zinc",
|
||||
"zoology"];
|
||||
50
.gear/predownloaded-development/vendor/Inflector/src/string/deconstantize/mod.rs
vendored
Normal file
50
.gear/predownloaded-development/vendor/Inflector/src/string/deconstantize/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#[cfg(feature = "heavyweight")]
|
||||
use cases::classcase::to_class_case;
|
||||
|
||||
#[cfg(feature = "heavyweight")]
|
||||
/// Deconstantizes a `&str`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::string::deconstantize::deconstantize;
|
||||
/// let mock_string: &str = "Bar";
|
||||
/// let expected_string: String = "".to_owned();
|
||||
/// let asserted_string: String = deconstantize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::deconstantize::deconstantize;
|
||||
/// let mock_string: &str = "::Bar";
|
||||
/// let expected_string: String = "".to_owned();
|
||||
/// let asserted_string: String = deconstantize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::deconstantize::deconstantize;
|
||||
/// let mock_string: &str = "Foo::Bar";
|
||||
/// let expected_string: String = "Foo".to_owned();
|
||||
/// let asserted_string: String = deconstantize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::deconstantize::deconstantize;
|
||||
/// let mock_string: &str = "Test::Foo::Bar";
|
||||
/// let expected_string: String = "Foo".to_owned();
|
||||
/// let asserted_string: String = deconstantize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
pub fn deconstantize(non_deconstantized_string: &str) -> String {
|
||||
if non_deconstantized_string.contains("::") {
|
||||
let split_string: Vec<&str> = non_deconstantized_string.split("::").collect();
|
||||
if split_string.len() > 1 {
|
||||
to_class_case(split_string[split_string.len() - 2])
|
||||
} else {
|
||||
"".to_owned()
|
||||
}
|
||||
} else {
|
||||
"".to_owned()
|
||||
}
|
||||
}
|
||||
46
.gear/predownloaded-development/vendor/Inflector/src/string/demodulize/mod.rs
vendored
Normal file
46
.gear/predownloaded-development/vendor/Inflector/src/string/demodulize/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#[cfg(feature = "heavyweight")]
|
||||
use cases::classcase::to_class_case;
|
||||
|
||||
#[cfg(feature = "heavyweight")]
|
||||
/// Demodulize a `&str`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::string::demodulize::demodulize;
|
||||
/// let mock_string: &str = "Bar";
|
||||
/// let expected_string: String = "Bar".to_owned();
|
||||
/// let asserted_string: String = demodulize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::demodulize::demodulize;
|
||||
/// let mock_string: &str = "::Bar";
|
||||
/// let expected_string: String = "Bar".to_owned();
|
||||
/// let asserted_string: String = demodulize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::demodulize::demodulize;
|
||||
/// let mock_string: &str = "Foo::Bar";
|
||||
/// let expected_string: String = "Bar".to_owned();
|
||||
/// let asserted_string: String = demodulize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::demodulize::demodulize;
|
||||
/// let mock_string: &str = "Test::Foo::Bar";
|
||||
/// let expected_string: String = "Bar".to_owned();
|
||||
/// let asserted_string: String = demodulize(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
pub fn demodulize(non_demodulize_string: &str) -> String {
|
||||
if non_demodulize_string.contains("::") {
|
||||
let split_string: Vec<&str> = non_demodulize_string.split("::").collect();
|
||||
to_class_case(split_string[split_string.len() - 1])
|
||||
} else {
|
||||
non_demodulize_string.to_owned()
|
||||
}
|
||||
}
|
||||
23
.gear/predownloaded-development/vendor/Inflector/src/string/mod.rs
vendored
Normal file
23
.gear/predownloaded-development/vendor/Inflector/src/string/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#![deny(warnings)]
|
||||
/// Provides demodulize a string.
|
||||
///
|
||||
/// Example string `Foo::Bar` becomes `Bar`
|
||||
#[cfg(feature = "heavyweight")]
|
||||
pub mod demodulize;
|
||||
/// Provides deconstantizea string.
|
||||
///
|
||||
/// Example string `Foo::Bar` becomes `Foo`
|
||||
#[cfg(feature = "heavyweight")]
|
||||
pub mod deconstantize;
|
||||
/// Provides conversion to plural strings.
|
||||
///
|
||||
/// Example string `FooBar` -> `FooBars`
|
||||
#[cfg(feature = "heavyweight")]
|
||||
pub mod pluralize;
|
||||
/// Provides conversion to singular strings.
|
||||
///
|
||||
/// Example string `FooBars` -> `FooBar`
|
||||
#[cfg(feature = "heavyweight")]
|
||||
pub mod singularize;
|
||||
|
||||
mod constants;
|
||||
194
.gear/predownloaded-development/vendor/Inflector/src/string/pluralize/mod.rs
vendored
Normal file
194
.gear/predownloaded-development/vendor/Inflector/src/string/pluralize/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
#![deny(warnings)]
|
||||
use regex::Regex;
|
||||
use string::constants::UNACCONTABLE_WORDS;
|
||||
|
||||
macro_rules! add_rule{
|
||||
($r:ident, $rule:expr => $replace:expr) => {
|
||||
$r.push((Regex::new($rule).unwrap(), $replace));
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! rules{
|
||||
($r:ident; $($rule:expr => $replace:expr), *) => {
|
||||
$(
|
||||
add_rule!{$r, $rule => $replace}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lazy_static!{
|
||||
static ref RULES: Vec<(Regex, &'static str)> = {
|
||||
let mut r = Vec::with_capacity(24);
|
||||
rules![r;
|
||||
r"(\w*)s$" => "s",
|
||||
r"(\w*([^aeiou]ese))$" => "",
|
||||
r"(\w*(ax|test))is$" => "es",
|
||||
r"(\w*(alias|[^aou]us|tlas|gas|ris))$" => "es",
|
||||
r"(\w*(e[mn]u))s?$" => "s",
|
||||
r"(\w*([^l]ias|[aeiou]las|[emjzr]as|[iu]am))$" => "",
|
||||
r"(\w*(alumn|syllab|octop|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat))(?:us|i)$" => "i",
|
||||
r"(\w*(alumn|alg|vertebr))(?:a|ae)$" => "ae",
|
||||
r"(\w*(seraph|cherub))(?:im)?$" => "im",
|
||||
r"(\w*(her|at|gr))o$" => "oes",
|
||||
r"(\w*(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|automat|quor))(?:a|um)$" => "a",
|
||||
r"(\w*(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat))(?:a|on)$" => "a",
|
||||
r"(\w*)sis$" => "ses",
|
||||
r"(\w*(kni|wi|li))fe$" => "ves",
|
||||
r"(\w*(ar|l|ea|eo|oa|hoo))f$" => "ves",
|
||||
r"(\w*([^aeiouy]|qu))y$" => "ies",
|
||||
r"(\w*([^ch][ieo][ln]))ey$" => "ies",
|
||||
r"(\w*(x|ch|ss|sh|zz)es)$" => "",
|
||||
r"(\w*(x|ch|ss|sh|zz))$" => "es",
|
||||
r"(\w*(matr|cod|mur|sil|vert|ind|append))(?:ix|ex)$" => "ices",
|
||||
r"(\w*(m|l)(?:ice|ouse))$" => "ice",
|
||||
r"(\w*(pe)(?:rson|ople))$" => "ople",
|
||||
r"(\w*(child))(?:ren)?$" => "ren",
|
||||
r"(\w*eaux)$" => ""
|
||||
];
|
||||
r
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! special_cases{
|
||||
($s:ident, $($singular: expr => $plural:expr), *) => {
|
||||
match &$s[..] {
|
||||
$(
|
||||
$singular => {
|
||||
return $plural.to_owned();
|
||||
},
|
||||
)*
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Converts a `&str` to pluralized `String`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::string::pluralize::to_plural;
|
||||
/// let mock_string: &str = "foo_bar";
|
||||
/// let expected_string: String = "foo_bars".to_owned();
|
||||
/// let asserted_string: String = to_plural(mock_string);
|
||||
/// assert_eq!(asserted_string, expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::pluralize::to_plural;
|
||||
/// let mock_string: &str = "ox";
|
||||
/// let expected_string: String = "oxen".to_owned();
|
||||
/// let asserted_string: String = to_plural(mock_string);
|
||||
/// assert_eq!(asserted_string, expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::pluralize::to_plural;
|
||||
/// let mock_string: &str = "crate";
|
||||
/// let expected_string: String = "crates".to_owned();
|
||||
/// let asserted_string: String = to_plural(mock_string);
|
||||
/// assert_eq!(asserted_string, expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::pluralize::to_plural;
|
||||
/// let mock_string: &str = "boxes";
|
||||
/// let expected_string: String = "boxes".to_owned();
|
||||
/// let asserted_string: String = to_plural(mock_string);
|
||||
/// assert_eq!(asserted_string, expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::pluralize::to_plural;
|
||||
/// let mock_string: &str = "vengeance";
|
||||
/// let expected_string: String = "vengeance".to_owned();
|
||||
/// let asserted_string: String = to_plural(mock_string);
|
||||
/// assert_eq!(asserted_string, expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::pluralize::to_plural;
|
||||
/// let mock_string: &str = "yoga";
|
||||
/// let expected_string: String = "yoga".to_owned();
|
||||
/// let asserted_string: String = to_plural(mock_string);
|
||||
/// assert_eq!(asserted_string, expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::pluralize::to_plural;
|
||||
/// let mock_string: &str = "geometry";
|
||||
/// let expected_string: String = "geometries".to_owned();
|
||||
/// let asserted_string: String = to_plural(mock_string);
|
||||
/// assert_eq!(asserted_string, expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
pub fn to_plural(non_plural_string: &str) -> String {
|
||||
if UNACCONTABLE_WORDS.contains(&non_plural_string.as_ref()) {
|
||||
non_plural_string.to_owned()
|
||||
} else {
|
||||
special_cases![non_plural_string,
|
||||
"ox" => "oxen",
|
||||
"man" => "men",
|
||||
"woman" => "women",
|
||||
"die" => "dice",
|
||||
"yes" => "yeses",
|
||||
"foot" => "feet",
|
||||
"eave" => "eaves",
|
||||
"goose" => "geese",
|
||||
"tooth" => "teeth",
|
||||
"quiz" => "quizzes"
|
||||
];
|
||||
for &(ref rule, replace) in RULES.iter().rev() {
|
||||
if let Some(c) = rule.captures(&non_plural_string) {
|
||||
if let Some(c) = c.get(1) {
|
||||
return format!("{}{}", c.as_str(), replace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
format!("{}s", non_plural_string)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
macro_rules! as_item {
|
||||
($i:item) => { $i };
|
||||
}
|
||||
|
||||
macro_rules! make_tests{
|
||||
($($singular:ident => $plural:ident); *) =>{
|
||||
$(
|
||||
as_item! {
|
||||
#[test]
|
||||
fn $singular(){
|
||||
assert_eq!(
|
||||
stringify!($plural),
|
||||
super::to_plural(stringify!($singular))
|
||||
);
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn boxes() {
|
||||
assert_eq!("boxes", super::to_plural("box"));
|
||||
}
|
||||
|
||||
make_tests!{
|
||||
geometry => geometries;
|
||||
ox => oxen;
|
||||
woman => women;
|
||||
test => tests;
|
||||
axis => axes;
|
||||
knife => knives;
|
||||
agendum => agenda;
|
||||
elf => elves;
|
||||
zoology => zoology
|
||||
}
|
||||
}
|
||||
189
.gear/predownloaded-development/vendor/Inflector/src/string/singularize/mod.rs
vendored
Normal file
189
.gear/predownloaded-development/vendor/Inflector/src/string/singularize/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
use regex::Regex;
|
||||
use string::constants::UNACCONTABLE_WORDS;
|
||||
|
||||
macro_rules! special_cases{
|
||||
($s:ident, $($singular: expr => $plural:expr), *) => {
|
||||
match &$s[..] {
|
||||
$(
|
||||
$singular => {
|
||||
return $plural.to_owned();
|
||||
},
|
||||
)*
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Converts a `&str` to singularized `String`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::string::singularize::to_singular;
|
||||
/// let mock_string: &str = "foo_bars";
|
||||
/// let expected_string: String = "foo_bar".to_owned();
|
||||
/// let asserted_string: String = to_singular(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::singularize::to_singular;
|
||||
/// let mock_string: &str = "oxen";
|
||||
/// let expected_string: String = "ox".to_owned();
|
||||
/// let asserted_string: String = to_singular(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::singularize::to_singular;
|
||||
/// let mock_string: &str = "crates";
|
||||
/// let expected_string: String = "crate".to_owned();
|
||||
/// let asserted_string: String = to_singular(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::singularize::to_singular;
|
||||
/// let mock_string: &str = "oxen";
|
||||
/// let expected_string: String = "ox".to_owned();
|
||||
/// let asserted_string: String = to_singular(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::singularize::to_singular;
|
||||
/// let mock_string: &str = "boxes";
|
||||
/// let expected_string: String = "box".to_owned();
|
||||
/// let asserted_string: String = to_singular(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::singularize::to_singular;
|
||||
/// let mock_string: &str = "vengeance";
|
||||
/// let expected_string: String = "vengeance".to_owned();
|
||||
/// let asserted_string: String = to_singular(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::string::singularize::to_singular;
|
||||
/// let mock_string: &str = "yoga";
|
||||
/// let expected_string: String = "yoga".to_owned();
|
||||
/// let asserted_string: String = to_singular(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
pub fn to_singular(non_singular_string: &str) -> String {
|
||||
if UNACCONTABLE_WORDS.contains(&non_singular_string.as_ref()) {
|
||||
non_singular_string.to_owned()
|
||||
} else {
|
||||
special_cases![non_singular_string,
|
||||
"oxen" => "ox",
|
||||
"boxes" => "box",
|
||||
"men" => "man",
|
||||
"women" => "woman",
|
||||
"dice" => "die",
|
||||
"yeses" => "yes",
|
||||
"feet" => "foot",
|
||||
"eaves" => "eave",
|
||||
"geese" => "goose",
|
||||
"teeth" => "tooth",
|
||||
"quizzes" => "quiz"
|
||||
];
|
||||
for &(ref rule, replace) in RULES.iter().rev() {
|
||||
if let Some(captures) = rule.captures(&non_singular_string) {
|
||||
if let Some(c) = captures.get(1) {
|
||||
let mut buf = String::new();
|
||||
captures.expand(&format!("{}{}", c.as_str(), replace), &mut buf);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
format!("{}", non_singular_string)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! add_rule{
|
||||
($r:ident, $rule:expr => $replace:expr) => {
|
||||
$r.push((Regex::new($rule).unwrap(), $replace));
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! rules{
|
||||
($r:ident; $($rule:expr => $replace:expr), *) => {
|
||||
$(
|
||||
add_rule!{$r, $rule => $replace}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lazy_static!{
|
||||
static ref RULES: Vec<(Regex, &'static str)> = {
|
||||
let mut r = Vec::with_capacity(27);
|
||||
rules![r;
|
||||
r"(\w*)s$" => "",
|
||||
r"(\w*)(ss)$" => "$2",
|
||||
r"(n)ews$" => "ews",
|
||||
r"(\w*)(o)es$" => "",
|
||||
r"(\w*)([ti])a$" => "um",
|
||||
r"((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$" => "sis",
|
||||
r"(^analy)(sis|ses)$" => "sis",
|
||||
r"(\w*)([^f])ves$" => "fe",
|
||||
r"(\w*)(hive)s$" => "",
|
||||
r"(\w*)(tive)s$" => "",
|
||||
r"(\w*)([lr])ves$" => "f",
|
||||
r"(\w*([^aeiouy]|qu))ies$" => "y",
|
||||
r"(s)eries$" => "eries",
|
||||
r"(m)ovies$" => "ovie",
|
||||
r"(\w*)(x|ch|ss|sh)es$" => "$2",
|
||||
r"(m|l)ice$" => "ouse",
|
||||
r"(bus)(es)?$" => "",
|
||||
r"(shoe)s$" => "",
|
||||
r"(cris|test)(is|es)$" => "is",
|
||||
r"^(a)x[ie]s$" => "xis",
|
||||
r"(octop|vir)(us|i)$" => "us",
|
||||
r"(alias|status)(es)?$" => "",
|
||||
r"^(ox)en" => "",
|
||||
r"(vert|ind)ices$" => "ex",
|
||||
r"(matr)ices$" => "ix",
|
||||
r"(quiz)zes$" => "",
|
||||
r"(database)s$" => ""
|
||||
];
|
||||
r
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn singularize_ies_suffix() {
|
||||
assert_eq!("reply", to_singular("replies"));
|
||||
assert_eq!("lady", to_singular("ladies"));
|
||||
assert_eq!("soliloquy", to_singular("soliloquies"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn singularize_ss_suffix() {
|
||||
assert_eq!("glass", to_singular("glass"));
|
||||
assert_eq!("access", to_singular("access"));
|
||||
assert_eq!("glass", to_singular("glasses"));
|
||||
assert_eq!("witch", to_singular("witches"));
|
||||
assert_eq!("dish", to_singular("dishes"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn singularize_string_if_a_regex_will_match() {
|
||||
let expected_string: String = "ox".to_owned();
|
||||
let asserted_string: String = to_singular("oxen");
|
||||
assert!(expected_string == asserted_string);
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn singularize_string_returns_none_option_if_no_match() {
|
||||
let expected_string: String = "bacon".to_owned();
|
||||
let asserted_string: String = to_singular("bacon");
|
||||
|
||||
assert!(expected_string == asserted_string);
|
||||
}
|
||||
139
.gear/predownloaded-development/vendor/Inflector/src/suffix/foreignkey/mod.rs
vendored
Normal file
139
.gear/predownloaded-development/vendor/Inflector/src/suffix/foreignkey/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
use cases::snakecase::to_snake_case;
|
||||
|
||||
/// Converts a `&str` to a `foreign_key`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::suffix::foreignkey::to_foreign_key;
|
||||
/// let mock_string: &str = "foo_bar";
|
||||
/// let expected_string: String = "foo_bar_id".to_owned();
|
||||
/// let asserted_string: String = to_foreign_key(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::suffix::foreignkey::to_foreign_key;
|
||||
/// let mock_string: &str = "Foo bar";
|
||||
/// let expected_string: String = "foo_bar_id".to_owned();
|
||||
/// let asserted_string: String = to_foreign_key(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::suffix::foreignkey::to_foreign_key;
|
||||
/// let mock_string: &str = "Foo Bar";
|
||||
/// let expected_string: String = "foo_bar_id".to_owned();
|
||||
/// let asserted_string: String = to_foreign_key(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::suffix::foreignkey::to_foreign_key;
|
||||
/// let mock_string: &str = "Foo::Bar";
|
||||
/// let expected_string: String = "bar_id".to_owned();
|
||||
/// let asserted_string: String = to_foreign_key(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::suffix::foreignkey::to_foreign_key;
|
||||
/// let mock_string: &str = "Test::Foo::Bar";
|
||||
/// let expected_string: String = "bar_id".to_owned();
|
||||
/// let asserted_string: String = to_foreign_key(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::suffix::foreignkey::to_foreign_key;
|
||||
/// let mock_string: &str = "FooBar";
|
||||
/// let expected_string: String = "foo_bar_id".to_owned();
|
||||
/// let asserted_string: String = to_foreign_key(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::suffix::foreignkey::to_foreign_key;
|
||||
/// let mock_string: &str = "fooBar";
|
||||
/// let expected_string: String = "foo_bar_id".to_owned();
|
||||
/// let asserted_string: String = to_foreign_key(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::suffix::foreignkey::to_foreign_key;
|
||||
/// let mock_string: &str = "fooBar3";
|
||||
/// let expected_string: String = "foo_bar_3_id".to_owned();
|
||||
/// let asserted_string: String = to_foreign_key(mock_string);
|
||||
/// assert!(asserted_string == expected_string);
|
||||
///
|
||||
/// ```
|
||||
pub fn to_foreign_key(non_foreign_key_string: &str) -> String {
|
||||
if non_foreign_key_string.contains("::") {
|
||||
let split_string: Vec<&str> = non_foreign_key_string.split("::").collect();
|
||||
safe_convert(split_string[split_string.len() - 1])
|
||||
} else {
|
||||
safe_convert(non_foreign_key_string)
|
||||
}
|
||||
}
|
||||
fn safe_convert(safe_string: &str) -> String {
|
||||
let snake_cased: String = to_snake_case(safe_string);
|
||||
if snake_cased.ends_with("_id") {
|
||||
snake_cased
|
||||
} else {
|
||||
format!("{}{}", snake_cased, "_id")
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines if a `&str` is a `foreign_key`
|
||||
///
|
||||
/// ```
|
||||
/// use inflector::suffix::foreignkey::is_foreign_key;
|
||||
/// let mock_string: &str = "Foo bar string that is really really long";
|
||||
/// let asserted_bool: bool = is_foreign_key(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::suffix::foreignkey::is_foreign_key;
|
||||
/// let mock_string: &str = "foo-bar-string-that-is-really-really-long";
|
||||
/// let asserted_bool: bool = is_foreign_key(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::suffix::foreignkey::is_foreign_key;
|
||||
/// let mock_string: &str = "FooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_foreign_key(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::suffix::foreignkey::is_foreign_key;
|
||||
/// let mock_string: &str = "Foo Bar Is A Really Really Long String";
|
||||
/// let asserted_bool: bool = is_foreign_key(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::suffix::foreignkey::is_foreign_key;
|
||||
/// let mock_string: &str = "fooBarIsAReallyReallyLongString";
|
||||
/// let asserted_bool: bool = is_foreign_key(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::suffix::foreignkey::is_foreign_key;
|
||||
/// let mock_string: &str = "foo_bar_string_that_is_really_really_long";
|
||||
/// let asserted_bool: bool = is_foreign_key(mock_string);
|
||||
/// assert!(asserted_bool == false);
|
||||
///
|
||||
/// ```
|
||||
/// ```
|
||||
/// use inflector::suffix::foreignkey::is_foreign_key;
|
||||
/// let mock_string: &str = "foo_bar_string_that_is_really_really_long_id";
|
||||
/// let asserted_bool: bool = is_foreign_key(mock_string);
|
||||
/// assert!(asserted_bool == true);
|
||||
///
|
||||
/// ```
|
||||
pub fn is_foreign_key(test_string: &str) -> bool {
|
||||
to_foreign_key(test_string.clone()) == test_string
|
||||
}
|
||||
5
.gear/predownloaded-development/vendor/Inflector/src/suffix/mod.rs
vendored
Normal file
5
.gear/predownloaded-development/vendor/Inflector/src/suffix/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#![deny(warnings)]
|
||||
/// Provides foreign key conversion for String.
|
||||
///
|
||||
/// Example string `foo` becomes `foo_id`
|
||||
pub mod foreignkey;
|
||||
162
.gear/predownloaded-development/vendor/Inflector/tests/lib.rs
vendored
Normal file
162
.gear/predownloaded-development/vendor/Inflector/tests/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
#![deny(warnings)]
|
||||
extern crate inflector;
|
||||
|
||||
use inflector::Inflector;
|
||||
use inflector::InflectorNumbers;
|
||||
|
||||
macro_rules! str_tests {
|
||||
( $($test_name:ident => $imp_trait:ident => $to_cast:expr => $casted:expr), *) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
assert_eq!($to_cast.$imp_trait(), $casted)
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! string_tests {
|
||||
( $($test_name:ident => $imp_trait:ident => $to_cast:expr => $casted:expr), *) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
assert_eq!($to_cast.to_string().$imp_trait(), $casted)
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! number_tests {
|
||||
( $($test_name:ident => $imp_trait:ident => $typ:ident => $to_cast:expr => $casted:expr), *) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
let to_cast: $typ = $to_cast;
|
||||
assert_eq!(to_cast.$imp_trait(), $casted)
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! gated_str_tests {
|
||||
( $($test_name:ident => $imp_trait:ident => $to_cast:expr => $casted:expr), *) => {
|
||||
$(
|
||||
#[test]
|
||||
#[cfg(feature = "heavyweight")]
|
||||
fn $test_name() {
|
||||
assert_eq!($to_cast.$imp_trait(), $casted)
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! gated_string_tests {
|
||||
( $($test_name:ident => $imp_trait:ident => $to_cast:expr => $casted:expr), *) => {
|
||||
$(
|
||||
#[test]
|
||||
#[cfg(feature = "heavyweight")]
|
||||
fn $test_name() {
|
||||
assert_eq!($to_cast.to_string().$imp_trait(), $casted)
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
str_tests![
|
||||
str_to_camel => to_camel_case => "foo_bar" => "fooBar".to_string(),
|
||||
str_is_camel => is_camel_case => "fooBar" => true,
|
||||
str_is_not_camel => is_camel_case => "foo_bar" => false,
|
||||
str_to_screaming_snake => to_screaming_snake_case => "fooBar" => "FOO_BAR".to_string(),
|
||||
str_is_screaming_snake => is_screaming_snake_case => "FOO_BAR" => true,
|
||||
str_is_not_screaming_snake => is_screaming_snake_case => "foo_bar" => false,
|
||||
str_to_snake => to_snake_case => "fooBar" => "foo_bar".to_string(),
|
||||
str_is_snake => is_snake_case => "foo_bar" => true,
|
||||
str_is_not_snake => is_snake_case => "fooBar" => false,
|
||||
str_to_kebab => to_kebab_case => "fooBar" => "foo-bar".to_string(),
|
||||
str_is_kebab => is_kebab_case => "foo-bar" => true,
|
||||
str_is_not_kebab => is_kebab_case => "fooBar" => false,
|
||||
str_to_train => to_train_case => "fooBar" => "Foo-Bar".to_string(),
|
||||
str_is_train => is_train_case => "Foo-Bar" => true,
|
||||
str_is_not_train => is_train_case => "FOO-Bar" => false,
|
||||
str_to_sentence => to_sentence_case => "fooBar" => "Foo bar".to_string(),
|
||||
str_is_sentence => is_sentence_case => "Foo bar" => true,
|
||||
str_is_not_sentence => is_sentence_case => "foo_bar" => false,
|
||||
str_to_title => to_title_case => "fooBar" => "Foo Bar".to_string(),
|
||||
str_is_title => is_title_case => "Foo Bar" => true,
|
||||
str_is_not_title => is_title_case => "Foo_Bar" => false,
|
||||
str_ordinalize => ordinalize => "1" => "1st".to_string(),
|
||||
str_deordinalize => deordinalize => "1st" => "1".to_string(),
|
||||
str_to_foreign_key => to_foreign_key => "Foo::Bar" => "bar_id".to_string(),
|
||||
str_is_foreign_key => is_foreign_key => "bar_id" => true,
|
||||
str_is_not_foreign_key => is_foreign_key => "bar" => false
|
||||
];
|
||||
|
||||
gated_str_tests![
|
||||
str_to_class_case => to_class_case => "foo" => "Foo".to_string(),
|
||||
str_is_class_case => is_class_case => "Foo" => true,
|
||||
str_is_not_class_case => is_class_case => "foo" => false,
|
||||
str_to_table => to_table_case => "fooBar" => "foo_bars".to_string(),
|
||||
str_is_table => is_table_case => "foo_bars" => true,
|
||||
str_is_not_table => is_table_case => "fooBars" => false,
|
||||
str_pluralize => to_plural => "crate" => "crates".to_string(),
|
||||
str_singular => to_singular => "crates" => "crate".to_string(),
|
||||
str_demodulize => demodulize => "Foo::Bar" => "Bar".to_string(),
|
||||
str_deconstantize => deconstantize => "Foo::Bar" => "Foo".to_string()
|
||||
];
|
||||
|
||||
string_tests![
|
||||
string_to_camel => to_camel_case => "foo_bar".to_string() => "fooBar".to_string(),
|
||||
string_is_camel => is_camel_case => "fooBar".to_string() => true,
|
||||
string_is_not_camel => is_camel_case => "foo_bar".to_string() => false,
|
||||
string_to_screaming_snake => to_screaming_snake_case => "fooBar".to_string() => "FOO_BAR".to_string(),
|
||||
string_is_screaming_snake => is_screaming_snake_case => "FOO_BAR".to_string() => true,
|
||||
string_is_not_screaming_snake => is_screaming_snake_case => "foo_bar".to_string() => false,
|
||||
string_to_snake => to_snake_case => "fooBar".to_string() => "foo_bar".to_string(),
|
||||
string_is_snake => is_snake_case => "foo_bar".to_string() => true,
|
||||
string_is_not_snake => is_snake_case => "fooBar".to_string() => false,
|
||||
string_to_kebab => to_kebab_case => "fooBar".to_string() => "foo-bar".to_string(),
|
||||
string_is_kebab => is_kebab_case => "foo-bar".to_string() => true,
|
||||
string_is_not_kebab => is_kebab_case => "fooBar".to_string() => false,
|
||||
string_to_train => to_train_case => "fooBar".to_string() => "Foo-Bar".to_string(),
|
||||
string_is_train => is_train_case => "Foo-Bar".to_string() => true,
|
||||
string_is_not_train => is_train_case => "foo-Bar".to_string() => false,
|
||||
string_to_sentence => to_sentence_case => "fooBar".to_string() => "Foo bar".to_string(),
|
||||
string_is_sentence => is_sentence_case => "Foo bar".to_string() => true,
|
||||
string_is_not_sentence => is_sentence_case => "fooBar".to_string() => false,
|
||||
string_to_title => to_title_case => "fooBar".to_string() => "Foo Bar".to_string(),
|
||||
string_is_title => is_title_case => "Foo Bar".to_string() => true,
|
||||
string_is_not_title => is_title_case => "fooBar".to_string() => false,
|
||||
string_ordinalize => ordinalize => "1".to_string() => "1st".to_string(),
|
||||
string_deordinalize => deordinalize => "1st".to_string() => "1".to_string(),
|
||||
string_to_foreign_key => to_foreign_key => "Foo::Bar".to_string() => "bar_id".to_string(),
|
||||
string_is_foreign_key => is_foreign_key => "bar_id".to_string() => true,
|
||||
string_is_not_foreign_key => is_foreign_key => "bar".to_string() => false
|
||||
];
|
||||
|
||||
gated_string_tests![
|
||||
string_to_class_case => to_class_case => "foo".to_string() => "Foo".to_string(),
|
||||
string_is_class_case => is_class_case => "Foo".to_string() => true,
|
||||
string_is_not_class_case => is_class_case => "ooBar".to_string() => false,
|
||||
string_to_table => to_table_case => "fooBar".to_string() => "foo_bars".to_string(),
|
||||
string_is_table => is_table_case => "foo_bars".to_string() => true,
|
||||
string_is_not_table => is_table_case => "fooBar".to_string() => false,
|
||||
string_pluralize => to_plural => "crate".to_string() => "crates".to_string(),
|
||||
string_singular => to_singular => "crates".to_string() => "crate".to_string(),
|
||||
string_demodulize => demodulize => "Foo::Bar".to_string() => "Bar".to_string(),
|
||||
string_deconstantize => deconstantize => "Foo::Bar".to_string() => "Foo".to_string()
|
||||
];
|
||||
|
||||
number_tests![
|
||||
i8_ordinalize => ordinalize => i8 => 1 => "1st".to_string(),
|
||||
i16_ordinalize => ordinalize => i16 => 1 => "1st".to_string(),
|
||||
i32_ordinalize => ordinalize => i32 => 1 => "1st".to_string(),
|
||||
i64_ordinalize => ordinalize => i64 => 1 => "1st".to_string(),
|
||||
u8_ordinalize => ordinalize => u8 => 1 => "1st".to_string(),
|
||||
u16_ordinalize => ordinalize => u16 => 1 => "1st".to_string(),
|
||||
u32_ordinalize => ordinalize => u32 => 1 => "1st".to_string(),
|
||||
u64_ordinalize => ordinalize => u64 => 1 => "1st".to_string(),
|
||||
isize_ordinalize => ordinalize => isize => 1 => "1st".to_string(),
|
||||
usize_ordinalize => ordinalize => usize => 1 => "1st".to_string(),
|
||||
f32_ordinalize => ordinalize => f32 => 1.0 => "1st".to_string(),
|
||||
f64_ordinalize => ordinalize => f64 => 1.0 => "1st".to_string()
|
||||
];
|
||||
1
.gear/predownloaded-development/vendor/addr2line/.cargo-checksum.json
vendored
Normal file
1
.gear/predownloaded-development/vendor/addr2line/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{".cargo_vcs_info.json":"70f22e279a4a1b2697dfc1b53ead965a913faa3d2604545c439b28a24bf5eaf5","CHANGELOG.md":"2bfe37c8240577170e3e9122c2e17942e8b2aba73fee100eeeede47b1107f8b8","Cargo.lock":"c9e56108c9a0cadb122774fbe24b2085a521ac1252686dc3cb70ae165af6bdf2","Cargo.toml":"6c371cb14bed07740324acb5b126bd58cf87771be72d4d88366b000f138b8001","Cargo.toml.orig":"1ce22b0b31c6bd077501c96cd568a95ee894042d651b0db9245a2f4395d12872","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"e99d88d232bf57d70f0fb87f6b496d44b6653f99f8a63d250a54c61ea4bcde40","README.md":"c635ed91d7b0c87ff2f0f311cd1a31336d2cbc4d011965d3b58afaca073538d9","src/bin/addr2line.rs":"147c07d761c845c5faf3e1e3904c33374bc84bc79b2b95ae892b1def5ce6ced6","src/frame.rs":"de3b23388c36a0874db5569d1f49ce6cc52ef2006b9ae9b9a3eba7654b201e2b","src/function.rs":"6e0aceeb826db8fcec78376ee72b5dca098ae3e409e9defc5f1af9bfb2c7f173","src/lib.rs":"79fea2e8912719a0a4e30207839e7689e66f6c801a80dde3e81f0fed9c7fd3e8","src/line.rs":"374afffcd11e38dc1b093d38b16b42d33c2a5fa9e7dbb759ecf15c1f6c58a7a0","src/loader.rs":"d94f6ca760382a2f3260fa8e6382196eaba07aaced308f088e8957f94cd21479","src/lookup.rs":"0d28a2fd00f0696f8fb50cdc88cb7d55a910df8bf3052b7c74ae50a387346e67","src/unit.rs":"ec201e91333dc8919ab64f0144025521c46ac897679538432a84788af5244667"},"package":"1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"}
|
||||
6
.gear/predownloaded-development/vendor/addr2line/.cargo_vcs_info.json
vendored
Normal file
6
.gear/predownloaded-development/vendor/addr2line/.cargo_vcs_info.json
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"git": {
|
||||
"sha1": "f02db009deb9b441818afa49cb1b17453c1e4243"
|
||||
},
|
||||
"path_in_vcs": ""
|
||||
}
|
||||
485
.gear/predownloaded-development/vendor/addr2line/CHANGELOG.md
vendored
Normal file
485
.gear/predownloaded-development/vendor/addr2line/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,485 @@
|
|||
# `addr2line` Change Log
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.25.1 (2025/09/13)
|
||||
|
||||
### Changed
|
||||
|
||||
* Fixed line parsing for split DWARF.
|
||||
[#353](https://github.com/gimli-rs/addr2line/pull/353)
|
||||
|
||||
* Changed `.debug_aranges` parsing to skip invalid entries instead of failing.
|
||||
[#355](https://github.com/gimli-rs/addr2line/pull/355)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.25.0 (2025/06/11)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Updated `gimli` dependency.
|
||||
|
||||
### Added
|
||||
|
||||
* Added `Loader::find_symbol`.
|
||||
[#341](https://github.com/gimli-rs/addr2line/pull/341)
|
||||
[#349](https://github.com/gimli-rs/addr2line/pull/349)
|
||||
|
||||
* Added `Loader::get_section_range`.
|
||||
Added `--section` option to `addr2line` binary.
|
||||
[#343](https://github.com/gimli-rs/addr2line/pull/343)
|
||||
|
||||
* Added `wasm` feature.
|
||||
[#348](https://github.com/gimli-rs/addr2line/pull/348)
|
||||
|
||||
### Changed
|
||||
|
||||
* Fixed handling of Windows paths that use forward slashes.
|
||||
[#342](https://github.com/gimli-rs/addr2line/pull/342)
|
||||
|
||||
* Removed `compiler-builtins` from `rustc-dep-of-std` dependencies.
|
||||
[#345](https://github.com/gimli-rs/addr2line/pull/345)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.24.2 (2024/10/04)
|
||||
|
||||
### Changed
|
||||
|
||||
* Enabled caching of DWARF abbreviations.
|
||||
[#318](https://github.com/gimli-rs/addr2line/pull/318)
|
||||
|
||||
* Changed the `addr2line` binary to prefer symbol names over DWARF names.
|
||||
[#332](https://github.com/gimli-rs/addr2line/pull/332)
|
||||
|
||||
* Updated `gimli` dependency.
|
||||
|
||||
### Added
|
||||
|
||||
* Added `Context::from_arc_dwarf`.
|
||||
[#327](https://github.com/gimli-rs/addr2line/pull/327)
|
||||
|
||||
* Added benchmark comparison.
|
||||
[#315](https://github.com/gimli-rs/addr2line/pull/315)
|
||||
[#321](https://github.com/gimli-rs/addr2line/pull/321)
|
||||
[#322](https://github.com/gimli-rs/addr2line/pull/322)
|
||||
[#325](https://github.com/gimli-rs/addr2line/pull/325)
|
||||
|
||||
* Added more tests.
|
||||
[#328](https://github.com/gimli-rs/addr2line/pull/328)
|
||||
[#330](https://github.com/gimli-rs/addr2line/pull/330)
|
||||
[#331](https://github.com/gimli-rs/addr2line/pull/331)
|
||||
[#333](https://github.com/gimli-rs/addr2line/pull/333)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.24.1 (2024/07/26)
|
||||
|
||||
### Changed
|
||||
|
||||
* Fixed parsing of partial units, which are found in supplementary object files.
|
||||
[#313](https://github.com/gimli-rs/addr2line/pull/313)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.24.0 (2024/07/16)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Updated `gimli` dependency.
|
||||
|
||||
### Changed
|
||||
|
||||
* Changed the order of ranges returned by `Context::find_location_range`, and
|
||||
fixed handling in rare situations.
|
||||
[#303](https://github.com/gimli-rs/addr2line/pull/303)
|
||||
[#304](https://github.com/gimli-rs/addr2line/pull/304)
|
||||
[#306](https://github.com/gimli-rs/addr2line/pull/306)
|
||||
|
||||
* Improved the performance of `Context::find_location`.
|
||||
[#305](https://github.com/gimli-rs/addr2line/pull/305)
|
||||
|
||||
### Added
|
||||
|
||||
* Added `LoaderReader`.
|
||||
[#307](https://github.com/gimli-rs/addr2line/pull/307)
|
||||
|
||||
* Added `--all` option to `addr2line`.
|
||||
[#307](https://github.com/gimli-rs/addr2line/pull/307)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.23.0 (2024/05/26)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Updated `gimli` dependency.
|
||||
|
||||
* Deleted `Context::new`, `Context::new_with_sup`, and `builtin_split_dwarf_loader`.
|
||||
Use `Context::from_dwarf` or `Loader::new` instead.
|
||||
This removes `object` from the public API.
|
||||
[#296](https://github.com/gimli-rs/addr2line/pull/296)
|
||||
|
||||
### Changed
|
||||
|
||||
* Fixed handling of column 0 in the line table.
|
||||
[#290](https://github.com/gimli-rs/addr2line/pull/290)
|
||||
|
||||
* Moved `addr2line` from `examples` to `bin`. Requires the `bin` feature.
|
||||
[#291](https://github.com/gimli-rs/addr2line/pull/291)
|
||||
|
||||
* Split up `lib.rs` into smaller modules.
|
||||
[#292](https://github.com/gimli-rs/addr2line/pull/292)
|
||||
|
||||
### Added
|
||||
|
||||
* Added `Loader`. Requires the `loader` feature.
|
||||
[#296](https://github.com/gimli-rs/addr2line/pull/296)
|
||||
[#297](https://github.com/gimli-rs/addr2line/pull/297)
|
||||
|
||||
* Added unpacked Mach-O support to `Loader`.
|
||||
[#298](https://github.com/gimli-rs/addr2line/pull/298)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.22.0 (2024/04/11)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Updated `gimli` and `object` dependencies.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.21.0 (2023/08/12)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Updated `gimli`, `object`, and `fallible-iterator` dependencies.
|
||||
|
||||
### Changed
|
||||
|
||||
* The minimum supported rust version is 1.65.0.
|
||||
|
||||
* Store boxed slices instead of `Vec` objects in `Context`.
|
||||
[#278](https://github.com/gimli-rs/addr2line/pull/278)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.20.0 (2023/04/15)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* The minimum supported rust version is 1.58.0.
|
||||
|
||||
* Changed `Context::find_frames` to return `LookupResult`.
|
||||
Use `LookupResult::skip_all_loads` to obtain the result without loading split DWARF.
|
||||
[#260](https://github.com/gimli-rs/addr2line/pull/260)
|
||||
|
||||
* Replaced `Context::find_dwarf_unit` with `Context::find_dwarf_and_unit`.
|
||||
[#260](https://github.com/gimli-rs/addr2line/pull/260)
|
||||
|
||||
* Updated `object` dependency.
|
||||
|
||||
### Changed
|
||||
|
||||
* Fix handling of file index 0 for DWARF 5.
|
||||
[#264](https://github.com/gimli-rs/addr2line/pull/264)
|
||||
|
||||
### Added
|
||||
|
||||
* Added types and methods to support loading split DWARF:
|
||||
`LookupResult`, `SplitDwarfLoad`, `SplitDwarfLoader`, `Context::preload_units`.
|
||||
[#260](https://github.com/gimli-rs/addr2line/pull/260)
|
||||
[#262](https://github.com/gimli-rs/addr2line/pull/262)
|
||||
[#263](https://github.com/gimli-rs/addr2line/pull/263)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.19.0 (2022/11/24)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Updated `gimli` and `object` dependencies.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.18.0 (2022/07/16)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Updated `object` dependency.
|
||||
|
||||
### Changed
|
||||
|
||||
* Fixed handling of relative path for `DW_AT_comp_dir`.
|
||||
[#239](https://github.com/gimli-rs/addr2line/pull/239)
|
||||
|
||||
* Fixed handling of `DW_FORM_addrx` for DWARF 5 support.
|
||||
[#243](https://github.com/gimli-rs/addr2line/pull/243)
|
||||
|
||||
* Fixed handling of units that are missing range information.
|
||||
[#249](https://github.com/gimli-rs/addr2line/pull/249)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.17.0 (2021/10/24)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Updated `gimli` and `object` dependencies.
|
||||
|
||||
### Changed
|
||||
|
||||
* Use `skip_attributes` to improve performance.
|
||||
[#236](https://github.com/gimli-rs/addr2line/pull/236)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.16.0 (2021/07/26)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Updated `gimli` and `object` dependencies.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.15.2 (2021/06/04)
|
||||
|
||||
### Fixed
|
||||
|
||||
* Allow `Context` to be `Send`.
|
||||
[#219](https://github.com/gimli-rs/addr2line/pull/219)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.15.1 (2021/05/02)
|
||||
|
||||
### Fixed
|
||||
|
||||
* Don't ignore aranges with address 0.
|
||||
[#217](https://github.com/gimli-rs/addr2line/pull/217)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.15.0 (2021/05/02)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Updated `gimli` and `object` dependencies.
|
||||
[#215](https://github.com/gimli-rs/addr2line/pull/215)
|
||||
|
||||
* Added `debug_aranges` parameter to `Context::from_sections`.
|
||||
[#200](https://github.com/gimli-rs/addr2line/pull/200)
|
||||
|
||||
### Added
|
||||
|
||||
* Added `.debug_aranges` support.
|
||||
[#200](https://github.com/gimli-rs/addr2line/pull/200)
|
||||
|
||||
* Added supplementary object file support.
|
||||
[#208](https://github.com/gimli-rs/addr2line/pull/208)
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed handling of Windows paths in locations.
|
||||
[#209](https://github.com/gimli-rs/addr2line/pull/209)
|
||||
|
||||
* examples/addr2line: Flush stdout after each response.
|
||||
[#210](https://github.com/gimli-rs/addr2line/pull/210)
|
||||
|
||||
* examples/addr2line: Avoid copying every section.
|
||||
[#213](https://github.com/gimli-rs/addr2line/pull/213)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.14.1 (2020/12/31)
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fix location lookup for skeleton units.
|
||||
[#201](https://github.com/gimli-rs/addr2line/pull/201)
|
||||
|
||||
### Added
|
||||
|
||||
* Added `Context::find_location_range`.
|
||||
[#196](https://github.com/gimli-rs/addr2line/pull/196)
|
||||
[#199](https://github.com/gimli-rs/addr2line/pull/199)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.14.0 (2020/10/27)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Updated `gimli` and `object` dependencies.
|
||||
|
||||
### Fixed
|
||||
|
||||
* Handle units that only have line information.
|
||||
[#188](https://github.com/gimli-rs/addr2line/pull/188)
|
||||
|
||||
* Handle DWARF units with version <= 4 and no `DW_AT_name`.
|
||||
[#191](https://github.com/gimli-rs/addr2line/pull/191)
|
||||
|
||||
* Fix handling of `DW_FORM_ref_addr`.
|
||||
[#193](https://github.com/gimli-rs/addr2line/pull/193)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.13.0 (2020/07/07)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Updated `gimli` and `object` dependencies.
|
||||
|
||||
* Added `rustc-dep-of-std` feature.
|
||||
[#166](https://github.com/gimli-rs/addr2line/pull/166)
|
||||
|
||||
### Changed
|
||||
|
||||
* Improve performance by parsing function contents lazily.
|
||||
[#178](https://github.com/gimli-rs/addr2line/pull/178)
|
||||
|
||||
* Don't skip `.debug_info` and `.debug_line` entries with a zero address.
|
||||
[#182](https://github.com/gimli-rs/addr2line/pull/182)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.12.2 (2020/06/21)
|
||||
|
||||
### Fixed
|
||||
|
||||
* Avoid linear search for `DW_FORM_ref_addr`.
|
||||
[#175](https://github.com/gimli-rs/addr2line/pull/175)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.12.1 (2020/05/19)
|
||||
|
||||
### Fixed
|
||||
|
||||
* Handle units with overlapping address ranges.
|
||||
[#163](https://github.com/gimli-rs/addr2line/pull/163)
|
||||
|
||||
* Don't assert for functions with overlapping address ranges.
|
||||
[#168](https://github.com/gimli-rs/addr2line/pull/168)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.12.0 (2020/05/12)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Updated `gimli` and `object` dependencies.
|
||||
|
||||
* Added more optional features: `smallvec` and `fallible-iterator`.
|
||||
[#160](https://github.com/gimli-rs/addr2line/pull/160)
|
||||
|
||||
### Added
|
||||
|
||||
* Added `Context::dwarf` and `Context::find_dwarf_unit`.
|
||||
[#159](https://github.com/gimli-rs/addr2line/pull/159)
|
||||
|
||||
### Changed
|
||||
|
||||
* Removed `lazycell` dependency.
|
||||
[#160](https://github.com/gimli-rs/addr2line/pull/160)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.11.0 (2020/01/11)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Updated `gimli` and `object` dependencies.
|
||||
|
||||
* [#130](https://github.com/gimli-rs/addr2line/pull/130)
|
||||
Changed `Location::file` from `Option<String>` to `Option<&str>`.
|
||||
This required adding lifetime parameters to `Location` and other structs that
|
||||
contain it.
|
||||
|
||||
* [#152](https://github.com/gimli-rs/addr2line/pull/152)
|
||||
Changed `Location::line` and `Location::column` from `Option<u64>`to `Option<u32>`.
|
||||
|
||||
* [#156](https://github.com/gimli-rs/addr2line/pull/156)
|
||||
Deleted `alloc` feature, and fixed `no-std` builds with stable rust.
|
||||
Removed default `Reader` parameter for `Context`, and added `ObjectContext` instead.
|
||||
|
||||
### Added
|
||||
|
||||
* [#134](https://github.com/gimli-rs/addr2line/pull/134)
|
||||
Added `Context::from_dwarf`.
|
||||
|
||||
### Changed
|
||||
|
||||
* [#133](https://github.com/gimli-rs/addr2line/pull/133)
|
||||
Fixed handling of units that can't be parsed.
|
||||
|
||||
* [#155](https://github.com/gimli-rs/addr2line/pull/155)
|
||||
Fixed `addr2line` output to match binutils.
|
||||
|
||||
* [#130](https://github.com/gimli-rs/addr2line/pull/130)
|
||||
Improved `.debug_line` parsing performance.
|
||||
|
||||
* [#148](https://github.com/gimli-rs/addr2line/pull/148)
|
||||
[#150](https://github.com/gimli-rs/addr2line/pull/150)
|
||||
[#151](https://github.com/gimli-rs/addr2line/pull/151)
|
||||
[#152](https://github.com/gimli-rs/addr2line/pull/152)
|
||||
Improved `.debug_info` parsing performance.
|
||||
|
||||
* [#137](https://github.com/gimli-rs/addr2line/pull/137)
|
||||
[#138](https://github.com/gimli-rs/addr2line/pull/138)
|
||||
[#139](https://github.com/gimli-rs/addr2line/pull/139)
|
||||
[#140](https://github.com/gimli-rs/addr2line/pull/140)
|
||||
[#146](https://github.com/gimli-rs/addr2line/pull/146)
|
||||
Improved benchmarks.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.10.0 (2019/07/07)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* [#127](https://github.com/gimli-rs/addr2line/pull/127)
|
||||
Update `gimli`.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.9.0 (2019/05/02)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* [#121](https://github.com/gimli-rs/addr2line/pull/121)
|
||||
Update `gimli`, `object`, and `fallible-iterator` dependencies.
|
||||
|
||||
### Added
|
||||
|
||||
* [#121](https://github.com/gimli-rs/addr2line/pull/121)
|
||||
Reexport `gimli`, `object`, and `fallible-iterator`.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 0.8.0 (2019/02/06)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* [#107](https://github.com/gimli-rs/addr2line/pull/107)
|
||||
Update `object` dependency to 0.11. This is part of the public API.
|
||||
|
||||
### Added
|
||||
|
||||
* [#101](https://github.com/gimli-rs/addr2line/pull/101)
|
||||
Add `object` feature (enabled by default). Disable this feature to remove
|
||||
the `object` dependency and `Context::new` API.
|
||||
|
||||
* [#102](https://github.com/gimli-rs/addr2line/pull/102)
|
||||
Add `std` (enabled by default) and `alloc` features.
|
||||
|
||||
### Changed
|
||||
|
||||
* [#108](https://github.com/gimli-rs/addr2line/issues/108)
|
||||
`demangle` no longer outputs the hash for rust symbols.
|
||||
|
||||
* [#109](https://github.com/gimli-rs/addr2line/issues/109)
|
||||
Set default `R` for `Context<R>`.
|
||||
1089
.gear/predownloaded-development/vendor/addr2line/Cargo.lock
generated
vendored
Normal file
1089
.gear/predownloaded-development/vendor/addr2line/Cargo.lock
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
164
.gear/predownloaded-development/vendor/addr2line/Cargo.toml
vendored
Normal file
164
.gear/predownloaded-development/vendor/addr2line/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
rust-version = "1.81"
|
||||
name = "addr2line"
|
||||
version = "0.25.1"
|
||||
build = false
|
||||
include = [
|
||||
"/CHANGELOG.md",
|
||||
"/Cargo.lock",
|
||||
"/Cargo.toml",
|
||||
"/LICENSE-APACHE",
|
||||
"/LICENSE-MIT",
|
||||
"/README.md",
|
||||
"/src",
|
||||
]
|
||||
autolib = false
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
description = "A cross-platform symbolication library written in Rust, using `gimli`"
|
||||
documentation = "https://docs.rs/addr2line"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"DWARF",
|
||||
"debug",
|
||||
"elf",
|
||||
"symbolicate",
|
||||
"atos",
|
||||
]
|
||||
categories = ["development-tools::debugging"]
|
||||
license = "Apache-2.0 OR MIT"
|
||||
repository = "https://github.com/gimli-rs/addr2line"
|
||||
|
||||
[features]
|
||||
all = [
|
||||
"bin",
|
||||
"wasm",
|
||||
]
|
||||
bin = [
|
||||
"loader",
|
||||
"rustc-demangle",
|
||||
"cpp_demangle",
|
||||
"fallible-iterator",
|
||||
"smallvec",
|
||||
"dep:clap",
|
||||
]
|
||||
cargo-all = []
|
||||
default = [
|
||||
"rustc-demangle",
|
||||
"cpp_demangle",
|
||||
"loader",
|
||||
"fallible-iterator",
|
||||
"smallvec",
|
||||
]
|
||||
loader = [
|
||||
"std",
|
||||
"dep:object",
|
||||
"dep:memmap2",
|
||||
"dep:typed-arena",
|
||||
]
|
||||
rustc-dep-of-std = [
|
||||
"core",
|
||||
"alloc",
|
||||
"gimli/rustc-dep-of-std",
|
||||
]
|
||||
std = ["gimli/std"]
|
||||
wasm = ["object/wasm"]
|
||||
|
||||
[lib]
|
||||
name = "addr2line"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "addr2line"
|
||||
path = "src/bin/addr2line.rs"
|
||||
required-features = ["bin"]
|
||||
|
||||
[dependencies.alloc]
|
||||
version = "1.0.0"
|
||||
optional = true
|
||||
package = "rustc-std-workspace-alloc"
|
||||
|
||||
[dependencies.clap]
|
||||
version = "4.3.21"
|
||||
features = ["wrap_help"]
|
||||
optional = true
|
||||
|
||||
[dependencies.core]
|
||||
version = "1.0.0"
|
||||
optional = true
|
||||
package = "rustc-std-workspace-core"
|
||||
|
||||
[dependencies.cpp_demangle]
|
||||
version = "0.4"
|
||||
features = ["alloc"]
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.fallible-iterator]
|
||||
version = "0.3.0"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.gimli]
|
||||
version = "0.32.0"
|
||||
features = ["read"]
|
||||
default-features = false
|
||||
|
||||
[dependencies.memmap2]
|
||||
version = "0.9.4"
|
||||
optional = true
|
||||
|
||||
[dependencies.object]
|
||||
version = "0.37.0"
|
||||
features = [
|
||||
"read",
|
||||
"compression",
|
||||
]
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.rustc-demangle]
|
||||
version = "0.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.smallvec]
|
||||
version = "1"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.typed-arena]
|
||||
version = "2"
|
||||
optional = true
|
||||
|
||||
[dev-dependencies.backtrace]
|
||||
version = "0.3.13"
|
||||
|
||||
[dev-dependencies.criterion]
|
||||
version = "0.7.0"
|
||||
|
||||
[dev-dependencies.findshlibs]
|
||||
version = "0.10"
|
||||
|
||||
[dev-dependencies.libtest-mimic]
|
||||
version = "0.8.1"
|
||||
|
||||
[profile.bench]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
|
||||
[profile.release]
|
||||
debug = 2
|
||||
92
.gear/predownloaded-development/vendor/addr2line/Cargo.toml.orig
generated
vendored
Normal file
92
.gear/predownloaded-development/vendor/addr2line/Cargo.toml.orig
generated
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
[package]
|
||||
name = "addr2line"
|
||||
version = "0.25.1"
|
||||
description = "A cross-platform symbolication library written in Rust, using `gimli`"
|
||||
documentation = "https://docs.rs/addr2line"
|
||||
keywords = ["DWARF", "debug", "elf", "symbolicate", "atos"]
|
||||
categories = ["development-tools::debugging"]
|
||||
license = "Apache-2.0 OR MIT"
|
||||
readme = "./README.md"
|
||||
repository = "https://github.com/gimli-rs/addr2line"
|
||||
edition = "2018"
|
||||
rust-version = "1.81"
|
||||
include = [
|
||||
"/CHANGELOG.md",
|
||||
"/Cargo.lock",
|
||||
"/Cargo.toml",
|
||||
"/LICENSE-APACHE",
|
||||
"/LICENSE-MIT",
|
||||
"/README.md",
|
||||
"/src",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
gimli = { version = "0.32.0", default-features = false, features = ["read"] }
|
||||
fallible-iterator = { version = "0.3.0", default-features = false, optional = true }
|
||||
smallvec = { version = "1", default-features = false, optional = true }
|
||||
rustc-demangle = { version = "0.1", optional = true }
|
||||
cpp_demangle = { version = "0.4", default-features = false, features = ["alloc"], optional = true }
|
||||
|
||||
# loader dependencies
|
||||
object = { version = "0.37.0", default-features = false, features = ["read", "compression"], optional = true }
|
||||
memmap2 = { version = "0.9.4", optional = true }
|
||||
typed-arena = { version = "2", optional = true }
|
||||
|
||||
# bin dependencies
|
||||
clap = { version = "4.3.21", features = ["wrap_help"], optional = true }
|
||||
|
||||
# Internal feature, only used when building as part of libstd, not part of the
|
||||
# stable interface of this crate.
|
||||
core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' }
|
||||
alloc = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-alloc' }
|
||||
|
||||
[dev-dependencies]
|
||||
backtrace = "0.3.13"
|
||||
criterion = "0.7.0"
|
||||
findshlibs = "0.10"
|
||||
libtest-mimic = "0.8.1"
|
||||
auxiliary = { path = "tests/auxiliary" }
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
|
||||
[profile.bench]
|
||||
debug = true
|
||||
codegen-units = 1
|
||||
|
||||
[features]
|
||||
default = ["rustc-demangle", "cpp_demangle", "loader", "fallible-iterator", "smallvec"]
|
||||
std = ["gimli/std"]
|
||||
wasm = ["object/wasm"]
|
||||
loader = ["std", "dep:object", "dep:memmap2", "dep:typed-arena"]
|
||||
bin = ["loader", "rustc-demangle", "cpp_demangle", "fallible-iterator", "smallvec", "dep:clap"]
|
||||
all = ["bin", "wasm"]
|
||||
|
||||
# Use of --all-features is not supported.
|
||||
# This is a dummy feature to detect when --all-features is used.
|
||||
cargo-all = []
|
||||
|
||||
# Internal feature, only used when building as part of libstd, not part of the
|
||||
# stable interface of this crate.
|
||||
rustc-dep-of-std = ['core', 'alloc', 'gimli/rustc-dep-of-std']
|
||||
|
||||
[[test]]
|
||||
name = "testinput"
|
||||
harness = false
|
||||
required-features = ["bin"]
|
||||
|
||||
[[test]]
|
||||
name = "correctness"
|
||||
required-features = ["loader", "fallible-iterator"]
|
||||
|
||||
[[test]]
|
||||
name = "parse"
|
||||
required-features = ["loader"]
|
||||
|
||||
[[bin]]
|
||||
name = "addr2line"
|
||||
required-features = ["bin"]
|
||||
|
||||
[[bench]]
|
||||
name = "bench"
|
||||
harness = false
|
||||
201
.gear/predownloaded-development/vendor/addr2line/LICENSE-APACHE
vendored
Normal file
201
.gear/predownloaded-development/vendor/addr2line/LICENSE-APACHE
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
25
.gear/predownloaded-development/vendor/addr2line/LICENSE-MIT
vendored
Normal file
25
.gear/predownloaded-development/vendor/addr2line/LICENSE-MIT
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2016-2018 The gimli Developers
|
||||
|
||||
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.
|
||||
50
.gear/predownloaded-development/vendor/addr2line/README.md
vendored
Normal file
50
.gear/predownloaded-development/vendor/addr2line/README.md
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# addr2line
|
||||
|
||||
[](https://crates.io/crates/addr2line)
|
||||
[](https://docs.rs/addr2line)
|
||||
[](https://coveralls.io/github/gimli-rs/addr2line?branch=master)
|
||||
|
||||
`addr2line` provides a cross-platform library for retrieving per-address debug information
|
||||
from files with DWARF debug information. Given an address, it can return the file name,
|
||||
line number, and function name associated with that address, as well as the inline call
|
||||
stack leading to that address.
|
||||
|
||||
The crate has a CLI wrapper around the library which provides some of
|
||||
the functionality of the `addr2line` command line tool distributed with
|
||||
[GNU binutils](https://sourceware.org/binutils/docs/binutils/addr2line.html).
|
||||
|
||||
# Quickstart
|
||||
- Add the [`addr2line` crate](https://crates.io/crates/addr2line) to your `Cargo.toml`.
|
||||
- Call [`addr2line::Loader::new`](https://docs.rs/addr2line/*/addr2line/struct.Loader.html#method.new) with the file path.
|
||||
- Use [`addr2line::Loader::find_location`](https://docs.rs/addr2line/*/addr2line/struct.Loader.html#method.find_location)
|
||||
or [`addr2line::Loader::find_frames`](https://docs.rs/addr2line/*/addr2line/struct.Loader.html#method.find_frames)
|
||||
to look up debug information for an address.
|
||||
|
||||
If you want to provide your own file loading and memory management, use
|
||||
[`addr2line::Context`](https://docs.rs/addr2line/*/addr2line/struct.Context.html)
|
||||
instead of `addr2line::Loader`.
|
||||
|
||||
# Performance
|
||||
|
||||
`addr2line` optimizes for speed over memory by caching parsed information.
|
||||
The DWARF information is parsed lazily where possible.
|
||||
|
||||
The library aims to perform similarly to equivalent existing tools such
|
||||
as `addr2line` from binutils, `eu-addr2line` from elfutils, and
|
||||
`llvm-addr2line` from the llvm project. Current benchmarks show a performance
|
||||
improvement in all cases:
|
||||
|
||||

|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
* Apache License, Version 2.0 ([`LICENSE-APACHE`](./LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([`LICENSE-MIT`](./LICENSE-MIT) or https://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
||||
313
.gear/predownloaded-development/vendor/addr2line/src/bin/addr2line.rs
vendored
Normal file
313
.gear/predownloaded-development/vendor/addr2line/src/bin/addr2line.rs
vendored
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
use fallible_iterator::FallibleIterator;
|
||||
use std::borrow::Cow;
|
||||
use std::io::{BufRead, Lines, StdinLock, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use clap::{Arg, ArgAction, Command};
|
||||
|
||||
use addr2line::{Loader, LoaderReader, Location};
|
||||
|
||||
fn parse_uint_from_hex_string(string: &str) -> Option<u64> {
|
||||
if string.len() > 2 && string.starts_with("0x") {
|
||||
u64::from_str_radix(&string[2..], 16).ok()
|
||||
} else {
|
||||
u64::from_str_radix(string, 16).ok()
|
||||
}
|
||||
}
|
||||
|
||||
enum Addrs<'a> {
|
||||
Args(clap::parser::ValuesRef<'a, String>),
|
||||
Stdin(Lines<StdinLock<'a>>),
|
||||
All {
|
||||
iter: addr2line::LocationRangeIter<'a, LoaderReader<'a>>,
|
||||
max: u64,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Addrs<'a> {
|
||||
type Item = Option<u64>;
|
||||
|
||||
fn next(&mut self) -> Option<Option<u64>> {
|
||||
let text = match self {
|
||||
Addrs::Args(vals) => vals.next().map(Cow::from),
|
||||
Addrs::Stdin(lines) => lines.next().map(Result::unwrap).map(Cow::from),
|
||||
Addrs::All { iter, max } => {
|
||||
for (addr, _len, _loc) in iter {
|
||||
if addr >= *max {
|
||||
*max = addr + 1;
|
||||
return Some(Some(addr));
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
};
|
||||
text.as_ref()
|
||||
.map(Cow::as_ref)
|
||||
.map(parse_uint_from_hex_string)
|
||||
}
|
||||
}
|
||||
|
||||
fn print_loc(loc: Option<&Location<'_>>, basenames: bool, llvm: bool) {
|
||||
if let Some(loc) = loc {
|
||||
if let Some(ref file) = loc.file.as_ref() {
|
||||
let path = if basenames {
|
||||
Path::new(Path::new(file).file_name().unwrap())
|
||||
} else {
|
||||
Path::new(file)
|
||||
};
|
||||
print!("{}:", path.display());
|
||||
} else {
|
||||
print!("??:");
|
||||
}
|
||||
if llvm {
|
||||
print!("{}:{}", loc.line.unwrap_or(0), loc.column.unwrap_or(0));
|
||||
} else if let Some(line) = loc.line {
|
||||
print!("{}", line);
|
||||
} else {
|
||||
print!("?");
|
||||
}
|
||||
println!();
|
||||
} else if llvm {
|
||||
println!("??:0:0");
|
||||
} else {
|
||||
println!("??:0");
|
||||
}
|
||||
}
|
||||
|
||||
fn print_function(name: Option<&str>, language: Option<gimli::DwLang>, demangle: bool) {
|
||||
if let Some(name) = name {
|
||||
if demangle {
|
||||
print!("{}", addr2line::demangle_auto(Cow::from(name), language));
|
||||
} else {
|
||||
print!("{}", name);
|
||||
}
|
||||
} else {
|
||||
print!("??");
|
||||
}
|
||||
}
|
||||
|
||||
struct Options<'a> {
|
||||
do_functions: bool,
|
||||
do_inlines: bool,
|
||||
pretty: bool,
|
||||
print_addrs: bool,
|
||||
basenames: bool,
|
||||
demangle: bool,
|
||||
llvm: bool,
|
||||
exe: &'a PathBuf,
|
||||
sup: Option<&'a PathBuf>,
|
||||
section: Option<&'a String>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let matches = Command::new("addr2line")
|
||||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.about("A fast addr2line Rust port")
|
||||
.max_term_width(100)
|
||||
.args(&[
|
||||
Arg::new("exe")
|
||||
.short('e')
|
||||
.long("exe")
|
||||
.value_name("filename")
|
||||
.value_parser(clap::value_parser!(PathBuf))
|
||||
.help(
|
||||
"Specify the name of the executable for which addresses should be translated.",
|
||||
)
|
||||
.required(true),
|
||||
Arg::new("sup")
|
||||
.long("sup")
|
||||
.value_name("filename")
|
||||
.value_parser(clap::value_parser!(PathBuf))
|
||||
.help("Path to supplementary object file."),
|
||||
Arg::new("section")
|
||||
.short('j')
|
||||
.long("section")
|
||||
.value_name("name")
|
||||
.help(
|
||||
"Read offsets relative to the specified section instead of absolute addresses.",
|
||||
),
|
||||
Arg::new("all")
|
||||
.long("all")
|
||||
.action(ArgAction::SetTrue)
|
||||
.conflicts_with("addrs")
|
||||
.help("Display all addresses that have line number information."),
|
||||
Arg::new("functions")
|
||||
.short('f')
|
||||
.long("functions")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Display function names as well as file and line number information."),
|
||||
Arg::new("pretty").short('p').long("pretty-print")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help(
|
||||
"Make the output more human friendly: each location are printed on one line.",
|
||||
),
|
||||
Arg::new("inlines").short('i').long("inlines")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help(
|
||||
"If the address belongs to a function that was inlined, the source information for \
|
||||
all enclosing scopes back to the first non-inlined function will also be printed.",
|
||||
),
|
||||
Arg::new("addresses").short('a').long("addresses")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help(
|
||||
"Display the address before the function name, file and line number information.",
|
||||
),
|
||||
Arg::new("basenames")
|
||||
.short('s')
|
||||
.long("basenames")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Display only the base of each file name."),
|
||||
Arg::new("demangle").short('C').long("demangle")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help(
|
||||
"Demangle function names. \
|
||||
Specifying a specific demangling style (like GNU addr2line) is not supported. \
|
||||
(TODO)"
|
||||
),
|
||||
Arg::new("llvm")
|
||||
.long("llvm")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Display output in the same format as llvm-symbolizer."),
|
||||
Arg::new("addrs")
|
||||
.action(ArgAction::Append)
|
||||
.help("Addresses to use instead of reading from stdin."),
|
||||
])
|
||||
.get_matches();
|
||||
|
||||
let opts = Options {
|
||||
do_functions: matches.get_flag("functions"),
|
||||
do_inlines: matches.get_flag("inlines"),
|
||||
pretty: matches.get_flag("pretty"),
|
||||
print_addrs: matches.get_flag("addresses"),
|
||||
basenames: matches.get_flag("basenames"),
|
||||
demangle: matches.get_flag("demangle"),
|
||||
llvm: matches.get_flag("llvm"),
|
||||
exe: matches.get_one::<PathBuf>("exe").unwrap(),
|
||||
sup: matches.get_one::<PathBuf>("sup"),
|
||||
section: matches.get_one::<String>("section"),
|
||||
};
|
||||
|
||||
let ctx = Loader::new_with_sup(opts.exe, opts.sup).unwrap();
|
||||
|
||||
let section_range = opts.section.map(|section_name| {
|
||||
ctx.get_section_range(section_name.as_bytes())
|
||||
.unwrap_or_else(|| panic!("cannot find section {}", section_name))
|
||||
});
|
||||
|
||||
let stdin = std::io::stdin();
|
||||
let addrs = if matches.get_flag("all") {
|
||||
Addrs::All {
|
||||
iter: ctx.find_location_range(0, !0).unwrap(),
|
||||
max: 0,
|
||||
}
|
||||
} else {
|
||||
matches
|
||||
.get_many::<String>("addrs")
|
||||
.map(Addrs::Args)
|
||||
.unwrap_or_else(|| Addrs::Stdin(stdin.lock().lines()))
|
||||
};
|
||||
|
||||
for probe in addrs {
|
||||
if opts.print_addrs {
|
||||
let addr = probe.unwrap_or(0);
|
||||
if opts.llvm {
|
||||
print!("0x{:x}", addr);
|
||||
} else {
|
||||
print!("0x{:016x}", addr);
|
||||
}
|
||||
if opts.pretty {
|
||||
print!(": ");
|
||||
} else {
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
// If --section is given, add the section address to probe.
|
||||
let probe = probe.and_then(|probe| {
|
||||
if let Some(section_range) = section_range {
|
||||
if probe < (section_range.end - section_range.begin) {
|
||||
Some(probe + section_range.begin)
|
||||
} else {
|
||||
// If addr >= section size, treat it as if no line number information was found.
|
||||
None
|
||||
}
|
||||
} else {
|
||||
Some(probe)
|
||||
}
|
||||
});
|
||||
|
||||
if opts.do_functions || opts.do_inlines {
|
||||
let mut printed_anything = false;
|
||||
if let Some(probe) = probe {
|
||||
let mut frames = ctx.find_frames(probe).unwrap().peekable();
|
||||
let mut first = true;
|
||||
while let Some(frame) = frames.next().unwrap() {
|
||||
if opts.pretty && !first {
|
||||
print!(" (inlined by) ");
|
||||
}
|
||||
first = false;
|
||||
|
||||
if opts.do_functions {
|
||||
// Only use the symbol table if this isn't an inlined function.
|
||||
let symbol = if matches!(frames.peek(), Ok(None)) {
|
||||
ctx.find_symbol(probe)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if symbol.is_some() {
|
||||
// Prefer the symbol table over the DWARF name because:
|
||||
// - the symbol can include a clone suffix
|
||||
// - llvm may omit the linkage name in the DWARF with -g1
|
||||
print_function(symbol, None, opts.demangle);
|
||||
} else if let Some(func) = frame.function {
|
||||
print_function(
|
||||
func.raw_name().ok().as_deref(),
|
||||
func.language,
|
||||
opts.demangle,
|
||||
);
|
||||
} else {
|
||||
print_function(None, None, opts.demangle);
|
||||
}
|
||||
|
||||
if opts.pretty {
|
||||
print!(" at ");
|
||||
} else {
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
print_loc(frame.location.as_ref(), opts.basenames, opts.llvm);
|
||||
|
||||
printed_anything = true;
|
||||
|
||||
if !opts.do_inlines {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !printed_anything {
|
||||
if opts.do_functions {
|
||||
let name = probe.and_then(|probe| ctx.find_symbol(probe));
|
||||
print_function(name, None, opts.demangle);
|
||||
|
||||
if opts.pretty {
|
||||
print!(" at ");
|
||||
} else {
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
print_loc(None, opts.basenames, opts.llvm);
|
||||
}
|
||||
} else {
|
||||
let loc = probe.and_then(|probe| ctx.find_location(probe).unwrap());
|
||||
print_loc(loc.as_ref(), opts.basenames, opts.llvm);
|
||||
}
|
||||
|
||||
if opts.llvm {
|
||||
println!();
|
||||
}
|
||||
std::io::stdout().flush().unwrap();
|
||||
}
|
||||
}
|
||||
221
.gear/predownloaded-development/vendor/addr2line/src/frame.rs
vendored
Normal file
221
.gear/predownloaded-development/vendor/addr2line/src/frame.rs
vendored
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
use alloc::borrow::Cow;
|
||||
use alloc::string::String;
|
||||
use core::iter;
|
||||
|
||||
use crate::{maybe_small, Error, Function, InlinedFunction, ResUnit};
|
||||
|
||||
/// A source location.
|
||||
pub struct Location<'a> {
|
||||
/// The file name.
|
||||
pub file: Option<&'a str>,
|
||||
/// The line number.
|
||||
pub line: Option<u32>,
|
||||
/// The column number.
|
||||
///
|
||||
/// A value of `Some(0)` indicates the left edge.
|
||||
pub column: Option<u32>,
|
||||
}
|
||||
|
||||
/// A function frame.
|
||||
pub struct Frame<'ctx, R: gimli::Reader> {
|
||||
/// The DWARF unit offset corresponding to the DIE of the function.
|
||||
pub dw_die_offset: Option<gimli::UnitOffset<R::Offset>>,
|
||||
/// The name of the function.
|
||||
pub function: Option<FunctionName<R>>,
|
||||
/// The source location corresponding to this frame.
|
||||
pub location: Option<Location<'ctx>>,
|
||||
}
|
||||
|
||||
/// An iterator over function frames.
|
||||
pub struct FrameIter<'ctx, R>(FrameIterState<'ctx, R>)
|
||||
where
|
||||
R: gimli::Reader;
|
||||
|
||||
enum FrameIterState<'ctx, R>
|
||||
where
|
||||
R: gimli::Reader,
|
||||
{
|
||||
Empty,
|
||||
Location(Option<Location<'ctx>>),
|
||||
Frames(FrameIterFrames<'ctx, R>),
|
||||
}
|
||||
|
||||
struct FrameIterFrames<'ctx, R>
|
||||
where
|
||||
R: gimli::Reader,
|
||||
{
|
||||
unit: &'ctx ResUnit<R>,
|
||||
sections: &'ctx gimli::Dwarf<R>,
|
||||
function: &'ctx Function<R>,
|
||||
inlined_functions: iter::Rev<maybe_small::IntoIter<&'ctx InlinedFunction<R>>>,
|
||||
next: Option<Location<'ctx>>,
|
||||
}
|
||||
|
||||
impl<'ctx, R> FrameIter<'ctx, R>
|
||||
where
|
||||
R: gimli::Reader + 'ctx,
|
||||
{
|
||||
pub(crate) fn new_empty() -> Self {
|
||||
FrameIter(FrameIterState::Empty)
|
||||
}
|
||||
|
||||
pub(crate) fn new_location(location: Location<'ctx>) -> Self {
|
||||
FrameIter(FrameIterState::Location(Some(location)))
|
||||
}
|
||||
|
||||
pub(crate) fn new_frames(
|
||||
unit: &'ctx ResUnit<R>,
|
||||
sections: &'ctx gimli::Dwarf<R>,
|
||||
function: &'ctx Function<R>,
|
||||
inlined_functions: maybe_small::Vec<&'ctx InlinedFunction<R>>,
|
||||
location: Option<Location<'ctx>>,
|
||||
) -> Self {
|
||||
FrameIter(FrameIterState::Frames(FrameIterFrames {
|
||||
unit,
|
||||
sections,
|
||||
function,
|
||||
inlined_functions: inlined_functions.into_iter().rev(),
|
||||
next: location,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Advances the iterator and returns the next frame.
|
||||
#[allow(clippy::should_implement_trait)]
|
||||
pub fn next(&mut self) -> Result<Option<Frame<'ctx, R>>, Error> {
|
||||
let frames = match &mut self.0 {
|
||||
FrameIterState::Empty => return Ok(None),
|
||||
FrameIterState::Location(location) => {
|
||||
// We can't move out of a mutable reference, so use `take` instead.
|
||||
let location = location.take();
|
||||
self.0 = FrameIterState::Empty;
|
||||
return Ok(Some(Frame {
|
||||
dw_die_offset: None,
|
||||
function: None,
|
||||
location,
|
||||
}));
|
||||
}
|
||||
FrameIterState::Frames(frames) => frames,
|
||||
};
|
||||
|
||||
let loc = frames.next.take();
|
||||
let func = match frames.inlined_functions.next() {
|
||||
Some(func) => func,
|
||||
None => {
|
||||
let frame = Frame {
|
||||
dw_die_offset: Some(frames.function.dw_die_offset),
|
||||
function: frames.function.name.clone().map(|name| FunctionName {
|
||||
name,
|
||||
language: frames.unit.lang,
|
||||
}),
|
||||
location: loc,
|
||||
};
|
||||
self.0 = FrameIterState::Empty;
|
||||
return Ok(Some(frame));
|
||||
}
|
||||
};
|
||||
|
||||
let mut next = Location {
|
||||
file: None,
|
||||
line: if func.call_line != 0 {
|
||||
Some(func.call_line)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
column: if func.call_column != 0 {
|
||||
Some(func.call_column)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
};
|
||||
if let Some(call_file) = func.call_file {
|
||||
if let Some(lines) = frames.unit.parse_lines(frames.sections)? {
|
||||
next.file = lines.file(call_file);
|
||||
}
|
||||
}
|
||||
frames.next = Some(next);
|
||||
|
||||
Ok(Some(Frame {
|
||||
dw_die_offset: Some(func.dw_die_offset),
|
||||
function: func.name.clone().map(|name| FunctionName {
|
||||
name,
|
||||
language: frames.unit.lang,
|
||||
}),
|
||||
location: loc,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "fallible-iterator")]
|
||||
impl<'ctx, R> fallible_iterator::FallibleIterator for FrameIter<'ctx, R>
|
||||
where
|
||||
R: gimli::Reader + 'ctx,
|
||||
{
|
||||
type Item = Frame<'ctx, R>;
|
||||
type Error = Error;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Result<Option<Frame<'ctx, R>>, Error> {
|
||||
self.next()
|
||||
}
|
||||
}
|
||||
|
||||
/// A function name.
|
||||
pub struct FunctionName<R: gimli::Reader> {
|
||||
/// The name of the function.
|
||||
pub name: R,
|
||||
/// The language of the compilation unit containing this function.
|
||||
pub language: Option<gimli::DwLang>,
|
||||
}
|
||||
|
||||
impl<R: gimli::Reader> FunctionName<R> {
|
||||
/// The raw name of this function before demangling.
|
||||
pub fn raw_name(&self) -> Result<Cow<'_, str>, Error> {
|
||||
self.name.to_string_lossy()
|
||||
}
|
||||
|
||||
/// The name of this function after demangling (if applicable).
|
||||
pub fn demangle(&self) -> Result<Cow<'_, str>, Error> {
|
||||
self.raw_name().map(|x| demangle_auto(x, self.language))
|
||||
}
|
||||
}
|
||||
|
||||
/// Demangle a symbol name using the demangling scheme for the given language.
|
||||
///
|
||||
/// Returns `None` if demangling failed or is not required.
|
||||
#[allow(unused_variables)]
|
||||
pub fn demangle(name: &str, language: gimli::DwLang) -> Option<String> {
|
||||
match language {
|
||||
#[cfg(feature = "rustc-demangle")]
|
||||
gimli::DW_LANG_Rust => rustc_demangle::try_demangle(name)
|
||||
.ok()
|
||||
.as_ref()
|
||||
.map(|x| format!("{:#}", x)),
|
||||
#[cfg(feature = "cpp_demangle")]
|
||||
gimli::DW_LANG_C_plus_plus
|
||||
| gimli::DW_LANG_C_plus_plus_03
|
||||
| gimli::DW_LANG_C_plus_plus_11
|
||||
| gimli::DW_LANG_C_plus_plus_14 => cpp_demangle::Symbol::new(name)
|
||||
.ok()
|
||||
.and_then(|x| x.demangle(&Default::default()).ok()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply 'best effort' demangling of a symbol name.
|
||||
///
|
||||
/// If `language` is given, then only the demangling scheme for that language
|
||||
/// is used.
|
||||
///
|
||||
/// If `language` is `None`, then heuristics are used to determine how to
|
||||
/// demangle the name. Currently, these heuristics are very basic.
|
||||
///
|
||||
/// If demangling fails or is not required, then `name` is returned unchanged.
|
||||
pub fn demangle_auto(name: Cow<'_, str>, language: Option<gimli::DwLang>) -> Cow<'_, str> {
|
||||
match language {
|
||||
Some(language) => demangle(name.as_ref(), language),
|
||||
None => demangle(name.as_ref(), gimli::DW_LANG_Rust)
|
||||
.or_else(|| demangle(name.as_ref(), gimli::DW_LANG_C_plus_plus)),
|
||||
}
|
||||
.map(Cow::from)
|
||||
.unwrap_or(name)
|
||||
}
|
||||
563
.gear/predownloaded-development/vendor/addr2line/src/function.rs
vendored
Normal file
563
.gear/predownloaded-development/vendor/addr2line/src/function.rs
vendored
Normal file
|
|
@ -0,0 +1,563 @@
|
|||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use core::cmp::Ordering;
|
||||
|
||||
use crate::maybe_small;
|
||||
use crate::{Context, DebugFile, Error, LazyResult, RangeAttributes};
|
||||
|
||||
pub(crate) struct LazyFunctions<R: gimli::Reader>(LazyResult<Functions<R>>);
|
||||
|
||||
impl<R: gimli::Reader> LazyFunctions<R> {
|
||||
pub(crate) fn new() -> Self {
|
||||
LazyFunctions(LazyResult::new())
|
||||
}
|
||||
|
||||
pub(crate) fn borrow(&self, unit: gimli::UnitRef<R>) -> Result<&Functions<R>, Error> {
|
||||
self.0
|
||||
.get_or_init(|| Functions::parse(unit))
|
||||
.as_ref()
|
||||
.map_err(Error::clone)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Functions<R: gimli::Reader> {
|
||||
/// List of all `DW_TAG_subprogram` details in the unit.
|
||||
pub(crate) functions: Box<[LazyFunction<R>]>,
|
||||
/// List of `DW_TAG_subprogram` address ranges in the unit.
|
||||
pub(crate) addresses: Box<[FunctionAddress]>,
|
||||
}
|
||||
|
||||
/// A single address range for a function.
|
||||
///
|
||||
/// It is possible for a function to have multiple address ranges; this
|
||||
/// is handled by having multiple `FunctionAddress` entries with the same
|
||||
/// `function` field.
|
||||
pub(crate) struct FunctionAddress {
|
||||
range: gimli::Range,
|
||||
/// An index into `Functions::functions`.
|
||||
pub(crate) function: usize,
|
||||
}
|
||||
|
||||
pub(crate) struct LazyFunction<R: gimli::Reader> {
|
||||
dw_die_offset: gimli::UnitOffset<R::Offset>,
|
||||
lazy: LazyResult<Function<R>>,
|
||||
}
|
||||
|
||||
impl<R: gimli::Reader> LazyFunction<R> {
|
||||
fn new(dw_die_offset: gimli::UnitOffset<R::Offset>) -> Self {
|
||||
LazyFunction {
|
||||
dw_die_offset,
|
||||
lazy: LazyResult::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn borrow(
|
||||
&self,
|
||||
file: DebugFile,
|
||||
unit: gimli::UnitRef<R>,
|
||||
ctx: &Context<R>,
|
||||
) -> Result<&Function<R>, Error> {
|
||||
self.lazy
|
||||
.get_or_init(|| Function::parse(self.dw_die_offset, file, unit, ctx))
|
||||
.as_ref()
|
||||
.map_err(Error::clone)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Function<R: gimli::Reader> {
|
||||
pub(crate) dw_die_offset: gimli::UnitOffset<R::Offset>,
|
||||
pub(crate) name: Option<R>,
|
||||
/// List of all `DW_TAG_inlined_subroutine` details in this function.
|
||||
inlined_functions: Box<[InlinedFunction<R>]>,
|
||||
/// List of `DW_TAG_inlined_subroutine` address ranges in this function.
|
||||
inlined_addresses: Box<[InlinedFunctionAddress]>,
|
||||
}
|
||||
|
||||
pub(crate) struct InlinedFunctionAddress {
|
||||
range: gimli::Range,
|
||||
call_depth: usize,
|
||||
/// An index into `Function::inlined_functions`.
|
||||
function: usize,
|
||||
}
|
||||
|
||||
pub(crate) struct InlinedFunction<R: gimli::Reader> {
|
||||
pub(crate) dw_die_offset: gimli::UnitOffset<R::Offset>,
|
||||
pub(crate) name: Option<R>,
|
||||
pub(crate) call_file: Option<u64>,
|
||||
pub(crate) call_line: u32,
|
||||
pub(crate) call_column: u32,
|
||||
}
|
||||
|
||||
impl<R: gimli::Reader> Functions<R> {
|
||||
fn parse(unit: gimli::UnitRef<R>) -> Result<Functions<R>, Error> {
|
||||
let mut functions = Vec::new();
|
||||
let mut addresses = Vec::new();
|
||||
let mut entries = unit.entries_raw(None)?;
|
||||
while !entries.is_empty() {
|
||||
let dw_die_offset = entries.next_offset();
|
||||
if let Some(abbrev) = entries.read_abbreviation()? {
|
||||
if abbrev.tag() == gimli::DW_TAG_subprogram {
|
||||
let mut ranges = RangeAttributes::default();
|
||||
for spec in abbrev.attributes() {
|
||||
match entries.read_attribute(*spec) {
|
||||
Ok(ref attr) => {
|
||||
match attr.name() {
|
||||
gimli::DW_AT_low_pc => match attr.value() {
|
||||
gimli::AttributeValue::Addr(val) => {
|
||||
ranges.low_pc = Some(val)
|
||||
}
|
||||
gimli::AttributeValue::DebugAddrIndex(index) => {
|
||||
ranges.low_pc = Some(unit.address(index)?);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
gimli::DW_AT_high_pc => match attr.value() {
|
||||
gimli::AttributeValue::Addr(val) => {
|
||||
ranges.high_pc = Some(val)
|
||||
}
|
||||
gimli::AttributeValue::DebugAddrIndex(index) => {
|
||||
ranges.high_pc = Some(unit.address(index)?);
|
||||
}
|
||||
gimli::AttributeValue::Udata(val) => {
|
||||
ranges.size = Some(val)
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
gimli::DW_AT_ranges => {
|
||||
ranges.ranges_offset =
|
||||
unit.attr_ranges_offset(attr.value())?;
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
let function_index = functions.len();
|
||||
let has_address = ranges.for_each_range(unit, |range| {
|
||||
addresses.push(FunctionAddress {
|
||||
range,
|
||||
function: function_index,
|
||||
});
|
||||
})?;
|
||||
if has_address {
|
||||
functions.push(LazyFunction::new(dw_die_offset));
|
||||
}
|
||||
} else {
|
||||
entries.skip_attributes(abbrev.attributes())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The binary search requires the addresses to be sorted.
|
||||
//
|
||||
// It also requires them to be non-overlapping. In practice, overlapping
|
||||
// function ranges are unlikely, so we don't try to handle that yet.
|
||||
//
|
||||
// It's possible for multiple functions to have the same address range if the
|
||||
// compiler can detect and remove functions with identical code. In that case
|
||||
// we'll nondeterministically return one of them.
|
||||
addresses.sort_by_key(|x| x.range.begin);
|
||||
|
||||
Ok(Functions {
|
||||
functions: functions.into_boxed_slice(),
|
||||
addresses: addresses.into_boxed_slice(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn find_address(&self, probe: u64) -> Option<usize> {
|
||||
self.addresses
|
||||
.binary_search_by(|address| {
|
||||
if probe < address.range.begin {
|
||||
Ordering::Greater
|
||||
} else if probe >= address.range.end {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Equal
|
||||
}
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
|
||||
pub(crate) fn parse_inlined_functions(
|
||||
&self,
|
||||
file: DebugFile,
|
||||
unit: gimli::UnitRef<R>,
|
||||
ctx: &Context<R>,
|
||||
) -> Result<(), Error> {
|
||||
for function in &*self.functions {
|
||||
function.borrow(file, unit, ctx)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: gimli::Reader> Function<R> {
|
||||
fn parse(
|
||||
dw_die_offset: gimli::UnitOffset<R::Offset>,
|
||||
file: DebugFile,
|
||||
unit: gimli::UnitRef<R>,
|
||||
ctx: &Context<R>,
|
||||
) -> Result<Self, Error> {
|
||||
let mut entries = unit.entries_raw(Some(dw_die_offset))?;
|
||||
let depth = entries.next_depth();
|
||||
let abbrev = entries.read_abbreviation()?.unwrap();
|
||||
debug_assert_eq!(abbrev.tag(), gimli::DW_TAG_subprogram);
|
||||
|
||||
let mut name = None;
|
||||
for spec in abbrev.attributes() {
|
||||
match entries.read_attribute(*spec) {
|
||||
Ok(ref attr) => {
|
||||
match attr.name() {
|
||||
gimli::DW_AT_linkage_name | gimli::DW_AT_MIPS_linkage_name => {
|
||||
if let Ok(val) = unit.attr_string(attr.value()) {
|
||||
name = Some(val);
|
||||
}
|
||||
}
|
||||
gimli::DW_AT_name => {
|
||||
if name.is_none() {
|
||||
name = unit.attr_string(attr.value()).ok();
|
||||
}
|
||||
}
|
||||
gimli::DW_AT_abstract_origin | gimli::DW_AT_specification => {
|
||||
if name.is_none() {
|
||||
name = name_attr(attr.value(), file, unit, ctx, 16)?;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
let mut state = InlinedState {
|
||||
entries,
|
||||
functions: Vec::new(),
|
||||
addresses: Vec::new(),
|
||||
file,
|
||||
unit,
|
||||
ctx,
|
||||
};
|
||||
Function::parse_children(&mut state, depth, 0)?;
|
||||
|
||||
// Sort ranges in "breadth-first traversal order", i.e. first by call_depth
|
||||
// and then by range.begin. This allows finding the range containing an
|
||||
// address at a certain depth using binary search.
|
||||
// Note: Using DFS order, i.e. ordering by range.begin first and then by
|
||||
// call_depth, would not work! Consider the two examples
|
||||
// "[0..10 at depth 0], [0..2 at depth 1], [6..8 at depth 1]" and
|
||||
// "[0..5 at depth 0], [0..2 at depth 1], [5..10 at depth 0], [6..8 at depth 1]".
|
||||
// In this example, if you want to look up address 7 at depth 0, and you
|
||||
// encounter [0..2 at depth 1], are you before or after the target range?
|
||||
// You don't know.
|
||||
state.addresses.sort_by(|r1, r2| {
|
||||
if r1.call_depth < r2.call_depth {
|
||||
Ordering::Less
|
||||
} else if r1.call_depth > r2.call_depth {
|
||||
Ordering::Greater
|
||||
} else if r1.range.begin < r2.range.begin {
|
||||
Ordering::Less
|
||||
} else if r1.range.begin > r2.range.begin {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
Ordering::Equal
|
||||
}
|
||||
});
|
||||
|
||||
Ok(Function {
|
||||
dw_die_offset,
|
||||
name,
|
||||
inlined_functions: state.functions.into_boxed_slice(),
|
||||
inlined_addresses: state.addresses.into_boxed_slice(),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_children(
|
||||
state: &mut InlinedState<R>,
|
||||
depth: isize,
|
||||
inlined_depth: usize,
|
||||
) -> Result<(), Error> {
|
||||
loop {
|
||||
let dw_die_offset = state.entries.next_offset();
|
||||
let next_depth = state.entries.next_depth();
|
||||
if next_depth <= depth {
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(abbrev) = state.entries.read_abbreviation()? {
|
||||
match abbrev.tag() {
|
||||
gimli::DW_TAG_subprogram => {
|
||||
Function::skip(&mut state.entries, abbrev, next_depth)?;
|
||||
}
|
||||
gimli::DW_TAG_inlined_subroutine => {
|
||||
InlinedFunction::parse(
|
||||
state,
|
||||
dw_die_offset,
|
||||
abbrev,
|
||||
next_depth,
|
||||
inlined_depth,
|
||||
)?;
|
||||
}
|
||||
_ => {
|
||||
state.entries.skip_attributes(abbrev.attributes())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn skip(
|
||||
entries: &mut gimli::EntriesRaw<'_, '_, R>,
|
||||
abbrev: &gimli::Abbreviation,
|
||||
depth: isize,
|
||||
) -> Result<(), Error> {
|
||||
// TODO: use DW_AT_sibling
|
||||
entries.skip_attributes(abbrev.attributes())?;
|
||||
while entries.next_depth() > depth {
|
||||
if let Some(abbrev) = entries.read_abbreviation()? {
|
||||
entries.skip_attributes(abbrev.attributes())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Build the list of inlined functions that contain `probe`.
|
||||
pub(crate) fn find_inlined_functions(
|
||||
&self,
|
||||
probe: u64,
|
||||
) -> maybe_small::Vec<&InlinedFunction<R>> {
|
||||
// `inlined_functions` is ordered from outside to inside.
|
||||
let mut inlined_functions = maybe_small::Vec::new();
|
||||
let mut inlined_addresses = &self.inlined_addresses[..];
|
||||
loop {
|
||||
let current_depth = inlined_functions.len();
|
||||
// Look up (probe, current_depth) in inline_ranges.
|
||||
// `inlined_addresses` is sorted in "breadth-first traversal order", i.e.
|
||||
// by `call_depth` first, and then by `range.begin`. See the comment at
|
||||
// the sort call for more information about why.
|
||||
let search = inlined_addresses.binary_search_by(|range| {
|
||||
if range.call_depth > current_depth {
|
||||
Ordering::Greater
|
||||
} else if range.call_depth < current_depth {
|
||||
Ordering::Less
|
||||
} else if range.range.begin > probe {
|
||||
Ordering::Greater
|
||||
} else if range.range.end <= probe {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Equal
|
||||
}
|
||||
});
|
||||
if let Ok(index) = search {
|
||||
let function_index = inlined_addresses[index].function;
|
||||
inlined_functions.push(&self.inlined_functions[function_index]);
|
||||
inlined_addresses = &inlined_addresses[index + 1..];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
inlined_functions
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: gimli::Reader> InlinedFunction<R> {
|
||||
fn parse(
|
||||
state: &mut InlinedState<R>,
|
||||
dw_die_offset: gimli::UnitOffset<R::Offset>,
|
||||
abbrev: &gimli::Abbreviation,
|
||||
depth: isize,
|
||||
inlined_depth: usize,
|
||||
) -> Result<(), Error> {
|
||||
let unit = state.unit;
|
||||
let mut ranges = RangeAttributes::default();
|
||||
let mut name = None;
|
||||
let mut call_file = None;
|
||||
let mut call_line = 0;
|
||||
let mut call_column = 0;
|
||||
for spec in abbrev.attributes() {
|
||||
match state.entries.read_attribute(*spec) {
|
||||
Ok(ref attr) => match attr.name() {
|
||||
gimli::DW_AT_low_pc => match attr.value() {
|
||||
gimli::AttributeValue::Addr(val) => ranges.low_pc = Some(val),
|
||||
gimli::AttributeValue::DebugAddrIndex(index) => {
|
||||
ranges.low_pc = Some(unit.address(index)?);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
gimli::DW_AT_high_pc => match attr.value() {
|
||||
gimli::AttributeValue::Addr(val) => ranges.high_pc = Some(val),
|
||||
gimli::AttributeValue::DebugAddrIndex(index) => {
|
||||
ranges.high_pc = Some(unit.address(index)?);
|
||||
}
|
||||
gimli::AttributeValue::Udata(val) => ranges.size = Some(val),
|
||||
_ => {}
|
||||
},
|
||||
gimli::DW_AT_ranges => {
|
||||
ranges.ranges_offset = unit.attr_ranges_offset(attr.value())?;
|
||||
}
|
||||
gimli::DW_AT_linkage_name | gimli::DW_AT_MIPS_linkage_name => {
|
||||
if let Ok(val) = unit.attr_string(attr.value()) {
|
||||
name = Some(val);
|
||||
}
|
||||
}
|
||||
gimli::DW_AT_name => {
|
||||
if name.is_none() {
|
||||
name = unit.attr_string(attr.value()).ok();
|
||||
}
|
||||
}
|
||||
gimli::DW_AT_abstract_origin | gimli::DW_AT_specification => {
|
||||
if name.is_none() {
|
||||
name = name_attr(attr.value(), state.file, unit, state.ctx, 16)?;
|
||||
}
|
||||
}
|
||||
gimli::DW_AT_call_file => {
|
||||
// There is a spec issue [1] with how DW_AT_call_file is specified in DWARF 5.
|
||||
// Before, a file index of 0 would indicate no source file, however in
|
||||
// DWARF 5 this could be a valid index into the file table.
|
||||
//
|
||||
// Implementations such as LLVM generates a file index of 0 when DWARF 5 is
|
||||
// used.
|
||||
//
|
||||
// Thus, if we see a version of 5 or later, treat a file index of 0 as such.
|
||||
// [1]: http://wiki.dwarfstd.org/index.php?title=DWARF5_Line_Table_File_Numbers
|
||||
if let gimli::AttributeValue::FileIndex(fi) = attr.value() {
|
||||
if fi > 0 || unit.header.version() >= 5 {
|
||||
call_file = Some(fi);
|
||||
}
|
||||
}
|
||||
}
|
||||
gimli::DW_AT_call_line => {
|
||||
call_line = attr.udata_value().unwrap_or(0) as u32;
|
||||
}
|
||||
gimli::DW_AT_call_column => {
|
||||
call_column = attr.udata_value().unwrap_or(0) as u32;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
let function_index = state.functions.len();
|
||||
state.functions.push(InlinedFunction {
|
||||
dw_die_offset,
|
||||
name,
|
||||
call_file,
|
||||
call_line,
|
||||
call_column,
|
||||
});
|
||||
|
||||
ranges.for_each_range(unit, |range| {
|
||||
state.addresses.push(InlinedFunctionAddress {
|
||||
range,
|
||||
call_depth: inlined_depth,
|
||||
function: function_index,
|
||||
});
|
||||
})?;
|
||||
|
||||
Function::parse_children(state, depth, inlined_depth + 1)
|
||||
}
|
||||
}
|
||||
|
||||
struct InlinedState<'a, R: gimli::Reader> {
|
||||
// Mutable fields.
|
||||
entries: gimli::EntriesRaw<'a, 'a, R>,
|
||||
functions: Vec<InlinedFunction<R>>,
|
||||
addresses: Vec<InlinedFunctionAddress>,
|
||||
|
||||
// Constant fields.
|
||||
file: DebugFile,
|
||||
unit: gimli::UnitRef<'a, R>,
|
||||
ctx: &'a Context<R>,
|
||||
}
|
||||
|
||||
fn name_attr<R>(
|
||||
attr: gimli::AttributeValue<R>,
|
||||
mut file: DebugFile,
|
||||
unit: gimli::UnitRef<R>,
|
||||
ctx: &Context<R>,
|
||||
recursion_limit: usize,
|
||||
) -> Result<Option<R>, Error>
|
||||
where
|
||||
R: gimli::Reader,
|
||||
{
|
||||
if recursion_limit == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
match attr {
|
||||
gimli::AttributeValue::UnitRef(offset) => {
|
||||
name_entry(file, unit, offset, ctx, recursion_limit)
|
||||
}
|
||||
gimli::AttributeValue::DebugInfoRef(dr) => {
|
||||
let sections = unit.dwarf;
|
||||
let (unit, offset) = ctx.find_unit(dr, file)?;
|
||||
let unit = gimli::UnitRef::new(sections, unit);
|
||||
name_entry(file, unit, offset, ctx, recursion_limit)
|
||||
}
|
||||
gimli::AttributeValue::DebugInfoRefSup(dr) => {
|
||||
if let Some(sup_sections) = unit.dwarf.sup.as_ref() {
|
||||
file = DebugFile::Supplementary;
|
||||
let (unit, offset) = ctx.find_unit(dr, file)?;
|
||||
let unit = gimli::UnitRef::new(sup_sections, unit);
|
||||
name_entry(file, unit, offset, ctx, recursion_limit)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn name_entry<R>(
|
||||
file: DebugFile,
|
||||
unit: gimli::UnitRef<R>,
|
||||
offset: gimli::UnitOffset<R::Offset>,
|
||||
ctx: &Context<R>,
|
||||
recursion_limit: usize,
|
||||
) -> Result<Option<R>, Error>
|
||||
where
|
||||
R: gimli::Reader,
|
||||
{
|
||||
let mut entries = unit.entries_raw(Some(offset))?;
|
||||
let abbrev = if let Some(abbrev) = entries.read_abbreviation()? {
|
||||
abbrev
|
||||
} else {
|
||||
return Err(gimli::Error::NoEntryAtGivenOffset);
|
||||
};
|
||||
|
||||
let mut name = None;
|
||||
let mut next = None;
|
||||
for spec in abbrev.attributes() {
|
||||
match entries.read_attribute(*spec) {
|
||||
Ok(ref attr) => match attr.name() {
|
||||
gimli::DW_AT_linkage_name | gimli::DW_AT_MIPS_linkage_name => {
|
||||
if let Ok(val) = unit.attr_string(attr.value()) {
|
||||
return Ok(Some(val));
|
||||
}
|
||||
}
|
||||
gimli::DW_AT_name => {
|
||||
if let Ok(val) = unit.attr_string(attr.value()) {
|
||||
name = Some(val);
|
||||
}
|
||||
}
|
||||
gimli::DW_AT_abstract_origin | gimli::DW_AT_specification => {
|
||||
next = Some(attr.value());
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
if name.is_some() {
|
||||
return Ok(name);
|
||||
}
|
||||
|
||||
if let Some(next) = next {
|
||||
return name_attr(next, file, unit, ctx, recursion_limit - 1);
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
418
.gear/predownloaded-development/vendor/addr2line/src/lib.rs
vendored
Normal file
418
.gear/predownloaded-development/vendor/addr2line/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,418 @@
|
|||
//! `addr2line` provides a cross-platform library for retrieving per-address debug information
|
||||
//! from files with DWARF debug information. Given an address, it can return the file name,
|
||||
//! line number, and function name associated with that address, as well as the inline call
|
||||
//! stack leading to that address.
|
||||
//!
|
||||
//! At the lowest level, the library uses a [`Context`] to cache parsed information so that
|
||||
//! multiple lookups are efficient. To create a `Context`, you first need to open and parse the
|
||||
//! file using an object file parser such as [`object`](https://github.com/gimli-rs/object),
|
||||
//! create a [`gimli::Dwarf`], and finally call [`Context::from_dwarf`].
|
||||
//!
|
||||
//! Location information is obtained with [`Context::find_location`] or
|
||||
//! [`Context::find_location_range`]. Function information is obtained with
|
||||
//! [`Context::find_frames`], which returns a frame for each inline function. Each frame
|
||||
//! contains both name and location.
|
||||
//!
|
||||
//! The library also provides a [`Loader`] which internally memory maps the files,
|
||||
//! uses the `object` crate to do the parsing, and creates a `Context`.
|
||||
//! The `Context` is not exposed, but the `Loader` provides the same functionality
|
||||
//! via [`Loader::find_location`], [`Loader::find_location_range`], and
|
||||
//! [`Loader::find_frames`]. The `Loader` also provides [`Loader::find_symbol`]
|
||||
//! to use the symbol table instead of DWARF debugging information.
|
||||
//! The `Loader` will load Mach-O dSYM files and split DWARF files as needed.
|
||||
//!
|
||||
//! The crate has a CLI wrapper around the library which provides some of
|
||||
//! the functionality of the `addr2line` command line tool distributed with
|
||||
//! [GNU binutils](https://sourceware.org/binutils/docs/binutils/addr2line.html).
|
||||
#![deny(missing_docs)]
|
||||
#![no_std]
|
||||
|
||||
#[cfg(feature = "cargo-all")]
|
||||
compile_error!("'--all-features' is not supported; use '--features all' instead");
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(feature = "fallible-iterator")]
|
||||
pub extern crate fallible_iterator;
|
||||
pub extern crate gimli;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use core::cell::OnceCell;
|
||||
use core::ops::ControlFlow;
|
||||
|
||||
use crate::function::{Function, Functions, InlinedFunction, LazyFunctions};
|
||||
use crate::line::{LazyLines, LineLocationRangeIter, Lines};
|
||||
use crate::lookup::{LoopingLookup, SimpleLookup};
|
||||
use crate::unit::{ResUnit, ResUnits, SupUnits};
|
||||
|
||||
#[cfg(feature = "smallvec")]
|
||||
mod maybe_small {
|
||||
pub type Vec<T> = smallvec::SmallVec<[T; 16]>;
|
||||
pub type IntoIter<T> = smallvec::IntoIter<[T; 16]>;
|
||||
}
|
||||
#[cfg(not(feature = "smallvec"))]
|
||||
mod maybe_small {
|
||||
pub type Vec<T> = alloc::vec::Vec<T>;
|
||||
pub type IntoIter<T> = alloc::vec::IntoIter<T>;
|
||||
}
|
||||
|
||||
mod frame;
|
||||
pub use frame::{demangle, demangle_auto, Frame, FrameIter, FunctionName, Location};
|
||||
|
||||
mod function;
|
||||
mod line;
|
||||
|
||||
#[cfg(feature = "loader")]
|
||||
mod loader;
|
||||
#[cfg(feature = "loader")]
|
||||
pub use loader::{Loader, LoaderReader, Symbol};
|
||||
|
||||
mod lookup;
|
||||
pub use lookup::{LookupContinuation, LookupResult, SplitDwarfLoad};
|
||||
|
||||
mod unit;
|
||||
pub use unit::LocationRangeIter;
|
||||
|
||||
type Error = gimli::Error;
|
||||
type LazyResult<T> = OnceCell<Result<T, Error>>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum DebugFile {
|
||||
Primary,
|
||||
Supplementary,
|
||||
Dwo,
|
||||
}
|
||||
|
||||
/// The state necessary to perform address to line translation.
|
||||
///
|
||||
/// Constructing a `Context` is somewhat costly, so users should aim to reuse `Context`s
|
||||
/// when performing lookups for many addresses in the same executable.
|
||||
pub struct Context<R: gimli::Reader> {
|
||||
sections: Arc<gimli::Dwarf<R>>,
|
||||
units: ResUnits<R>,
|
||||
sup_units: SupUnits<R>,
|
||||
}
|
||||
|
||||
impl<R: gimli::Reader> Context<R> {
|
||||
/// Construct a new `Context` from DWARF sections.
|
||||
///
|
||||
/// This method does not support using a supplementary object file.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn from_sections(
|
||||
debug_abbrev: gimli::DebugAbbrev<R>,
|
||||
debug_addr: gimli::DebugAddr<R>,
|
||||
debug_aranges: gimli::DebugAranges<R>,
|
||||
debug_info: gimli::DebugInfo<R>,
|
||||
debug_line: gimli::DebugLine<R>,
|
||||
debug_line_str: gimli::DebugLineStr<R>,
|
||||
debug_ranges: gimli::DebugRanges<R>,
|
||||
debug_rnglists: gimli::DebugRngLists<R>,
|
||||
debug_str: gimli::DebugStr<R>,
|
||||
debug_str_offsets: gimli::DebugStrOffsets<R>,
|
||||
default_section: R,
|
||||
) -> Result<Self, Error> {
|
||||
Self::from_dwarf(gimli::Dwarf {
|
||||
debug_abbrev,
|
||||
debug_addr,
|
||||
debug_aranges,
|
||||
debug_info,
|
||||
debug_line,
|
||||
debug_line_str,
|
||||
debug_macinfo: default_section.clone().into(),
|
||||
debug_macro: default_section.clone().into(),
|
||||
debug_str,
|
||||
debug_str_offsets,
|
||||
debug_types: default_section.clone().into(),
|
||||
locations: gimli::LocationLists::new(
|
||||
default_section.clone().into(),
|
||||
default_section.into(),
|
||||
),
|
||||
ranges: gimli::RangeLists::new(debug_ranges, debug_rnglists),
|
||||
file_type: gimli::DwarfFileType::Main,
|
||||
sup: None,
|
||||
abbreviations_cache: gimli::AbbreviationsCache::new(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Construct a new `Context` from an existing [`gimli::Dwarf`] object.
|
||||
#[inline]
|
||||
pub fn from_dwarf(sections: gimli::Dwarf<R>) -> Result<Context<R>, Error> {
|
||||
Self::from_arc_dwarf(Arc::new(sections))
|
||||
}
|
||||
|
||||
/// Construct a new `Context` from an existing [`gimli::Dwarf`] object.
|
||||
#[inline]
|
||||
pub fn from_arc_dwarf(sections: Arc<gimli::Dwarf<R>>) -> Result<Context<R>, Error> {
|
||||
let units = ResUnits::parse(§ions)?;
|
||||
let sup_units = if let Some(sup) = sections.sup.as_ref() {
|
||||
SupUnits::parse(sup)?
|
||||
} else {
|
||||
SupUnits::default()
|
||||
};
|
||||
Ok(Context {
|
||||
sections,
|
||||
units,
|
||||
sup_units,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: gimli::Reader> Context<R> {
|
||||
/// Find the DWARF unit corresponding to the given virtual memory address.
|
||||
pub fn find_dwarf_and_unit(
|
||||
&self,
|
||||
probe: u64,
|
||||
) -> LookupResult<impl LookupContinuation<Output = Option<gimli::UnitRef<'_, R>>, Buf = R>>
|
||||
{
|
||||
let mut units_iter = self.units.find(probe);
|
||||
if let Some(unit) = units_iter.next() {
|
||||
return LoopingLookup::new_lookup(
|
||||
unit.find_function_or_location(probe, self),
|
||||
move |r| {
|
||||
ControlFlow::Break(match r {
|
||||
Ok((Some(_), _)) | Ok((_, Some(_))) => {
|
||||
let (_file, unit) = unit
|
||||
.dwarf_and_unit(self)
|
||||
// We've already been through both error cases here to get to this point.
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
Some(unit)
|
||||
}
|
||||
_ => match units_iter.next() {
|
||||
Some(next_unit) => {
|
||||
return ControlFlow::Continue(
|
||||
next_unit.find_function_or_location(probe, self),
|
||||
);
|
||||
}
|
||||
None => None,
|
||||
},
|
||||
})
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
LoopingLookup::new_complete(None)
|
||||
}
|
||||
|
||||
/// Find the source file and line corresponding to the given virtual memory address.
|
||||
pub fn find_location(&self, probe: u64) -> Result<Option<Location<'_>>, Error> {
|
||||
for unit in self.units.find(probe) {
|
||||
if let Some(location) = unit.find_location(probe, &self.sections)? {
|
||||
return Ok(Some(location));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Return source file and lines for a range of addresses. For each location it also
|
||||
/// returns the address and size of the range of the underlying instructions.
|
||||
pub fn find_location_range(
|
||||
&self,
|
||||
probe_low: u64,
|
||||
probe_high: u64,
|
||||
) -> Result<LocationRangeIter<'_, R>, Error> {
|
||||
self.units
|
||||
.find_location_range(probe_low, probe_high, &self.sections)
|
||||
}
|
||||
|
||||
/// Return an iterator for the function frames corresponding to the given virtual
|
||||
/// memory address.
|
||||
///
|
||||
/// If the probe address is not for an inline function then only one frame is
|
||||
/// returned.
|
||||
///
|
||||
/// If the probe address is for an inline function then the first frame corresponds
|
||||
/// to the innermost inline function. Subsequent frames contain the caller and call
|
||||
/// location, until an non-inline caller is reached.
|
||||
pub fn find_frames(
|
||||
&self,
|
||||
probe: u64,
|
||||
) -> LookupResult<impl LookupContinuation<Output = Result<FrameIter<'_, R>, Error>, Buf = R>>
|
||||
{
|
||||
let mut units_iter = self.units.find(probe);
|
||||
if let Some(unit) = units_iter.next() {
|
||||
LoopingLookup::new_lookup(unit.find_function_or_location(probe, self), move |r| {
|
||||
ControlFlow::Break(match r {
|
||||
Err(e) => Err(e),
|
||||
Ok((Some(function), location)) => {
|
||||
let inlined_functions = function.find_inlined_functions(probe);
|
||||
Ok(FrameIter::new_frames(
|
||||
unit,
|
||||
&self.sections,
|
||||
function,
|
||||
inlined_functions,
|
||||
location,
|
||||
))
|
||||
}
|
||||
Ok((None, Some(location))) => Ok(FrameIter::new_location(location)),
|
||||
Ok((None, None)) => match units_iter.next() {
|
||||
Some(next_unit) => {
|
||||
return ControlFlow::Continue(
|
||||
next_unit.find_function_or_location(probe, self),
|
||||
);
|
||||
}
|
||||
None => Ok(FrameIter::new_empty()),
|
||||
},
|
||||
})
|
||||
})
|
||||
} else {
|
||||
LoopingLookup::new_complete(Ok(FrameIter::new_empty()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Preload units for `probe`.
|
||||
///
|
||||
/// The iterator returns pairs of `SplitDwarfLoad`s containing the
|
||||
/// information needed to locate and load split DWARF for `probe` and
|
||||
/// a matching callback to invoke once that data is available.
|
||||
///
|
||||
/// If this method is called, and all of the returned closures are invoked,
|
||||
/// addr2line guarantees that any future API call for the address `probe`
|
||||
/// will not require the loading of any split DWARF.
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use addr2line::*;
|
||||
/// # use std::sync::Arc;
|
||||
/// # let ctx: Context<gimli::EndianSlice<gimli::RunTimeEndian>> = todo!();
|
||||
/// # let do_split_dwarf_load = |load: SplitDwarfLoad<gimli::EndianSlice<gimli::RunTimeEndian>>| -> Option<Arc<gimli::Dwarf<gimli::EndianSlice<gimli::RunTimeEndian>>>> { None };
|
||||
/// const ADDRESS: u64 = 0xdeadbeef;
|
||||
/// ctx.preload_units(ADDRESS).for_each(|(load, callback)| {
|
||||
/// let dwo = do_split_dwarf_load(load);
|
||||
/// callback(dwo);
|
||||
/// });
|
||||
///
|
||||
/// let frames_iter = match ctx.find_frames(ADDRESS) {
|
||||
/// LookupResult::Output(result) => result,
|
||||
/// LookupResult::Load { .. } => unreachable!("addr2line promised we wouldn't get here"),
|
||||
/// };
|
||||
///
|
||||
/// // ...
|
||||
/// ```
|
||||
pub fn preload_units(
|
||||
&'_ self,
|
||||
probe: u64,
|
||||
) -> impl Iterator<
|
||||
Item = (
|
||||
SplitDwarfLoad<R>,
|
||||
impl FnOnce(Option<Arc<gimli::Dwarf<R>>>) -> Result<(), gimli::Error> + '_,
|
||||
),
|
||||
> {
|
||||
self.units
|
||||
.find(probe)
|
||||
.filter_map(move |unit| match unit.dwarf_and_unit(self) {
|
||||
LookupResult::Output(_) => None,
|
||||
LookupResult::Load { load, continuation } => Some((load, |result| {
|
||||
continuation.resume(result).unwrap().map(|_| ())
|
||||
})),
|
||||
})
|
||||
}
|
||||
|
||||
/// Initialize all line data structures. This is used for benchmarks.
|
||||
#[doc(hidden)]
|
||||
pub fn parse_lines(&self) -> Result<(), Error> {
|
||||
for unit in self.units.iter() {
|
||||
unit.parse_lines(&self.sections)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Initialize all function data structures. This is used for benchmarks.
|
||||
#[doc(hidden)]
|
||||
pub fn parse_functions(&self) -> Result<(), Error> {
|
||||
for unit in self.units.iter() {
|
||||
unit.parse_functions(self).skip_all_loads()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Initialize all inlined function data structures. This is used for benchmarks.
|
||||
#[doc(hidden)]
|
||||
pub fn parse_inlined_functions(&self) -> Result<(), Error> {
|
||||
for unit in self.units.iter() {
|
||||
unit.parse_inlined_functions(self).skip_all_loads()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: gimli::Reader> Context<R> {
|
||||
// Find the unit containing the given offset, and convert the offset into a unit offset.
|
||||
fn find_unit(
|
||||
&self,
|
||||
offset: gimli::DebugInfoOffset<R::Offset>,
|
||||
file: DebugFile,
|
||||
) -> Result<(&gimli::Unit<R>, gimli::UnitOffset<R::Offset>), Error> {
|
||||
let unit = match file {
|
||||
DebugFile::Primary => self.units.find_offset(offset)?,
|
||||
DebugFile::Supplementary => self.sup_units.find_offset(offset)?,
|
||||
DebugFile::Dwo => return Err(gimli::Error::NoEntryAtGivenOffset),
|
||||
};
|
||||
|
||||
let unit_offset = offset
|
||||
.to_unit_offset(&unit.header)
|
||||
.ok_or(gimli::Error::NoEntryAtGivenOffset)?;
|
||||
Ok((unit, unit_offset))
|
||||
}
|
||||
}
|
||||
|
||||
struct RangeAttributes<R: gimli::Reader> {
|
||||
low_pc: Option<u64>,
|
||||
high_pc: Option<u64>,
|
||||
size: Option<u64>,
|
||||
ranges_offset: Option<gimli::RangeListsOffset<<R as gimli::Reader>::Offset>>,
|
||||
}
|
||||
|
||||
impl<R: gimli::Reader> Default for RangeAttributes<R> {
|
||||
fn default() -> Self {
|
||||
RangeAttributes {
|
||||
low_pc: None,
|
||||
high_pc: None,
|
||||
size: None,
|
||||
ranges_offset: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: gimli::Reader> RangeAttributes<R> {
|
||||
fn for_each_range<F: FnMut(gimli::Range)>(
|
||||
&self,
|
||||
unit: gimli::UnitRef<R>,
|
||||
mut f: F,
|
||||
) -> Result<bool, Error> {
|
||||
let mut added_any = false;
|
||||
let mut add_range = |range: gimli::Range| {
|
||||
if range.begin < range.end {
|
||||
f(range);
|
||||
added_any = true
|
||||
}
|
||||
};
|
||||
if let Some(ranges_offset) = self.ranges_offset {
|
||||
let mut range_list = unit.ranges(ranges_offset)?;
|
||||
while let Some(range) = range_list.next()? {
|
||||
add_range(range);
|
||||
}
|
||||
} else if let (Some(begin), Some(end)) = (self.low_pc, self.high_pc) {
|
||||
add_range(gimli::Range { begin, end });
|
||||
} else if let (Some(begin), Some(size)) = (self.low_pc, self.size) {
|
||||
// If `begin` is a -1 tombstone, this will overflow and the check in
|
||||
// `add_range` will ignore it.
|
||||
let end = begin.wrapping_add(size);
|
||||
add_range(gimli::Range { begin, end });
|
||||
}
|
||||
Ok(added_any)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn context_is_send() {
|
||||
fn assert_is_send<T: Send>() {}
|
||||
assert_is_send::<crate::Context<gimli::read::EndianSlice<'_, gimli::LittleEndian>>>();
|
||||
}
|
||||
}
|
||||
313
.gear/predownloaded-development/vendor/addr2line/src/line.rs
vendored
Normal file
313
.gear/predownloaded-development/vendor/addr2line/src/line.rs
vendored
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
use alloc::boxed::Box;
|
||||
use alloc::string::{String, ToString};
|
||||
use alloc::vec::Vec;
|
||||
use core::cmp::Ordering;
|
||||
use core::mem;
|
||||
use core::num::NonZeroU64;
|
||||
|
||||
use crate::{Error, LazyResult, Location};
|
||||
|
||||
pub(crate) struct LazyLines(LazyResult<Lines>);
|
||||
|
||||
impl LazyLines {
|
||||
pub(crate) fn new() -> Self {
|
||||
LazyLines(LazyResult::new())
|
||||
}
|
||||
|
||||
pub(crate) fn borrow<R: gimli::Reader>(
|
||||
&self,
|
||||
dw_unit: gimli::UnitRef<R>,
|
||||
ilnp: &gimli::IncompleteLineProgram<R, R::Offset>,
|
||||
) -> Result<&Lines, Error> {
|
||||
self.0
|
||||
.get_or_init(|| Lines::parse(dw_unit, ilnp.clone()))
|
||||
.as_ref()
|
||||
.map_err(Error::clone)
|
||||
}
|
||||
}
|
||||
|
||||
struct LineSequence {
|
||||
start: u64,
|
||||
end: u64,
|
||||
rows: Box<[LineRow]>,
|
||||
}
|
||||
|
||||
struct LineRow {
|
||||
address: u64,
|
||||
file_index: u64,
|
||||
line: u32,
|
||||
column: u32,
|
||||
}
|
||||
|
||||
pub(crate) struct Lines {
|
||||
files: Box<[String]>,
|
||||
sequences: Box<[LineSequence]>,
|
||||
}
|
||||
|
||||
impl Lines {
|
||||
fn parse<R: gimli::Reader>(
|
||||
dw_unit: gimli::UnitRef<R>,
|
||||
ilnp: gimli::IncompleteLineProgram<R, R::Offset>,
|
||||
) -> Result<Self, Error> {
|
||||
let mut sequences = Vec::new();
|
||||
let mut sequence_rows = Vec::<LineRow>::new();
|
||||
let mut rows = ilnp.rows();
|
||||
while let Some((_, row)) = rows.next_row()? {
|
||||
if row.end_sequence() {
|
||||
if let Some(start) = sequence_rows.first().map(|x| x.address) {
|
||||
let end = row.address();
|
||||
let mut rows = Vec::new();
|
||||
mem::swap(&mut rows, &mut sequence_rows);
|
||||
sequences.push(LineSequence {
|
||||
start,
|
||||
end,
|
||||
rows: rows.into_boxed_slice(),
|
||||
});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
let address = row.address();
|
||||
let file_index = row.file_index();
|
||||
// Convert line and column to u32 to save a little memory.
|
||||
// We'll handle the special case of line 0 later,
|
||||
// and return left edge as column 0 in the public API.
|
||||
let line = row.line().map(NonZeroU64::get).unwrap_or(0) as u32;
|
||||
let column = match row.column() {
|
||||
gimli::ColumnType::LeftEdge => 0,
|
||||
gimli::ColumnType::Column(x) => x.get() as u32,
|
||||
};
|
||||
|
||||
if let Some(last_row) = sequence_rows.last_mut() {
|
||||
if last_row.address == address {
|
||||
last_row.file_index = file_index;
|
||||
last_row.line = line;
|
||||
last_row.column = column;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
sequence_rows.push(LineRow {
|
||||
address,
|
||||
file_index,
|
||||
line,
|
||||
column,
|
||||
});
|
||||
}
|
||||
sequences.sort_by_key(|x| x.start);
|
||||
|
||||
let mut files = Vec::new();
|
||||
let header = rows.header();
|
||||
match header.file(0) {
|
||||
Some(file) => files.push(render_file(dw_unit, file, header)?),
|
||||
None => files.push(String::from("")), // DWARF version <= 4 may not have 0th index
|
||||
}
|
||||
let mut index = 1;
|
||||
while let Some(file) = header.file(index) {
|
||||
files.push(render_file(dw_unit, file, header)?);
|
||||
index += 1;
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
files: files.into_boxed_slice(),
|
||||
sequences: sequences.into_boxed_slice(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn file(&self, index: u64) -> Option<&str> {
|
||||
self.files.get(index as usize).map(String::as_str)
|
||||
}
|
||||
|
||||
pub(crate) fn ranges(&self) -> impl Iterator<Item = gimli::Range> + '_ {
|
||||
self.sequences.iter().map(|sequence| gimli::Range {
|
||||
begin: sequence.start,
|
||||
end: sequence.end,
|
||||
})
|
||||
}
|
||||
|
||||
fn row_location(&self, row: &LineRow) -> Location<'_> {
|
||||
let file = self.files.get(row.file_index as usize).map(String::as_str);
|
||||
Location {
|
||||
file,
|
||||
line: if row.line != 0 { Some(row.line) } else { None },
|
||||
// If row.line is specified then row.column always has meaning.
|
||||
column: if row.line != 0 {
|
||||
Some(row.column)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn find_location(&self, probe: u64) -> Result<Option<Location<'_>>, Error> {
|
||||
let seq_idx = self.sequences.binary_search_by(|sequence| {
|
||||
if probe < sequence.start {
|
||||
Ordering::Greater
|
||||
} else if probe >= sequence.end {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Equal
|
||||
}
|
||||
});
|
||||
let seq_idx = match seq_idx {
|
||||
Ok(x) => x,
|
||||
Err(_) => return Ok(None),
|
||||
};
|
||||
let sequence = &self.sequences[seq_idx];
|
||||
|
||||
let idx = sequence
|
||||
.rows
|
||||
.binary_search_by(|row| row.address.cmp(&probe));
|
||||
let idx = match idx {
|
||||
Ok(x) => x,
|
||||
Err(0) => return Ok(None),
|
||||
Err(x) => x - 1,
|
||||
};
|
||||
Ok(Some(self.row_location(&sequence.rows[idx])))
|
||||
}
|
||||
|
||||
pub(crate) fn find_location_range(
|
||||
&self,
|
||||
probe_low: u64,
|
||||
probe_high: u64,
|
||||
) -> Result<LineLocationRangeIter<'_>, Error> {
|
||||
// Find index for probe_low.
|
||||
let seq_idx = self.sequences.binary_search_by(|sequence| {
|
||||
if probe_low < sequence.start {
|
||||
Ordering::Greater
|
||||
} else if probe_low >= sequence.end {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Equal
|
||||
}
|
||||
});
|
||||
let seq_idx = match seq_idx {
|
||||
Ok(x) => x,
|
||||
Err(x) => x, // probe below sequence, but range could overlap
|
||||
};
|
||||
|
||||
let row_idx = if let Some(seq) = self.sequences.get(seq_idx) {
|
||||
let idx = seq.rows.binary_search_by(|row| row.address.cmp(&probe_low));
|
||||
match idx {
|
||||
Ok(x) => x,
|
||||
Err(0) => 0, // probe below sequence, but range could overlap
|
||||
Err(x) => x - 1,
|
||||
}
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
Ok(LineLocationRangeIter {
|
||||
lines: self,
|
||||
seq_idx,
|
||||
row_idx,
|
||||
probe_high,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct LineLocationRangeIter<'ctx> {
|
||||
lines: &'ctx Lines,
|
||||
seq_idx: usize,
|
||||
row_idx: usize,
|
||||
probe_high: u64,
|
||||
}
|
||||
|
||||
impl<'ctx> Iterator for LineLocationRangeIter<'ctx> {
|
||||
type Item = (u64, u64, Location<'ctx>);
|
||||
|
||||
fn next(&mut self) -> Option<(u64, u64, Location<'ctx>)> {
|
||||
while let Some(seq) = self.lines.sequences.get(self.seq_idx) {
|
||||
if seq.start >= self.probe_high {
|
||||
break;
|
||||
}
|
||||
|
||||
match seq.rows.get(self.row_idx) {
|
||||
Some(row) => {
|
||||
if row.address >= self.probe_high {
|
||||
break;
|
||||
}
|
||||
|
||||
let nextaddr = seq
|
||||
.rows
|
||||
.get(self.row_idx + 1)
|
||||
.map(|row| row.address)
|
||||
.unwrap_or(seq.end);
|
||||
|
||||
let item = (
|
||||
row.address,
|
||||
nextaddr - row.address,
|
||||
self.lines.row_location(row),
|
||||
);
|
||||
self.row_idx += 1;
|
||||
|
||||
return Some(item);
|
||||
}
|
||||
None => {
|
||||
self.seq_idx += 1;
|
||||
self.row_idx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn render_file<R: gimli::Reader>(
|
||||
dw_unit: gimli::UnitRef<R>,
|
||||
file: &gimli::FileEntry<R, R::Offset>,
|
||||
header: &gimli::LineProgramHeader<R, R::Offset>,
|
||||
) -> Result<String, gimli::Error> {
|
||||
let mut path = if let Some(ref comp_dir) = dw_unit.comp_dir {
|
||||
comp_dir.to_string_lossy()?.into_owned()
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
// The directory index 0 is defined to correspond to the compilation unit directory.
|
||||
if file.directory_index() != 0 {
|
||||
if let Some(directory) = file.directory(header) {
|
||||
path_push(
|
||||
&mut path,
|
||||
dw_unit.attr_string(directory)?.to_string_lossy()?.as_ref(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
path_push(
|
||||
&mut path,
|
||||
dw_unit
|
||||
.attr_string(file.path_name())?
|
||||
.to_string_lossy()?
|
||||
.as_ref(),
|
||||
);
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
fn path_push(path: &mut String, p: &str) {
|
||||
if has_forward_slash_root(p) || has_backward_slash_root(p) {
|
||||
*path = p.to_string();
|
||||
} else {
|
||||
let dir_separator = if has_backward_slash_root(path.as_str()) {
|
||||
'\\'
|
||||
} else {
|
||||
'/'
|
||||
};
|
||||
|
||||
if !path.is_empty() && !path.ends_with(dir_separator) {
|
||||
path.push(dir_separator);
|
||||
}
|
||||
*path += p;
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the path in the given string has a unix style root
|
||||
fn has_forward_slash_root(p: &str) -> bool {
|
||||
p.starts_with('/') || p.get(1..3) == Some(":/")
|
||||
}
|
||||
|
||||
/// Check if the path in the given string has a windows style root
|
||||
fn has_backward_slash_root(p: &str) -> bool {
|
||||
p.starts_with('\\') || p.get(1..3) == Some(":\\")
|
||||
}
|
||||
499
.gear/predownloaded-development/vendor/addr2line/src/loader.rs
vendored
Normal file
499
.gear/predownloaded-development/vendor/addr2line/src/loader.rs
vendored
Normal file
|
|
@ -0,0 +1,499 @@
|
|||
use alloc::borrow::Cow;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use core::cell::OnceCell;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::File;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use memmap2::Mmap;
|
||||
use object::{Object, ObjectMapFile, ObjectSection, SymbolMap, SymbolMapName};
|
||||
use typed_arena::Arena;
|
||||
|
||||
use crate::{
|
||||
Context, FrameIter, Location, LocationRangeIter, LookupContinuation, LookupResult,
|
||||
SplitDwarfLoad,
|
||||
};
|
||||
|
||||
/// The type used by [`Loader`] for reading DWARF data.
|
||||
///
|
||||
/// This is used in the return types of the methods of [`Loader`].
|
||||
// TODO: use impl Trait when stable
|
||||
pub type LoaderReader<'a> = gimli::EndianSlice<'a, gimli::RunTimeEndian>;
|
||||
|
||||
type Error = Box<dyn std::error::Error>;
|
||||
type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
/// A loader for the DWARF data required for a `Context`.
|
||||
///
|
||||
/// For performance reasons, a [`Context`] normally borrows the input data.
|
||||
/// However, that means the input data must outlive the `Context`, which
|
||||
/// is inconvenient for long-lived `Context`s.
|
||||
/// This loader uses an arena to store the input data, together with the
|
||||
/// `Context` itself. This ensures that the input data lives as long as
|
||||
/// the `Context`.
|
||||
///
|
||||
/// The loader performs some additional tasks:
|
||||
/// - Loads the symbol table from the executable file (see [`Self::find_symbol`]).
|
||||
/// - Loads Mach-O dSYM files that are located next to the executable file.
|
||||
/// - Locates and loads split DWARF files (DWO and DWP).
|
||||
pub struct Loader {
|
||||
internal: LoaderInternal<'static>,
|
||||
arena_data: Arena<Vec<u8>>,
|
||||
arena_mmap: Arena<Mmap>,
|
||||
}
|
||||
|
||||
impl Loader {
|
||||
/// Load the DWARF data for an executable file and create a `Context`.
|
||||
#[inline]
|
||||
pub fn new(path: impl AsRef<Path>) -> Result<Self> {
|
||||
Self::new_with_sup(path, None::<&Path>)
|
||||
}
|
||||
|
||||
/// Load the DWARF data for an executable file and create a `Context`.
|
||||
///
|
||||
/// Optionally also use a supplementary object file.
|
||||
pub fn new_with_sup(
|
||||
path: impl AsRef<Path>,
|
||||
sup_path: Option<impl AsRef<Path>>,
|
||||
) -> Result<Self> {
|
||||
let arena_data = Arena::new();
|
||||
let arena_mmap = Arena::new();
|
||||
|
||||
let internal = LoaderInternal::new(
|
||||
path.as_ref(),
|
||||
sup_path.as_ref().map(AsRef::as_ref),
|
||||
&arena_data,
|
||||
&arena_mmap,
|
||||
)?;
|
||||
Ok(Loader {
|
||||
// Convert to static lifetime to allow self-reference by `internal`.
|
||||
// `internal` is only accessed through `borrow_internal`, which ensures
|
||||
// that the static lifetime does not leak.
|
||||
internal: unsafe {
|
||||
core::mem::transmute::<LoaderInternal<'_>, LoaderInternal<'static>>(internal)
|
||||
},
|
||||
arena_data,
|
||||
arena_mmap,
|
||||
})
|
||||
}
|
||||
|
||||
fn borrow_internal<'a, F, T>(&'a self, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&'a LoaderInternal<'a>, &'a Arena<Vec<u8>>, &'a Arena<Mmap>) -> T,
|
||||
{
|
||||
// Do not leak the static lifetime.
|
||||
let internal = unsafe {
|
||||
core::mem::transmute::<&LoaderInternal<'static>, &'a LoaderInternal<'a>>(&self.internal)
|
||||
};
|
||||
f(internal, &self.arena_data, &self.arena_mmap)
|
||||
}
|
||||
|
||||
/// Get the base address used for relative virtual addresses.
|
||||
///
|
||||
/// Currently this is only non-zero for PE.
|
||||
pub fn relative_address_base(&self) -> u64 {
|
||||
self.borrow_internal(|i, _data, _mmap| i.relative_address_base)
|
||||
}
|
||||
|
||||
/// Find the source file and line corresponding to the given virtual memory address.
|
||||
///
|
||||
/// This calls [`Context::find_location`] with the given address.
|
||||
pub fn find_location(&self, probe: u64) -> Result<Option<Location<'_>>> {
|
||||
self.borrow_internal(|i, data, mmap| i.find_location(probe, data, mmap))
|
||||
}
|
||||
|
||||
/// Return source file and lines for a range of addresses.
|
||||
///
|
||||
/// This calls [`Context::find_location_range`] with the given range.
|
||||
pub fn find_location_range(
|
||||
&self,
|
||||
probe_low: u64,
|
||||
probe_high: u64,
|
||||
) -> Result<LocationRangeIter<'_, LoaderReader<'_>>> {
|
||||
self.borrow_internal(|i, data, mmap| {
|
||||
i.find_location_range(probe_low, probe_high, data, mmap)
|
||||
})
|
||||
}
|
||||
|
||||
/// Return an iterator for the function frames corresponding to the given virtual
|
||||
/// memory address.
|
||||
///
|
||||
/// This calls [`Context::find_frames`] with the given address.
|
||||
pub fn find_frames(&self, probe: u64) -> Result<FrameIter<'_, LoaderReader<'_>>> {
|
||||
self.borrow_internal(|i, data, mmap| i.find_frames(probe, data, mmap))
|
||||
}
|
||||
|
||||
/// Find the symbol table entry corresponding to the given virtual memory address.
|
||||
/// Return the symbol name.
|
||||
pub fn find_symbol(&self, probe: u64) -> Option<&str> {
|
||||
self.find_symbol_info(probe).map(|symbol| symbol.name)
|
||||
}
|
||||
|
||||
/// Find the symbol table entry corresponding to the given virtual memory address.
|
||||
pub fn find_symbol_info(&self, probe: u64) -> Option<Symbol<'_>> {
|
||||
self.borrow_internal(|i, _data, _mmap| i.find_symbol_info(probe))
|
||||
}
|
||||
|
||||
/// Get the address of a section
|
||||
pub fn get_section_range(&self, section_name: &[u8]) -> Option<gimli::Range> {
|
||||
self.borrow_internal(|i, _data, _mmap| i.get_section_range(section_name))
|
||||
}
|
||||
}
|
||||
|
||||
struct LoaderInternal<'a> {
|
||||
ctx: Context<LoaderReader<'a>>,
|
||||
object: object::File<'a>,
|
||||
relative_address_base: u64,
|
||||
symbols: SymbolMap<SymbolMapName<'a>>,
|
||||
dwarf_package: Option<gimli::DwarfPackage<LoaderReader<'a>>>,
|
||||
// Map from address to Mach-O object file path.
|
||||
object_map: object::ObjectMap<'a>,
|
||||
// A context for each Mach-O object file.
|
||||
objects: Vec<OnceCell<Option<ObjectContext<'a>>>>,
|
||||
}
|
||||
|
||||
impl<'a> LoaderInternal<'a> {
|
||||
fn new(
|
||||
path: &Path,
|
||||
sup_path: Option<&Path>,
|
||||
arena_data: &'a Arena<Vec<u8>>,
|
||||
arena_mmap: &'a Arena<Mmap>,
|
||||
) -> Result<Self> {
|
||||
let file = File::open(path)?;
|
||||
let map = arena_mmap.alloc(unsafe { Mmap::map(&file)? });
|
||||
let object = object::File::parse(&**map)?;
|
||||
|
||||
let relative_address_base = object.relative_address_base();
|
||||
let symbols = object.symbol_map();
|
||||
let object_map = object.object_map();
|
||||
let mut objects = Vec::new();
|
||||
objects.resize_with(object_map.objects().len(), OnceCell::new);
|
||||
|
||||
// Load supplementary object file.
|
||||
// TODO: use debuglink and debugaltlink
|
||||
let sup_map;
|
||||
let sup_object = if let Some(sup_path) = sup_path {
|
||||
let sup_file = File::open(sup_path)?;
|
||||
sup_map = arena_mmap.alloc(unsafe { Mmap::map(&sup_file)? });
|
||||
Some(object::File::parse(&**sup_map)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Load Mach-O dSYM file, ignoring errors.
|
||||
let dsym = if let Some(map) = (|| {
|
||||
let uuid = object.mach_uuid().ok()??;
|
||||
path.parent()?.read_dir().ok()?.find_map(|candidate| {
|
||||
let candidate = candidate.ok()?;
|
||||
let path = candidate.path();
|
||||
if path.extension().and_then(OsStr::to_str) != Some("dSYM") {
|
||||
return None;
|
||||
}
|
||||
let path = path.join("Contents/Resources/DWARF");
|
||||
path.read_dir().ok()?.find_map(|candidate| {
|
||||
let candidate = candidate.ok()?;
|
||||
let path = candidate.path();
|
||||
let file = File::open(path).ok()?;
|
||||
let map = unsafe { Mmap::map(&file) }.ok()?;
|
||||
let object = object::File::parse(&*map).ok()?;
|
||||
if object.mach_uuid() == Ok(Some(uuid)) {
|
||||
Some(map)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
})() {
|
||||
let map = arena_mmap.alloc(map);
|
||||
Some(object::File::parse(&**map)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let dwarf_object = dsym.as_ref().unwrap_or(&object);
|
||||
|
||||
// Load the DWARF sections.
|
||||
let endian = if dwarf_object.is_little_endian() {
|
||||
gimli::RunTimeEndian::Little
|
||||
} else {
|
||||
gimli::RunTimeEndian::Big
|
||||
};
|
||||
let mut dwarf = gimli::Dwarf::load(|id| {
|
||||
load_section(Some(id.name()), dwarf_object, endian, arena_data)
|
||||
})?;
|
||||
if let Some(sup_object) = &sup_object {
|
||||
dwarf.load_sup(|id| load_section(Some(id.name()), sup_object, endian, arena_data))?;
|
||||
}
|
||||
dwarf.populate_abbreviations_cache(gimli::AbbreviationsCacheStrategy::Duplicates);
|
||||
|
||||
let ctx = Context::from_dwarf(dwarf)?;
|
||||
|
||||
// Load the DWP file, ignoring errors.
|
||||
let dwarf_package = (|| {
|
||||
let mut dwp_path = path.to_path_buf();
|
||||
let dwp_extension = path
|
||||
.extension()
|
||||
.map(|previous_extension| {
|
||||
let mut previous_extension = previous_extension.to_os_string();
|
||||
previous_extension.push(".dwp");
|
||||
previous_extension
|
||||
})
|
||||
.unwrap_or_else(|| "dwp".into());
|
||||
dwp_path.set_extension(dwp_extension);
|
||||
let dwp_file = File::open(&dwp_path).ok()?;
|
||||
let map = arena_mmap.alloc(unsafe { Mmap::map(&dwp_file) }.ok()?);
|
||||
let dwp_object = object::File::parse(&**map).ok()?;
|
||||
|
||||
let endian = if dwp_object.is_little_endian() {
|
||||
gimli::RunTimeEndian::Little
|
||||
} else {
|
||||
gimli::RunTimeEndian::Big
|
||||
};
|
||||
let empty = gimli::EndianSlice::new(&[][..], endian);
|
||||
gimli::DwarfPackage::load(
|
||||
|id| load_section(id.dwo_name(), &dwp_object, endian, arena_data),
|
||||
empty,
|
||||
)
|
||||
.ok()
|
||||
})();
|
||||
|
||||
Ok(LoaderInternal {
|
||||
ctx,
|
||||
object,
|
||||
relative_address_base,
|
||||
symbols,
|
||||
dwarf_package,
|
||||
object_map,
|
||||
objects,
|
||||
})
|
||||
}
|
||||
|
||||
fn ctx(
|
||||
&self,
|
||||
probe: u64,
|
||||
arena_data: &'a Arena<Vec<u8>>,
|
||||
arena_mmap: &'a Arena<Mmap>,
|
||||
) -> (&Context<LoaderReader<'a>>, u64) {
|
||||
self.object_ctx(probe, arena_data, arena_mmap)
|
||||
.unwrap_or((&self.ctx, probe))
|
||||
}
|
||||
|
||||
fn object_ctx(
|
||||
&self,
|
||||
probe: u64,
|
||||
arena_data: &'a Arena<Vec<u8>>,
|
||||
arena_mmap: &'a Arena<Mmap>,
|
||||
) -> Option<(&Context<LoaderReader<'a>>, u64)> {
|
||||
let symbol = self.object_map.get(probe)?;
|
||||
let object_context = self.objects[symbol.object_index()]
|
||||
.get_or_init(|| {
|
||||
ObjectContext::new(symbol.object(&self.object_map), arena_data, arena_mmap)
|
||||
})
|
||||
.as_ref()?;
|
||||
object_context.ctx(symbol.name(), probe - symbol.address())
|
||||
}
|
||||
|
||||
fn find_symbol_info(&self, probe: u64) -> Option<Symbol<'a>> {
|
||||
self.symbols.get(probe).map(|x| Symbol {
|
||||
name: x.name(),
|
||||
address: x.address(),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_section_range(&self, section_name: &[u8]) -> Option<gimli::Range> {
|
||||
self.object
|
||||
.section_by_name_bytes(section_name)
|
||||
.map(|section| {
|
||||
let begin = section.address();
|
||||
let end = begin + section.size();
|
||||
gimli::Range { begin, end }
|
||||
})
|
||||
}
|
||||
|
||||
fn find_location(
|
||||
&'a self,
|
||||
probe: u64,
|
||||
arena_data: &'a Arena<Vec<u8>>,
|
||||
arena_mmap: &'a Arena<Mmap>,
|
||||
) -> Result<Option<Location<'a>>> {
|
||||
let (ctx, probe) = self.ctx(probe, arena_data, arena_mmap);
|
||||
Ok(ctx.find_location(probe)?)
|
||||
}
|
||||
|
||||
fn find_location_range(
|
||||
&self,
|
||||
probe_low: u64,
|
||||
probe_high: u64,
|
||||
arena_data: &'a Arena<Vec<u8>>,
|
||||
arena_mmap: &'a Arena<Mmap>,
|
||||
) -> Result<LocationRangeIter<'_, LoaderReader<'a>>> {
|
||||
let (ctx, probe) = self.ctx(probe_low, arena_data, arena_mmap);
|
||||
// TODO: handle ranges that cover multiple objects
|
||||
let probe_high = probe + (probe_high - probe_low);
|
||||
Ok(ctx.find_location_range(probe, probe_high)?)
|
||||
}
|
||||
|
||||
fn find_frames(
|
||||
&self,
|
||||
probe: u64,
|
||||
arena_data: &'a Arena<Vec<u8>>,
|
||||
arena_mmap: &'a Arena<Mmap>,
|
||||
) -> Result<FrameIter<'_, LoaderReader<'a>>> {
|
||||
let (ctx, probe) = self.ctx(probe, arena_data, arena_mmap);
|
||||
let mut frames = ctx.find_frames(probe);
|
||||
loop {
|
||||
let (load, continuation) = match frames {
|
||||
LookupResult::Output(output) => return Ok(output?),
|
||||
LookupResult::Load { load, continuation } => (load, continuation),
|
||||
};
|
||||
|
||||
let r = self.load_dwo(load, arena_data, arena_mmap)?;
|
||||
frames = continuation.resume(r);
|
||||
}
|
||||
}
|
||||
|
||||
fn load_dwo(
|
||||
&self,
|
||||
load: SplitDwarfLoad<LoaderReader<'a>>,
|
||||
arena_data: &'a Arena<Vec<u8>>,
|
||||
arena_mmap: &'a Arena<Mmap>,
|
||||
) -> Result<Option<Arc<gimli::Dwarf<LoaderReader<'a>>>>> {
|
||||
// Load the DWO file from the DWARF package, if available.
|
||||
if let Some(dwp) = self.dwarf_package.as_ref() {
|
||||
if let Some(cu) = dwp.find_cu(load.dwo_id, &load.parent)? {
|
||||
return Ok(Some(Arc::new(cu)));
|
||||
}
|
||||
}
|
||||
|
||||
// Determine the path to the DWO file.
|
||||
let mut path = PathBuf::new();
|
||||
if let Some(p) = load.comp_dir.as_ref() {
|
||||
path.push(convert_path(p.slice())?);
|
||||
}
|
||||
let Some(p) = load.path.as_ref() else {
|
||||
return Ok(None);
|
||||
};
|
||||
path.push(convert_path(p.slice())?);
|
||||
|
||||
// Load the DWO file, ignoring errors.
|
||||
let dwo = (|| {
|
||||
let file = File::open(&path).ok()?;
|
||||
let map = arena_mmap.alloc(unsafe { Mmap::map(&file) }.ok()?);
|
||||
let object = object::File::parse(&**map).ok()?;
|
||||
let endian = if object.is_little_endian() {
|
||||
gimli::RunTimeEndian::Little
|
||||
} else {
|
||||
gimli::RunTimeEndian::Big
|
||||
};
|
||||
let mut dwo_dwarf =
|
||||
gimli::Dwarf::load(|id| load_section(id.dwo_name(), &object, endian, arena_data))
|
||||
.ok()?;
|
||||
let dwo_unit_header = dwo_dwarf.units().next().ok()??;
|
||||
let dwo_unit = dwo_dwarf.unit(dwo_unit_header).ok()?;
|
||||
if dwo_unit.dwo_id != Some(load.dwo_id) {
|
||||
return None;
|
||||
}
|
||||
dwo_dwarf.make_dwo(&load.parent);
|
||||
Some(Arc::new(dwo_dwarf))
|
||||
})();
|
||||
Ok(dwo)
|
||||
}
|
||||
}
|
||||
|
||||
struct ObjectContext<'a> {
|
||||
ctx: Context<LoaderReader<'a>>,
|
||||
symbols: SymbolMap<SymbolMapName<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> ObjectContext<'a> {
|
||||
fn new(
|
||||
object: &ObjectMapFile<'a>,
|
||||
arena_data: &'a Arena<Vec<u8>>,
|
||||
arena_mmap: &'a Arena<Mmap>,
|
||||
) -> Option<Self> {
|
||||
let file = File::open(convert_path(object.path()).ok()?).ok()?;
|
||||
let map = &**arena_mmap.alloc(unsafe { Mmap::map(&file) }.ok()?);
|
||||
let data = if let Some(member_name) = object.member() {
|
||||
let archive = object::read::archive::ArchiveFile::parse(map).ok()?;
|
||||
let member = archive.members().find_map(|member| {
|
||||
let member = member.ok()?;
|
||||
if member.name() == member_name {
|
||||
Some(member)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})?;
|
||||
member.data(map).ok()?
|
||||
} else {
|
||||
map
|
||||
};
|
||||
let object = object::File::parse(data).ok()?;
|
||||
let endian = if object.is_little_endian() {
|
||||
gimli::RunTimeEndian::Little
|
||||
} else {
|
||||
gimli::RunTimeEndian::Big
|
||||
};
|
||||
let dwarf =
|
||||
gimli::Dwarf::load(|id| load_section(Some(id.name()), &object, endian, arena_data))
|
||||
.ok()?;
|
||||
let ctx = Context::from_dwarf(dwarf).ok()?;
|
||||
let symbols = object.symbol_map();
|
||||
Some(ObjectContext { ctx, symbols })
|
||||
}
|
||||
|
||||
fn ctx(&self, symbol_name: &[u8], probe: u64) -> Option<(&Context<LoaderReader<'a>>, u64)> {
|
||||
self.symbols
|
||||
.symbols()
|
||||
.iter()
|
||||
.find(|symbol| symbol.name().as_bytes() == symbol_name)
|
||||
.map(|symbol| (&self.ctx, probe + symbol.address()))
|
||||
}
|
||||
}
|
||||
|
||||
fn load_section<'input, Endian: gimli::Endianity>(
|
||||
name: Option<&'static str>,
|
||||
file: &object::File<'input>,
|
||||
endian: Endian,
|
||||
arena_data: &'input Arena<Vec<u8>>,
|
||||
) -> Result<gimli::EndianSlice<'input, Endian>> {
|
||||
let data = match name.and_then(|name| file.section_by_name(name)) {
|
||||
Some(section) => match section.uncompressed_data()? {
|
||||
Cow::Borrowed(b) => b,
|
||||
Cow::Owned(b) => arena_data.alloc(b),
|
||||
},
|
||||
None => &[],
|
||||
};
|
||||
Ok(gimli::EndianSlice::new(data, endian))
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn convert_path(bytes: &[u8]) -> Result<PathBuf> {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
let s = OsStr::from_bytes(bytes);
|
||||
Ok(PathBuf::from(s))
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn convert_path(bytes: &[u8]) -> Result<PathBuf> {
|
||||
let s = std::str::from_utf8(bytes)?;
|
||||
Ok(PathBuf::from(s))
|
||||
}
|
||||
|
||||
/// Information from a symbol table entry.
|
||||
pub struct Symbol<'a> {
|
||||
name: &'a str,
|
||||
address: u64,
|
||||
}
|
||||
|
||||
impl<'a> Symbol<'a> {
|
||||
/// Get the symbol name.
|
||||
pub fn name(&self) -> &'a str {
|
||||
self.name
|
||||
}
|
||||
|
||||
/// Get the symbol address.
|
||||
pub fn address(&self) -> u64 {
|
||||
self.address
|
||||
}
|
||||
}
|
||||
261
.gear/predownloaded-development/vendor/addr2line/src/lookup.rs
vendored
Normal file
261
.gear/predownloaded-development/vendor/addr2line/src/lookup.rs
vendored
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
use alloc::sync::Arc;
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::ControlFlow;
|
||||
|
||||
/// This struct contains the information needed to find split DWARF data
|
||||
/// and to produce a `gimli::Dwarf<R>` for it.
|
||||
pub struct SplitDwarfLoad<R> {
|
||||
/// The dwo id, for looking up in a DWARF package, or for
|
||||
/// verifying an unpacked dwo found on the file system
|
||||
pub dwo_id: gimli::DwoId,
|
||||
/// The compilation directory `path` is relative to.
|
||||
pub comp_dir: Option<R>,
|
||||
/// A path on the filesystem, relative to `comp_dir` to find this dwo.
|
||||
pub path: Option<R>,
|
||||
/// Once the split DWARF data is loaded, the loader is expected
|
||||
/// to call [make_dwo(parent)](gimli::read::Dwarf::make_dwo) before
|
||||
/// returning the data.
|
||||
pub parent: Arc<gimli::Dwarf<R>>,
|
||||
}
|
||||
|
||||
/// Operations that consult debug information may require additional files
|
||||
/// to be loaded if split DWARF is being used. This enum returns the result
|
||||
/// of the operation in the `Output` variant, or information about the split
|
||||
/// DWARF that is required and a continuation to invoke once it is available
|
||||
/// in the `Load` variant.
|
||||
///
|
||||
/// This enum is intended to be used in a loop like so:
|
||||
/// ```no_run
|
||||
/// # use addr2line::*;
|
||||
/// # use std::sync::Arc;
|
||||
/// # let ctx: Context<gimli::EndianSlice<gimli::RunTimeEndian>> = todo!();
|
||||
/// # let do_split_dwarf_load = |load: SplitDwarfLoad<gimli::EndianSlice<gimli::RunTimeEndian>>| -> Option<Arc<gimli::Dwarf<gimli::EndianSlice<gimli::RunTimeEndian>>>> { None };
|
||||
/// const ADDRESS: u64 = 0xdeadbeef;
|
||||
/// let mut r = ctx.find_frames(ADDRESS);
|
||||
/// let result = loop {
|
||||
/// match r {
|
||||
/// LookupResult::Output(result) => break result,
|
||||
/// LookupResult::Load { load, continuation } => {
|
||||
/// let dwo = do_split_dwarf_load(load);
|
||||
/// r = continuation.resume(dwo);
|
||||
/// }
|
||||
/// }
|
||||
/// };
|
||||
/// ```
|
||||
pub enum LookupResult<L: LookupContinuation> {
|
||||
/// The lookup requires split DWARF data to be loaded.
|
||||
Load {
|
||||
/// The information needed to find the split DWARF data.
|
||||
load: SplitDwarfLoad<<L as LookupContinuation>::Buf>,
|
||||
/// The continuation to resume with the loaded split DWARF data.
|
||||
continuation: L,
|
||||
},
|
||||
/// The lookup has completed and produced an output.
|
||||
Output(<L as LookupContinuation>::Output),
|
||||
}
|
||||
|
||||
/// This trait represents a partially complete operation that can be resumed
|
||||
/// once a load of needed split DWARF data is completed or abandoned by the
|
||||
/// API consumer.
|
||||
pub trait LookupContinuation: Sized {
|
||||
/// The final output of this operation.
|
||||
type Output;
|
||||
/// The type of reader used.
|
||||
type Buf: gimli::Reader;
|
||||
|
||||
/// Resumes the operation with the provided data.
|
||||
///
|
||||
/// After the caller loads the split DWARF data required, call this
|
||||
/// method to resume the operation. The return value of this method
|
||||
/// indicates if the computation has completed or if further data is
|
||||
/// required.
|
||||
///
|
||||
/// If the additional data cannot be located, or the caller does not
|
||||
/// support split DWARF, `resume(None)` can be used to continue the
|
||||
/// operation with the data that is available.
|
||||
fn resume(self, input: Option<Arc<gimli::Dwarf<Self::Buf>>>) -> LookupResult<Self>;
|
||||
}
|
||||
|
||||
impl<L: LookupContinuation> LookupResult<L> {
|
||||
/// Callers that do not handle split DWARF can call `skip_all_loads`
|
||||
/// to fast-forward to the end result. This result is produced with
|
||||
/// the data that is available and may be less accurate than the
|
||||
/// the results that would be produced if the caller did properly
|
||||
/// support split DWARF.
|
||||
pub fn skip_all_loads(mut self) -> L::Output {
|
||||
loop {
|
||||
self = match self {
|
||||
LookupResult::Output(t) => return t,
|
||||
LookupResult::Load { continuation, .. } => continuation.resume(None),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn map<T, F: FnOnce(L::Output) -> T>(
|
||||
self,
|
||||
f: F,
|
||||
) -> LookupResult<MappedLookup<T, L, F>> {
|
||||
match self {
|
||||
LookupResult::Output(t) => LookupResult::Output(f(t)),
|
||||
LookupResult::Load { load, continuation } => LookupResult::Load {
|
||||
load,
|
||||
continuation: MappedLookup {
|
||||
original: continuation,
|
||||
mutator: f,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn unwrap(self) -> L::Output {
|
||||
match self {
|
||||
LookupResult::Output(t) => t,
|
||||
LookupResult::Load { .. } => unreachable!("Internal API misuse"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct SimpleLookup<T, R, F>
|
||||
where
|
||||
F: FnOnce(Option<Arc<gimli::Dwarf<R>>>) -> T,
|
||||
R: gimli::Reader,
|
||||
{
|
||||
f: F,
|
||||
phantom: PhantomData<(T, R)>,
|
||||
}
|
||||
|
||||
impl<T, R, F> SimpleLookup<T, R, F>
|
||||
where
|
||||
F: FnOnce(Option<Arc<gimli::Dwarf<R>>>) -> T,
|
||||
R: gimli::Reader,
|
||||
{
|
||||
pub(crate) fn new_complete(t: F::Output) -> LookupResult<SimpleLookup<T, R, F>> {
|
||||
LookupResult::Output(t)
|
||||
}
|
||||
|
||||
pub(crate) fn new_needs_load(
|
||||
load: SplitDwarfLoad<R>,
|
||||
f: F,
|
||||
) -> LookupResult<SimpleLookup<T, R, F>> {
|
||||
LookupResult::Load {
|
||||
load,
|
||||
continuation: SimpleLookup {
|
||||
f,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R, F> LookupContinuation for SimpleLookup<T, R, F>
|
||||
where
|
||||
F: FnOnce(Option<Arc<gimli::Dwarf<R>>>) -> T,
|
||||
R: gimli::Reader,
|
||||
{
|
||||
type Output = T;
|
||||
type Buf = R;
|
||||
|
||||
fn resume(self, v: Option<Arc<gimli::Dwarf<Self::Buf>>>) -> LookupResult<Self> {
|
||||
LookupResult::Output((self.f)(v))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct MappedLookup<T, L, F>
|
||||
where
|
||||
L: LookupContinuation,
|
||||
F: FnOnce(L::Output) -> T,
|
||||
{
|
||||
original: L,
|
||||
mutator: F,
|
||||
}
|
||||
|
||||
impl<T, L, F> LookupContinuation for MappedLookup<T, L, F>
|
||||
where
|
||||
L: LookupContinuation,
|
||||
F: FnOnce(L::Output) -> T,
|
||||
{
|
||||
type Output = T;
|
||||
type Buf = L::Buf;
|
||||
|
||||
fn resume(self, v: Option<Arc<gimli::Dwarf<Self::Buf>>>) -> LookupResult<Self> {
|
||||
match self.original.resume(v) {
|
||||
LookupResult::Output(t) => LookupResult::Output((self.mutator)(t)),
|
||||
LookupResult::Load { load, continuation } => LookupResult::Load {
|
||||
load,
|
||||
continuation: MappedLookup {
|
||||
original: continuation,
|
||||
mutator: self.mutator,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Some functions (e.g. `find_frames`) require considering multiple
|
||||
/// compilation units, each of which might require their own split DWARF
|
||||
/// lookup (and thus produce a continuation).
|
||||
///
|
||||
/// We store the underlying continuation here as well as a mutator function
|
||||
/// that will either a) decide that the result of this continuation is
|
||||
/// what is needed and mutate it to the final result or b) produce another
|
||||
/// `LookupResult`. `new_lookup` will in turn eagerly drive any non-continuation
|
||||
/// `LookupResult` with successive invocations of the mutator, until a new
|
||||
/// continuation or a final result is produced. And finally, the impl of
|
||||
/// `LookupContinuation::resume` will call `new_lookup` each time the
|
||||
/// computation is resumed.
|
||||
pub(crate) struct LoopingLookup<T, L, F>
|
||||
where
|
||||
L: LookupContinuation,
|
||||
F: FnMut(L::Output) -> ControlFlow<T, LookupResult<L>>,
|
||||
{
|
||||
continuation: L,
|
||||
mutator: F,
|
||||
}
|
||||
|
||||
impl<T, L, F> LoopingLookup<T, L, F>
|
||||
where
|
||||
L: LookupContinuation,
|
||||
F: FnMut(L::Output) -> ControlFlow<T, LookupResult<L>>,
|
||||
{
|
||||
pub(crate) fn new_complete(t: T) -> LookupResult<Self> {
|
||||
LookupResult::Output(t)
|
||||
}
|
||||
|
||||
pub(crate) fn new_lookup(mut r: LookupResult<L>, mut mutator: F) -> LookupResult<Self> {
|
||||
// Drive the loop eagerly so that we only ever have to represent one state
|
||||
// (the r == ControlFlow::Continue state) in LoopingLookup.
|
||||
loop {
|
||||
match r {
|
||||
LookupResult::Output(l) => match mutator(l) {
|
||||
ControlFlow::Break(t) => return LookupResult::Output(t),
|
||||
ControlFlow::Continue(r2) => {
|
||||
r = r2;
|
||||
}
|
||||
},
|
||||
LookupResult::Load { load, continuation } => {
|
||||
return LookupResult::Load {
|
||||
load,
|
||||
continuation: LoopingLookup {
|
||||
continuation,
|
||||
mutator,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, L, F> LookupContinuation for LoopingLookup<T, L, F>
|
||||
where
|
||||
L: LookupContinuation,
|
||||
F: FnMut(L::Output) -> ControlFlow<T, LookupResult<L>>,
|
||||
{
|
||||
type Output = T;
|
||||
type Buf = L::Buf;
|
||||
|
||||
fn resume(self, v: Option<Arc<gimli::Dwarf<Self::Buf>>>) -> LookupResult<Self> {
|
||||
let r = self.continuation.resume(v);
|
||||
LoopingLookup::new_lookup(r, self.mutator)
|
||||
}
|
||||
}
|
||||
598
.gear/predownloaded-development/vendor/addr2line/src/unit.rs
vendored
Normal file
598
.gear/predownloaded-development/vendor/addr2line/src/unit.rs
vendored
Normal file
|
|
@ -0,0 +1,598 @@
|
|||
use alloc::boxed::Box;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use core::cmp;
|
||||
|
||||
use crate::{
|
||||
Context, DebugFile, Error, Function, Functions, LazyFunctions, LazyLines, LazyResult,
|
||||
LineLocationRangeIter, Lines, Location, LookupContinuation, LookupResult, RangeAttributes,
|
||||
SimpleLookup, SplitDwarfLoad,
|
||||
};
|
||||
|
||||
pub(crate) struct UnitRange {
|
||||
unit_id: usize,
|
||||
min_begin: u64,
|
||||
range: gimli::Range,
|
||||
}
|
||||
|
||||
pub(crate) struct ResUnit<R: gimli::Reader> {
|
||||
offset: gimli::DebugInfoOffset<R::Offset>,
|
||||
dw_unit: gimli::Unit<R>,
|
||||
pub(crate) lang: Option<gimli::DwLang>,
|
||||
lines: LazyLines,
|
||||
functions: LazyFunctions<R>,
|
||||
dwo: LazyResult<Option<Box<DwoUnit<R>>>>,
|
||||
}
|
||||
|
||||
type UnitRef<'unit, R> = (DebugFile, gimli::UnitRef<'unit, R>);
|
||||
|
||||
impl<R: gimli::Reader> ResUnit<R> {
|
||||
pub(crate) fn unit_ref<'a>(&'a self, sections: &'a gimli::Dwarf<R>) -> gimli::UnitRef<'a, R> {
|
||||
gimli::UnitRef::new(sections, &self.dw_unit)
|
||||
}
|
||||
|
||||
/// Returns the DWARF sections and the unit.
|
||||
///
|
||||
/// Loads the DWO unit if necessary.
|
||||
pub(crate) fn dwarf_and_unit<'unit, 'ctx: 'unit>(
|
||||
&'unit self,
|
||||
ctx: &'ctx Context<R>,
|
||||
) -> LookupResult<
|
||||
SimpleLookup<
|
||||
Result<UnitRef<'unit, R>, Error>,
|
||||
R,
|
||||
impl FnOnce(Option<Arc<gimli::Dwarf<R>>>) -> Result<UnitRef<'unit, R>, Error>,
|
||||
>,
|
||||
> {
|
||||
let map_dwo = move |dwo: &'unit Result<Option<Box<DwoUnit<R>>>, Error>| match dwo {
|
||||
Ok(Some(dwo)) => Ok((DebugFile::Dwo, dwo.unit_ref())),
|
||||
Ok(None) => Ok((DebugFile::Primary, self.unit_ref(&*ctx.sections))),
|
||||
Err(e) => Err(*e),
|
||||
};
|
||||
let complete = |dwo| SimpleLookup::new_complete(map_dwo(dwo));
|
||||
|
||||
if let Some(dwo) = self.dwo.get() {
|
||||
return complete(dwo);
|
||||
}
|
||||
|
||||
let dwo_id = match self.dw_unit.dwo_id {
|
||||
None => {
|
||||
return complete(self.dwo.get_or_init(|| Ok(None)));
|
||||
}
|
||||
Some(dwo_id) => dwo_id,
|
||||
};
|
||||
|
||||
let comp_dir = self.dw_unit.comp_dir.clone();
|
||||
|
||||
let dwo_name = self.dw_unit.dwo_name().and_then(|s| {
|
||||
if let Some(s) = s {
|
||||
Ok(Some(ctx.sections.attr_string(&self.dw_unit, s)?))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
});
|
||||
|
||||
let path = match dwo_name {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return complete(self.dwo.get_or_init(|| Err(e)));
|
||||
}
|
||||
};
|
||||
|
||||
let process_dwo = move |dwo_dwarf: Option<Arc<gimli::Dwarf<R>>>| {
|
||||
let dwo_dwarf = match dwo_dwarf {
|
||||
None => return Ok(None),
|
||||
Some(dwo_dwarf) => dwo_dwarf,
|
||||
};
|
||||
let mut dwo_units = dwo_dwarf.units();
|
||||
let dwo_header = match dwo_units.next()? {
|
||||
Some(dwo_header) => dwo_header,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
let mut dwo_unit = dwo_dwarf.unit(dwo_header)?;
|
||||
dwo_unit.copy_relocated_attributes(&self.dw_unit);
|
||||
Ok(Some(Box::new(DwoUnit {
|
||||
sections: dwo_dwarf,
|
||||
dw_unit: dwo_unit,
|
||||
})))
|
||||
};
|
||||
|
||||
SimpleLookup::new_needs_load(
|
||||
SplitDwarfLoad {
|
||||
dwo_id,
|
||||
comp_dir,
|
||||
path,
|
||||
parent: ctx.sections.clone(),
|
||||
},
|
||||
move |dwo_dwarf| map_dwo(self.dwo.get_or_init(|| process_dwo(dwo_dwarf))),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn parse_lines(&self, sections: &gimli::Dwarf<R>) -> Result<Option<&Lines>, Error> {
|
||||
// NB: line information is always stored in the main debug file so this does not need
|
||||
// to handle DWOs.
|
||||
let ilnp = match self.dw_unit.line_program {
|
||||
Some(ref ilnp) => ilnp,
|
||||
None => return Ok(None),
|
||||
};
|
||||
self.lines.borrow(self.unit_ref(sections), ilnp).map(Some)
|
||||
}
|
||||
|
||||
pub(crate) fn parse_functions<'unit, 'ctx: 'unit>(
|
||||
&'unit self,
|
||||
ctx: &'ctx Context<R>,
|
||||
) -> LookupResult<impl LookupContinuation<Output = Result<&'unit Functions<R>, Error>, Buf = R>>
|
||||
{
|
||||
self.dwarf_and_unit(ctx).map(move |r| {
|
||||
let (_file, unit) = r?;
|
||||
self.functions.borrow(unit)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn parse_inlined_functions<'unit, 'ctx: 'unit>(
|
||||
&'unit self,
|
||||
ctx: &'ctx Context<R>,
|
||||
) -> LookupResult<impl LookupContinuation<Output = Result<(), Error>, Buf = R> + 'unit> {
|
||||
self.dwarf_and_unit(ctx).map(move |r| {
|
||||
let (file, unit) = r?;
|
||||
self.functions
|
||||
.borrow(unit)?
|
||||
.parse_inlined_functions(file, unit, ctx)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn find_location(
|
||||
&self,
|
||||
probe: u64,
|
||||
sections: &gimli::Dwarf<R>,
|
||||
) -> Result<Option<Location<'_>>, Error> {
|
||||
let Some(lines) = self.parse_lines(sections)? else {
|
||||
return Ok(None);
|
||||
};
|
||||
lines.find_location(probe)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn find_location_range(
|
||||
&self,
|
||||
probe_low: u64,
|
||||
probe_high: u64,
|
||||
sections: &gimli::Dwarf<R>,
|
||||
) -> Result<Option<LineLocationRangeIter<'_>>, Error> {
|
||||
let Some(lines) = self.parse_lines(sections)? else {
|
||||
return Ok(None);
|
||||
};
|
||||
lines.find_location_range(probe_low, probe_high).map(Some)
|
||||
}
|
||||
|
||||
pub(crate) fn find_function_or_location<'unit, 'ctx: 'unit>(
|
||||
&'unit self,
|
||||
probe: u64,
|
||||
ctx: &'ctx Context<R>,
|
||||
) -> LookupResult<
|
||||
impl LookupContinuation<
|
||||
Output = Result<(Option<&'unit Function<R>>, Option<Location<'unit>>), Error>,
|
||||
Buf = R,
|
||||
>,
|
||||
> {
|
||||
self.dwarf_and_unit(ctx).map(move |r| {
|
||||
let (file, unit) = r?;
|
||||
let functions = self.functions.borrow(unit)?;
|
||||
let function = match functions.find_address(probe) {
|
||||
Some(address) => {
|
||||
let function_index = functions.addresses[address].function;
|
||||
let function = &functions.functions[function_index];
|
||||
Some(function.borrow(file, unit, ctx)?)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
let location = self.find_location(probe, &ctx.sections)?;
|
||||
Ok((function, location))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ResUnits<R: gimli::Reader> {
|
||||
ranges: Box<[UnitRange]>,
|
||||
units: Box<[ResUnit<R>]>,
|
||||
}
|
||||
|
||||
impl<R: gimli::Reader> ResUnits<R> {
|
||||
pub(crate) fn parse(sections: &gimli::Dwarf<R>) -> Result<Self, Error> {
|
||||
// Find all the references to compilation units in .debug_aranges.
|
||||
// Note that we always also iterate through all of .debug_info to
|
||||
// find compilation units, because .debug_aranges may be missing some.
|
||||
let mut aranges = Vec::new();
|
||||
let mut headers = sections.debug_aranges.headers();
|
||||
while let Some(header) = headers.next()? {
|
||||
aranges.push((header.debug_info_offset(), header.offset()));
|
||||
}
|
||||
aranges.sort_by_key(|i| i.0);
|
||||
|
||||
let mut unit_ranges = Vec::new();
|
||||
let mut res_units = Vec::new();
|
||||
let mut units = sections.units();
|
||||
while let Some(header) = units.next()? {
|
||||
let unit_id = res_units.len();
|
||||
let offset = match header.offset().as_debug_info_offset() {
|
||||
Some(offset) => offset,
|
||||
None => continue,
|
||||
};
|
||||
// We mainly want compile units, but we may need to follow references to entries
|
||||
// within other units for function names. We don't need anything from type units.
|
||||
let mut need_unit_range = match header.type_() {
|
||||
gimli::UnitType::Type { .. } | gimli::UnitType::SplitType { .. } => continue,
|
||||
gimli::UnitType::Partial => {
|
||||
// Partial units are only needed for references from other units.
|
||||
// They shouldn't have any address ranges.
|
||||
false
|
||||
}
|
||||
_ => true,
|
||||
};
|
||||
let dw_unit = match sections.unit(header) {
|
||||
Ok(dw_unit) => dw_unit,
|
||||
Err(_) => continue,
|
||||
};
|
||||
let dw_unit_ref = gimli::UnitRef::new(sections, &dw_unit);
|
||||
|
||||
let mut lang = None;
|
||||
if need_unit_range {
|
||||
let mut entries = dw_unit_ref.entries_raw(None)?;
|
||||
|
||||
let abbrev = match entries.read_abbreviation()? {
|
||||
Some(abbrev) => abbrev,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let mut ranges = RangeAttributes::default();
|
||||
for spec in abbrev.attributes() {
|
||||
let attr = entries.read_attribute(*spec)?;
|
||||
match attr.name() {
|
||||
gimli::DW_AT_low_pc => match attr.value() {
|
||||
gimli::AttributeValue::Addr(val) => ranges.low_pc = Some(val),
|
||||
gimli::AttributeValue::DebugAddrIndex(index) => {
|
||||
ranges.low_pc = Some(dw_unit_ref.address(index)?);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
gimli::DW_AT_high_pc => match attr.value() {
|
||||
gimli::AttributeValue::Addr(val) => ranges.high_pc = Some(val),
|
||||
gimli::AttributeValue::DebugAddrIndex(index) => {
|
||||
ranges.high_pc = Some(dw_unit_ref.address(index)?);
|
||||
}
|
||||
gimli::AttributeValue::Udata(val) => ranges.size = Some(val),
|
||||
_ => {}
|
||||
},
|
||||
gimli::DW_AT_ranges => {
|
||||
ranges.ranges_offset = dw_unit_ref.attr_ranges_offset(attr.value())?;
|
||||
}
|
||||
gimli::DW_AT_language => {
|
||||
if let gimli::AttributeValue::Language(val) = attr.value() {
|
||||
lang = Some(val);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the address ranges for the CU, using in order of preference:
|
||||
// - DW_AT_ranges
|
||||
// - .debug_aranges
|
||||
// - DW_AT_low_pc/DW_AT_high_pc
|
||||
//
|
||||
// Using DW_AT_ranges before .debug_aranges is possibly an arbitrary choice,
|
||||
// but the feeling is that DW_AT_ranges is more likely to be reliable or complete
|
||||
// if it is present.
|
||||
//
|
||||
// .debug_aranges must be used before DW_AT_low_pc/DW_AT_high_pc because
|
||||
// it has been observed on macOS that DW_AT_ranges was not emitted even for
|
||||
// discontiguous CUs.
|
||||
let i = match ranges.ranges_offset {
|
||||
Some(_) => None,
|
||||
None => aranges.binary_search_by_key(&offset, |x| x.0).ok(),
|
||||
};
|
||||
if let Some(mut i) = i {
|
||||
// There should be only one set per CU, but in practice multiple
|
||||
// sets have been observed. This is probably a compiler bug, but
|
||||
// either way we need to handle it.
|
||||
while i > 0 && aranges[i - 1].0 == offset {
|
||||
i -= 1;
|
||||
}
|
||||
for (_, aranges_offset) in aranges[i..].iter().take_while(|x| x.0 == offset) {
|
||||
let aranges_header = sections.debug_aranges.header(*aranges_offset)?;
|
||||
let mut aranges = aranges_header.entries();
|
||||
while let Some(arange) = aranges.next().transpose() {
|
||||
let Ok(arange) = arange else {
|
||||
// Ignore errors. In particular, this will ignore address overflow.
|
||||
// This has been seen for a unit that had a single variable
|
||||
// with rustc 1.89.0.
|
||||
//
|
||||
// This relies on `ArangeEntryIter::next` fusing for errors that
|
||||
// can't be ignored.
|
||||
continue;
|
||||
};
|
||||
if arange.length() != 0 {
|
||||
unit_ranges.push(UnitRange {
|
||||
range: arange.range(),
|
||||
unit_id,
|
||||
min_begin: 0,
|
||||
});
|
||||
need_unit_range = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if need_unit_range {
|
||||
need_unit_range = !ranges.for_each_range(dw_unit_ref, |range| {
|
||||
unit_ranges.push(UnitRange {
|
||||
range,
|
||||
unit_id,
|
||||
min_begin: 0,
|
||||
});
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
let lines = LazyLines::new();
|
||||
if need_unit_range {
|
||||
// The unit did not declare any ranges.
|
||||
// Try to get some ranges from the line program sequences.
|
||||
if let Some(ref ilnp) = dw_unit_ref.line_program {
|
||||
if let Ok(lines) = lines.borrow(dw_unit_ref, ilnp) {
|
||||
for range in lines.ranges() {
|
||||
unit_ranges.push(UnitRange {
|
||||
range,
|
||||
unit_id,
|
||||
min_begin: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res_units.push(ResUnit {
|
||||
offset,
|
||||
dw_unit,
|
||||
lang,
|
||||
lines,
|
||||
functions: LazyFunctions::new(),
|
||||
dwo: LazyResult::new(),
|
||||
});
|
||||
}
|
||||
|
||||
// Sort this for faster lookup in `Self::find_range`.
|
||||
unit_ranges.sort_by_key(|i| i.range.end);
|
||||
|
||||
// Calculate the `min_begin` field now that we've determined the order of
|
||||
// CUs.
|
||||
let mut min = !0;
|
||||
for i in unit_ranges.iter_mut().rev() {
|
||||
min = min.min(i.range.begin);
|
||||
i.min_begin = min;
|
||||
}
|
||||
|
||||
Ok(ResUnits {
|
||||
ranges: unit_ranges.into_boxed_slice(),
|
||||
units: res_units.into_boxed_slice(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = &ResUnit<R>> {
|
||||
self.units.iter()
|
||||
}
|
||||
|
||||
pub(crate) fn find_offset(
|
||||
&self,
|
||||
offset: gimli::DebugInfoOffset<R::Offset>,
|
||||
) -> Result<&gimli::Unit<R>, Error> {
|
||||
match self
|
||||
.units
|
||||
.binary_search_by_key(&offset.0, |unit| unit.offset.0)
|
||||
{
|
||||
// There is never a DIE at the unit offset or before the first unit.
|
||||
Ok(_) | Err(0) => Err(gimli::Error::NoEntryAtGivenOffset),
|
||||
Err(i) => Ok(&self.units[i - 1].dw_unit),
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds the CUs for the function address given.
|
||||
///
|
||||
/// There might be multiple CUs whose range contains this address.
|
||||
/// Weak symbols have shown up in the wild which cause this to happen
|
||||
/// but otherwise this can happen if the CU has non-contiguous functions
|
||||
/// but only reports a single range.
|
||||
///
|
||||
/// Consequently we return an iterator for all CUs which may contain the
|
||||
/// address, and the caller must check if there is actually a function or
|
||||
/// location in the CU for that address.
|
||||
pub(crate) fn find(&self, probe: u64) -> impl Iterator<Item = &ResUnit<R>> {
|
||||
self.find_range(probe, probe + 1).map(|(unit, _range)| unit)
|
||||
}
|
||||
|
||||
/// Finds the CUs covering the range of addresses given.
|
||||
///
|
||||
/// The range is [low, high) (ie, the upper bound is exclusive). This can return multiple
|
||||
/// ranges for the same unit.
|
||||
#[inline]
|
||||
pub(crate) fn find_range(
|
||||
&self,
|
||||
probe_low: u64,
|
||||
probe_high: u64,
|
||||
) -> impl Iterator<Item = (&ResUnit<R>, &gimli::Range)> {
|
||||
// Find the position of the next range after a range which
|
||||
// ends at `probe_low` or lower.
|
||||
let pos = match self
|
||||
.ranges
|
||||
.binary_search_by_key(&probe_low, |i| i.range.end)
|
||||
{
|
||||
Ok(i) => i + 1, // Range `i` ends at exactly `probe_low`.
|
||||
Err(i) => i, // Range `i - 1` ends at a lower address.
|
||||
};
|
||||
|
||||
// Iterate from that position to find matching CUs.
|
||||
self.ranges[pos..]
|
||||
.iter()
|
||||
.take_while(move |i| {
|
||||
// We know that this CU's end is at least `probe_low` because
|
||||
// of our sorted array.
|
||||
debug_assert!(i.range.end >= probe_low);
|
||||
|
||||
// Each entry keeps track of the minimum begin address for the
|
||||
// remainder of the array of unit ranges. If our probe is before
|
||||
// the minimum range begin of this entry, then it's guaranteed
|
||||
// to not fit in any subsequent entries, so we break out.
|
||||
probe_high > i.min_begin
|
||||
})
|
||||
.filter_map(move |i| {
|
||||
// If this CU doesn't actually contain this address, move to the
|
||||
// next CU.
|
||||
if probe_low >= i.range.end || probe_high <= i.range.begin {
|
||||
return None;
|
||||
}
|
||||
Some((&self.units[i.unit_id], &i.range))
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn find_location_range<'a>(
|
||||
&'a self,
|
||||
probe_low: u64,
|
||||
probe_high: u64,
|
||||
sections: &'a gimli::Dwarf<R>,
|
||||
) -> Result<LocationRangeIter<'a, R>, Error> {
|
||||
let unit_iter = Box::new(self.find_range(probe_low, probe_high));
|
||||
Ok(LocationRangeIter {
|
||||
unit_iter,
|
||||
iter: None,
|
||||
probe_low,
|
||||
probe_high,
|
||||
sections,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A DWO unit has its own DWARF sections.
|
||||
struct DwoUnit<R: gimli::Reader> {
|
||||
sections: Arc<gimli::Dwarf<R>>,
|
||||
dw_unit: gimli::Unit<R>,
|
||||
}
|
||||
|
||||
impl<R: gimli::Reader> DwoUnit<R> {
|
||||
fn unit_ref(&self) -> gimli::UnitRef<'_, R> {
|
||||
gimli::UnitRef::new(&self.sections, &self.dw_unit)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct SupUnit<R: gimli::Reader> {
|
||||
offset: gimli::DebugInfoOffset<R::Offset>,
|
||||
dw_unit: gimli::Unit<R>,
|
||||
}
|
||||
|
||||
pub(crate) struct SupUnits<R: gimli::Reader> {
|
||||
units: Box<[SupUnit<R>]>,
|
||||
}
|
||||
|
||||
impl<R: gimli::Reader> Default for SupUnits<R> {
|
||||
fn default() -> Self {
|
||||
SupUnits {
|
||||
units: Box::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: gimli::Reader> SupUnits<R> {
|
||||
pub(crate) fn parse(sections: &gimli::Dwarf<R>) -> Result<Self, Error> {
|
||||
let mut sup_units = Vec::new();
|
||||
let mut units = sections.units();
|
||||
while let Some(header) = units.next()? {
|
||||
let offset = match header.offset().as_debug_info_offset() {
|
||||
Some(offset) => offset,
|
||||
None => continue,
|
||||
};
|
||||
let dw_unit = match sections.unit(header) {
|
||||
Ok(dw_unit) => dw_unit,
|
||||
Err(_) => continue,
|
||||
};
|
||||
sup_units.push(SupUnit { dw_unit, offset });
|
||||
}
|
||||
Ok(SupUnits {
|
||||
units: sup_units.into_boxed_slice(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn find_offset(
|
||||
&self,
|
||||
offset: gimli::DebugInfoOffset<R::Offset>,
|
||||
) -> Result<&gimli::Unit<R>, Error> {
|
||||
match self
|
||||
.units
|
||||
.binary_search_by_key(&offset.0, |unit| unit.offset.0)
|
||||
{
|
||||
// There is never a DIE at the unit offset or before the first unit.
|
||||
Ok(_) | Err(0) => Err(gimli::Error::NoEntryAtGivenOffset),
|
||||
Err(i) => Ok(&self.units[i - 1].dw_unit),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator over `Location`s in a range of addresses, returned by `Context::find_location_range`.
|
||||
pub struct LocationRangeIter<'ctx, R: gimli::Reader> {
|
||||
unit_iter: Box<dyn Iterator<Item = (&'ctx ResUnit<R>, &'ctx gimli::Range)> + 'ctx>,
|
||||
iter: Option<LineLocationRangeIter<'ctx>>,
|
||||
|
||||
probe_low: u64,
|
||||
probe_high: u64,
|
||||
sections: &'ctx gimli::Dwarf<R>,
|
||||
}
|
||||
|
||||
impl<'ctx, R: gimli::Reader> LocationRangeIter<'ctx, R> {
|
||||
fn next_loc(&mut self) -> Result<Option<(u64, u64, Location<'ctx>)>, Error> {
|
||||
loop {
|
||||
let iter = self.iter.take();
|
||||
match iter {
|
||||
None => match self.unit_iter.next() {
|
||||
Some((unit, range)) => {
|
||||
self.iter = unit.find_location_range(
|
||||
cmp::max(self.probe_low, range.begin),
|
||||
cmp::min(self.probe_high, range.end),
|
||||
self.sections,
|
||||
)?;
|
||||
}
|
||||
None => return Ok(None),
|
||||
},
|
||||
Some(mut iter) => {
|
||||
if let item @ Some(_) = iter.next() {
|
||||
self.iter = Some(iter);
|
||||
return Ok(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, R> Iterator for LocationRangeIter<'ctx, R>
|
||||
where
|
||||
R: gimli::Reader + 'ctx,
|
||||
{
|
||||
type Item = (u64, u64, Location<'ctx>);
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.next_loc().unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "fallible-iterator")]
|
||||
impl<'ctx, R> fallible_iterator::FallibleIterator for LocationRangeIter<'ctx, R>
|
||||
where
|
||||
R: gimli::Reader + 'ctx,
|
||||
{
|
||||
type Item = (u64, u64, Location<'ctx>);
|
||||
type Error = Error;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> {
|
||||
self.next_loc()
|
||||
}
|
||||
}
|
||||
1
.gear/predownloaded-development/vendor/adler2/.cargo-checksum.json
vendored
Normal file
1
.gear/predownloaded-development/vendor/adler2/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{".cargo_vcs_info.json":"08071a308400282ad18ca2de0df6d1f2dc270475f69aa483740ce311af3f63e0","CHANGELOG.md":"04fa29ec6eb6b05b706247ecac2cbc7075792dbfcea0bf52715782cf42132e94","Cargo.lock":"3e44ced212a9e7ddc0a5450bcebb48ec67f32a058529856458efa36415554e53","Cargo.toml":"8f30dbd092f3acc475b9d339736cd7b64c6489bc47cd234a7f2232fc52e2d490","Cargo.toml.orig":"077df9094ac86443a4d05305f74782bd237c1f15fa39640463e4c62e9e4a310a","LICENSE-0BSD":"861399f8c21c042b110517e76dc6b63a2b334276c8cf17412fc3c8908ca8dc17","LICENSE-APACHE":"8ada45cd9f843acf64e4722ae262c622a2b3b3007c7310ef36ac1061a30f6adb","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"cd955d5d6a49161e6f7a04df4a5963581b66ed43fd5096b2dedca8e295efe4f9","RELEASE_PROCESS.md":"a86cd10fc70f167f8d00e9e4ce0c6b4ebdfa1865058390dffd1e0ad4d3e68d9d","benches/bench.rs":"d67bef1c7f36ed300a8fbcf9d50b9dfdead1fd340bf87a4d47d99a0c1c042c04","src/algo.rs":"932c2bc591d13fe4470185125617b5aaa660a3898f23b553acc85df0bf49dded","src/lib.rs":"4acd41668fe30daffa37084e7e223f268957b816afc1864ffb3f5d6d7adf0890"},"package":"320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"}
|
||||
6
.gear/predownloaded-development/vendor/adler2/.cargo_vcs_info.json
vendored
Normal file
6
.gear/predownloaded-development/vendor/adler2/.cargo_vcs_info.json
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"git": {
|
||||
"sha1": "89a031a0f42eeff31c70dc598b398cbf31f1680f"
|
||||
},
|
||||
"path_in_vcs": ""
|
||||
}
|
||||
84
.gear/predownloaded-development/vendor/adler2/CHANGELOG.md
vendored
Normal file
84
.gear/predownloaded-development/vendor/adler2/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
---
|
||||
## [2.0.1](https://github.com/Frommi/miniz_oxide/compare/2.0.0..2.0.1) - 2025-06-09
|
||||
|
||||
### Other
|
||||
|
||||
- Remove `compiler-builtins` from `rustc-dep-of-std` dependencies - ([7cdbd39](https://github.com/Frommi/miniz_oxide/commit/7cdbd3925a7f61cc075f44367b5d383861571b0a)) - Trevor Gross
|
||||
|
||||
---
|
||||
## [2.0.0](https://github.com/Frommi/miniz_oxide/compare/1.0.2..2.0.0) - 2024-08-04
|
||||
|
||||
First release of adler2 - fork of adler crate as the original is unmaintained and archived
|
||||
|
||||
##### Changes since last version of Adler:
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **(core)** change to rust 2021 edition, update repository info and links, update author info - ([867b115](https://github.com/Frommi/miniz_oxide/commit/867b115bad79bf62098f2acccc81bf53ec5a125d)) - oyvindln
|
||||
- **(core)** simplify some code and fix benches - ([128fb9c](https://github.com/Frommi/miniz_oxide/commit/128fb9cb6cad5c3a54fb0b6c68549d80b79a1fe0)) - oyvindln
|
||||
|
||||
### Changelog of original adler crate
|
||||
|
||||
---
|
||||
|
||||
## [1.0.2 - 2021-02-26](https://github.com/jonas-schievink/adler/releases/tag/v1.0.2)
|
||||
|
||||
- Fix doctest on big-endian systems ([#9]).
|
||||
|
||||
[#9]: https://github.com/jonas-schievink/adler/pull/9
|
||||
|
||||
## [1.0.1 - 2020-11-08](https://github.com/jonas-schievink/adler/releases/tag/v1.0.1)
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fix documentation on docs.rs.
|
||||
|
||||
## [1.0.0 - 2020-11-08](https://github.com/jonas-schievink/adler/releases/tag/v1.0.0)
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fix `cargo test --no-default-features` ([#5]).
|
||||
|
||||
### Improvements
|
||||
|
||||
- Extended and clarified documentation.
|
||||
- Added more rustdoc examples.
|
||||
- Extended CI to test the crate with `--no-default-features`.
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- `adler32_reader` now takes its generic argument by value instead of as a `&mut`.
|
||||
- Renamed `adler32_reader` to `adler32`.
|
||||
|
||||
## [0.2.3 - 2020-07-11](https://github.com/jonas-schievink/adler/releases/tag/v0.2.3)
|
||||
|
||||
- Process 4 Bytes at a time, improving performance by up to 50% ([#2]).
|
||||
|
||||
## [0.2.2 - 2020-06-27](https://github.com/jonas-schievink/adler/releases/tag/v0.2.2)
|
||||
|
||||
- Bump MSRV to 1.31.0.
|
||||
|
||||
## [0.2.1 - 2020-06-27](https://github.com/jonas-schievink/adler/releases/tag/v0.2.1)
|
||||
|
||||
- Add a few `#[inline]` annotations to small functions.
|
||||
- Fix CI badge.
|
||||
- Allow integration into libstd.
|
||||
|
||||
## [0.2.0 - 2020-06-27](https://github.com/jonas-schievink/adler/releases/tag/v0.2.0)
|
||||
|
||||
- Support `#![no_std]` when using `default-features = false`.
|
||||
- Improve performance by around 7x.
|
||||
- Support Rust 1.8.0.
|
||||
- Improve API naming.
|
||||
|
||||
## [0.1.0 - 2020-06-26](https://github.com/jonas-schievink/adler/releases/tag/v0.1.0)
|
||||
|
||||
Initial release.
|
||||
|
||||
|
||||
[#2]: https://github.com/jonas-schievink/adler/pull/2
|
||||
[#5]: https://github.com/jonas-schievink/adler/pull/5
|
||||
16
.gear/predownloaded-development/vendor/adler2/Cargo.lock
generated
vendored
Normal file
16
.gear/predownloaded-development/vendor/adler2/Cargo.lock
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-std-workspace-core"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c"
|
||||
91
.gear/predownloaded-development/vendor/adler2/Cargo.toml
vendored
Normal file
91
.gear/predownloaded-development/vendor/adler2/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
authors = [
|
||||
"Jonas Schievink <jonasschievink@gmail.com>",
|
||||
"oyvindln <oyvindln@users.noreply.github.com>",
|
||||
]
|
||||
build = false
|
||||
exclude = [".*"]
|
||||
autolib = false
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
description = "A simple clean-room implementation of the Adler-32 checksum"
|
||||
documentation = "https://docs.rs/adler2/"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"checksum",
|
||||
"integrity",
|
||||
"hash",
|
||||
"adler32",
|
||||
"zlib",
|
||||
]
|
||||
categories = ["algorithms"]
|
||||
license = "0BSD OR MIT OR Apache-2.0"
|
||||
repository = "https://github.com/oyvindln/adler2"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--cfg=docsrs"]
|
||||
|
||||
[package.metadata.release]
|
||||
no-dev-version = true
|
||||
pre-release-commit-message = "Release {{version}}"
|
||||
tag-message = "{{version}}"
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "CHANGELOG.md"
|
||||
replace = """
|
||||
## Unreleased
|
||||
|
||||
No changes.
|
||||
|
||||
## [{{version}} - {{date}}](https://github.com/jonas-schievink/adler/releases/tag/v{{version}})
|
||||
"""
|
||||
search = """
|
||||
## Unreleased
|
||||
"""
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "README.md"
|
||||
replace = 'adler = "{{version}}"'
|
||||
search = 'adler = "[a-z0-9\\.-]+"'
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "src/lib.rs"
|
||||
replace = "https://docs.rs/adler/{{version}}"
|
||||
search = 'https://docs.rs/adler/[a-z0-9\.-]+'
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
rustc-dep-of-std = ["core"]
|
||||
std = []
|
||||
|
||||
[lib]
|
||||
name = "adler2"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[bench]]
|
||||
name = "bench"
|
||||
path = "benches/bench.rs"
|
||||
harness = false
|
||||
|
||||
[dependencies.core]
|
||||
version = "1.0.0"
|
||||
optional = true
|
||||
package = "rustc-std-workspace-core"
|
||||
|
||||
[dev-dependencies]
|
||||
71
.gear/predownloaded-development/vendor/adler2/Cargo.toml.orig
generated
vendored
Normal file
71
.gear/predownloaded-development/vendor/adler2/Cargo.toml.orig
generated
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
[package]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
authors = ["Jonas Schievink <jonasschievink@gmail.com>", "oyvindln <oyvindln@users.noreply.github.com>"]
|
||||
description = "A simple clean-room implementation of the Adler-32 checksum"
|
||||
documentation = "https://docs.rs/adler2/"
|
||||
repository = "https://github.com/oyvindln/adler2"
|
||||
keywords = ["checksum", "integrity", "hash", "adler32", "zlib"]
|
||||
categories = ["algorithms"]
|
||||
readme = "README.md"
|
||||
license = "0BSD OR MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
exclude = [".*"]
|
||||
|
||||
[[bench]]
|
||||
name = "bench"
|
||||
harness = false
|
||||
|
||||
[dependencies]
|
||||
# Internal features, only used when building as part of libstd, not part of the
|
||||
# stable interface of this crate.
|
||||
core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' }
|
||||
|
||||
[dev-dependencies]
|
||||
## Messes with minimum rust version and drags in deps just for running tests
|
||||
## so just comment out for now and enable manually when needed for enabling benches
|
||||
## criterion = "0.3.2"
|
||||
|
||||
[features]
|
||||
# Disable default features to enable `#![no_std]` support.
|
||||
default = ["std"]
|
||||
std = []
|
||||
|
||||
# Internal feature, only used when building as part of libstd, not part of the
|
||||
# stable interface of this crate.
|
||||
rustc-dep-of-std = ['core']
|
||||
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = [ "--cfg=docsrs" ]
|
||||
|
||||
# cargo-release configuration
|
||||
[package.metadata.release]
|
||||
tag-message = "{{version}}"
|
||||
no-dev-version = true
|
||||
pre-release-commit-message = "Release {{version}}"
|
||||
|
||||
# Change the changelog's `Unreleased` section to refer to this release and
|
||||
# prepend a new `Unreleased` section
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "CHANGELOG.md"
|
||||
search = "## Unreleased\n"
|
||||
replace = """
|
||||
## Unreleased
|
||||
|
||||
No changes.
|
||||
|
||||
## [{{version}} - {{date}}](https://github.com/jonas-schievink/adler/releases/tag/v{{version}})
|
||||
"""
|
||||
|
||||
# Bump the version inside the example manifest in `README.md`
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "README.md"
|
||||
search = 'adler = "[a-z0-9\\.-]+"'
|
||||
replace = 'adler = "{{version}}"'
|
||||
|
||||
# Bump the version referenced by the `html_root_url` attribute in `lib.rs`
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "src/lib.rs"
|
||||
search = "https://docs.rs/adler/[a-z0-9\\.-]+"
|
||||
replace = "https://docs.rs/adler/{{version}}"
|
||||
12
.gear/predownloaded-development/vendor/adler2/LICENSE-0BSD
vendored
Normal file
12
.gear/predownloaded-development/vendor/adler2/LICENSE-0BSD
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
Copyright (C) Jonas Schievink <jonasschievink@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for
|
||||
any purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
201
.gear/predownloaded-development/vendor/adler2/LICENSE-APACHE
vendored
Normal file
201
.gear/predownloaded-development/vendor/adler2/LICENSE-APACHE
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
23
.gear/predownloaded-development/vendor/adler2/LICENSE-MIT
vendored
Normal file
23
.gear/predownloaded-development/vendor/adler2/LICENSE-MIT
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
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.
|
||||
46
.gear/predownloaded-development/vendor/adler2/README.md
vendored
Normal file
46
.gear/predownloaded-development/vendor/adler2/README.md
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# Adler-32 checksums for Rust
|
||||
|
||||
This is a fork of the adler crate as the [original](https://github.com/jonas-schievink/adler) has been archived and is no longer updated by it's author
|
||||
|
||||
[](https://crates.io/crates/adler)
|
||||
[](https://docs.rs/adler/)
|
||||

|
||||
|
||||
This crate provides a simple implementation of the Adler-32 checksum, used in
|
||||
the zlib compression format.
|
||||
|
||||
Please refer to the [changelog](CHANGELOG.md) to see what changed in the last
|
||||
releases.
|
||||
|
||||
## Features
|
||||
|
||||
- Permissively licensed (0BSD) clean-room implementation.
|
||||
- Zero dependencies.
|
||||
- Zero `unsafe`.
|
||||
- Decent performance (3-4 GB/s) (see note).
|
||||
- Supports `#![no_std]` (with `default-features = false`).
|
||||
|
||||
## Usage
|
||||
|
||||
Add an entry to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
adler2 = "2.0.0"
|
||||
```
|
||||
|
||||
Check the [API Documentation](https://docs.rs/adler/) for how to use the
|
||||
crate's functionality.
|
||||
|
||||
## Rust version support
|
||||
|
||||
Currently, this crate supports all Rust versions starting at Rust 1.56.0.
|
||||
|
||||
Bumping the Minimum Supported Rust Version (MSRV) is *not* considered a breaking
|
||||
change, but will not be done without good reasons. The latest 3 stable Rust
|
||||
versions will always be supported no matter what.
|
||||
|
||||
## Performance
|
||||
|
||||
Due to the way the algorithm works this crate and the fact that it's not possible to use explicit simd in safe rust currently, this crate benefits drastically from being compiled with newer cpu instructions enabled (using e.g ```RUSTFLAGS=-C target-feature'+sse4.1``` or ```-C target-cpu=x86-64-v2```/```-C target-cpu=x86-64-v3``` arguments depending on what cpu support is being targeted.)
|
||||
Judging by the crate benchmarks, on a Ryzen 5600, compiling with SSE 4.1 (enabled in x86-64-v2 feature level) enabled can give a ~50-150% speedup, enabling the LZCNT instruction (enabled in x86-64-v3 feature level) can give a further ~50% speedup,
|
||||
13
.gear/predownloaded-development/vendor/adler2/RELEASE_PROCESS.md
vendored
Normal file
13
.gear/predownloaded-development/vendor/adler2/RELEASE_PROCESS.md
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# What to do to publish a new release
|
||||
|
||||
1. Ensure all notable changes are in the changelog under "Unreleased".
|
||||
|
||||
2. Execute `cargo release <level>` to bump version(s), tag and publish
|
||||
everything. External subcommand, must be installed with `cargo install
|
||||
cargo-release`.
|
||||
|
||||
`<level>` can be one of `major|minor|patch`. If this is the first release
|
||||
(`0.1.0`), use `minor`, since the version starts out as `0.0.0`.
|
||||
|
||||
3. Go to the GitHub releases, edit the just-pushed tag. Copy the release notes
|
||||
from the changelog.
|
||||
109
.gear/predownloaded-development/vendor/adler2/benches/bench.rs
vendored
Normal file
109
.gear/predownloaded-development/vendor/adler2/benches/bench.rs
vendored
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
extern crate adler2;
|
||||
extern crate criterion;
|
||||
|
||||
use adler2::{adler32_slice, Adler32};
|
||||
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
|
||||
|
||||
fn simple(c: &mut Criterion) {
|
||||
{
|
||||
const SIZE: usize = 100;
|
||||
|
||||
let mut group = c.benchmark_group("simple-100b");
|
||||
group.throughput(Throughput::Bytes(SIZE as u64));
|
||||
group.bench_function("zeroes-100", |bencher| {
|
||||
bencher.iter(|| {
|
||||
adler32_slice(&[0; SIZE]);
|
||||
});
|
||||
});
|
||||
group.bench_function("ones-100", |bencher| {
|
||||
bencher.iter(|| {
|
||||
adler32_slice(&[0xff; SIZE]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
const SIZE: usize = 1024;
|
||||
|
||||
let mut group = c.benchmark_group("simple-1k");
|
||||
group.throughput(Throughput::Bytes(SIZE as u64));
|
||||
|
||||
group.bench_function("zeroes-1k", |bencher| {
|
||||
bencher.iter(|| {
|
||||
adler32_slice(&[0; SIZE]);
|
||||
});
|
||||
});
|
||||
|
||||
group.bench_function("ones-1k", |bencher| {
|
||||
bencher.iter(|| {
|
||||
adler32_slice(&[0xff; SIZE]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
const SIZE: usize = 1024 * 1024;
|
||||
|
||||
let mut group = c.benchmark_group("simple-1m");
|
||||
group.throughput(Throughput::Bytes(SIZE as u64));
|
||||
group.bench_function("zeroes-1m", |bencher| {
|
||||
bencher.iter(|| {
|
||||
adler32_slice(&[0; SIZE]);
|
||||
});
|
||||
});
|
||||
|
||||
group.bench_function("ones-1m", |bencher| {
|
||||
bencher.iter(|| {
|
||||
adler32_slice(&[0xff; SIZE]);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn chunked(c: &mut Criterion) {
|
||||
const SIZE: usize = 16 * 1024 * 1024;
|
||||
|
||||
let data = vec![0xAB; SIZE];
|
||||
|
||||
let mut group = c.benchmark_group("chunked-16m");
|
||||
group.throughput(Throughput::Bytes(SIZE as u64));
|
||||
group.bench_function("5552", |bencher| {
|
||||
bencher.iter(|| {
|
||||
let mut h = Adler32::new();
|
||||
for chunk in data.chunks(5552) {
|
||||
h.write_slice(chunk);
|
||||
}
|
||||
h.checksum()
|
||||
});
|
||||
});
|
||||
group.bench_function("8k", |bencher| {
|
||||
bencher.iter(|| {
|
||||
let mut h = Adler32::new();
|
||||
for chunk in data.chunks(8 * 1024) {
|
||||
h.write_slice(chunk);
|
||||
}
|
||||
h.checksum()
|
||||
});
|
||||
});
|
||||
group.bench_function("64k", |bencher| {
|
||||
bencher.iter(|| {
|
||||
let mut h = Adler32::new();
|
||||
for chunk in data.chunks(64 * 1024) {
|
||||
h.write_slice(chunk);
|
||||
}
|
||||
h.checksum()
|
||||
});
|
||||
});
|
||||
group.bench_function("1m", |bencher| {
|
||||
bencher.iter(|| {
|
||||
let mut h = Adler32::new();
|
||||
for chunk in data.chunks(1024 * 1024) {
|
||||
h.write_slice(chunk);
|
||||
}
|
||||
h.checksum()
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, simple, chunked);
|
||||
criterion_main!(benches);
|
||||
155
.gear/predownloaded-development/vendor/adler2/src/algo.rs
vendored
Normal file
155
.gear/predownloaded-development/vendor/adler2/src/algo.rs
vendored
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
use crate::Adler32;
|
||||
use std::ops::{AddAssign, MulAssign, RemAssign};
|
||||
|
||||
impl Adler32 {
|
||||
pub(crate) fn compute(&mut self, bytes: &[u8]) {
|
||||
// The basic algorithm is, for every byte:
|
||||
// a = (a + byte) % MOD
|
||||
// b = (b + a) % MOD
|
||||
// where MOD = 65521.
|
||||
//
|
||||
// For efficiency, we can defer the `% MOD` operations as long as neither a nor b overflows:
|
||||
// - Between calls to `write`, we ensure that a and b are always in range 0..MOD.
|
||||
// - We use 32-bit arithmetic in this function.
|
||||
// - Therefore, a and b must not increase by more than 2^32-MOD without performing a `% MOD`
|
||||
// operation.
|
||||
//
|
||||
// According to Wikipedia, b is calculated as follows for non-incremental checksumming:
|
||||
// b = n×D1 + (n−1)×D2 + (n−2)×D3 + ... + Dn + n*1 (mod 65521)
|
||||
// Where n is the number of bytes and Di is the i-th Byte. We need to change this to account
|
||||
// for the previous values of a and b, as well as treat every input Byte as being 255:
|
||||
// b_inc = n×255 + (n-1)×255 + ... + 255 + n*65520
|
||||
// Or in other words:
|
||||
// b_inc = n*65520 + n(n+1)/2*255
|
||||
// The max chunk size is thus the largest value of n so that b_inc <= 2^32-65521.
|
||||
// 2^32-65521 = n*65520 + n(n+1)/2*255
|
||||
// Plugging this into an equation solver since I can't math gives n = 5552.18..., so 5552.
|
||||
//
|
||||
// On top of the optimization outlined above, the algorithm can also be parallelized with a
|
||||
// bit more work:
|
||||
//
|
||||
// Note that b is a linear combination of a vector of input bytes (D1, ..., Dn).
|
||||
//
|
||||
// If we fix some value k<N and rewrite indices 1, ..., N as
|
||||
//
|
||||
// 1_1, 1_2, ..., 1_k, 2_1, ..., 2_k, ..., (N/k)_k,
|
||||
//
|
||||
// then we can express a and b in terms of sums of smaller sequences kb and ka:
|
||||
//
|
||||
// ka(j) := D1_j + D2_j + ... + D(N/k)_j where j <= k
|
||||
// kb(j) := (N/k)*D1_j + (N/k-1)*D2_j + ... + D(N/k)_j where j <= k
|
||||
//
|
||||
// a = ka(1) + ka(2) + ... + ka(k) + 1
|
||||
// b = k*(kb(1) + kb(2) + ... + kb(k)) - 1*ka(2) - ... - (k-1)*ka(k) + N
|
||||
//
|
||||
// We use this insight to unroll the main loop and process k=4 bytes at a time.
|
||||
// The resulting code is highly amenable to SIMD acceleration, although the immediate speedups
|
||||
// stem from increased pipeline parallelism rather than auto-vectorization.
|
||||
//
|
||||
// This technique is described in-depth (here:)[https://software.intel.com/content/www/us/\
|
||||
// en/develop/articles/fast-computation-of-fletcher-checksums.html]
|
||||
|
||||
const MOD: u32 = 65521;
|
||||
const CHUNK_SIZE: usize = 5552 * 4;
|
||||
|
||||
let mut a = u32::from(self.a);
|
||||
let mut b = u32::from(self.b);
|
||||
let mut a_vec = U32X4([0; 4]);
|
||||
let mut b_vec = a_vec;
|
||||
|
||||
let (bytes, remainder) = bytes.split_at(bytes.len() - bytes.len() % 4);
|
||||
|
||||
// iterate over 4 bytes at a time
|
||||
let chunk_iter = bytes.chunks_exact(CHUNK_SIZE);
|
||||
let remainder_chunk = chunk_iter.remainder();
|
||||
for chunk in chunk_iter {
|
||||
for byte_vec in chunk.chunks_exact(4) {
|
||||
let val = U32X4::from(byte_vec);
|
||||
a_vec += val;
|
||||
b_vec += a_vec;
|
||||
}
|
||||
|
||||
b += CHUNK_SIZE as u32 * a;
|
||||
a_vec %= MOD;
|
||||
b_vec %= MOD;
|
||||
b %= MOD;
|
||||
}
|
||||
// special-case the final chunk because it may be shorter than the rest
|
||||
for byte_vec in remainder_chunk.chunks_exact(4) {
|
||||
let val = U32X4::from(byte_vec);
|
||||
a_vec += val;
|
||||
b_vec += a_vec;
|
||||
}
|
||||
b += remainder_chunk.len() as u32 * a;
|
||||
a_vec %= MOD;
|
||||
b_vec %= MOD;
|
||||
b %= MOD;
|
||||
|
||||
// combine the sub-sum results into the main sum
|
||||
b_vec *= 4;
|
||||
b_vec.0[1] += MOD - a_vec.0[1];
|
||||
b_vec.0[2] += (MOD - a_vec.0[2]) * 2;
|
||||
b_vec.0[3] += (MOD - a_vec.0[3]) * 3;
|
||||
for &av in a_vec.0.iter() {
|
||||
a += av;
|
||||
}
|
||||
for &bv in b_vec.0.iter() {
|
||||
b += bv;
|
||||
}
|
||||
|
||||
// iterate over the remaining few bytes in serial
|
||||
for &byte in remainder.iter() {
|
||||
a += u32::from(byte);
|
||||
b += a;
|
||||
}
|
||||
|
||||
self.a = (a % MOD) as u16;
|
||||
self.b = (b % MOD) as u16;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct U32X4([u32; 4]);
|
||||
|
||||
impl U32X4 {
|
||||
#[inline]
|
||||
fn from(bytes: &[u8]) -> Self {
|
||||
U32X4([
|
||||
u32::from(bytes[0]),
|
||||
u32::from(bytes[1]),
|
||||
u32::from(bytes[2]),
|
||||
u32::from(bytes[3]),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<Self> for U32X4 {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, other: Self) {
|
||||
// Implement this in a primitive manner to help out the compiler a bit.
|
||||
self.0[0] += other.0[0];
|
||||
self.0[1] += other.0[1];
|
||||
self.0[2] += other.0[2];
|
||||
self.0[3] += other.0[3];
|
||||
}
|
||||
}
|
||||
|
||||
impl RemAssign<u32> for U32X4 {
|
||||
#[inline]
|
||||
fn rem_assign(&mut self, quotient: u32) {
|
||||
self.0[0] %= quotient;
|
||||
self.0[1] %= quotient;
|
||||
self.0[2] %= quotient;
|
||||
self.0[3] %= quotient;
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign<u32> for U32X4 {
|
||||
#[inline]
|
||||
fn mul_assign(&mut self, rhs: u32) {
|
||||
self.0[0] *= rhs;
|
||||
self.0[1] *= rhs;
|
||||
self.0[2] *= rhs;
|
||||
self.0[3] *= rhs;
|
||||
}
|
||||
}
|
||||
287
.gear/predownloaded-development/vendor/adler2/src/lib.rs
vendored
Normal file
287
.gear/predownloaded-development/vendor/adler2/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
//! Adler-32 checksum implementation.
|
||||
//!
|
||||
//! This implementation features:
|
||||
//!
|
||||
//! - Permissively licensed (0BSD) clean-room implementation.
|
||||
//! - Zero dependencies.
|
||||
//! - Zero `unsafe`.
|
||||
//! - Decent performance (3-4 GB/s).
|
||||
//! - `#![no_std]` support (with `default-features = false`).
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/adler2/2.0.0")]
|
||||
// Deny a few warnings in doctests, since rustdoc `allow`s many warnings by default
|
||||
#![doc(test(attr(deny(unused_imports, unused_must_use))))]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![warn(missing_debug_implementations)]
|
||||
#![forbid(unsafe_code)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
extern crate core as std;
|
||||
|
||||
mod algo;
|
||||
|
||||
use std::hash::Hasher;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::io::{self, BufRead};
|
||||
|
||||
/// Adler-32 checksum calculator.
|
||||
///
|
||||
/// An instance of this type is equivalent to an Adler-32 checksum: It can be created in the default
|
||||
/// state via [`new`] (or the provided `Default` impl), or from a precalculated checksum via
|
||||
/// [`from_checksum`], and the currently stored checksum can be fetched via [`checksum`].
|
||||
///
|
||||
/// This type also implements `Hasher`, which makes it easy to calculate Adler-32 checksums of any
|
||||
/// type that implements or derives `Hash`. This also allows using Adler-32 in a `HashMap`, although
|
||||
/// that is not recommended (while every checksum is a hash function, they are not necessarily a
|
||||
/// good one).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic, piecewise checksum calculation:
|
||||
///
|
||||
/// ```
|
||||
/// use adler2::Adler32;
|
||||
///
|
||||
/// let mut adler = Adler32::new();
|
||||
///
|
||||
/// adler.write_slice(&[0, 1, 2]);
|
||||
/// adler.write_slice(&[3, 4, 5]);
|
||||
///
|
||||
/// assert_eq!(adler.checksum(), 0x00290010);
|
||||
/// ```
|
||||
///
|
||||
/// Using `Hash` to process structures:
|
||||
///
|
||||
/// ```
|
||||
/// use std::hash::Hash;
|
||||
/// use adler2::Adler32;
|
||||
///
|
||||
/// #[derive(Hash)]
|
||||
/// struct Data {
|
||||
/// byte: u8,
|
||||
/// word: u16,
|
||||
/// big: u64,
|
||||
/// }
|
||||
///
|
||||
/// let mut adler = Adler32::new();
|
||||
///
|
||||
/// let data = Data { byte: 0x1F, word: 0xABCD, big: !0 };
|
||||
/// data.hash(&mut adler);
|
||||
///
|
||||
/// // hash value depends on architecture endianness
|
||||
/// if cfg!(target_endian = "little") {
|
||||
/// assert_eq!(adler.checksum(), 0x33410990);
|
||||
/// }
|
||||
/// if cfg!(target_endian = "big") {
|
||||
/// assert_eq!(adler.checksum(), 0x331F0990);
|
||||
/// }
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// [`new`]: #method.new
|
||||
/// [`from_checksum`]: #method.from_checksum
|
||||
/// [`checksum`]: #method.checksum
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Adler32 {
|
||||
a: u16,
|
||||
b: u16,
|
||||
}
|
||||
|
||||
impl Adler32 {
|
||||
/// Creates a new Adler-32 instance with default state.
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Creates an `Adler32` instance from a precomputed Adler-32 checksum.
|
||||
///
|
||||
/// This allows resuming checksum calculation without having to keep the `Adler32` instance
|
||||
/// around.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use adler2::Adler32;
|
||||
/// let parts = [
|
||||
/// "rust",
|
||||
/// "acean",
|
||||
/// ];
|
||||
/// let whole = adler2::adler32_slice(b"rustacean");
|
||||
///
|
||||
/// let mut sum = Adler32::new();
|
||||
/// sum.write_slice(parts[0].as_bytes());
|
||||
/// let partial = sum.checksum();
|
||||
///
|
||||
/// // ...later
|
||||
///
|
||||
/// let mut sum = Adler32::from_checksum(partial);
|
||||
/// sum.write_slice(parts[1].as_bytes());
|
||||
/// assert_eq!(sum.checksum(), whole);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub const fn from_checksum(sum: u32) -> Self {
|
||||
Adler32 {
|
||||
a: sum as u16,
|
||||
b: (sum >> 16) as u16,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the calculated checksum at this point in time.
|
||||
#[inline]
|
||||
pub fn checksum(&self) -> u32 {
|
||||
(u32::from(self.b) << 16) | u32::from(self.a)
|
||||
}
|
||||
|
||||
/// Adds `bytes` to the checksum calculation.
|
||||
///
|
||||
/// If efficiency matters, this should be called with Byte slices that contain at least a few
|
||||
/// thousand Bytes.
|
||||
pub fn write_slice(&mut self, bytes: &[u8]) {
|
||||
self.compute(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Adler32 {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Adler32 { a: 1, b: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Hasher for Adler32 {
|
||||
#[inline]
|
||||
fn finish(&self) -> u64 {
|
||||
u64::from(self.checksum())
|
||||
}
|
||||
|
||||
fn write(&mut self, bytes: &[u8]) {
|
||||
self.write_slice(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the Adler-32 checksum of a byte slice.
|
||||
///
|
||||
/// This is a convenience function around the [`Adler32`] type.
|
||||
///
|
||||
/// [`Adler32`]: struct.Adler32.html
|
||||
pub fn adler32_slice(data: &[u8]) -> u32 {
|
||||
let mut h = Adler32::new();
|
||||
h.write_slice(data);
|
||||
h.checksum()
|
||||
}
|
||||
|
||||
/// Calculates the Adler-32 checksum of a `BufRead`'s contents.
|
||||
///
|
||||
/// The passed `BufRead` implementor will be read until it reaches EOF (or until it reports an
|
||||
/// error).
|
||||
///
|
||||
/// If you only have a `Read` implementor, you can wrap it in `std::io::BufReader` before calling
|
||||
/// this function.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Any error returned by the reader are bubbled up by this function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// use adler2::adler32;
|
||||
///
|
||||
/// use std::fs::File;
|
||||
/// use std::io::BufReader;
|
||||
///
|
||||
/// let file = File::open("input.txt")?;
|
||||
/// let mut file = BufReader::new(file);
|
||||
///
|
||||
/// adler32(&mut file)?;
|
||||
/// # Ok(()) }
|
||||
/// # fn main() { run().unwrap() }
|
||||
/// ```
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
pub fn adler32<R: BufRead>(mut reader: R) -> io::Result<u32> {
|
||||
let mut h = Adler32::new();
|
||||
loop {
|
||||
let len = {
|
||||
let buf = reader.fill_buf()?;
|
||||
if buf.is_empty() {
|
||||
return Ok(h.checksum());
|
||||
}
|
||||
|
||||
h.write_slice(buf);
|
||||
buf.len()
|
||||
};
|
||||
reader.consume(len);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn zeroes() {
|
||||
assert_eq!(adler32_slice(&[]), 1);
|
||||
assert_eq!(adler32_slice(&[0]), 1 | 1 << 16);
|
||||
assert_eq!(adler32_slice(&[0, 0]), 1 | 2 << 16);
|
||||
assert_eq!(adler32_slice(&[0; 100]), 0x00640001);
|
||||
assert_eq!(adler32_slice(&[0; 1024]), 0x04000001);
|
||||
assert_eq!(adler32_slice(&[0; 1024 * 1024]), 0x00f00001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ones() {
|
||||
assert_eq!(adler32_slice(&[0xff; 1024]), 0x79a6fc2e);
|
||||
assert_eq!(adler32_slice(&[0xff; 1024 * 1024]), 0x8e88ef11);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mixed() {
|
||||
assert_eq!(adler32_slice(&[1]), 2 | 2 << 16);
|
||||
assert_eq!(adler32_slice(&[40]), 41 | 41 << 16);
|
||||
|
||||
assert_eq!(adler32_slice(&[0xA5; 1024 * 1024]), 0xd5009ab1);
|
||||
}
|
||||
|
||||
/// Example calculation from https://en.wikipedia.org/wiki/Adler-32.
|
||||
#[test]
|
||||
fn wiki() {
|
||||
assert_eq!(adler32_slice(b"Wikipedia"), 0x11E60398);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resume() {
|
||||
let mut adler = Adler32::new();
|
||||
adler.write_slice(&[0xff; 1024]);
|
||||
let partial = adler.checksum();
|
||||
assert_eq!(partial, 0x79a6fc2e); // from above
|
||||
adler.write_slice(&[0xff; 1024 * 1024 - 1024]);
|
||||
assert_eq!(adler.checksum(), 0x8e88ef11); // from above
|
||||
|
||||
// Make sure that we can resume computing from the partial checksum via `from_checksum`.
|
||||
let mut adler = Adler32::from_checksum(partial);
|
||||
adler.write_slice(&[0xff; 1024 * 1024 - 1024]);
|
||||
assert_eq!(adler.checksum(), 0x8e88ef11); // from above
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn bufread() {
|
||||
use std::io::BufReader;
|
||||
fn test(data: &[u8], checksum: u32) {
|
||||
// `BufReader` uses an 8 KB buffer, so this will test buffer refilling.
|
||||
let mut buf = BufReader::new(data);
|
||||
let real_sum = adler32(&mut buf).unwrap();
|
||||
assert_eq!(checksum, real_sum);
|
||||
}
|
||||
|
||||
test(&[], 1);
|
||||
test(&[0; 1024], 0x04000001);
|
||||
test(&[0; 1024 * 1024], 0x00f00001);
|
||||
test(&[0xA5; 1024 * 1024], 0xd5009ab1);
|
||||
}
|
||||
}
|
||||
1
.gear/predownloaded-development/vendor/aead/.cargo-checksum.json
vendored
Normal file
1
.gear/predownloaded-development/vendor/aead/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{".cargo_vcs_info.json":"d25ef64c47aa2a16d9200724c0f56bddb4f5c24800986e070517867cfcdee0a4","CHANGELOG.md":"8870cb71cd8b46213591c7a4ee7ad80985600bd00c9f88331f825407498a00a7","Cargo.toml":"bf935971de51d6c168946e1822e1e4c3267aad0e1ae6e036b4e5baeb6d81a4be","Cargo.toml.orig":"c541eaa8f4355b379a5d3cf15e6ac710fde852fce72b5d5e9293f328d4f40622","LICENSE-APACHE":"b1cf9a3333ca78152b859012cd4a804156e5243e9ca20ad1df7327ba5ea7405c","LICENSE-MIT":"949ab7b3e7140fee216f06fe3a2bd67d68dd511f8ea73c1e01c98cb348e9c8ae","README.md":"8e195a2c3d0437b035de4640adabc6fb29ed91d814ec5073e7c2ae1a4d988748","src/dev.rs":"8a615fadb1236158cea9fde4ea96e8bb2ced4757c43b829c23eb143fc816d894","src/lib.rs":"477a851e2666a29dc3a724a75b7558d32d9ed7584364e1567dc6746c32a74fc5","src/stream.rs":"0b89b1e648972b2434cfed6556302f28ad2d8bdc11434f6905354167bf8a38e7"},"package":"d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"}
|
||||
6
.gear/predownloaded-development/vendor/aead/.cargo_vcs_info.json
vendored
Normal file
6
.gear/predownloaded-development/vendor/aead/.cargo_vcs_info.json
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"git": {
|
||||
"sha1": "1ae238c527c204dd9590e3abc406cfbb342d46ea"
|
||||
},
|
||||
"path_in_vcs": "aead"
|
||||
}
|
||||
106
.gear/predownloaded-development/vendor/aead/CHANGELOG.md
vendored
Normal file
106
.gear/predownloaded-development/vendor/aead/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.5.2 (2023-04-02)
|
||||
### Added
|
||||
- `arrayvec` feature ([#1219])
|
||||
|
||||
[#1219]: https://github.com/RustCrypto/traits/pull/1219
|
||||
|
||||
## 0.5.1 (2022-08-09)
|
||||
### Added
|
||||
- `AeadCore::generate_nonce` ([#1073])
|
||||
|
||||
[#1073]: https://github.com/RustCrypto/traits/pull/1073
|
||||
|
||||
## 0.5.0 (2022-07-23)
|
||||
### Added
|
||||
- Optional support for `BytesMut` as a `Buffer` ([#956])
|
||||
- `getrandom` feature ([#1042])
|
||||
|
||||
### Changed
|
||||
- Replace `NewAead` trait with `KeyInit` trait from `crypto-common` ([#1033])
|
||||
- Rust 2021 edition upgrade; MSRV 1.56+ ([#1044])
|
||||
|
||||
[#956]: https://github.com/RustCrypto/traits/pull/956
|
||||
[#1033]: https://github.com/RustCrypto/traits/pull/1033
|
||||
[#1042]: https://github.com/RustCrypto/traits/pull/1042
|
||||
[#1044]: https://github.com/RustCrypto/traits/pull/1044
|
||||
|
||||
## 0.4.3 (2021-08-29)
|
||||
### Added
|
||||
- `Result` type alias ([#725])
|
||||
|
||||
[#725]: https://github.com/RustCrypto/traits/pull/725
|
||||
|
||||
## 0.4.2 (2021-07-12)
|
||||
### Added
|
||||
- Re-export `rand_core` ([#682])
|
||||
|
||||
[#682]: https://github.com/RustCrypto/traits/pull/682
|
||||
|
||||
## 0.4.1 (2021-05-03)
|
||||
### Changed
|
||||
- Bump `heapless` dependency to v0.7 ([#628])
|
||||
|
||||
[#628]: https://github.com/RustCrypto/traits/pull/628
|
||||
|
||||
## 0.4.0 (2021-02-05) [YANKED]
|
||||
### Added
|
||||
- `stream` module ([#436], [#445], [#447])
|
||||
- `NewAead::generate_key` method gated under `rand_core` feature ([#513])
|
||||
|
||||
### Changed
|
||||
- Extract `AeadCore` trait ([#508])
|
||||
- Rename `NewAead::new_var` to `::new_from_slice` ([#512])
|
||||
- Disable alloc by default ([#514])
|
||||
- Bump `heapless` dependency to v0.6 ([#522])
|
||||
|
||||
[#436]: https://github.com/RustCrypto/traits/pull/436
|
||||
[#445]: https://github.com/RustCrypto/traits/pull/445
|
||||
[#447]: https://github.com/RustCrypto/traits/pull/447
|
||||
[#508]: https://github.com/RustCrypto/traits/pull/508
|
||||
[#512]: https://github.com/RustCrypto/traits/pull/512
|
||||
[#513]: https://github.com/RustCrypto/traits/pull/513
|
||||
[#514]: https://github.com/RustCrypto/traits/pull/514
|
||||
[#522]: https://github.com/RustCrypto/traits/pull/522
|
||||
|
||||
## 0.3.2 (2020-07-01)
|
||||
### Added
|
||||
- `dev` module ([#194])
|
||||
|
||||
[#194]: https://github.com/RustCrypto/traits/pull/194
|
||||
|
||||
## 0.3.1 (2020-06-12)
|
||||
### Added
|
||||
- `NewAead::new_varkey` method ([#191])
|
||||
|
||||
[#191]: https://github.com/RustCrypto/traits/pull/191
|
||||
|
||||
## 0.3.0 (2020-06-04)
|
||||
### Added
|
||||
- Type aliases for `Key`, `Nonce`, and `Tag` ([#125])
|
||||
- Optional `std` feature ([#63])
|
||||
|
||||
### Changed
|
||||
- `NewAead` now borrows the key ([#124])
|
||||
- Split `Aead`/`AeadMut` into `AeadInPlace`/`AeadMutInPlace` ([#120])
|
||||
- Bump `generic-array` dependency to v0.14 ([#95])
|
||||
|
||||
[#125]: https://github.com/RustCrypto/traits/pull/125
|
||||
[#124]: https://github.com/RustCrypto/traits/pull/124
|
||||
[#120]: https://github.com/RustCrypto/traits/pull/120
|
||||
[#95]: https://github.com/RustCrypto/traits/pull/95
|
||||
[#63]: https://github.com/RustCrypto/traits/pull/63
|
||||
|
||||
## 0.2.0 (2019-11-17)
|
||||
|
||||
## 0.1.2 (2019-11-17) [YANKED]
|
||||
|
||||
## 0.1.1 (2019-08-30)
|
||||
|
||||
## 0.1.0 (2019-08-29)
|
||||
81
.gear/predownloaded-development/vendor/aead/Cargo.toml
vendored
Normal file
81
.gear/predownloaded-development/vendor/aead/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
name = "aead"
|
||||
version = "0.5.2"
|
||||
authors = ["RustCrypto Developers"]
|
||||
description = """
|
||||
Traits for Authenticated Encryption with Associated Data (AEAD) algorithms,
|
||||
such as AES-GCM as ChaCha20Poly1305, which provide a high-level API
|
||||
"""
|
||||
documentation = "https://docs.rs/aead"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"crypto",
|
||||
"encryption",
|
||||
]
|
||||
categories = [
|
||||
"cryptography",
|
||||
"no-std",
|
||||
]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/RustCrypto/traits"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = [
|
||||
"--cfg",
|
||||
"docsrs",
|
||||
]
|
||||
|
||||
[dependencies.arrayvec]
|
||||
version = "0.7"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.blobby]
|
||||
version = "0.3"
|
||||
optional = true
|
||||
|
||||
[dependencies.bytes]
|
||||
version = "1"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.crypto-common]
|
||||
version = "0.1.4"
|
||||
|
||||
[dependencies.generic-array]
|
||||
version = "0.14"
|
||||
default-features = false
|
||||
|
||||
[dependencies.heapless]
|
||||
version = "0.7"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[features]
|
||||
alloc = []
|
||||
default = ["rand_core"]
|
||||
dev = ["blobby"]
|
||||
getrandom = [
|
||||
"crypto-common/getrandom",
|
||||
"rand_core",
|
||||
]
|
||||
rand_core = ["crypto-common/rand_core"]
|
||||
std = [
|
||||
"alloc",
|
||||
"crypto-common/std",
|
||||
]
|
||||
stream = []
|
||||
39
.gear/predownloaded-development/vendor/aead/Cargo.toml.orig
generated
vendored
Normal file
39
.gear/predownloaded-development/vendor/aead/Cargo.toml.orig
generated
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
[package]
|
||||
name = "aead"
|
||||
version = "0.5.2"
|
||||
description = """
|
||||
Traits for Authenticated Encryption with Associated Data (AEAD) algorithms,
|
||||
such as AES-GCM as ChaCha20Poly1305, which provide a high-level API
|
||||
"""
|
||||
authors = ["RustCrypto Developers"]
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
readme = "README.md"
|
||||
documentation = "https://docs.rs/aead"
|
||||
repository = "https://github.com/RustCrypto/traits"
|
||||
keywords = ["crypto", "encryption"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
rust-version = "1.56"
|
||||
|
||||
[dependencies]
|
||||
crypto-common = "0.1.4"
|
||||
generic-array = { version = "0.14", default-features = false }
|
||||
|
||||
# optional dependencies
|
||||
arrayvec = { version = "0.7", optional = true, default-features = false }
|
||||
blobby = { version = "0.3", optional = true }
|
||||
bytes = { version = "1", optional = true, default-features = false }
|
||||
heapless = { version = "0.7", optional = true, default-features = false }
|
||||
|
||||
[features]
|
||||
default = ["rand_core"]
|
||||
alloc = []
|
||||
std = ["alloc", "crypto-common/std"]
|
||||
dev = ["blobby"]
|
||||
getrandom = ["crypto-common/getrandom", "rand_core"]
|
||||
rand_core = ["crypto-common/rand_core"]
|
||||
stream = []
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
202
.gear/predownloaded-development/vendor/aead/LICENSE-APACHE
vendored
Normal file
202
.gear/predownloaded-development/vendor/aead/LICENSE-APACHE
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
26
.gear/predownloaded-development/vendor/aead/LICENSE-MIT
vendored
Normal file
26
.gear/predownloaded-development/vendor/aead/LICENSE-MIT
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
Copyright (c) 2019 The RustCrypto Project Developers
|
||||
Copyright (c) 2019 MobileCoin, LLC
|
||||
|
||||
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.
|
||||
65
.gear/predownloaded-development/vendor/aead/README.md
vendored
Normal file
65
.gear/predownloaded-development/vendor/aead/README.md
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# RustCrypto: Authenticated Encryption with Additional Data Traits
|
||||
|
||||
[![crate][crate-image]][crate-link]
|
||||
[![Docs][docs-image]][docs-link]
|
||||
![Apache2/MIT licensed][license-image]
|
||||
![Rust Version][rustc-image]
|
||||
[![Project Chat][chat-image]][chat-link]
|
||||
[![Build Status][build-image]][build-link]
|
||||
|
||||
This crate provides an abstract interface for [AEAD] ciphers, which guarantee
|
||||
both confidentiality and integrity, even from a powerful attacker who is
|
||||
able to execute [chosen-ciphertext attacks]. The resulting security property,
|
||||
[ciphertext indistinguishability], is considered a basic requirement for
|
||||
modern cryptographic implementations.
|
||||
|
||||
See [RustCrypto/AEADs] for cipher implementations which use this trait.
|
||||
|
||||
[Documentation][docs-link]
|
||||
|
||||
## Minimum Supported Rust Version
|
||||
|
||||
Rust **1.56** or higher.
|
||||
|
||||
Minimum supported Rust version can be changed in the future, but it will be
|
||||
done with a minor version bump.
|
||||
|
||||
## SemVer Policy
|
||||
|
||||
- All on-by-default features of this library are covered by SemVer
|
||||
- MSRV is considered exempt from SemVer as noted above
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of:
|
||||
|
||||
* [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* [MIT license](http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
||||
|
||||
[//]: # (badges)
|
||||
|
||||
[crate-image]: https://img.shields.io/crates/v/aead.svg
|
||||
[crate-link]: https://crates.io/crates/aead
|
||||
[docs-image]: https://docs.rs/aead/badge.svg
|
||||
[docs-link]: https://docs.rs/aead/
|
||||
[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
|
||||
[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg
|
||||
[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
|
||||
[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260038-AEADs
|
||||
[build-image]: https://github.com/RustCrypto/traits/workflows/aead/badge.svg?branch=master&event=push
|
||||
[build-link]: https://github.com/RustCrypto/traits/actions?query=workflow%3Aaead
|
||||
|
||||
[//]: # (general links)
|
||||
|
||||
[AEAD]: https://en.wikipedia.org/wiki/Authenticated_encryption
|
||||
[chosen-ciphertext attacks]: https://en.wikipedia.org/wiki/Chosen-ciphertext_attack
|
||||
[ciphertext indistinguishability]: https://en.wikipedia.org/wiki/Ciphertext_indistinguishability
|
||||
[RustCrypto/AEADs]: https://github.com/RustCrypto/AEADs
|
||||
78
.gear/predownloaded-development/vendor/aead/src/dev.rs
vendored
Normal file
78
.gear/predownloaded-development/vendor/aead/src/dev.rs
vendored
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
//! Development-related functionality
|
||||
pub use blobby;
|
||||
|
||||
/// Define AEAD test
|
||||
#[macro_export]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
|
||||
macro_rules! new_test {
|
||||
($name:ident, $test_name:expr, $cipher:ty $(,)?) => {
|
||||
#[test]
|
||||
fn $name() {
|
||||
use aead::{
|
||||
dev::blobby::Blob6Iterator,
|
||||
generic_array::{typenum::Unsigned, GenericArray},
|
||||
Aead, KeyInit, Payload,
|
||||
};
|
||||
|
||||
fn run_test(
|
||||
key: &[u8],
|
||||
nonce: &[u8],
|
||||
aad: &[u8],
|
||||
pt: &[u8],
|
||||
ct: &[u8],
|
||||
pass: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
let key = key.try_into().map_err(|_| "wrong key size")?;
|
||||
let cipher = <$cipher>::new(key);
|
||||
let nonce = nonce.try_into().map_err(|_| "wrong nonce size")?;
|
||||
|
||||
if !pass {
|
||||
let res = cipher.decrypt(nonce, Payload { aad: aad, msg: ct });
|
||||
if res.is_ok() {
|
||||
return Err("decryption must return error");
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let res = cipher
|
||||
.encrypt(nonce, Payload { aad: aad, msg: pt })
|
||||
.map_err(|_| "encryption failure")?;
|
||||
if res != ct {
|
||||
return Err("encrypted data is different from target ciphertext");
|
||||
}
|
||||
let res = cipher
|
||||
.decrypt(nonce, Payload { aad: aad, msg: ct })
|
||||
.map_err(|_| "decryption failure")?;
|
||||
if res != pt {
|
||||
return Err("decrypted data is different from target plaintext");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let data = include_bytes!(concat!("data/", $test_name, ".blb"));
|
||||
for (i, row) in Blob6Iterator::new(data).unwrap().enumerate() {
|
||||
let [key, nonce, aad, pt, ct, status] = row.unwrap();
|
||||
let pass = match status[0] {
|
||||
0 => false,
|
||||
1 => true,
|
||||
_ => panic!("invalid value for pass flag"),
|
||||
};
|
||||
if let Err(reason) = run_test(key, nonce, aad, pt, ct, pass) {
|
||||
panic!(
|
||||
"\n\
|
||||
Failed test №{}\n\
|
||||
reason: \t{:?}\n\
|
||||
key:\t{:?}\n\
|
||||
nonce:\t{:?}\n\
|
||||
aad:\t{:?}\n\
|
||||
plaintext:\t{:?}\n\
|
||||
ciphertext:\t{:?}\n\
|
||||
pass:\t{}\n\
|
||||
",
|
||||
i, reason, key, nonce, aad, pt, ct, pass,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
591
.gear/predownloaded-development/vendor/aead/src/lib.rs
vendored
Normal file
591
.gear/predownloaded-development/vendor/aead/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,591 @@
|
|||
//! [Authenticated Encryption with Associated Data] (AEAD) traits
|
||||
//!
|
||||
//! This crate provides an abstract interface for AEAD ciphers, which guarantee
|
||||
//! both confidentiality and integrity, even from a powerful attacker who is
|
||||
//! able to execute [chosen-ciphertext attacks]. The resulting security property,
|
||||
//! [ciphertext indistinguishability], is considered a basic requirement for
|
||||
//! modern cryptographic implementations.
|
||||
//!
|
||||
//! See [RustCrypto/AEADs] for cipher implementations which use this trait.
|
||||
//!
|
||||
//! [Authenticated Encryption with Associated Data]: https://en.wikipedia.org/wiki/Authenticated_encryption
|
||||
//! [chosen-ciphertext attacks]: https://en.wikipedia.org/wiki/Chosen-ciphertext_attack
|
||||
//! [ciphertext indistinguishability]: https://en.wikipedia.org/wiki/Ciphertext_indistinguishability
|
||||
//! [RustCrypto/AEADs]: https://github.com/RustCrypto/AEADs
|
||||
|
||||
#![no_std]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
|
||||
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
|
||||
)]
|
||||
#![forbid(unsafe_code)]
|
||||
#![warn(clippy::unwrap_used, missing_docs, rust_2018_idioms)]
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
#[cfg(feature = "dev")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
|
||||
pub mod dev;
|
||||
|
||||
#[cfg(feature = "stream")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "stream")))]
|
||||
pub mod stream;
|
||||
|
||||
pub use crypto_common::{Key, KeyInit, KeySizeUser};
|
||||
pub use generic_array::{self, typenum::consts};
|
||||
|
||||
#[cfg(feature = "arrayvec")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "arrayvec")))]
|
||||
pub use arrayvec;
|
||||
|
||||
#[cfg(feature = "bytes")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "bytes")))]
|
||||
pub use bytes;
|
||||
|
||||
#[cfg(feature = "getrandom")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "getrandom")))]
|
||||
pub use crypto_common::rand_core::OsRng;
|
||||
|
||||
#[cfg(feature = "heapless")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "heapless")))]
|
||||
pub use heapless;
|
||||
|
||||
#[cfg(feature = "rand_core")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
|
||||
pub use crypto_common::rand_core;
|
||||
|
||||
use core::fmt;
|
||||
use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#[cfg(feature = "bytes")]
|
||||
use bytes::BytesMut;
|
||||
|
||||
#[cfg(feature = "rand_core")]
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
|
||||
/// Error type.
|
||||
///
|
||||
/// This type is deliberately opaque as to avoid potential side-channel
|
||||
/// leakage (e.g. padding oracle).
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct Error;
|
||||
|
||||
/// Result type alias with [`Error`].
|
||||
pub type Result<T> = core::result::Result<T, Error>;
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("aead::Error")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
/// Nonce: single-use value for ensuring ciphertexts are unique
|
||||
pub type Nonce<A> = GenericArray<u8, <A as AeadCore>::NonceSize>;
|
||||
|
||||
/// Tag: authentication code which ensures ciphertexts are authentic
|
||||
pub type Tag<A> = GenericArray<u8, <A as AeadCore>::TagSize>;
|
||||
|
||||
/// Authenticated Encryption with Associated Data (AEAD) algorithm core trait.
|
||||
///
|
||||
/// Defines nonce, tag, and overhead sizes that are consumed by various other
|
||||
/// `Aead*` traits.
|
||||
pub trait AeadCore {
|
||||
/// The length of a nonce.
|
||||
type NonceSize: ArrayLength<u8>;
|
||||
|
||||
/// The maximum length of the nonce.
|
||||
type TagSize: ArrayLength<u8>;
|
||||
|
||||
/// The upper bound amount of additional space required to support a
|
||||
/// ciphertext vs. a plaintext.
|
||||
type CiphertextOverhead: ArrayLength<u8> + Unsigned;
|
||||
|
||||
/// Generate a random nonce for this AEAD algorithm.
|
||||
///
|
||||
/// AEAD algorithms accept a parameter to encryption/decryption called
|
||||
/// a "nonce" which must be unique every time encryption is performed and
|
||||
/// never repeated for the same key. The nonce is often prepended to the
|
||||
/// ciphertext. The nonce used to produce a given ciphertext must be passed
|
||||
/// to the decryption function in order for it to decrypt correctly.
|
||||
///
|
||||
/// Nonces don't necessarily have to be random, but it is one strategy
|
||||
/// which is implemented by this function.
|
||||
///
|
||||
/// # ⚠️Security Warning
|
||||
///
|
||||
/// AEAD algorithms often fail catastrophically if nonces are ever repeated
|
||||
/// (with SIV modes being an exception).
|
||||
///
|
||||
/// Using random nonces runs the risk of repeating them unless the nonce
|
||||
/// size is particularly large (e.g. 192-bit extended nonces used by the
|
||||
/// `XChaCha20Poly1305` and `XSalsa20Poly1305` constructions.
|
||||
///
|
||||
/// [NIST SP 800-38D] recommends the following:
|
||||
///
|
||||
/// > The total number of invocations of the authenticated encryption
|
||||
/// > function shall not exceed 2^32, including all IV lengths and all
|
||||
/// > instances of the authenticated encryption function with the given key.
|
||||
///
|
||||
/// Following this guideline, only 4,294,967,296 messages with random
|
||||
/// nonces can be encrypted under a given key. While this bound is high,
|
||||
/// it's possible to encounter in practice, and systems which might
|
||||
/// reach it should consider alternatives to purely random nonces, like
|
||||
/// a counter or a combination of a random nonce + counter.
|
||||
///
|
||||
/// See the [`stream`] module for a ready-made implementation of the latter.
|
||||
///
|
||||
/// [NIST SP 800-38D]: https://csrc.nist.gov/publications/detail/sp/800-38d/final
|
||||
#[cfg(feature = "rand_core")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
|
||||
fn generate_nonce(mut rng: impl CryptoRng + RngCore) -> Nonce<Self>
|
||||
where
|
||||
Nonce<Self>: Default,
|
||||
{
|
||||
let mut nonce = Nonce::<Self>::default();
|
||||
rng.fill_bytes(&mut nonce);
|
||||
nonce
|
||||
}
|
||||
}
|
||||
|
||||
/// Authenticated Encryption with Associated Data (AEAD) algorithm.
|
||||
///
|
||||
/// This trait is intended for use with stateless AEAD algorithms. The
|
||||
/// [`AeadMut`] trait provides a stateful interface.
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
|
||||
pub trait Aead: AeadCore {
|
||||
/// Encrypt the given plaintext payload, and return the resulting
|
||||
/// ciphertext as a vector of bytes.
|
||||
///
|
||||
/// The [`Payload`] type can be used to provide Additional Associated Data
|
||||
/// (AAD) along with the message: this is an optional bytestring which is
|
||||
/// not encrypted, but *is* authenticated along with the message. Failure
|
||||
/// to pass the same AAD that was used during encryption will cause
|
||||
/// decryption to fail, which is useful if you would like to "bind" the
|
||||
/// ciphertext to some other identifier, like a digital signature key
|
||||
/// or other identifier.
|
||||
///
|
||||
/// If you don't care about AAD and just want to encrypt a plaintext
|
||||
/// message, `&[u8]` will automatically be coerced into a `Payload`:
|
||||
///
|
||||
/// ```nobuild
|
||||
/// let plaintext = b"Top secret message, handle with care";
|
||||
/// let ciphertext = cipher.encrypt(nonce, plaintext);
|
||||
/// ```
|
||||
///
|
||||
/// The default implementation assumes a postfix tag (ala AES-GCM,
|
||||
/// AES-GCM-SIV, ChaCha20Poly1305). [`Aead`] implementations which do not
|
||||
/// use a postfix tag will need to override this to correctly assemble the
|
||||
/// ciphertext message.
|
||||
fn encrypt<'msg, 'aad>(
|
||||
&self,
|
||||
nonce: &Nonce<Self>,
|
||||
plaintext: impl Into<Payload<'msg, 'aad>>,
|
||||
) -> Result<Vec<u8>>;
|
||||
|
||||
/// Decrypt the given ciphertext slice, and return the resulting plaintext
|
||||
/// as a vector of bytes.
|
||||
///
|
||||
/// See notes on [`Aead::encrypt()`] about allowable message payloads and
|
||||
/// Associated Additional Data (AAD).
|
||||
///
|
||||
/// If you have no AAD, you can call this as follows:
|
||||
///
|
||||
/// ```nobuild
|
||||
/// let ciphertext = b"...";
|
||||
/// let plaintext = cipher.decrypt(nonce, ciphertext)?;
|
||||
/// ```
|
||||
///
|
||||
/// The default implementation assumes a postfix tag (ala AES-GCM,
|
||||
/// AES-GCM-SIV, ChaCha20Poly1305). [`Aead`] implementations which do not
|
||||
/// use a postfix tag will need to override this to correctly parse the
|
||||
/// ciphertext message.
|
||||
fn decrypt<'msg, 'aad>(
|
||||
&self,
|
||||
nonce: &Nonce<Self>,
|
||||
ciphertext: impl Into<Payload<'msg, 'aad>>,
|
||||
) -> Result<Vec<u8>>;
|
||||
}
|
||||
|
||||
/// Stateful Authenticated Encryption with Associated Data algorithm.
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
|
||||
pub trait AeadMut: AeadCore {
|
||||
/// Encrypt the given plaintext slice, and return the resulting ciphertext
|
||||
/// as a vector of bytes.
|
||||
///
|
||||
/// See notes on [`Aead::encrypt()`] about allowable message payloads and
|
||||
/// Associated Additional Data (AAD).
|
||||
fn encrypt<'msg, 'aad>(
|
||||
&mut self,
|
||||
nonce: &Nonce<Self>,
|
||||
plaintext: impl Into<Payload<'msg, 'aad>>,
|
||||
) -> Result<Vec<u8>>;
|
||||
|
||||
/// Decrypt the given ciphertext slice, and return the resulting plaintext
|
||||
/// as a vector of bytes.
|
||||
///
|
||||
/// See notes on [`Aead::encrypt()`] and [`Aead::decrypt()`] about allowable
|
||||
/// message payloads and Associated Additional Data (AAD).
|
||||
fn decrypt<'msg, 'aad>(
|
||||
&mut self,
|
||||
nonce: &Nonce<Self>,
|
||||
ciphertext: impl Into<Payload<'msg, 'aad>>,
|
||||
) -> Result<Vec<u8>>;
|
||||
}
|
||||
|
||||
/// Implement the `decrypt_in_place` method on [`AeadInPlace`] and
|
||||
/// [`AeadMutInPlace]`, using a macro to gloss over the `&self` vs `&mut self`.
|
||||
///
|
||||
/// Assumes a postfix authentication tag. AEAD ciphers which do not use a
|
||||
/// postfix authentication tag will need to define their own implementation.
|
||||
macro_rules! impl_decrypt_in_place {
|
||||
($aead:expr, $nonce:expr, $aad:expr, $buffer:expr) => {{
|
||||
if $buffer.len() < Self::TagSize::to_usize() {
|
||||
return Err(Error);
|
||||
}
|
||||
|
||||
let tag_pos = $buffer.len() - Self::TagSize::to_usize();
|
||||
let (msg, tag) = $buffer.as_mut().split_at_mut(tag_pos);
|
||||
$aead.decrypt_in_place_detached($nonce, $aad, msg, Tag::<Self>::from_slice(tag))?;
|
||||
$buffer.truncate(tag_pos);
|
||||
Ok(())
|
||||
}};
|
||||
}
|
||||
|
||||
/// In-place stateless AEAD trait.
|
||||
///
|
||||
/// This trait is both object safe and has no dependencies on `alloc` or `std`.
|
||||
pub trait AeadInPlace: AeadCore {
|
||||
/// Encrypt the given buffer containing a plaintext message in-place.
|
||||
///
|
||||
/// The buffer must have sufficient capacity to store the ciphertext
|
||||
/// message, which will always be larger than the original plaintext.
|
||||
/// The exact size needed is cipher-dependent, but generally includes
|
||||
/// the size of an authentication tag.
|
||||
///
|
||||
/// Returns an error if the buffer has insufficient capacity to store the
|
||||
/// resulting ciphertext message.
|
||||
fn encrypt_in_place(
|
||||
&self,
|
||||
nonce: &Nonce<Self>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut dyn Buffer,
|
||||
) -> Result<()> {
|
||||
let tag = self.encrypt_in_place_detached(nonce, associated_data, buffer.as_mut())?;
|
||||
buffer.extend_from_slice(tag.as_slice())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Encrypt the data in-place, returning the authentication tag
|
||||
fn encrypt_in_place_detached(
|
||||
&self,
|
||||
nonce: &Nonce<Self>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut [u8],
|
||||
) -> Result<Tag<Self>>;
|
||||
|
||||
/// Decrypt the message in-place, returning an error in the event the
|
||||
/// provided authentication tag does not match the given ciphertext.
|
||||
///
|
||||
/// The buffer will be truncated to the length of the original plaintext
|
||||
/// message upon success.
|
||||
fn decrypt_in_place(
|
||||
&self,
|
||||
nonce: &Nonce<Self>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut dyn Buffer,
|
||||
) -> Result<()> {
|
||||
impl_decrypt_in_place!(self, nonce, associated_data, buffer)
|
||||
}
|
||||
|
||||
/// Decrypt the message in-place, returning an error in the event the provided
|
||||
/// authentication tag does not match the given ciphertext (i.e. ciphertext
|
||||
/// is modified/unauthentic)
|
||||
fn decrypt_in_place_detached(
|
||||
&self,
|
||||
nonce: &Nonce<Self>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut [u8],
|
||||
tag: &Tag<Self>,
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
||||
/// In-place stateful AEAD trait.
|
||||
///
|
||||
/// This trait is both object safe and has no dependencies on `alloc` or `std`.
|
||||
pub trait AeadMutInPlace: AeadCore {
|
||||
/// Encrypt the given buffer containing a plaintext message in-place.
|
||||
///
|
||||
/// The buffer must have sufficient capacity to store the ciphertext
|
||||
/// message, which will always be larger than the original plaintext.
|
||||
/// The exact size needed is cipher-dependent, but generally includes
|
||||
/// the size of an authentication tag.
|
||||
///
|
||||
/// Returns an error if the buffer has insufficient capacity to store the
|
||||
/// resulting ciphertext message.
|
||||
fn encrypt_in_place(
|
||||
&mut self,
|
||||
nonce: &Nonce<Self>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut impl Buffer,
|
||||
) -> Result<()> {
|
||||
let tag = self.encrypt_in_place_detached(nonce, associated_data, buffer.as_mut())?;
|
||||
buffer.extend_from_slice(tag.as_slice())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Encrypt the data in-place, returning the authentication tag
|
||||
fn encrypt_in_place_detached(
|
||||
&mut self,
|
||||
nonce: &Nonce<Self>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut [u8],
|
||||
) -> Result<Tag<Self>>;
|
||||
|
||||
/// Decrypt the message in-place, returning an error in the event the
|
||||
/// provided authentication tag does not match the given ciphertext.
|
||||
///
|
||||
/// The buffer will be truncated to the length of the original plaintext
|
||||
/// message upon success.
|
||||
fn decrypt_in_place(
|
||||
&mut self,
|
||||
nonce: &Nonce<Self>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut impl Buffer,
|
||||
) -> Result<()> {
|
||||
impl_decrypt_in_place!(self, nonce, associated_data, buffer)
|
||||
}
|
||||
|
||||
/// Decrypt the data in-place, returning an error in the event the provided
|
||||
/// authentication tag does not match the given ciphertext (i.e. ciphertext
|
||||
/// is modified/unauthentic)
|
||||
fn decrypt_in_place_detached(
|
||||
&mut self,
|
||||
nonce: &Nonce<Self>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut [u8],
|
||||
tag: &Tag<Self>,
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<Alg: AeadInPlace> Aead for Alg {
|
||||
fn encrypt<'msg, 'aad>(
|
||||
&self,
|
||||
nonce: &Nonce<Self>,
|
||||
plaintext: impl Into<Payload<'msg, 'aad>>,
|
||||
) -> Result<Vec<u8>> {
|
||||
let payload = plaintext.into();
|
||||
let mut buffer = Vec::with_capacity(payload.msg.len() + Self::TagSize::to_usize());
|
||||
buffer.extend_from_slice(payload.msg);
|
||||
self.encrypt_in_place(nonce, payload.aad, &mut buffer)?;
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
fn decrypt<'msg, 'aad>(
|
||||
&self,
|
||||
nonce: &Nonce<Self>,
|
||||
ciphertext: impl Into<Payload<'msg, 'aad>>,
|
||||
) -> Result<Vec<u8>> {
|
||||
let payload = ciphertext.into();
|
||||
let mut buffer = Vec::from(payload.msg);
|
||||
self.decrypt_in_place(nonce, payload.aad, &mut buffer)?;
|
||||
Ok(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<Alg: AeadMutInPlace> AeadMut for Alg {
|
||||
fn encrypt<'msg, 'aad>(
|
||||
&mut self,
|
||||
nonce: &Nonce<Self>,
|
||||
plaintext: impl Into<Payload<'msg, 'aad>>,
|
||||
) -> Result<Vec<u8>> {
|
||||
let payload = plaintext.into();
|
||||
let mut buffer = Vec::with_capacity(payload.msg.len() + Self::TagSize::to_usize());
|
||||
buffer.extend_from_slice(payload.msg);
|
||||
self.encrypt_in_place(nonce, payload.aad, &mut buffer)?;
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
fn decrypt<'msg, 'aad>(
|
||||
&mut self,
|
||||
nonce: &Nonce<Self>,
|
||||
ciphertext: impl Into<Payload<'msg, 'aad>>,
|
||||
) -> Result<Vec<u8>> {
|
||||
let payload = ciphertext.into();
|
||||
let mut buffer = Vec::from(payload.msg);
|
||||
self.decrypt_in_place(nonce, payload.aad, &mut buffer)?;
|
||||
Ok(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Alg: AeadInPlace> AeadMutInPlace for Alg {
|
||||
fn encrypt_in_place(
|
||||
&mut self,
|
||||
nonce: &Nonce<Self>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut impl Buffer,
|
||||
) -> Result<()> {
|
||||
<Self as AeadInPlace>::encrypt_in_place(self, nonce, associated_data, buffer)
|
||||
}
|
||||
|
||||
fn encrypt_in_place_detached(
|
||||
&mut self,
|
||||
nonce: &Nonce<Self>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut [u8],
|
||||
) -> Result<Tag<Self>> {
|
||||
<Self as AeadInPlace>::encrypt_in_place_detached(self, nonce, associated_data, buffer)
|
||||
}
|
||||
|
||||
fn decrypt_in_place(
|
||||
&mut self,
|
||||
nonce: &Nonce<Self>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut impl Buffer,
|
||||
) -> Result<()> {
|
||||
<Self as AeadInPlace>::decrypt_in_place(self, nonce, associated_data, buffer)
|
||||
}
|
||||
|
||||
fn decrypt_in_place_detached(
|
||||
&mut self,
|
||||
nonce: &Nonce<Self>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut [u8],
|
||||
tag: &Tag<Self>,
|
||||
) -> Result<()> {
|
||||
<Self as AeadInPlace>::decrypt_in_place_detached(self, nonce, associated_data, buffer, tag)
|
||||
}
|
||||
}
|
||||
|
||||
/// AEAD payloads (message + AAD).
|
||||
///
|
||||
/// Combination of a message (plaintext or ciphertext) and
|
||||
/// "additional associated data" (AAD) to be authenticated (in cleartext)
|
||||
/// along with the message.
|
||||
///
|
||||
/// If you don't care about AAD, you can pass a `&[u8]` as the payload to
|
||||
/// `encrypt`/`decrypt` and it will automatically be coerced to this type.
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
|
||||
pub struct Payload<'msg, 'aad> {
|
||||
/// Message to be encrypted/decrypted
|
||||
pub msg: &'msg [u8],
|
||||
|
||||
/// Optional "additional associated data" to authenticate along with
|
||||
/// this message. If AAD is provided at the time the message is encrypted,
|
||||
/// the same AAD *MUST* be provided at the time the message is decrypted,
|
||||
/// or decryption will fail.
|
||||
pub aad: &'aad [u8],
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<'msg, 'aad> From<&'msg [u8]> for Payload<'msg, 'aad> {
|
||||
fn from(msg: &'msg [u8]) -> Self {
|
||||
Self { msg, aad: b"" }
|
||||
}
|
||||
}
|
||||
|
||||
/// In-place encryption/decryption byte buffers.
|
||||
///
|
||||
/// This trait defines the set of methods needed to support in-place operations
|
||||
/// on a `Vec`-like data type.
|
||||
pub trait Buffer: AsRef<[u8]> + AsMut<[u8]> {
|
||||
/// Get the length of the buffer
|
||||
fn len(&self) -> usize {
|
||||
self.as_ref().len()
|
||||
}
|
||||
|
||||
/// Is the buffer empty?
|
||||
fn is_empty(&self) -> bool {
|
||||
self.as_ref().is_empty()
|
||||
}
|
||||
|
||||
/// Extend this buffer from the given slice
|
||||
fn extend_from_slice(&mut self, other: &[u8]) -> Result<()>;
|
||||
|
||||
/// Truncate this buffer to the given size
|
||||
fn truncate(&mut self, len: usize);
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl Buffer for Vec<u8> {
|
||||
fn extend_from_slice(&mut self, other: &[u8]) -> Result<()> {
|
||||
Vec::extend_from_slice(self, other);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn truncate(&mut self, len: usize) {
|
||||
Vec::truncate(self, len);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "bytes")]
|
||||
impl Buffer for BytesMut {
|
||||
fn len(&self) -> usize {
|
||||
BytesMut::len(self)
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
BytesMut::is_empty(self)
|
||||
}
|
||||
|
||||
fn extend_from_slice(&mut self, other: &[u8]) -> Result<()> {
|
||||
BytesMut::extend_from_slice(self, other);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn truncate(&mut self, len: usize) {
|
||||
BytesMut::truncate(self, len);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "arrayvec")]
|
||||
impl<const N: usize> Buffer for arrayvec::ArrayVec<u8, N> {
|
||||
fn extend_from_slice(&mut self, other: &[u8]) -> Result<()> {
|
||||
arrayvec::ArrayVec::try_extend_from_slice(self, other).map_err(|_| Error)
|
||||
}
|
||||
|
||||
fn truncate(&mut self, len: usize) {
|
||||
arrayvec::ArrayVec::truncate(self, len);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "heapless")]
|
||||
impl<const N: usize> Buffer for heapless::Vec<u8, N> {
|
||||
fn extend_from_slice(&mut self, other: &[u8]) -> Result<()> {
|
||||
heapless::Vec::extend_from_slice(self, other).map_err(|_| Error)
|
||||
}
|
||||
|
||||
fn truncate(&mut self, len: usize) {
|
||||
heapless::Vec::truncate(self, len);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// Ensure that `AeadInPlace` is object-safe
|
||||
#[allow(dead_code)]
|
||||
type DynAeadInPlace<N, T, O> =
|
||||
dyn AeadInPlace<NonceSize = N, TagSize = T, CiphertextOverhead = O>;
|
||||
|
||||
/// Ensure that `AeadMutInPlace` is object-safe
|
||||
#[allow(dead_code)]
|
||||
type DynAeadMutInPlace<N, T, O> =
|
||||
dyn AeadMutInPlace<NonceSize = N, TagSize = T, CiphertextOverhead = O>;
|
||||
}
|
||||
542
.gear/predownloaded-development/vendor/aead/src/stream.rs
vendored
Normal file
542
.gear/predownloaded-development/vendor/aead/src/stream.rs
vendored
Normal file
|
|
@ -0,0 +1,542 @@
|
|||
//! Streaming AEAD support.
|
||||
//!
|
||||
//! Implementation of the STREAM online authenticated encryption construction
|
||||
//! as described in the paper
|
||||
//! [Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance][1].
|
||||
//!
|
||||
//! ## About
|
||||
//!
|
||||
//! The STREAM construction supports encrypting/decrypting sequences of AEAD
|
||||
//! message segments, which is useful in cases where the overall message is too
|
||||
//! large to fit in a single buffer and needs to be processed incrementally.
|
||||
//!
|
||||
//! STREAM defends against reordering and truncation attacks which are common
|
||||
//! in naive schemes which attempt to provide these properties, and is proven
|
||||
//! to meet the security definition of "nonce-based online authenticated
|
||||
//! encryption" (nOAE) as given in the aforementioned paper.
|
||||
//!
|
||||
//! ## Diagram
|
||||
//!
|
||||
//! 
|
||||
//!
|
||||
//! Legend:
|
||||
//!
|
||||
//! - 𝐄k: AEAD encryption under key `k`
|
||||
//! - 𝐌: message
|
||||
//! - 𝐍: nonce
|
||||
//! - 𝐀: additional associated data
|
||||
//! - 𝐂: ciphertext
|
||||
//! - 𝜏: MAC tag
|
||||
//!
|
||||
//! [1]: https://eprint.iacr.org/2015/189.pdf
|
||||
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
|
||||
use crate::{AeadCore, AeadInPlace, Buffer, Error, Key, KeyInit, Result};
|
||||
use core::ops::{AddAssign, Sub};
|
||||
use generic_array::{
|
||||
typenum::{Unsigned, U4, U5},
|
||||
ArrayLength, GenericArray,
|
||||
};
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use {crate::Payload, alloc::vec::Vec};
|
||||
|
||||
/// Nonce as used by a given AEAD construction and STREAM primitive.
|
||||
pub type Nonce<A, S> = GenericArray<u8, NonceSize<A, S>>;
|
||||
|
||||
/// Size of a nonce as used by a STREAM construction, sans the overhead of
|
||||
/// the STREAM protocol itself.
|
||||
pub type NonceSize<A, S> =
|
||||
<<A as AeadCore>::NonceSize as Sub<<S as StreamPrimitive<A>>::NonceOverhead>>::Output;
|
||||
|
||||
/// STREAM encryptor instantiated with [`StreamBE32`] as the underlying
|
||||
/// STREAM primitive.
|
||||
pub type EncryptorBE32<A> = Encryptor<A, StreamBE32<A>>;
|
||||
|
||||
/// STREAM decryptor instantiated with [`StreamBE32`] as the underlying
|
||||
/// STREAM primitive.
|
||||
pub type DecryptorBE32<A> = Decryptor<A, StreamBE32<A>>;
|
||||
|
||||
/// STREAM encryptor instantiated with [`StreamLE31`] as the underlying
|
||||
/// STREAM primitive.
|
||||
pub type EncryptorLE31<A> = Encryptor<A, StreamLE31<A>>;
|
||||
|
||||
/// STREAM decryptor instantiated with [`StreamLE31`] as the underlying
|
||||
/// STREAM primitive.
|
||||
pub type DecryptorLE31<A> = Decryptor<A, StreamLE31<A>>;
|
||||
|
||||
/// Create a new STREAM from the provided AEAD.
|
||||
pub trait NewStream<A>: StreamPrimitive<A>
|
||||
where
|
||||
A: AeadInPlace,
|
||||
A::NonceSize: Sub<Self::NonceOverhead>,
|
||||
NonceSize<A, Self>: ArrayLength<u8>,
|
||||
{
|
||||
/// Create a new STREAM with the given key and nonce.
|
||||
fn new(key: &Key<A>, nonce: &Nonce<A, Self>) -> Self
|
||||
where
|
||||
A: KeyInit,
|
||||
Self: Sized,
|
||||
{
|
||||
Self::from_aead(A::new(key), nonce)
|
||||
}
|
||||
|
||||
/// Create a new STREAM from the given AEAD cipher.
|
||||
fn from_aead(aead: A, nonce: &Nonce<A, Self>) -> Self;
|
||||
}
|
||||
|
||||
/// Low-level STREAM implementation.
|
||||
///
|
||||
/// This trait provides a particular "flavor" of STREAM, as there are
|
||||
/// different ways the specifics of the construction can be implemented.
|
||||
///
|
||||
/// Deliberately immutable and stateless to permit parallel operation.
|
||||
pub trait StreamPrimitive<A>
|
||||
where
|
||||
A: AeadInPlace,
|
||||
A::NonceSize: Sub<Self::NonceOverhead>,
|
||||
NonceSize<A, Self>: ArrayLength<u8>,
|
||||
{
|
||||
/// Number of bytes this STREAM primitive requires from the nonce.
|
||||
type NonceOverhead: ArrayLength<u8>;
|
||||
|
||||
/// Type used as the STREAM counter.
|
||||
type Counter: AddAssign + Copy + Default + Eq;
|
||||
|
||||
/// Value to use when incrementing the STREAM counter (i.e. one)
|
||||
const COUNTER_INCR: Self::Counter;
|
||||
|
||||
/// Maximum value of the STREAM counter.
|
||||
const COUNTER_MAX: Self::Counter;
|
||||
|
||||
/// Encrypt an AEAD message in-place at the given position in the STREAM.
|
||||
fn encrypt_in_place(
|
||||
&self,
|
||||
position: Self::Counter,
|
||||
last_block: bool,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut dyn Buffer,
|
||||
) -> Result<()>;
|
||||
|
||||
/// Decrypt an AEAD message in-place at the given position in the STREAM.
|
||||
fn decrypt_in_place(
|
||||
&self,
|
||||
position: Self::Counter,
|
||||
last_block: bool,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut dyn Buffer,
|
||||
) -> Result<()>;
|
||||
|
||||
/// Encrypt the given plaintext payload, and return the resulting
|
||||
/// ciphertext as a vector of bytes.
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
|
||||
fn encrypt<'msg, 'aad>(
|
||||
&self,
|
||||
position: Self::Counter,
|
||||
last_block: bool,
|
||||
plaintext: impl Into<Payload<'msg, 'aad>>,
|
||||
) -> Result<Vec<u8>> {
|
||||
let payload = plaintext.into();
|
||||
let mut buffer = Vec::with_capacity(payload.msg.len() + A::TagSize::to_usize());
|
||||
buffer.extend_from_slice(payload.msg);
|
||||
self.encrypt_in_place(position, last_block, payload.aad, &mut buffer)?;
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
/// Decrypt the given ciphertext slice, and return the resulting plaintext
|
||||
/// as a vector of bytes.
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
|
||||
fn decrypt<'msg, 'aad>(
|
||||
&self,
|
||||
position: Self::Counter,
|
||||
last_block: bool,
|
||||
ciphertext: impl Into<Payload<'msg, 'aad>>,
|
||||
) -> Result<Vec<u8>> {
|
||||
let payload = ciphertext.into();
|
||||
let mut buffer = Vec::from(payload.msg);
|
||||
self.decrypt_in_place(position, last_block, payload.aad, &mut buffer)?;
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
/// Obtain [`Encryptor`] for this [`StreamPrimitive`].
|
||||
fn encryptor(self) -> Encryptor<A, Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Encryptor::from_stream_primitive(self)
|
||||
}
|
||||
|
||||
/// Obtain [`Decryptor`] for this [`StreamPrimitive`].
|
||||
fn decryptor(self) -> Decryptor<A, Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Decryptor::from_stream_primitive(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement a stateful STREAM object (i.e. encryptor or decryptor)
|
||||
macro_rules! impl_stream_object {
|
||||
(
|
||||
$name:ident,
|
||||
$next_method:tt,
|
||||
$next_in_place_method:tt,
|
||||
$last_method:tt,
|
||||
$last_in_place_method:tt,
|
||||
$op:tt,
|
||||
$in_place_op:tt,
|
||||
$op_desc:expr,
|
||||
$obj_desc:expr
|
||||
) => {
|
||||
#[doc = "Stateful STREAM object which can"]
|
||||
#[doc = $op_desc]
|
||||
#[doc = "AEAD messages one-at-a-time."]
|
||||
#[doc = ""]
|
||||
#[doc = "This corresponds to the "]
|
||||
#[doc = $obj_desc]
|
||||
#[doc = "object as defined in the paper"]
|
||||
#[doc = "[Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance][1]."]
|
||||
#[doc = ""]
|
||||
#[doc = "[1]: https://eprint.iacr.org/2015/189.pdf"]
|
||||
pub struct $name<A, S>
|
||||
where
|
||||
A: AeadInPlace,
|
||||
S: StreamPrimitive<A>,
|
||||
A::NonceSize: Sub<<S as StreamPrimitive<A>>::NonceOverhead>,
|
||||
NonceSize<A, S>: ArrayLength<u8>,
|
||||
{
|
||||
/// Underlying STREAM primitive.
|
||||
stream: S,
|
||||
|
||||
/// Current position in the STREAM.
|
||||
position: S::Counter,
|
||||
}
|
||||
|
||||
impl<A, S> $name<A, S>
|
||||
where
|
||||
A: AeadInPlace,
|
||||
S: StreamPrimitive<A>,
|
||||
A::NonceSize: Sub<<S as StreamPrimitive<A>>::NonceOverhead>,
|
||||
NonceSize<A, S>: ArrayLength<u8>,
|
||||
{
|
||||
#[doc = "Create a"]
|
||||
#[doc = $obj_desc]
|
||||
#[doc = "object from the given AEAD key and nonce."]
|
||||
pub fn new(key: &Key<A>, nonce: &Nonce<A, S>) -> Self
|
||||
where
|
||||
A: KeyInit,
|
||||
S: NewStream<A>,
|
||||
{
|
||||
Self::from_stream_primitive(S::new(key, nonce))
|
||||
}
|
||||
|
||||
#[doc = "Create a"]
|
||||
#[doc = $obj_desc]
|
||||
#[doc = "object from the given AEAD primitive."]
|
||||
pub fn from_aead(aead: A, nonce: &Nonce<A, S>) -> Self
|
||||
where
|
||||
A: KeyInit,
|
||||
S: NewStream<A>,
|
||||
{
|
||||
Self::from_stream_primitive(S::from_aead(aead, nonce))
|
||||
}
|
||||
|
||||
#[doc = "Create a"]
|
||||
#[doc = $obj_desc]
|
||||
#[doc = "object from the given STREAM primitive."]
|
||||
pub fn from_stream_primitive(stream: S) -> Self {
|
||||
Self {
|
||||
stream,
|
||||
position: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "Use the underlying AEAD to"]
|
||||
#[doc = $op_desc]
|
||||
#[doc = "the next AEAD message in this STREAM, returning the"]
|
||||
#[doc = "result as a [`Vec`]."]
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
|
||||
pub fn $next_method<'msg, 'aad>(
|
||||
&mut self,
|
||||
payload: impl Into<Payload<'msg, 'aad>>,
|
||||
) -> Result<Vec<u8>> {
|
||||
if self.position == S::COUNTER_MAX {
|
||||
// Counter overflow. Note that the maximum counter value is
|
||||
// deliberately disallowed, as it would preclude being able
|
||||
// to encrypt a last block (i.e. with `$last_in_place_method`)
|
||||
return Err(Error);
|
||||
}
|
||||
|
||||
let result = self.stream.$op(self.position, false, payload)?;
|
||||
|
||||
// Note: overflow checked above
|
||||
self.position += S::COUNTER_INCR;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[doc = "Use the underlying AEAD to"]
|
||||
#[doc = $op_desc]
|
||||
#[doc = "the next AEAD message in this STREAM in-place."]
|
||||
pub fn $next_in_place_method(
|
||||
&mut self,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut dyn Buffer,
|
||||
) -> Result<()> {
|
||||
if self.position == S::COUNTER_MAX {
|
||||
// Counter overflow. Note that the maximum counter value is
|
||||
// deliberately disallowed, as it would preclude being able
|
||||
// to encrypt a last block (i.e. with `$last_in_place_method`)
|
||||
return Err(Error);
|
||||
}
|
||||
|
||||
self.stream
|
||||
.$in_place_op(self.position, false, associated_data, buffer)?;
|
||||
|
||||
// Note: overflow checked above
|
||||
self.position += S::COUNTER_INCR;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[doc = "Use the underlying AEAD to"]
|
||||
#[doc = $op_desc]
|
||||
#[doc = "the last AEAD message in this STREAM,"]
|
||||
#[doc = "consuming the "]
|
||||
#[doc = $obj_desc]
|
||||
#[doc = "object in order to prevent further use."]
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
|
||||
pub fn $last_method<'msg, 'aad>(
|
||||
self,
|
||||
payload: impl Into<Payload<'msg, 'aad>>,
|
||||
) -> Result<Vec<u8>> {
|
||||
self.stream.$op(self.position, true, payload)
|
||||
}
|
||||
|
||||
#[doc = "Use the underlying AEAD to"]
|
||||
#[doc = $op_desc]
|
||||
#[doc = "the last AEAD message in this STREAM in-place,"]
|
||||
#[doc = "consuming the "]
|
||||
#[doc = $obj_desc]
|
||||
#[doc = "object in order to prevent further use."]
|
||||
pub fn $last_in_place_method(
|
||||
self,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut dyn Buffer,
|
||||
) -> Result<()> {
|
||||
self.stream
|
||||
.$in_place_op(self.position, true, associated_data, buffer)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_stream_object!(
|
||||
Encryptor,
|
||||
encrypt_next,
|
||||
encrypt_next_in_place,
|
||||
encrypt_last,
|
||||
encrypt_last_in_place,
|
||||
encrypt,
|
||||
encrypt_in_place,
|
||||
"encrypt",
|
||||
"ℰ STREAM encryptor"
|
||||
);
|
||||
|
||||
impl_stream_object!(
|
||||
Decryptor,
|
||||
decrypt_next,
|
||||
decrypt_next_in_place,
|
||||
decrypt_last,
|
||||
decrypt_last_in_place,
|
||||
decrypt,
|
||||
decrypt_in_place,
|
||||
"decrypt",
|
||||
"𝒟 STREAM decryptor"
|
||||
);
|
||||
|
||||
/// The original "Rogaway-flavored" STREAM as described in the paper
|
||||
/// [Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance][1].
|
||||
///
|
||||
/// Uses a 32-bit big endian counter and 1-byte "last block" flag stored as
|
||||
/// the last 5-bytes of the AEAD nonce.
|
||||
///
|
||||
/// [1]: https://eprint.iacr.org/2015/189.pdf
|
||||
pub struct StreamBE32<A>
|
||||
where
|
||||
A: AeadInPlace,
|
||||
A::NonceSize: Sub<U5>,
|
||||
<<A as AeadCore>::NonceSize as Sub<U5>>::Output: ArrayLength<u8>,
|
||||
{
|
||||
/// Underlying AEAD cipher
|
||||
aead: A,
|
||||
|
||||
/// Nonce (sans STREAM overhead)
|
||||
nonce: Nonce<A, Self>,
|
||||
}
|
||||
|
||||
impl<A> NewStream<A> for StreamBE32<A>
|
||||
where
|
||||
A: AeadInPlace,
|
||||
A::NonceSize: Sub<U5>,
|
||||
<<A as AeadCore>::NonceSize as Sub<U5>>::Output: ArrayLength<u8>,
|
||||
{
|
||||
fn from_aead(aead: A, nonce: &Nonce<A, Self>) -> Self {
|
||||
Self {
|
||||
aead,
|
||||
nonce: nonce.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> StreamPrimitive<A> for StreamBE32<A>
|
||||
where
|
||||
A: AeadInPlace,
|
||||
A::NonceSize: Sub<U5>,
|
||||
<<A as AeadCore>::NonceSize as Sub<U5>>::Output: ArrayLength<u8>,
|
||||
{
|
||||
type NonceOverhead = U5;
|
||||
type Counter = u32;
|
||||
const COUNTER_INCR: u32 = 1;
|
||||
const COUNTER_MAX: u32 = core::u32::MAX;
|
||||
|
||||
fn encrypt_in_place(
|
||||
&self,
|
||||
position: u32,
|
||||
last_block: bool,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut dyn Buffer,
|
||||
) -> Result<()> {
|
||||
let nonce = self.aead_nonce(position, last_block);
|
||||
self.aead.encrypt_in_place(&nonce, associated_data, buffer)
|
||||
}
|
||||
|
||||
fn decrypt_in_place(
|
||||
&self,
|
||||
position: Self::Counter,
|
||||
last_block: bool,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut dyn Buffer,
|
||||
) -> Result<()> {
|
||||
let nonce = self.aead_nonce(position, last_block);
|
||||
self.aead.decrypt_in_place(&nonce, associated_data, buffer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> StreamBE32<A>
|
||||
where
|
||||
A: AeadInPlace,
|
||||
A::NonceSize: Sub<U5>,
|
||||
<<A as AeadCore>::NonceSize as Sub<U5>>::Output: ArrayLength<u8>,
|
||||
{
|
||||
/// Compute the full AEAD nonce including the STREAM counter and last
|
||||
/// block flag.
|
||||
fn aead_nonce(&self, position: u32, last_block: bool) -> crate::Nonce<A> {
|
||||
let mut result = GenericArray::default();
|
||||
|
||||
// TODO(tarcieri): use `generic_array::sequence::Concat` (or const generics)
|
||||
let (prefix, tail) = result.split_at_mut(NonceSize::<A, Self>::to_usize());
|
||||
prefix.copy_from_slice(&self.nonce);
|
||||
|
||||
let (counter, flag) = tail.split_at_mut(4);
|
||||
counter.copy_from_slice(&position.to_be_bytes());
|
||||
flag[0] = last_block as u8;
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
/// STREAM as instantiated with a 31-bit little endian counter and 1-bit
|
||||
/// "last block" flag stored as the most significant bit of the counter
|
||||
/// when interpreted as a 32-bit integer.
|
||||
///
|
||||
/// The 31-bit + 1-bit value is stored as the last 4 bytes of the AEAD nonce.
|
||||
pub struct StreamLE31<A>
|
||||
where
|
||||
A: AeadInPlace,
|
||||
A::NonceSize: Sub<U4>,
|
||||
<<A as AeadCore>::NonceSize as Sub<U4>>::Output: ArrayLength<u8>,
|
||||
{
|
||||
/// Underlying AEAD cipher
|
||||
aead: A,
|
||||
|
||||
/// Nonce (sans STREAM overhead)
|
||||
nonce: Nonce<A, Self>,
|
||||
}
|
||||
|
||||
impl<A> NewStream<A> for StreamLE31<A>
|
||||
where
|
||||
A: AeadInPlace,
|
||||
A::NonceSize: Sub<U4>,
|
||||
<<A as AeadCore>::NonceSize as Sub<U4>>::Output: ArrayLength<u8>,
|
||||
{
|
||||
fn from_aead(aead: A, nonce: &Nonce<A, Self>) -> Self {
|
||||
Self {
|
||||
aead,
|
||||
nonce: nonce.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> StreamPrimitive<A> for StreamLE31<A>
|
||||
where
|
||||
A: AeadInPlace,
|
||||
A::NonceSize: Sub<U4>,
|
||||
<<A as AeadCore>::NonceSize as Sub<U4>>::Output: ArrayLength<u8>,
|
||||
{
|
||||
type NonceOverhead = U4;
|
||||
type Counter = u32;
|
||||
const COUNTER_INCR: u32 = 1;
|
||||
const COUNTER_MAX: u32 = 0xfff_ffff;
|
||||
|
||||
fn encrypt_in_place(
|
||||
&self,
|
||||
position: u32,
|
||||
last_block: bool,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut dyn Buffer,
|
||||
) -> Result<()> {
|
||||
let nonce = self.aead_nonce(position, last_block)?;
|
||||
self.aead.encrypt_in_place(&nonce, associated_data, buffer)
|
||||
}
|
||||
|
||||
fn decrypt_in_place(
|
||||
&self,
|
||||
position: Self::Counter,
|
||||
last_block: bool,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut dyn Buffer,
|
||||
) -> Result<()> {
|
||||
let nonce = self.aead_nonce(position, last_block)?;
|
||||
self.aead.decrypt_in_place(&nonce, associated_data, buffer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> StreamLE31<A>
|
||||
where
|
||||
A: AeadInPlace,
|
||||
A::NonceSize: Sub<U4>,
|
||||
<<A as AeadCore>::NonceSize as Sub<U4>>::Output: ArrayLength<u8>,
|
||||
{
|
||||
/// Compute the full AEAD nonce including the STREAM counter and last
|
||||
/// block flag.
|
||||
fn aead_nonce(&self, position: u32, last_block: bool) -> Result<crate::Nonce<A>> {
|
||||
if position > Self::COUNTER_MAX {
|
||||
return Err(Error);
|
||||
}
|
||||
|
||||
let mut result = GenericArray::default();
|
||||
|
||||
// TODO(tarcieri): use `generic_array::sequence::Concat` (or const generics)
|
||||
let (prefix, tail) = result.split_at_mut(NonceSize::<A, Self>::to_usize());
|
||||
prefix.copy_from_slice(&self.nonce);
|
||||
|
||||
let position_with_flag = position | ((last_block as u32) << 31);
|
||||
tail.copy_from_slice(&position_with_flag.to_le_bytes());
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
1
.gear/predownloaded-development/vendor/aes-gcm/.cargo-checksum.json
vendored
Normal file
1
.gear/predownloaded-development/vendor/aes-gcm/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{".cargo_vcs_info.json":"eae7b633402a41733812a3705a0c22fb73cf86ac53c41f900d2c9b9cfeaa6731","CHANGELOG.md":"8b877289aed51a5c313286e2387abc4f17b3e6c284dc04eaf0f98846ccb18534","Cargo.toml":"cc58c8b539bdfdfa7f665340209afcf428962b8368c6b0beef3809dac3559506","Cargo.toml.orig":"515687dfeea618632d79fbbf2fb85570622306a7eec5344ae0594714eb6bb844","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"3c0dfa33fd2e6976038555b52095699452653b1fcabe113074f14e0848a6b11e","README.md":"20c9c6169af0c2b9ef737de89cf3d2d36f7122bdb8e4b6d95ccb4b04e75afecc","src/lib.rs":"9261306cb6e8ce08a3559d69b2c301b9c0474234b3ff4b92e3e3c8cd7937f479","tests/aes128gcm.rs":"fef2d95b49d245714256370207f6ce324bf90c7eb06dc742f9908470b39ae616","tests/aes256gcm.rs":"eac354157fa0574e58d569cfd541222bb1e4a0ca9561e2a578e3e1101214bbbc","tests/common/mod.rs":"f54a4dd4147b2e726139606e2afe6bf36444d5eff44a6fea61fb633e326985ba","tests/data/wycheproof-128.blb":"50031c7935b9c0608955601ca0aa573de58517aaa4986fc16550a91fa286ff8b","tests/data/wycheproof-256.blb":"d301c0cc24dccb3cdcb9db71b55e694d7dc31b166bf830ce2b3fc896567e1e1c","tests/other_ivlen.rs":"4ef546d000ba162c8a795f35a1c7eb9e6a6d563e0cc1214071ecb6573f79a3a2"},"package":"831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"}
|
||||
6
.gear/predownloaded-development/vendor/aes-gcm/.cargo_vcs_info.json
vendored
Normal file
6
.gear/predownloaded-development/vendor/aes-gcm/.cargo_vcs_info.json
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"git": {
|
||||
"sha1": "fa8197f11d79a079fcb1f6ef67fa9119ce6939b9"
|
||||
},
|
||||
"path_in_vcs": "aes-gcm"
|
||||
}
|
||||
179
.gear/predownloaded-development/vendor/aes-gcm/CHANGELOG.md
vendored
Normal file
179
.gear/predownloaded-development/vendor/aes-gcm/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.10.3 (2023-09-21)
|
||||
### Security
|
||||
- Avoid exposing plaintext on tag verification failure ([#551])
|
||||
|
||||
[#551]: https://github.com/RustCrypto/AEADs/pull/551
|
||||
|
||||
## 0.10.2 (2023-05-20)
|
||||
### Added
|
||||
- `rand_core` feature to all crates ([#467])
|
||||
- Support for partial tag sizes ([#501])
|
||||
- `ArrayVec` support ([#503])
|
||||
|
||||
[#467]: https://github.com/RustCrypto/AEADs/pull/467
|
||||
[#501]: https://github.com/RustCrypto/AEADs/pull/501
|
||||
[#503]: https://github.com/RustCrypto/AEADs/pull/503
|
||||
|
||||
## 0.10.1 (2022-07-31)
|
||||
### Fixed
|
||||
- rustdoc typos and formatting ([#461], [#462])
|
||||
|
||||
[#461]: https://github.com/RustCrypto/AEADs/pull/461
|
||||
[#462]: https://github.com/RustCrypto/AEADs/pull/462
|
||||
|
||||
## 0.10.0 (2022-07-31)
|
||||
### Added
|
||||
- `getrandom` feature ([#446])
|
||||
|
||||
### Changed
|
||||
- Bump `aes` dependency to v0.8 ([#430])
|
||||
- Rust 2021 edition upgrade; MSRV 1.56+ ([#435])
|
||||
- Bump `aead` dependency to v0.5 ([#444])
|
||||
- Bump `ghash` dependency to v0.5 ([#454])
|
||||
|
||||
[#435]: https://github.com/RustCrypto/AEADs/pull/435
|
||||
[#444]: https://github.com/RustCrypto/AEADs/pull/444
|
||||
[#446]: https://github.com/RustCrypto/AEADs/pull/446
|
||||
[#454]: https://github.com/RustCrypto/AEADs/pull/454
|
||||
|
||||
## 0.9.4 (2021-08-28)
|
||||
### Changed
|
||||
- Relax `subtle` and `zeroize` requirements ([#360])
|
||||
|
||||
[#360]: https://github.com/RustCrypto/AEADs/pull/360
|
||||
|
||||
## 0.9.3 (2021-07-20)
|
||||
### Changed
|
||||
- Pin `zeroize` dependency to v1.3 and `subtle` to v2.4 ([#349])
|
||||
|
||||
[#349]: https://github.com/RustCrypto/AEADs/pull/349
|
||||
|
||||
## 0.9.2 (2021-05-31)
|
||||
### Added
|
||||
- Nightly-only `armv8` feature ([#318])
|
||||
|
||||
[#318]: https://github.com/RustCrypto/AEADs/pull/318
|
||||
|
||||
## 0.9.1 (2021-05-04)
|
||||
### Added
|
||||
- `force-soft` feature ([#305])
|
||||
|
||||
[#305]: https://github.com/RustCrypto/AEADs/pull/305
|
||||
|
||||
## 0.9.0 (2021-04-29)
|
||||
### Added
|
||||
- Wycheproof test vectors ([#274])
|
||||
|
||||
### Changed
|
||||
- Bump `aead` crate dependency to v0.4 ([#270])
|
||||
- Bump `aes` crate dependency to v0.7; MSRV 1.49+ ([#283])
|
||||
- Bump `ctr` crate dependency to v0.7 ([#283])
|
||||
- Bump `ghash` crate dependency to v0.4 ([#284])
|
||||
|
||||
[#270]: https://github.com/RustCrypto/AEADs/pull/270
|
||||
[#274]: https://github.com/RustCrypto/AEADs/pull/274
|
||||
[#283]: https://github.com/RustCrypto/AEADs/pull/283
|
||||
[#284]: https://github.com/RustCrypto/AEADs/pull/284
|
||||
|
||||
## 0.8.0 (2020-10-16)
|
||||
### Changed
|
||||
- Replace `block-cipher`/`stream-cipher` with `cipher` crate ([#229])
|
||||
- Bump `aes` dependency to v0.6 ([#229])
|
||||
- Use `ctr::Ctr32BE` ([#227])
|
||||
|
||||
[#229]: https://github.com/RustCrypto/AEADs/pull/229
|
||||
[#227]: https://github.com/RustCrypto/AEADs/pull/227
|
||||
|
||||
## 0.7.0 (2020-09-17)
|
||||
### Added
|
||||
- Optional `std` feature; disabled by default ([#217])
|
||||
|
||||
### Changed
|
||||
- Renamed generic parameters to `Aes` and `NonceSize` ([#166])
|
||||
- Upgrade `aes` to v0.5; `block-cipher` to v0.8 ([#209])
|
||||
|
||||
[#217]: https://github.com/RustCrypto/AEADs/pull/217
|
||||
[#209]: https://github.com/RustCrypto/AEADs/pull/209
|
||||
[#166]: https://github.com/RustCrypto/AEADs/pull/166
|
||||
|
||||
## 0.6.0 (2020-06-06)
|
||||
### Changed
|
||||
- Bump `aead` crate dependency to v0.3.0; MSRV 1.41+ ([#140])
|
||||
|
||||
[#140]: https://github.com/RustCrypto/AEADs/pull/140
|
||||
|
||||
## 0.5.0 (2020-03-15)
|
||||
### Added
|
||||
- Support for non-96-bit nonces ([#126])
|
||||
|
||||
### Changed
|
||||
- `AesGcm` type is now generic around nonce size ([#126])
|
||||
|
||||
[#126]: https://github.com/RustCrypto/AEADs/pull/126
|
||||
|
||||
## 0.4.2 (2020-03-09)
|
||||
### Fixed
|
||||
- Off-by-one error in `debug_assert` for `BlockCipher::ParBlocks` ([#104])
|
||||
|
||||
[#104]: https://github.com/RustCrypto/AEADs/pull/104
|
||||
|
||||
## 0.4.1 (2020-03-07) - YANKED, see [#104]
|
||||
### Added
|
||||
- Support instantiation from an existing cipher instance ([#101])
|
||||
|
||||
[#101]: https://github.com/RustCrypto/AEADs/pull/101
|
||||
|
||||
## 0.4.0 (2020-03-07) - YANKED, see [#104]
|
||||
### Added
|
||||
- `aes` cargo feature; 3rd-party AES crate support ([#96])
|
||||
|
||||
### Changed
|
||||
- Make generic around `BlockCipher::ParBlocks` ([#97])
|
||||
|
||||
[#96]: https://github.com/RustCrypto/AEADs/pull/96
|
||||
[#97]: https://github.com/RustCrypto/AEADs/pull/97
|
||||
|
||||
## 0.3.2 (2020-02-27)
|
||||
### Fixed
|
||||
- Wording in documentation about security audit ([#84])
|
||||
|
||||
[#84]: https://github.com/RustCrypto/AEADs/pull/84
|
||||
|
||||
## 0.3.1 (2020-02-26)
|
||||
### Added
|
||||
- Notes about NCC audit to documentation ([#80])
|
||||
|
||||
[#80]: https://github.com/RustCrypto/AEADs/pull/80
|
||||
|
||||
## 0.3.0 (2019-11-26)
|
||||
### Added
|
||||
- `heapless` feature ([#51])
|
||||
|
||||
[#51]: https://github.com/RustCrypto/AEADs/pull/51
|
||||
|
||||
## 0.2.1 (2019-11-26)
|
||||
### Added
|
||||
- Document in-place API ([#49])
|
||||
|
||||
[#49]: https://github.com/RustCrypto/AEADs/pull/49
|
||||
|
||||
## 0.2.0 (2019-11-26)
|
||||
### Changed
|
||||
- Upgrade `aead` crate to v0.2; `alloc` now optional ([#43])
|
||||
|
||||
[#43]: https://github.com/RustCrypto/AEADs/pull/43
|
||||
|
||||
## 0.1.1 (2019-11-14)
|
||||
### Changed
|
||||
- Upgrade `zeroize` to 1.0 ([#36])
|
||||
|
||||
[#36]: https://github.com/RustCrypto/AEADs/pull/36
|
||||
|
||||
## 0.1.0 (2019-10-06)
|
||||
- Initial release
|
||||
100
.gear/predownloaded-development/vendor/aes-gcm/Cargo.toml
vendored
Normal file
100
.gear/predownloaded-development/vendor/aes-gcm/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
name = "aes-gcm"
|
||||
version = "0.10.3"
|
||||
authors = ["RustCrypto Developers"]
|
||||
description = """
|
||||
Pure Rust implementation of the AES-GCM (Galois/Counter Mode)
|
||||
Authenticated Encryption with Associated Data (AEAD) Cipher
|
||||
with optional architecture-specific hardware acceleration
|
||||
"""
|
||||
documentation = "https://docs.rs/aes-gcm"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"aead",
|
||||
"aes",
|
||||
"encryption",
|
||||
"gcm",
|
||||
"ghash",
|
||||
]
|
||||
categories = [
|
||||
"cryptography",
|
||||
"no-std",
|
||||
]
|
||||
license = "Apache-2.0 OR MIT"
|
||||
repository = "https://github.com/RustCrypto/AEADs"
|
||||
resolver = "1"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = [
|
||||
"--cfg",
|
||||
"docsrs",
|
||||
]
|
||||
|
||||
[dependencies.aead]
|
||||
version = "0.5"
|
||||
default-features = false
|
||||
|
||||
[dependencies.aes]
|
||||
version = "0.8"
|
||||
optional = true
|
||||
|
||||
[dependencies.cipher]
|
||||
version = "0.4"
|
||||
|
||||
[dependencies.ctr]
|
||||
version = "0.9"
|
||||
|
||||
[dependencies.ghash]
|
||||
version = "0.5"
|
||||
default-features = false
|
||||
|
||||
[dependencies.subtle]
|
||||
version = "2"
|
||||
default-features = false
|
||||
|
||||
[dependencies.zeroize]
|
||||
version = "1"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.aead]
|
||||
version = "0.5"
|
||||
features = ["dev"]
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.hex-literal]
|
||||
version = "0.3"
|
||||
|
||||
[features]
|
||||
alloc = ["aead/alloc"]
|
||||
arrayvec = ["aead/arrayvec"]
|
||||
default = [
|
||||
"aes",
|
||||
"alloc",
|
||||
"getrandom",
|
||||
]
|
||||
getrandom = [
|
||||
"aead/getrandom",
|
||||
"rand_core",
|
||||
]
|
||||
heapless = ["aead/heapless"]
|
||||
rand_core = ["aead/rand_core"]
|
||||
std = [
|
||||
"aead/std",
|
||||
"alloc",
|
||||
]
|
||||
stream = ["aead/stream"]
|
||||
44
.gear/predownloaded-development/vendor/aes-gcm/Cargo.toml.orig
generated
vendored
Normal file
44
.gear/predownloaded-development/vendor/aes-gcm/Cargo.toml.orig
generated
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
[package]
|
||||
name = "aes-gcm"
|
||||
version = "0.10.3"
|
||||
description = """
|
||||
Pure Rust implementation of the AES-GCM (Galois/Counter Mode)
|
||||
Authenticated Encryption with Associated Data (AEAD) Cipher
|
||||
with optional architecture-specific hardware acceleration
|
||||
"""
|
||||
authors = ["RustCrypto Developers"]
|
||||
edition = "2021"
|
||||
license = "Apache-2.0 OR MIT"
|
||||
readme = "README.md"
|
||||
documentation = "https://docs.rs/aes-gcm"
|
||||
repository = "https://github.com/RustCrypto/AEADs"
|
||||
keywords = ["aead", "aes", "encryption", "gcm", "ghash"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
rust-version = "1.56"
|
||||
|
||||
[dependencies]
|
||||
aead = { version = "0.5", default-features = false }
|
||||
aes = { version = "0.8", optional = true }
|
||||
cipher = "0.4"
|
||||
ctr = "0.9"
|
||||
ghash = { version = "0.5", default-features = false }
|
||||
subtle = { version = "2", default-features = false }
|
||||
zeroize = { version = "1", optional = true, default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
aead = { version = "0.5", features = ["dev"], default-features = false }
|
||||
hex-literal = "0.3"
|
||||
|
||||
[features]
|
||||
default = ["aes", "alloc", "getrandom"]
|
||||
std = ["aead/std", "alloc"]
|
||||
alloc = ["aead/alloc"]
|
||||
arrayvec = ["aead/arrayvec"]
|
||||
getrandom = ["aead/getrandom", "rand_core"]
|
||||
heapless = ["aead/heapless"]
|
||||
rand_core = ["aead/rand_core"]
|
||||
stream = ["aead/stream"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
201
.gear/predownloaded-development/vendor/aes-gcm/LICENSE-APACHE
vendored
Normal file
201
.gear/predownloaded-development/vendor/aes-gcm/LICENSE-APACHE
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
25
.gear/predownloaded-development/vendor/aes-gcm/LICENSE-MIT
vendored
Normal file
25
.gear/predownloaded-development/vendor/aes-gcm/LICENSE-MIT
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2019 The RustCrypto Project Developers
|
||||
|
||||
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.
|
||||
61
.gear/predownloaded-development/vendor/aes-gcm/README.md
vendored
Normal file
61
.gear/predownloaded-development/vendor/aes-gcm/README.md
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# RustCrypto: AES-GCM
|
||||
|
||||
[![crate][crate-image]][crate-link]
|
||||
[![Docs][docs-image]][docs-link]
|
||||
![Apache2/MIT licensed][license-image]
|
||||
![Rust Version][rustc-image]
|
||||
[![Project Chat][chat-image]][chat-link]
|
||||
[![Build Status][build-image]][build-link]
|
||||
|
||||
Pure Rust implementation of the AES-GCM
|
||||
[Authenticated Encryption with Associated Data (AEAD)][1] cipher.
|
||||
|
||||
[Documentation][docs-link]
|
||||
|
||||
## Security Notes
|
||||
|
||||
This crate has received one [security audit by NCC Group][2], with no significant
|
||||
findings. We would like to thank [MobileCoin][3] for funding the audit.
|
||||
|
||||
All implementations contained in the crate are designed to execute in constant
|
||||
time, either by relying on hardware intrinsics (i.e. AES-NI and CLMUL on
|
||||
x86/x86_64), or using a portable implementation which is only constant time
|
||||
on processors which implement constant-time multiplication.
|
||||
|
||||
It is not suitable for use on processors with a variable-time multiplication
|
||||
operation (e.g. short circuit on multiply-by-zero / multiply-by-one, such as
|
||||
certain 32-bit PowerPC CPUs and some non-ARM microcontrollers).
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of:
|
||||
|
||||
* [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* [MIT license](http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
||||
|
||||
[//]: # (badges)
|
||||
|
||||
[crate-image]: https://buildstats.info/crate/aes-gcm
|
||||
[crate-link]: https://crates.io/crates/aes-gcm
|
||||
[docs-image]: https://docs.rs/aes-gcm/badge.svg
|
||||
[docs-link]: https://docs.rs/aes-gcm/
|
||||
[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
|
||||
[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg
|
||||
[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
|
||||
[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260038-AEADs
|
||||
[build-image]: https://github.com/RustCrypto/AEADs/workflows/aes-gcm/badge.svg?branch=master&event=push
|
||||
[build-link]: https://github.com/RustCrypto/AEADs/actions
|
||||
|
||||
[//]: # (general links)
|
||||
|
||||
[1]: https://en.wikipedia.org/wiki/Authenticated_encryption
|
||||
[2]: https://research.nccgroup.com/2020/02/26/public-report-rustcrypto-aes-gcm-and-chacha20poly1305-implementation-review/
|
||||
[3]: https://www.mobilecoin.com/
|
||||
373
.gear/predownloaded-development/vendor/aes-gcm/src/lib.rs
vendored
Normal file
373
.gear/predownloaded-development/vendor/aes-gcm/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
#![no_std]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
|
||||
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
|
||||
)]
|
||||
#![deny(unsafe_code)]
|
||||
#![warn(missing_docs, rust_2018_idioms)]
|
||||
|
||||
//! # Usage
|
||||
//!
|
||||
//! Simple usage (allocating, no associated data):
|
||||
//!
|
||||
//! ```
|
||||
//! use aes_gcm::{
|
||||
//! aead::{Aead, AeadCore, KeyInit, OsRng},
|
||||
//! Aes256Gcm, Nonce, Key // Or `Aes128Gcm`
|
||||
//! };
|
||||
//!
|
||||
//! # fn gen_key() -> Result<(), core::array::TryFromSliceError> {
|
||||
//! // The encryption key can be generated randomly:
|
||||
//! # #[cfg(all(feature = "getrandom", feature = "std"))] {
|
||||
//! let key = Aes256Gcm::generate_key(OsRng);
|
||||
//! # }
|
||||
//!
|
||||
//! // Transformed from a byte array:
|
||||
//! let key: &[u8; 32] = &[42; 32];
|
||||
//! let key: &Key<Aes256Gcm> = key.into();
|
||||
//!
|
||||
//! // Note that you can get byte array from slice using the `TryInto` trait:
|
||||
//! let key: &[u8] = &[42; 32];
|
||||
//! let key: [u8; 32] = key.try_into()?;
|
||||
//! # Ok(()) }
|
||||
//!
|
||||
//! # fn main() -> Result<(), aes_gcm::Error> {
|
||||
//! // Alternatively, the key can be transformed directly from a byte slice
|
||||
//! // (panicks on length mismatch):
|
||||
//! # let key: &[u8] = &[42; 32];
|
||||
//! let key = Key::<Aes256Gcm>::from_slice(key);
|
||||
//!
|
||||
//! let cipher = Aes256Gcm::new(&key);
|
||||
//! let nonce = Aes256Gcm::generate_nonce(&mut OsRng); // 96-bits; unique per message
|
||||
//! let ciphertext = cipher.encrypt(&nonce, b"plaintext message".as_ref())?;
|
||||
//! let plaintext = cipher.decrypt(&nonce, ciphertext.as_ref())?;
|
||||
//! assert_eq!(&plaintext, b"plaintext message");
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! ## In-place Usage (eliminates `alloc` requirement)
|
||||
//!
|
||||
//! This crate has an optional `alloc` feature which can be disabled in e.g.
|
||||
//! microcontroller environments that don't have a heap.
|
||||
//!
|
||||
//! The [`AeadInPlace::encrypt_in_place`] and [`AeadInPlace::decrypt_in_place`]
|
||||
//! methods accept any type that impls the [`aead::Buffer`] trait which
|
||||
//! contains the plaintext for encryption or ciphertext for decryption.
|
||||
//!
|
||||
//! Note that if you enable the `heapless` feature of this crate,
|
||||
//! you will receive an impl of [`aead::Buffer`] for `heapless::Vec`
|
||||
//! (re-exported from the [`aead`] crate as [`aead::heapless::Vec`]),
|
||||
//! which can then be passed as the `buffer` parameter to the in-place encrypt
|
||||
//! and decrypt methods:
|
||||
//!
|
||||
#![cfg_attr(
|
||||
all(feature = "getrandom", feature = "heapless", feature = "std"),
|
||||
doc = "```"
|
||||
)]
|
||||
#![cfg_attr(
|
||||
not(all(feature = "getrandom", feature = "heapless", feature = "std")),
|
||||
doc = "```ignore"
|
||||
)]
|
||||
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! use aes_gcm::{
|
||||
//! aead::{AeadCore, AeadInPlace, KeyInit, OsRng, heapless::Vec},
|
||||
//! Aes256Gcm, Nonce, // Or `Aes128Gcm`
|
||||
//! };
|
||||
//!
|
||||
//! let key = Aes256Gcm::generate_key(&mut OsRng);
|
||||
//! let cipher = Aes256Gcm::new(&key);
|
||||
//! let nonce = Aes256Gcm::generate_nonce(&mut OsRng); // 96-bits; unique per message
|
||||
//!
|
||||
//! let mut buffer: Vec<u8, 128> = Vec::new(); // Note: buffer needs 16-bytes overhead for auth tag
|
||||
//! buffer.extend_from_slice(b"plaintext message");
|
||||
//!
|
||||
//! // Encrypt `buffer` in-place, replacing the plaintext contents with ciphertext
|
||||
//! cipher.encrypt_in_place(&nonce, b"", &mut buffer)?;
|
||||
//!
|
||||
//! // `buffer` now contains the message ciphertext
|
||||
//! assert_ne!(&buffer, b"plaintext message");
|
||||
//!
|
||||
//! // Decrypt `buffer` in-place, replacing its ciphertext context with the original plaintext
|
||||
//! cipher.decrypt_in_place(&nonce, b"", &mut buffer)?;
|
||||
//! assert_eq!(&buffer, b"plaintext message");
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! Similarly, enabling the `arrayvec` feature of this crate will provide an impl of
|
||||
//! [`aead::Buffer`] for `arrayvec::ArrayVec` (re-exported from the [`aead`] crate as
|
||||
//! [`aead::arrayvec::ArrayVec`]).
|
||||
|
||||
pub use aead::{self, AeadCore, AeadInPlace, Error, Key, KeyInit, KeySizeUser};
|
||||
|
||||
#[cfg(feature = "aes")]
|
||||
pub use aes;
|
||||
|
||||
use cipher::{
|
||||
consts::{U0, U16},
|
||||
generic_array::{ArrayLength, GenericArray},
|
||||
BlockCipher, BlockEncrypt, BlockSizeUser, InnerIvInit, StreamCipherCore,
|
||||
};
|
||||
use core::marker::PhantomData;
|
||||
use ghash::{universal_hash::UniversalHash, GHash};
|
||||
|
||||
#[cfg(feature = "zeroize")]
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[cfg(feature = "aes")]
|
||||
use aes::{cipher::consts::U12, Aes128, Aes256};
|
||||
|
||||
/// Maximum length of associated data.
|
||||
pub const A_MAX: u64 = 1 << 36;
|
||||
|
||||
/// Maximum length of plaintext.
|
||||
pub const P_MAX: u64 = 1 << 36;
|
||||
|
||||
/// Maximum length of ciphertext.
|
||||
pub const C_MAX: u64 = (1 << 36) + 16;
|
||||
|
||||
/// AES-GCM nonces.
|
||||
pub type Nonce<NonceSize> = GenericArray<u8, NonceSize>;
|
||||
|
||||
/// AES-GCM tags.
|
||||
pub type Tag<TagSize = U16> = GenericArray<u8, TagSize>;
|
||||
|
||||
/// Trait implemented for valid tag sizes, i.e.
|
||||
/// [`U12`][consts::U12], [`U13`][consts::U13], [`U14`][consts::U14],
|
||||
/// [`U15`][consts::U15] and [`U16`][consts::U16].
|
||||
pub trait TagSize: private::SealedTagSize {}
|
||||
|
||||
impl<T: private::SealedTagSize> TagSize for T {}
|
||||
|
||||
mod private {
|
||||
use aead::generic_array::ArrayLength;
|
||||
use cipher::{consts, Unsigned};
|
||||
|
||||
// Sealed traits stop other crates from implementing any traits that use it.
|
||||
pub trait SealedTagSize: ArrayLength<u8> + Unsigned {}
|
||||
|
||||
impl SealedTagSize for consts::U12 {}
|
||||
impl SealedTagSize for consts::U13 {}
|
||||
impl SealedTagSize for consts::U14 {}
|
||||
impl SealedTagSize for consts::U15 {}
|
||||
impl SealedTagSize for consts::U16 {}
|
||||
}
|
||||
|
||||
/// AES-GCM with a 128-bit key and 96-bit nonce.
|
||||
#[cfg(feature = "aes")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "aes")))]
|
||||
pub type Aes128Gcm = AesGcm<Aes128, U12>;
|
||||
|
||||
/// AES-GCM with a 256-bit key and 96-bit nonce.
|
||||
#[cfg(feature = "aes")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "aes")))]
|
||||
pub type Aes256Gcm = AesGcm<Aes256, U12>;
|
||||
|
||||
/// AES block.
|
||||
type Block = GenericArray<u8, U16>;
|
||||
|
||||
/// Counter mode with a 32-bit big endian counter.
|
||||
type Ctr32BE<Aes> = ctr::CtrCore<Aes, ctr::flavors::Ctr32BE>;
|
||||
|
||||
/// AES-GCM: generic over an underlying AES implementation and nonce size.
|
||||
///
|
||||
/// This type is generic to support substituting alternative AES implementations
|
||||
/// (e.g. embedded hardware implementations)
|
||||
///
|
||||
/// It is NOT intended to be instantiated with any block cipher besides AES!
|
||||
/// Doing so runs the risk of unintended cryptographic properties!
|
||||
///
|
||||
/// The `NonceSize` generic parameter can be used to instantiate AES-GCM with other
|
||||
/// nonce sizes, however it's recommended to use it with `typenum::U12`,
|
||||
/// the default of 96-bits.
|
||||
///
|
||||
/// The `TagSize` generic parameter can be used to instantiate AES-GCM with other
|
||||
/// authorization tag sizes, however it's recommended to use it with `typenum::U16`,
|
||||
/// the default of 128-bits.
|
||||
///
|
||||
/// If in doubt, use the built-in [`Aes128Gcm`] and [`Aes256Gcm`] type aliases.
|
||||
#[derive(Clone)]
|
||||
pub struct AesGcm<Aes, NonceSize, TagSize = U16>
|
||||
where
|
||||
TagSize: self::TagSize,
|
||||
{
|
||||
/// Encryption cipher.
|
||||
cipher: Aes,
|
||||
|
||||
/// GHASH authenticator.
|
||||
ghash: GHash,
|
||||
|
||||
/// Length of the nonce.
|
||||
nonce_size: PhantomData<NonceSize>,
|
||||
|
||||
/// Length of the tag.
|
||||
tag_size: PhantomData<TagSize>,
|
||||
}
|
||||
|
||||
impl<Aes, NonceSize, TagSize> KeySizeUser for AesGcm<Aes, NonceSize, TagSize>
|
||||
where
|
||||
Aes: KeySizeUser,
|
||||
TagSize: self::TagSize,
|
||||
{
|
||||
type KeySize = Aes::KeySize;
|
||||
}
|
||||
|
||||
impl<Aes, NonceSize, TagSize> KeyInit for AesGcm<Aes, NonceSize, TagSize>
|
||||
where
|
||||
Aes: BlockSizeUser<BlockSize = U16> + BlockEncrypt + KeyInit,
|
||||
TagSize: self::TagSize,
|
||||
{
|
||||
fn new(key: &Key<Self>) -> Self {
|
||||
Aes::new(key).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Aes, NonceSize, TagSize> From<Aes> for AesGcm<Aes, NonceSize, TagSize>
|
||||
where
|
||||
Aes: BlockSizeUser<BlockSize = U16> + BlockEncrypt,
|
||||
TagSize: self::TagSize,
|
||||
{
|
||||
fn from(cipher: Aes) -> Self {
|
||||
let mut ghash_key = ghash::Key::default();
|
||||
cipher.encrypt_block(&mut ghash_key);
|
||||
|
||||
let ghash = GHash::new(&ghash_key);
|
||||
|
||||
#[cfg(feature = "zeroize")]
|
||||
ghash_key.zeroize();
|
||||
|
||||
Self {
|
||||
cipher,
|
||||
ghash,
|
||||
nonce_size: PhantomData,
|
||||
tag_size: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Aes, NonceSize, TagSize> AeadCore for AesGcm<Aes, NonceSize, TagSize>
|
||||
where
|
||||
NonceSize: ArrayLength<u8>,
|
||||
TagSize: self::TagSize,
|
||||
{
|
||||
type NonceSize = NonceSize;
|
||||
type TagSize = TagSize;
|
||||
type CiphertextOverhead = U0;
|
||||
}
|
||||
|
||||
impl<Aes, NonceSize, TagSize> AeadInPlace for AesGcm<Aes, NonceSize, TagSize>
|
||||
where
|
||||
Aes: BlockCipher + BlockSizeUser<BlockSize = U16> + BlockEncrypt,
|
||||
NonceSize: ArrayLength<u8>,
|
||||
TagSize: self::TagSize,
|
||||
{
|
||||
fn encrypt_in_place_detached(
|
||||
&self,
|
||||
nonce: &Nonce<NonceSize>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut [u8],
|
||||
) -> Result<Tag<TagSize>, Error> {
|
||||
if buffer.len() as u64 > P_MAX || associated_data.len() as u64 > A_MAX {
|
||||
return Err(Error);
|
||||
}
|
||||
|
||||
let (ctr, mask) = self.init_ctr(nonce);
|
||||
|
||||
// TODO(tarcieri): interleave encryption with GHASH
|
||||
// See: <https://github.com/RustCrypto/AEADs/issues/74>
|
||||
ctr.apply_keystream_partial(buffer.into());
|
||||
|
||||
let full_tag = self.compute_tag(mask, associated_data, buffer);
|
||||
Ok(Tag::clone_from_slice(&full_tag[..TagSize::to_usize()]))
|
||||
}
|
||||
|
||||
fn decrypt_in_place_detached(
|
||||
&self,
|
||||
nonce: &Nonce<NonceSize>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut [u8],
|
||||
tag: &Tag<TagSize>,
|
||||
) -> Result<(), Error> {
|
||||
if buffer.len() as u64 > C_MAX || associated_data.len() as u64 > A_MAX {
|
||||
return Err(Error);
|
||||
}
|
||||
|
||||
let (ctr, mask) = self.init_ctr(nonce);
|
||||
|
||||
// TODO(tarcieri): interleave encryption with GHASH
|
||||
// See: <https://github.com/RustCrypto/AEADs/issues/74>
|
||||
let expected_tag = self.compute_tag(mask, associated_data, buffer);
|
||||
|
||||
use subtle::ConstantTimeEq;
|
||||
if expected_tag[..TagSize::to_usize()].ct_eq(tag).into() {
|
||||
ctr.apply_keystream_partial(buffer.into());
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Aes, NonceSize, TagSize> AesGcm<Aes, NonceSize, TagSize>
|
||||
where
|
||||
Aes: BlockCipher + BlockSizeUser<BlockSize = U16> + BlockEncrypt,
|
||||
NonceSize: ArrayLength<u8>,
|
||||
TagSize: self::TagSize,
|
||||
{
|
||||
/// Initialize counter mode.
|
||||
///
|
||||
/// See algorithm described in Section 7.2 of NIST SP800-38D:
|
||||
/// <https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf>
|
||||
///
|
||||
/// > Define a block, J0, as follows:
|
||||
/// > If len(IV)=96, then J0 = IV || 0{31} || 1.
|
||||
/// > If len(IV) ≠ 96, then let s = 128 ⎡len(IV)/128⎤-len(IV), and
|
||||
/// > J0=GHASH(IV||0s+64||[len(IV)]64).
|
||||
fn init_ctr(&self, nonce: &Nonce<NonceSize>) -> (Ctr32BE<&Aes>, Block) {
|
||||
let j0 = if NonceSize::to_usize() == 12 {
|
||||
let mut block = ghash::Block::default();
|
||||
block[..12].copy_from_slice(nonce);
|
||||
block[15] = 1;
|
||||
block
|
||||
} else {
|
||||
let mut ghash = self.ghash.clone();
|
||||
ghash.update_padded(nonce);
|
||||
|
||||
let mut block = ghash::Block::default();
|
||||
let nonce_bits = (NonceSize::to_usize() as u64) * 8;
|
||||
block[8..].copy_from_slice(&nonce_bits.to_be_bytes());
|
||||
ghash.update(&[block]);
|
||||
ghash.finalize()
|
||||
};
|
||||
|
||||
let mut ctr = Ctr32BE::inner_iv_init(&self.cipher, &j0);
|
||||
let mut tag_mask = Block::default();
|
||||
ctr.write_keystream_block(&mut tag_mask);
|
||||
(ctr, tag_mask)
|
||||
}
|
||||
|
||||
/// Authenticate the given plaintext and associated data using GHASH.
|
||||
fn compute_tag(&self, mask: Block, associated_data: &[u8], buffer: &[u8]) -> Tag {
|
||||
let mut ghash = self.ghash.clone();
|
||||
ghash.update_padded(associated_data);
|
||||
ghash.update_padded(buffer);
|
||||
|
||||
let associated_data_bits = (associated_data.len() as u64) * 8;
|
||||
let buffer_bits = (buffer.len() as u64) * 8;
|
||||
|
||||
let mut block = ghash::Block::default();
|
||||
block[..8].copy_from_slice(&associated_data_bits.to_be_bytes());
|
||||
block[8..].copy_from_slice(&buffer_bits.to_be_bytes());
|
||||
ghash.update(&[block]);
|
||||
|
||||
let mut tag = ghash.finalize();
|
||||
for (a, b) in tag.as_mut_slice().iter_mut().zip(mask.as_slice()) {
|
||||
*a ^= *b;
|
||||
}
|
||||
|
||||
tag
|
||||
}
|
||||
}
|
||||
3022
.gear/predownloaded-development/vendor/aes-gcm/tests/aes128gcm.rs
vendored
Normal file
3022
.gear/predownloaded-development/vendor/aes-gcm/tests/aes128gcm.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
3022
.gear/predownloaded-development/vendor/aes-gcm/tests/aes256gcm.rs
vendored
Normal file
3022
.gear/predownloaded-development/vendor/aes-gcm/tests/aes256gcm.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
97
.gear/predownloaded-development/vendor/aes-gcm/tests/common/mod.rs
vendored
Normal file
97
.gear/predownloaded-development/vendor/aes-gcm/tests/common/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
//! Common functionality shared by tests
|
||||
|
||||
/// Test vectors
|
||||
#[derive(Debug)]
|
||||
pub struct TestVector<K: 'static> {
|
||||
pub key: &'static K,
|
||||
pub nonce: &'static [u8; 12],
|
||||
pub aad: &'static [u8],
|
||||
pub plaintext: &'static [u8],
|
||||
pub ciphertext: &'static [u8],
|
||||
pub tag: &'static [u8; 16],
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! tests {
|
||||
($aead:ty, $vectors:expr) => {
|
||||
#[test]
|
||||
fn encrypt() {
|
||||
for vector in $vectors {
|
||||
let key = GenericArray::from_slice(vector.key);
|
||||
let nonce = GenericArray::from_slice(vector.nonce);
|
||||
let payload = Payload {
|
||||
msg: vector.plaintext,
|
||||
aad: vector.aad,
|
||||
};
|
||||
|
||||
let cipher = <$aead>::new(key);
|
||||
let ciphertext = cipher.encrypt(nonce, payload).unwrap();
|
||||
let (ct, tag) = ciphertext.split_at(ciphertext.len() - 16);
|
||||
assert_eq!(vector.ciphertext, ct);
|
||||
assert_eq!(vector.tag, tag);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decrypt() {
|
||||
for vector in $vectors {
|
||||
let key = GenericArray::from_slice(vector.key);
|
||||
let nonce = GenericArray::from_slice(vector.nonce);
|
||||
let mut ciphertext = Vec::from(vector.ciphertext);
|
||||
ciphertext.extend_from_slice(vector.tag);
|
||||
|
||||
let payload = Payload {
|
||||
msg: &ciphertext,
|
||||
aad: vector.aad,
|
||||
};
|
||||
|
||||
let cipher = <$aead>::new(key);
|
||||
let plaintext = cipher.decrypt(nonce, payload).unwrap();
|
||||
|
||||
assert_eq!(vector.plaintext, plaintext.as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decrypt_modified() {
|
||||
let vector = &$vectors[0];
|
||||
let key = GenericArray::from_slice(vector.key);
|
||||
let nonce = GenericArray::from_slice(vector.nonce);
|
||||
|
||||
let mut ciphertext = Vec::from(vector.ciphertext);
|
||||
ciphertext.extend_from_slice(vector.tag);
|
||||
|
||||
// Tweak the first byte
|
||||
ciphertext[0] ^= 0xaa;
|
||||
|
||||
let payload = Payload {
|
||||
msg: &ciphertext,
|
||||
aad: vector.aad,
|
||||
};
|
||||
|
||||
let cipher = <$aead>::new(key);
|
||||
assert!(cipher.decrypt(nonce, payload).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decrypt_in_place_detached_modified() {
|
||||
let vector = &$vectors.iter().last().unwrap();
|
||||
let key = GenericArray::from_slice(vector.key);
|
||||
let nonce = GenericArray::from_slice(vector.nonce);
|
||||
|
||||
let mut buffer = Vec::from(vector.ciphertext);
|
||||
assert!(!buffer.is_empty());
|
||||
|
||||
// Tweak the first byte
|
||||
let mut tag = GenericArray::clone_from_slice(vector.tag);
|
||||
tag[0] ^= 0xaa;
|
||||
|
||||
let cipher = <$aead>::new(key);
|
||||
assert!(cipher
|
||||
.decrypt_in_place_detached(nonce, &[], &mut buffer, &tag)
|
||||
.is_err());
|
||||
|
||||
assert_eq!(vector.ciphertext, buffer);
|
||||
}
|
||||
};
|
||||
}
|
||||
BIN
.gear/predownloaded-development/vendor/aes-gcm/tests/data/wycheproof-128.blb
vendored
Normal file
BIN
.gear/predownloaded-development/vendor/aes-gcm/tests/data/wycheproof-128.blb
vendored
Normal file
Binary file not shown.
BIN
.gear/predownloaded-development/vendor/aes-gcm/tests/data/wycheproof-256.blb
vendored
Normal file
BIN
.gear/predownloaded-development/vendor/aes-gcm/tests/data/wycheproof-256.blb
vendored
Normal file
Binary file not shown.
77
.gear/predownloaded-development/vendor/aes-gcm/tests/other_ivlen.rs
vendored
Normal file
77
.gear/predownloaded-development/vendor/aes-gcm/tests/other_ivlen.rs
vendored
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
//! Tests for AES-GCM when used with non-96-bit nonces.
|
||||
//!
|
||||
//! Vectors taken from NIST CAVS vectors' `gcmEncryptExtIV128.rsp` file:
|
||||
//! <https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/CAVP-TESTING-BLOCK-CIPHER-MODES>
|
||||
|
||||
use aead::{
|
||||
generic_array::{typenum, GenericArray},
|
||||
Aead, KeyInit,
|
||||
};
|
||||
use aes::Aes128;
|
||||
use aes_gcm::AesGcm;
|
||||
use hex_literal::hex;
|
||||
|
||||
/// Based on the following `gcmEncryptExtIV128.rsp` test vector:
|
||||
///
|
||||
/// [Keylen = 128]
|
||||
/// [IVlen = 8]
|
||||
/// [PTlen = 128]
|
||||
/// [AADlen = 0]
|
||||
/// [Taglen = 128]
|
||||
///
|
||||
/// Count = 0
|
||||
mod ivlen8 {
|
||||
use super::*;
|
||||
|
||||
type Aes128GcmWith8BitNonce = AesGcm<Aes128, typenum::U1>;
|
||||
|
||||
#[test]
|
||||
fn encrypt() {
|
||||
let key = hex!("15b2d414826453f9e1c7dd0b69d8d1eb");
|
||||
let nonce = hex!("b6");
|
||||
let plaintext = hex!("8cfa255530c6fbc19d51bd4aeb39c91b");
|
||||
|
||||
let ciphertext = Aes128GcmWith8BitNonce::new(&key.into())
|
||||
.encrypt(GenericArray::from_slice(&nonce), &plaintext[..])
|
||||
.unwrap();
|
||||
|
||||
let (ct, tag) = ciphertext.split_at(ciphertext.len() - 16);
|
||||
assert_eq!(hex!("4822cb98bd5f5d921ee19285c9032375"), ct);
|
||||
assert_eq!(hex!("8a40670ebac98cf4e9cc1bf8f803167d"), tag);
|
||||
}
|
||||
}
|
||||
|
||||
/// Based on the following `gcmEncryptExtIV128.rsp` test vector:
|
||||
///
|
||||
/// [Keylen = 128]
|
||||
/// [IVlen = 1024]
|
||||
/// [PTlen = 128]
|
||||
/// [AADlen = 0]
|
||||
/// [Taglen = 128]
|
||||
///
|
||||
/// Count = 0
|
||||
mod ivlen1024 {
|
||||
use super::*;
|
||||
|
||||
type Aes128GcmWith1024BitNonce = AesGcm<Aes128, typenum::U128>;
|
||||
|
||||
#[test]
|
||||
fn encrypt() {
|
||||
let key = hex!("71eebc49c8fb773b2224eaff3ad68714");
|
||||
let nonce = hex!(
|
||||
"07e961e67784011f72faafd95b0eb64089c8de15ad685ec57e63d56e679d3e20
|
||||
2b18b75fcbbec3185ffc41653bc2ac4ae6ae8be8c85636f353a9d19a86100d0b
|
||||
d035cc6bdefcab4318ac7b1a08b819427ad8f6abc782466c6ebd4d6a0dd76e78
|
||||
389b0a2a66506bb85f038ffc1da220c24f3817c7b2d02c5e8fc5e7e3be5074bc"
|
||||
);
|
||||
let plaintext = hex!("705da82292143d2c949dc4ba014f6396");
|
||||
|
||||
let ciphertext = Aes128GcmWith1024BitNonce::new(&key.into())
|
||||
.encrypt(GenericArray::from_slice(&nonce), &plaintext[..])
|
||||
.unwrap();
|
||||
|
||||
let (ct, tag) = ciphertext.split_at(ciphertext.len() - 16);
|
||||
assert_eq!(hex!("032363cf0828a03553478bec0f51f372"), ct);
|
||||
assert_eq!(hex!("c681b2c568feaa21900bc44b86aeb946"), tag);
|
||||
}
|
||||
}
|
||||
1
.gear/predownloaded-development/vendor/aes/.cargo-checksum.json
vendored
Normal file
1
.gear/predownloaded-development/vendor/aes/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{".cargo_vcs_info.json":"0fcef950ece96a5a772adf08b17fa0027c70619e0b0b0d904e1900365978b387","CHANGELOG.md":"eca699db9c1d803f1dd09b642057b24bcec570c47ad44d5ffd6df2499ea0355a","Cargo.toml":"0e3a91948ceb119a3f36209a8c5a6a7627cd7a09de903b5e606f563276376fed","Cargo.toml.orig":"2ef9247afd1c06e7832dc432bdf02a9467260716310cf8cb248f42b51014c005","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"f7e8ab639afef15573680c97f796166835cbeb3865175882fea41c60d106b733","README.md":"fd8bd9c342defe127d5e751445af9b67ff84de509a3e595c66011909ef8d4428","benches/mod.rs":"dbd545b67721cd5e351c431c0eeb115699c903a2584a3d414ccbb919c44221c2","src/armv8.rs":"bc8ff3cae2f799d849105b79091604e1579ae5e8a8fbe19db24c6ccbf48146a4","src/armv8/encdec.rs":"54f85c5942fbb384c106321fb54aa06f29ae16be87ebce127fd4932a329a4feb","src/armv8/expand.rs":"d40ee141eb7dec4ccb675455ec93fe08a75dfd228bc5339096cfa8d7270ff375","src/armv8/hazmat.rs":"f6d722a53ca464b16b1bc9bb7c23a5780510252cbcb059735e2acf656c5b2cbe","src/armv8/intrinsics.rs":"3192f65da7cac81f3a48601d950c66c72814fa9cacab9a9d8c8969dbae6b098c","src/armv8/test_expand.rs":"7bc04e7fc5bba65f4451c86ba2e80ce98b04faa734f16d28af09660c5623d96a","src/autodetect.rs":"150d63066a8f1a6cac359661752db49d2d5c8d2d5b34cfee413072ff95b9041f","src/hazmat.rs":"7198ef0d62287642cd4d7394295f333fbc69d95938c7541f82f2492ce9bd7d47","src/lib.rs":"8904ed0f1da5d3c6ca6cfb61add4a957054a9f95ce573c3ab198b59ba9ab06cd","src/ni.rs":"15b9a67dbedc3b558ddec063489be4a6607e568afddd8345506be36952fc3bde","src/ni/aes128.rs":"88b94c99163b6b82810d7817e02374ddca4086b0896a8ebe183241a604ec92be","src/ni/aes192.rs":"156254b46e469a20e09a1cefa22bae2afd9c10e2b68fd2bf40eaf9a05095cdda","src/ni/aes256.rs":"f9fba1a4ac1e91fc908f3164460fc531f91cf0b0d015b3463056d0bd97981eae","src/ni/hazmat.rs":"eeeb4a8cd92204095ecef3d40e1786dede05b63afba41c9fa3e9b871f40eb6d8","src/ni/test_expand.rs":"6ad46711aeb49c21144ea31f801493ab87d3cb19d35bb3610657bfadfa75d044","src/ni/utils.rs":"10fe6c0ad778a59cde5cef6cb6bc478cc68d21e28bda9331ced3c26b0a732426","src/soft.rs":"3a84211717fdc86a2b0f0d9086f33410bee2ff9be480f50c981980f678a0c2a8","src/soft/fixslice32.rs":"c69c0fa430cb62c4d88a13d5c3387202e1962b47978a6a7026bd34789f2d2577","src/soft/fixslice64.rs":"b071d85916e4e09da703168eb7cebc2ba4c4ab2b783713b8caf9541742b741e3","tests/data/aes128.blb":"96bd534f5025089a88d1062d666e1228fc507334b61f08ba9033d3e85e36a356","tests/data/aes192.blb":"4361e569dd7413058b1c73b89eeff9db1f7fd199c36f21a2e63c6a667f81d23d","tests/data/aes256.blb":"28c4f1e84e188645a59077f1304816d18ff1115f974a46eea19ab76a26ef467e","tests/hazmat.rs":"c74cc6eb51f1064222206e9ae7a21fafc9188dd3ba3d3cde7aeb4f9e388cd1ce","tests/mod.rs":"33a9de6d44d892e24c6fdd58b584d1d7f625adefce065a2c4134095177d3d723"},"package":"b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"}
|
||||
6
.gear/predownloaded-development/vendor/aes/.cargo_vcs_info.json
vendored
Normal file
6
.gear/predownloaded-development/vendor/aes/.cargo_vcs_info.json
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"git": {
|
||||
"sha1": "f2dbee516b4d0cf4cb4f3045d09e35b5fd80087b"
|
||||
},
|
||||
"path_in_vcs": "aes"
|
||||
}
|
||||
146
.gear/predownloaded-development/vendor/aes/CHANGELOG.md
vendored
Normal file
146
.gear/predownloaded-development/vendor/aes/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.8.4 (2024-02-13)
|
||||
### Changed
|
||||
- Assert soundness preconditions for ARMv8 key expansion ([#407], [#408])
|
||||
|
||||
[#407]: https://github.com/RustCrypto/block-ciphers/pull/407
|
||||
[#408]: https://github.com/RustCrypto/block-ciphers/pull/408
|
||||
|
||||
## 0.8.3 (2023-06-17)
|
||||
### Added
|
||||
- Support `aes_armv8` on Rust 1.61+ using `asm!` ([#365])
|
||||
|
||||
[#365]: https://github.com/RustCrypto/block-ciphers/pull/365
|
||||
|
||||
## 0.8.2 (2022-10-27)
|
||||
### Fixed
|
||||
- Crate documentation around configuration flags ([#343])
|
||||
|
||||
[#343]: https://github.com/RustCrypto/block-ciphers/pull/343
|
||||
|
||||
## 0.8.1 (2022-02-17)
|
||||
### Fixed
|
||||
- Minimal versions build ([#303])
|
||||
|
||||
[#303]: https://github.com/RustCrypto/block-ciphers/pull/303
|
||||
|
||||
## 0.8.0 (2022-02-10)
|
||||
### Changed
|
||||
- Bump `cipher` dependency to v0.4 ([#284])
|
||||
|
||||
### Added
|
||||
- Encrypt-only and decrypt-only cipher types ([#284])
|
||||
|
||||
[#284]: https://github.com/RustCrypto/block-ciphers/pull/284
|
||||
|
||||
## 0.7.5 (2021-08-26)
|
||||
### Changed
|
||||
- Bump `ctr` dependency to v0.8 ([#275])
|
||||
- Use the `aes` target feature instead of `crypto` on ARMv8 ([#279])
|
||||
- Use `core::arch::aarch64::vst1q_u8` intrinsic on `armv8` ([#280])
|
||||
- Bump `cpufeatures` dependency to v0.2 ([#281])
|
||||
|
||||
[#275]: https://github.com/RustCrypto/block-ciphers/pull/275
|
||||
[#279]: https://github.com/RustCrypto/block-ciphers/pull/279
|
||||
[#280]: https://github.com/RustCrypto/block-ciphers/pull/280
|
||||
[#281]: https://github.com/RustCrypto/block-ciphers/pull/281
|
||||
|
||||
## 0.7.4 (2021-06-01)
|
||||
### Added
|
||||
- Soft `hazmat` backend ([#267], [#268])
|
||||
- Parallel `hazmat` APIs ([#269])
|
||||
|
||||
[#267]: https://github.com/RustCrypto/block-ciphers/pull/267
|
||||
[#268]: https://github.com/RustCrypto/block-ciphers/pull/268
|
||||
[#269]: https://github.com/RustCrypto/block-ciphers/pull/269
|
||||
|
||||
## 0.7.3 (2021-05-26)
|
||||
### Added
|
||||
- `hazmat` feature/module providing round function access ([#257], [#259], [#260])
|
||||
- `BLOCK_SIZE` constant ([#263])
|
||||
|
||||
[#257]: https://github.com/RustCrypto/block-ciphers/pull/257
|
||||
[#259]: https://github.com/RustCrypto/block-ciphers/pull/259
|
||||
[#260]: https://github.com/RustCrypto/block-ciphers/pull/260
|
||||
[#263]: https://github.com/RustCrypto/block-ciphers/pull/263
|
||||
|
||||
## 0.7.2 (2021-05-17)
|
||||
### Added
|
||||
- Nightly-only ARMv8 intrinsics support gated under the `armv8` feature ([#250])
|
||||
|
||||
[#250]: https://github.com/RustCrypto/block-ciphers/pull/250
|
||||
|
||||
## 0.7.1 (2021-05-09)
|
||||
### Fixed
|
||||
- Restore `fixslice64.rs` ([#247])
|
||||
|
||||
[#247]: https://github.com/RustCrypto/block-ciphers/pull/247
|
||||
|
||||
## 0.7.0 (2021-04-29)
|
||||
### Added
|
||||
- Auto-detection support for AES-NI; MSRV 1.49+ ([#208], [#214], [#215], [#216])
|
||||
- `ctr` feature providing SIMD accelerated AES-CTR ([#200])
|
||||
|
||||
### Changed
|
||||
- Unify the `aes`, `aesni`, `aes-ctr`, and `aes-soft` crates ([#200])
|
||||
- Use `cfg-if` crate ([#203])
|
||||
- Rename `semi_fixslice` feature to `compact` ([#204])
|
||||
- Refactor NI backend ([#224], [#225])
|
||||
- Bump `cipher` crate dependency to v0.3 ([#235])
|
||||
- Bump `ctr` crate dependency to v0.7 ([#237])
|
||||
|
||||
[#200]: https://github.com/RustCrypto/block-ciphers/pull/200
|
||||
[#203]: https://github.com/RustCrypto/block-ciphers/pull/203
|
||||
[#204]: https://github.com/RustCrypto/block-ciphers/pull/204
|
||||
[#208]: https://github.com/RustCrypto/block-ciphers/pull/208
|
||||
[#214]: https://github.com/RustCrypto/block-ciphers/pull/214
|
||||
[#215]: https://github.com/RustCrypto/block-ciphers/pull/215
|
||||
[#216]: https://github.com/RustCrypto/block-ciphers/pull/216
|
||||
[#224]: https://github.com/RustCrypto/block-ciphers/pull/224
|
||||
[#225]: https://github.com/RustCrypto/block-ciphers/pull/225
|
||||
[#235]: https://github.com/RustCrypto/block-ciphers/pull/235
|
||||
[#237]: https://github.com/RustCrypto/block-ciphers/pull/237
|
||||
|
||||
## 0.6.0 (2020-10-16)
|
||||
### Changed
|
||||
- Replace `block-cipher`/`stream-cipher` with `cipher` crate ([#167])
|
||||
|
||||
[#167]: https://github.com/RustCrypto/block-ciphers/pull/167
|
||||
|
||||
## 0.5.1 (2020-08-25)
|
||||
### Changed
|
||||
- Bump `aesni` dependency to v0.9 ([#158])
|
||||
|
||||
[#158]: https://github.com/RustCrypto/block-ciphers/pull/158
|
||||
|
||||
## 0.5.0 (2020-08-07)
|
||||
### Changed
|
||||
- Bump `block-cipher` dependency to v0.8 ([#138])
|
||||
- Bump `opaque-debug` dependency to v0.3 ([#140])
|
||||
|
||||
[#138]: https://github.com/RustCrypto/block-ciphers/pull/138
|
||||
[#140]: https://github.com/RustCrypto/block-ciphers/pull/140
|
||||
|
||||
## 0.4.0 (2020-06-05)
|
||||
### Changed
|
||||
- Bump `block-cipher` dependency to v0.7 ([#86], [#122])
|
||||
- Update to Rust 2018 edition ([#86])
|
||||
|
||||
[#121]: https://github.com/RustCrypto/block-ciphers/pull/122
|
||||
[#86]: https://github.com/RustCrypto/block-ciphers/pull/86
|
||||
|
||||
## 0.3.2 (2018-11-01)
|
||||
|
||||
## 0.3.1 (2018-10-04)
|
||||
|
||||
## 0.3.0 (2018-10-03)
|
||||
|
||||
## 0.2.0 (2018-07-27)
|
||||
|
||||
## 0.1.0 (2018-06-22)
|
||||
70
.gear/predownloaded-development/vendor/aes/Cargo.toml
vendored
Normal file
70
.gear/predownloaded-development/vendor/aes/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
name = "aes"
|
||||
version = "0.8.4"
|
||||
authors = ["RustCrypto Developers"]
|
||||
description = "Pure Rust implementation of the Advanced Encryption Standard (a.k.a. Rijndael)"
|
||||
documentation = "https://docs.rs/aes"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"crypto",
|
||||
"aes",
|
||||
"rijndael",
|
||||
"block-cipher",
|
||||
]
|
||||
categories = [
|
||||
"cryptography",
|
||||
"no-std",
|
||||
]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/RustCrypto/block-ciphers"
|
||||
resolver = "1"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = [
|
||||
"--cfg",
|
||||
"docsrs",
|
||||
]
|
||||
|
||||
[dependencies.cfg-if]
|
||||
version = "1"
|
||||
|
||||
[dependencies.cipher]
|
||||
version = "0.4.2"
|
||||
|
||||
[dev-dependencies.cipher]
|
||||
version = "0.4.2"
|
||||
features = ["dev"]
|
||||
|
||||
[dev-dependencies.hex-literal]
|
||||
version = "0.3"
|
||||
|
||||
[features]
|
||||
hazmat = []
|
||||
|
||||
[target."cfg(all(aes_armv8, target_arch = \"aarch64\"))".dependencies.zeroize]
|
||||
version = "1.5.6"
|
||||
features = ["aarch64"]
|
||||
optional = true
|
||||
default_features = false
|
||||
|
||||
[target."cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))".dependencies.cpufeatures]
|
||||
version = "0.2"
|
||||
|
||||
[target."cfg(not(all(aes_armv8, target_arch = \"aarch64\")))".dependencies.zeroize]
|
||||
version = "1.6.0"
|
||||
optional = true
|
||||
default_features = false
|
||||
38
.gear/predownloaded-development/vendor/aes/Cargo.toml.orig
generated
vendored
Normal file
38
.gear/predownloaded-development/vendor/aes/Cargo.toml.orig
generated
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
[package]
|
||||
name = "aes"
|
||||
version = "0.8.4"
|
||||
description = "Pure Rust implementation of the Advanced Encryption Standard (a.k.a. Rijndael)"
|
||||
authors = ["RustCrypto Developers"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
readme = "README.md"
|
||||
documentation = "https://docs.rs/aes"
|
||||
repository = "https://github.com/RustCrypto/block-ciphers"
|
||||
keywords = ["crypto", "aes", "rijndael", "block-cipher"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "1"
|
||||
cipher = "0.4.2"
|
||||
|
||||
[target.'cfg(any(target_arch = "aarch64", target_arch = "x86_64", target_arch = "x86"))'.dependencies]
|
||||
cpufeatures = "0.2"
|
||||
|
||||
[target.'cfg(not(all(aes_armv8, target_arch = "aarch64")))'.dependencies]
|
||||
zeroize = { version = "1.6.0", optional = true, default_features = false }
|
||||
|
||||
# TODO(tarcieri): unconditionally enable `aarch64` feature when MSRV is 1.59
|
||||
[target.'cfg(all(aes_armv8, target_arch = "aarch64"))'.dependencies]
|
||||
zeroize = { version = "1.5.6", optional = true, default_features = false, features = ["aarch64"] }
|
||||
|
||||
[dev-dependencies]
|
||||
cipher = { version = "0.4.2", features = ["dev"] }
|
||||
hex-literal = "0.3"
|
||||
|
||||
[features]
|
||||
hazmat = [] # Expose cryptographically hazardous APIs
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
201
.gear/predownloaded-development/vendor/aes/LICENSE-APACHE
vendored
Normal file
201
.gear/predownloaded-development/vendor/aes/LICENSE-APACHE
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
25
.gear/predownloaded-development/vendor/aes/LICENSE-MIT
vendored
Normal file
25
.gear/predownloaded-development/vendor/aes/LICENSE-MIT
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2018 Artyom Pavlov
|
||||
|
||||
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.
|
||||
95
.gear/predownloaded-development/vendor/aes/README.md
vendored
Normal file
95
.gear/predownloaded-development/vendor/aes/README.md
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# RustCrypto: Advanced Encryption Standard (AES)
|
||||
|
||||
[![crate][crate-image]][crate-link]
|
||||
[![Docs][docs-image]][docs-link]
|
||||
![Apache2/MIT licensed][license-image]
|
||||
![Rust Version][rustc-image]
|
||||
[![Project Chat][chat-image]][chat-link]
|
||||
[![Build Status][build-image]][build-link]
|
||||
[![Downloads][downloads-image]][crate-link]
|
||||
[![HAZMAT][hazmat-image]][hazmat-link]
|
||||
|
||||
Pure Rust implementation of the [Advanced Encryption Standard (AES)][1].
|
||||
|
||||
This crate implements the low-level AES block function, and is intended
|
||||
for use for implementing higher-level constructions *only*. It is NOT
|
||||
intended for direct use in applications.
|
||||
|
||||
[Documentation][docs-link]
|
||||
|
||||
<img src="https://raw.githubusercontent.com/RustCrypto/media/85f62bb/img/block-ciphers/aes-round.svg" width="480px">
|
||||
|
||||
## Security
|
||||
|
||||
### ⚠️ Warning: [Hazmat!][hazmat-link]
|
||||
|
||||
This crate does not ensure ciphertexts are authentic (i.e. by using a MAC to
|
||||
verify ciphertext integrity), which can lead to serious vulnerabilities
|
||||
if used incorrectly!
|
||||
|
||||
To avoid this, use an [AEAD][2] mode based on AES, such as [AES-GCM][3] or [AES-GCM-SIV][4].
|
||||
See the [RustCrypto/AEADs][5] repository for more information.
|
||||
|
||||
USE AT YOUR OWN RISK!
|
||||
|
||||
### Notes
|
||||
|
||||
This crate has received one [security audit by NCC Group][6], with no significant
|
||||
findings. We would like to thank [MobileCoin][7] for funding the audit.
|
||||
|
||||
All implementations contained in the crate are designed to execute in constant
|
||||
time, either by relying on hardware intrinsics (i.e. AES-NI on x86/x86_64), or
|
||||
using a portable implementation based on bitslicing.
|
||||
|
||||
## Minimum Supported Rust Version
|
||||
|
||||
Rust **1.56** or higher.
|
||||
|
||||
Minimum supported Rust version can be changed in future releases, but it will
|
||||
be done with a minor version bump.
|
||||
|
||||
## SemVer Policy
|
||||
|
||||
- All on-by-default features of this library are covered by SemVer
|
||||
- MSRV is considered exempt from SemVer as noted above
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of:
|
||||
|
||||
* [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* [MIT license](http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
||||
|
||||
[//]: # (badges)
|
||||
|
||||
[crate-image]: https://img.shields.io/crates/v/aes.svg
|
||||
[crate-link]: https://crates.io/crates/aes
|
||||
[docs-image]: https://docs.rs/aes/badge.svg
|
||||
[docs-link]: https://docs.rs/aes/
|
||||
[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
|
||||
[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg
|
||||
[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
|
||||
[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260039-block-ciphers
|
||||
[build-image]: https://github.com/RustCrypto/block-ciphers/workflows/aes/badge.svg?branch=master&event=push
|
||||
[build-link]: https://github.com/RustCrypto/block-ciphers/actions?query=workflow%3Aaes
|
||||
[downloads-image]: https://img.shields.io/crates/d/aes.svg
|
||||
[hazmat-image]: https://img.shields.io/badge/crypto-hazmat%E2%9A%A0-red.svg
|
||||
[hazmat-link]: https://github.com/RustCrypto/meta/blob/master/HAZMAT.md
|
||||
|
||||
[//]: # (general links)
|
||||
|
||||
[1]: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
|
||||
[2]: https://en.wikipedia.org/wiki/Authenticated_encryption
|
||||
[3]: https://github.com/RustCrypto/AEADs/tree/master/aes-gcm
|
||||
[4]: https://github.com/RustCrypto/AEADs/tree/master/aes-gcm-siv
|
||||
[5]: https://github.com/RustCrypto/AEADs
|
||||
[6]: https://research.nccgroup.com/2020/02/26/public-report-rustcrypto-aes-gcm-and-chacha20poly1305-implementation-review/
|
||||
[7]: https://www.mobilecoin.com/
|
||||
62
.gear/predownloaded-development/vendor/aes/benches/mod.rs
vendored
Normal file
62
.gear/predownloaded-development/vendor/aes/benches/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#![feature(test)]
|
||||
extern crate test;
|
||||
|
||||
use cipher::{block_decryptor_bench, block_encryptor_bench, KeyInit};
|
||||
|
||||
block_encryptor_bench!(
|
||||
Key: aes::Aes128,
|
||||
aes128_encrypt_block,
|
||||
aes128_encrypt_blocks,
|
||||
);
|
||||
block_decryptor_bench!(
|
||||
Key: aes::Aes128,
|
||||
aes128_decrypt_block,
|
||||
aes128_decrypt_blocks,
|
||||
);
|
||||
block_encryptor_bench!(
|
||||
Key: aes::Aes192,
|
||||
aes192_encrypt_block,
|
||||
aes192_encrypt_blocks,
|
||||
);
|
||||
block_decryptor_bench!(
|
||||
Key: aes::Aes192,
|
||||
aes192_decrypt_block,
|
||||
aes192_decrypt_blocks,
|
||||
);
|
||||
block_encryptor_bench!(
|
||||
Key: aes::Aes256,
|
||||
aes256_encrypt_block,
|
||||
aes256_encrypt_blocks,
|
||||
);
|
||||
block_decryptor_bench!(
|
||||
Key: aes::Aes256,
|
||||
aes256_decrypt_block,
|
||||
aes256_decrypt_blocks,
|
||||
);
|
||||
|
||||
#[bench]
|
||||
fn aes128_new(bh: &mut test::Bencher) {
|
||||
bh.iter(|| {
|
||||
let key = test::black_box(Default::default());
|
||||
let cipher = aes::Aes128::new(&key);
|
||||
test::black_box(&cipher);
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn aes192_new(bh: &mut test::Bencher) {
|
||||
bh.iter(|| {
|
||||
let key = test::black_box(Default::default());
|
||||
let cipher = aes::Aes192::new(&key);
|
||||
test::black_box(&cipher);
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn aes256_new(bh: &mut test::Bencher) {
|
||||
bh.iter(|| {
|
||||
let key = test::black_box(Default::default());
|
||||
let cipher = aes::Aes256::new(&key);
|
||||
test::black_box(&cipher);
|
||||
});
|
||||
}
|
||||
343
.gear/predownloaded-development/vendor/aes/src/armv8.rs
vendored
Normal file
343
.gear/predownloaded-development/vendor/aes/src/armv8.rs
vendored
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
//! AES block cipher implementation using the ARMv8 Cryptography Extensions.
|
||||
//!
|
||||
//! Based on this C intrinsics implementation:
|
||||
//! <https://github.com/noloader/AES-Intrinsics/blob/master/aes-arm.c>
|
||||
//!
|
||||
//! Original C written and placed in public domain by Jeffrey Walton.
|
||||
//! Based on code from ARM, and by Johannes Schneiders, Skip Hovsmith and
|
||||
//! Barry O'Rourke for the mbedTLS project.
|
||||
|
||||
#![allow(clippy::needless_range_loop)]
|
||||
|
||||
#[cfg(feature = "hazmat")]
|
||||
pub(crate) mod hazmat;
|
||||
|
||||
mod encdec;
|
||||
mod expand;
|
||||
mod intrinsics;
|
||||
#[cfg(test)]
|
||||
mod test_expand;
|
||||
|
||||
use self::{
|
||||
encdec::{decrypt1, decrypt8, encrypt1, encrypt8},
|
||||
expand::{expand_key, inv_expanded_keys},
|
||||
};
|
||||
use crate::{Block, Block8};
|
||||
use cipher::{
|
||||
consts::{U16, U24, U32, U8},
|
||||
inout::InOut,
|
||||
AlgorithmName, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt, BlockEncrypt,
|
||||
BlockSizeUser, Key, KeyInit, KeySizeUser, ParBlocksSizeUser,
|
||||
};
|
||||
use core::arch::aarch64::*;
|
||||
use core::fmt;
|
||||
|
||||
macro_rules! define_aes_impl {
|
||||
(
|
||||
$name:ident,
|
||||
$name_enc:ident,
|
||||
$name_dec:ident,
|
||||
$name_back_enc:ident,
|
||||
$name_back_dec:ident,
|
||||
$key_size:ty,
|
||||
$rounds:tt,
|
||||
$doc:expr $(,)?
|
||||
) => {
|
||||
#[doc=$doc]
|
||||
#[doc = "block cipher"]
|
||||
#[derive(Clone)]
|
||||
pub struct $name {
|
||||
encrypt: $name_enc,
|
||||
decrypt: $name_dec,
|
||||
}
|
||||
|
||||
impl $name {
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> {
|
||||
self.encrypt.get_enc_backend()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> {
|
||||
self.decrypt.get_dec_backend()
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockCipher for $name {}
|
||||
|
||||
impl KeySizeUser for $name {
|
||||
type KeySize = $key_size;
|
||||
}
|
||||
|
||||
impl KeyInit for $name {
|
||||
#[inline]
|
||||
fn new(key: &Key<Self>) -> Self {
|
||||
let encrypt = $name_enc::new(key);
|
||||
let decrypt = $name_dec::from(&encrypt);
|
||||
Self { encrypt, decrypt }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$name_enc> for $name {
|
||||
#[inline]
|
||||
fn from(encrypt: $name_enc) -> $name {
|
||||
let decrypt = (&encrypt).into();
|
||||
Self { encrypt, decrypt }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&$name_enc> for $name {
|
||||
#[inline]
|
||||
fn from(encrypt: &$name_enc) -> $name {
|
||||
let decrypt = encrypt.into();
|
||||
let encrypt = encrypt.clone();
|
||||
Self { encrypt, decrypt }
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockSizeUser for $name {
|
||||
type BlockSize = U16;
|
||||
}
|
||||
|
||||
impl BlockEncrypt for $name {
|
||||
fn encrypt_with_backend(&self, f: impl BlockClosure<BlockSize = U16>) {
|
||||
self.encrypt.encrypt_with_backend(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockDecrypt for $name {
|
||||
fn decrypt_with_backend(&self, f: impl BlockClosure<BlockSize = U16>) {
|
||||
self.decrypt.decrypt_with_backend(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for $name {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
f.write_str(concat!(stringify!($name), " { .. }"))
|
||||
}
|
||||
}
|
||||
|
||||
impl AlgorithmName for $name {
|
||||
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(stringify!($name))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "zeroize")]
|
||||
impl zeroize::ZeroizeOnDrop for $name {}
|
||||
|
||||
#[doc=$doc]
|
||||
#[doc = "block cipher (encrypt-only)"]
|
||||
#[derive(Clone)]
|
||||
pub struct $name_enc {
|
||||
round_keys: [uint8x16_t; $rounds],
|
||||
}
|
||||
|
||||
impl $name_enc {
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> {
|
||||
$name_back_enc(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockCipher for $name_enc {}
|
||||
|
||||
impl KeySizeUser for $name_enc {
|
||||
type KeySize = $key_size;
|
||||
}
|
||||
|
||||
impl KeyInit for $name_enc {
|
||||
fn new(key: &Key<Self>) -> Self {
|
||||
Self {
|
||||
round_keys: unsafe { expand_key(key.as_ref()) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockSizeUser for $name_enc {
|
||||
type BlockSize = U16;
|
||||
}
|
||||
|
||||
impl BlockEncrypt for $name_enc {
|
||||
fn encrypt_with_backend(&self, f: impl BlockClosure<BlockSize = U16>) {
|
||||
f.call(&mut self.get_enc_backend())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for $name_enc {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
f.write_str(concat!(stringify!($name_enc), " { .. }"))
|
||||
}
|
||||
}
|
||||
|
||||
impl AlgorithmName for $name_enc {
|
||||
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(stringify!($name_enc))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for $name_enc {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
#[cfg(feature = "zeroize")]
|
||||
zeroize::Zeroize::zeroize(&mut self.round_keys);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "zeroize")]
|
||||
impl zeroize::ZeroizeOnDrop for $name_enc {}
|
||||
|
||||
#[doc=$doc]
|
||||
#[doc = "block cipher (decrypt-only)"]
|
||||
#[derive(Clone)]
|
||||
pub struct $name_dec {
|
||||
round_keys: [uint8x16_t; $rounds],
|
||||
}
|
||||
|
||||
impl $name_dec {
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> {
|
||||
$name_back_dec(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockCipher for $name_dec {}
|
||||
|
||||
impl KeySizeUser for $name_dec {
|
||||
type KeySize = $key_size;
|
||||
}
|
||||
|
||||
impl KeyInit for $name_dec {
|
||||
fn new(key: &Key<Self>) -> Self {
|
||||
$name_enc::new(key).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$name_enc> for $name_dec {
|
||||
#[inline]
|
||||
fn from(enc: $name_enc) -> $name_dec {
|
||||
Self::from(&enc)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&$name_enc> for $name_dec {
|
||||
fn from(enc: &$name_enc) -> $name_dec {
|
||||
let mut round_keys = enc.round_keys;
|
||||
unsafe { inv_expanded_keys(&mut round_keys) };
|
||||
Self { round_keys }
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockSizeUser for $name_dec {
|
||||
type BlockSize = U16;
|
||||
}
|
||||
|
||||
impl BlockDecrypt for $name_dec {
|
||||
fn decrypt_with_backend(&self, f: impl BlockClosure<BlockSize = U16>) {
|
||||
f.call(&mut self.get_dec_backend());
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for $name_dec {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
f.write_str(concat!(stringify!($name_dec), " { .. }"))
|
||||
}
|
||||
}
|
||||
|
||||
impl AlgorithmName for $name_dec {
|
||||
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(stringify!($name_dec))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for $name_dec {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
#[cfg(feature = "zeroize")]
|
||||
zeroize::Zeroize::zeroize(&mut self.round_keys);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "zeroize")]
|
||||
impl zeroize::ZeroizeOnDrop for $name_dec {}
|
||||
|
||||
pub(crate) struct $name_back_enc<'a>(&'a $name_enc);
|
||||
|
||||
impl<'a> BlockSizeUser for $name_back_enc<'a> {
|
||||
type BlockSize = U16;
|
||||
}
|
||||
|
||||
impl<'a> ParBlocksSizeUser for $name_back_enc<'a> {
|
||||
type ParBlocksSize = U8;
|
||||
}
|
||||
|
||||
impl<'a> BlockBackend for $name_back_enc<'a> {
|
||||
#[inline(always)]
|
||||
fn proc_block(&mut self, block: InOut<'_, '_, Block>) {
|
||||
unsafe {
|
||||
encrypt1(&self.0.round_keys, block);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn proc_par_blocks(&mut self, blocks: InOut<'_, '_, Block8>) {
|
||||
unsafe { encrypt8(&self.0.round_keys, blocks) }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct $name_back_dec<'a>(&'a $name_dec);
|
||||
|
||||
impl<'a> BlockSizeUser for $name_back_dec<'a> {
|
||||
type BlockSize = U16;
|
||||
}
|
||||
|
||||
impl<'a> ParBlocksSizeUser for $name_back_dec<'a> {
|
||||
type ParBlocksSize = U8;
|
||||
}
|
||||
|
||||
impl<'a> BlockBackend for $name_back_dec<'a> {
|
||||
#[inline(always)]
|
||||
fn proc_block(&mut self, block: InOut<'_, '_, Block>) {
|
||||
unsafe {
|
||||
decrypt1(&self.0.round_keys, block);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn proc_par_blocks(&mut self, blocks: InOut<'_, '_, Block8>) {
|
||||
unsafe { decrypt8(&self.0.round_keys, blocks) }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
define_aes_impl!(
|
||||
Aes128,
|
||||
Aes128Enc,
|
||||
Aes128Dec,
|
||||
Aes128BackEnc,
|
||||
Aes128BackDec,
|
||||
U16,
|
||||
11,
|
||||
"AES-128",
|
||||
);
|
||||
define_aes_impl!(
|
||||
Aes192,
|
||||
Aes192Enc,
|
||||
Aes192Dec,
|
||||
Aes192BackEnc,
|
||||
Aes192BackDec,
|
||||
U24,
|
||||
13,
|
||||
"AES-192",
|
||||
);
|
||||
define_aes_impl!(
|
||||
Aes256,
|
||||
Aes256Enc,
|
||||
Aes256Dec,
|
||||
Aes256BackEnc,
|
||||
Aes256BackDec,
|
||||
U32,
|
||||
15,
|
||||
"AES-256",
|
||||
);
|
||||
152
.gear/predownloaded-development/vendor/aes/src/armv8/encdec.rs
vendored
Normal file
152
.gear/predownloaded-development/vendor/aes/src/armv8/encdec.rs
vendored
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
//! AES encryption support
|
||||
|
||||
use crate::{Block, Block8};
|
||||
use cipher::inout::InOut;
|
||||
use core::arch::aarch64::*;
|
||||
|
||||
// Stable "polyfills" for unstable core::arch::aarch64 intrinsics
|
||||
// TODO(tarcieri): remove when these intrinsics have been stabilized
|
||||
use super::intrinsics::{
|
||||
vaesdq_u8, vaesdq_u8_and_vaesimcq_u8, vaeseq_u8, vaeseq_u8_and_vaesmcq_u8,
|
||||
};
|
||||
|
||||
/// Perform AES encryption using the given expanded keys.
|
||||
#[target_feature(enable = "aes")]
|
||||
#[target_feature(enable = "neon")]
|
||||
pub(super) unsafe fn encrypt1<const N: usize>(
|
||||
expanded_keys: &[uint8x16_t; N],
|
||||
block: InOut<'_, '_, Block>,
|
||||
) {
|
||||
let rounds = N - 1;
|
||||
assert!(rounds == 10 || rounds == 12 || rounds == 14);
|
||||
|
||||
let (in_ptr, out_ptr) = block.into_raw();
|
||||
|
||||
let mut state = vld1q_u8(in_ptr as *const u8);
|
||||
|
||||
for k in expanded_keys.iter().take(rounds - 1) {
|
||||
// AES single round encryption and mix columns
|
||||
state = vaeseq_u8_and_vaesmcq_u8(state, *k);
|
||||
}
|
||||
|
||||
// AES single round encryption
|
||||
state = vaeseq_u8(state, expanded_keys[rounds - 1]);
|
||||
|
||||
// Final add (bitwise XOR)
|
||||
state = veorq_u8(state, expanded_keys[rounds]);
|
||||
|
||||
vst1q_u8(out_ptr as *mut u8, state);
|
||||
}
|
||||
|
||||
/// Perform parallel AES encryption 8-blocks-at-a-time using the given expanded keys.
|
||||
#[target_feature(enable = "aes")]
|
||||
#[target_feature(enable = "neon")]
|
||||
pub(super) unsafe fn encrypt8<const N: usize>(
|
||||
expanded_keys: &[uint8x16_t; N],
|
||||
blocks: InOut<'_, '_, Block8>,
|
||||
) {
|
||||
let rounds = N - 1;
|
||||
assert!(rounds == 10 || rounds == 12 || rounds == 14);
|
||||
|
||||
let (in_ptr, out_ptr) = blocks.into_raw();
|
||||
let in_ptr = in_ptr as *const Block;
|
||||
let out_ptr = out_ptr as *const Block;
|
||||
|
||||
let mut state = [
|
||||
vld1q_u8(in_ptr.add(0) as *const u8),
|
||||
vld1q_u8(in_ptr.add(1) as *const u8),
|
||||
vld1q_u8(in_ptr.add(2) as *const u8),
|
||||
vld1q_u8(in_ptr.add(3) as *const u8),
|
||||
vld1q_u8(in_ptr.add(4) as *const u8),
|
||||
vld1q_u8(in_ptr.add(5) as *const u8),
|
||||
vld1q_u8(in_ptr.add(6) as *const u8),
|
||||
vld1q_u8(in_ptr.add(7) as *const u8),
|
||||
];
|
||||
|
||||
for k in expanded_keys.iter().take(rounds - 1) {
|
||||
for i in 0..8 {
|
||||
// AES single round encryption and mix columns
|
||||
state[i] = vaeseq_u8_and_vaesmcq_u8(state[i], *k);
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0..8 {
|
||||
// AES single round encryption
|
||||
state[i] = vaeseq_u8(state[i], expanded_keys[rounds - 1]);
|
||||
|
||||
// Final add (bitwise XOR)
|
||||
state[i] = veorq_u8(state[i], expanded_keys[rounds]);
|
||||
|
||||
vst1q_u8(out_ptr.add(i) as *mut u8, state[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform AES decryption using the given expanded keys.
|
||||
#[target_feature(enable = "aes")]
|
||||
#[target_feature(enable = "neon")]
|
||||
pub(super) unsafe fn decrypt1<const N: usize>(
|
||||
expanded_keys: &[uint8x16_t; N],
|
||||
block: InOut<'_, '_, Block>,
|
||||
) {
|
||||
let rounds = N - 1;
|
||||
assert!(rounds == 10 || rounds == 12 || rounds == 14);
|
||||
|
||||
let (in_ptr, out_ptr) = block.into_raw();
|
||||
let mut state = vld1q_u8(in_ptr as *const u8);
|
||||
|
||||
for k in expanded_keys.iter().take(rounds - 1) {
|
||||
// AES single round decryption and inverse mix columns
|
||||
state = vaesdq_u8_and_vaesimcq_u8(state, *k);
|
||||
}
|
||||
|
||||
// AES single round decryption
|
||||
state = vaesdq_u8(state, expanded_keys[rounds - 1]);
|
||||
|
||||
// Final add (bitwise XOR)
|
||||
state = veorq_u8(state, expanded_keys[rounds]);
|
||||
|
||||
vst1q_u8(out_ptr as *mut u8, state);
|
||||
}
|
||||
|
||||
/// Perform parallel AES decryption 8-blocks-at-a-time using the given expanded keys.
|
||||
#[target_feature(enable = "aes")]
|
||||
#[target_feature(enable = "neon")]
|
||||
pub(super) unsafe fn decrypt8<const N: usize>(
|
||||
expanded_keys: &[uint8x16_t; N],
|
||||
blocks: InOut<'_, '_, Block8>,
|
||||
) {
|
||||
let rounds = N - 1;
|
||||
assert!(rounds == 10 || rounds == 12 || rounds == 14);
|
||||
|
||||
let (in_ptr, out_ptr) = blocks.into_raw();
|
||||
let in_ptr = in_ptr as *const Block;
|
||||
let out_ptr = out_ptr as *const Block;
|
||||
|
||||
let mut state = [
|
||||
vld1q_u8(in_ptr.add(0) as *const u8),
|
||||
vld1q_u8(in_ptr.add(1) as *const u8),
|
||||
vld1q_u8(in_ptr.add(2) as *const u8),
|
||||
vld1q_u8(in_ptr.add(3) as *const u8),
|
||||
vld1q_u8(in_ptr.add(4) as *const u8),
|
||||
vld1q_u8(in_ptr.add(5) as *const u8),
|
||||
vld1q_u8(in_ptr.add(6) as *const u8),
|
||||
vld1q_u8(in_ptr.add(7) as *const u8),
|
||||
];
|
||||
|
||||
for k in expanded_keys.iter().take(rounds - 1) {
|
||||
for i in 0..8 {
|
||||
// AES single round decryption and inverse mix columns
|
||||
state[i] = vaesdq_u8_and_vaesimcq_u8(state[i], *k);
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0..8 {
|
||||
// AES single round decryption
|
||||
state[i] = vaesdq_u8(state[i], expanded_keys[rounds - 1]);
|
||||
|
||||
// Final add (bitwise XOR)
|
||||
state[i] = veorq_u8(state[i], expanded_keys[rounds]);
|
||||
|
||||
vst1q_u8(out_ptr.add(i) as *mut u8, state[i]);
|
||||
}
|
||||
}
|
||||
79
.gear/predownloaded-development/vendor/aes/src/armv8/expand.rs
vendored
Normal file
79
.gear/predownloaded-development/vendor/aes/src/armv8/expand.rs
vendored
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
//! AES key expansion support.
|
||||
|
||||
use core::{arch::aarch64::*, mem, slice};
|
||||
|
||||
// Stable "polyfills" for unstable core::arch::aarch64 intrinsics
|
||||
// TODO(tarcieri): remove when these intrinsics have been stabilized
|
||||
use super::intrinsics::{vaeseq_u8, vaesimcq_u8};
|
||||
|
||||
/// There are 4 AES words in a block.
|
||||
const BLOCK_WORDS: usize = 4;
|
||||
|
||||
/// The AES (nee Rijndael) notion of a word is always 32-bits, or 4-bytes.
|
||||
const WORD_SIZE: usize = 4;
|
||||
|
||||
/// AES round constants.
|
||||
const ROUND_CONSTS: [u32; 10] = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
|
||||
|
||||
/// AES key expansion.
|
||||
#[target_feature(enable = "aes")]
|
||||
pub unsafe fn expand_key<const L: usize, const N: usize>(key: &[u8; L]) -> [uint8x16_t; N] {
|
||||
assert!((L == 16 && N == 11) || (L == 24 && N == 13) || (L == 32 && N == 15));
|
||||
|
||||
let mut expanded_keys: [uint8x16_t; N] = mem::zeroed();
|
||||
|
||||
// Sanity check, as this is required in order for the following line to be sound.
|
||||
const _: () = assert!(mem::align_of::<uint8x16_t>() >= mem::align_of::<u32>());
|
||||
let keys_ptr: *mut u32 = expanded_keys.as_mut_ptr().cast();
|
||||
let columns = slice::from_raw_parts_mut(keys_ptr, N * BLOCK_WORDS);
|
||||
|
||||
for (i, chunk) in key.chunks_exact(WORD_SIZE).enumerate() {
|
||||
columns[i] = u32::from_ne_bytes(chunk.try_into().unwrap());
|
||||
}
|
||||
|
||||
// From "The Rijndael Block Cipher" Section 4.1:
|
||||
// > The number of columns of the Cipher Key is denoted by `Nk` and is
|
||||
// > equal to the key length divided by 32 [bits].
|
||||
let nk = L / WORD_SIZE;
|
||||
|
||||
for i in nk..(N * BLOCK_WORDS) {
|
||||
let mut word = columns[i - 1];
|
||||
|
||||
if i % nk == 0 {
|
||||
word = sub_word(word).rotate_right(8) ^ ROUND_CONSTS[i / nk - 1];
|
||||
} else if nk > 6 && i % nk == 4 {
|
||||
word = sub_word(word);
|
||||
}
|
||||
|
||||
columns[i] = columns[i - nk] ^ word;
|
||||
}
|
||||
|
||||
expanded_keys
|
||||
}
|
||||
|
||||
/// Compute inverse expanded keys (for decryption).
|
||||
///
|
||||
/// This is the reverse of the encryption keys, with the Inverse Mix Columns
|
||||
/// operation applied to all but the first and last expanded key.
|
||||
#[target_feature(enable = "aes")]
|
||||
pub(super) unsafe fn inv_expanded_keys<const N: usize>(expanded_keys: &mut [uint8x16_t; N]) {
|
||||
assert!(N == 11 || N == 13 || N == 15);
|
||||
|
||||
for ek in expanded_keys.iter_mut().take(N - 1).skip(1) {
|
||||
*ek = vaesimcq_u8(*ek);
|
||||
}
|
||||
|
||||
expanded_keys.reverse();
|
||||
}
|
||||
|
||||
/// Sub bytes for a single AES word: used for key expansion.
|
||||
#[inline]
|
||||
#[target_feature(enable = "aes")]
|
||||
unsafe fn sub_word(input: u32) -> u32 {
|
||||
let input = vreinterpretq_u8_u32(vdupq_n_u32(input));
|
||||
|
||||
// AES single round encryption (with a "round" key of all zeros)
|
||||
let sub_input = vaeseq_u8(input, vdupq_n_u8(0));
|
||||
|
||||
vgetq_lane_u32(vreinterpretq_u32_u8(sub_input), 0)
|
||||
}
|
||||
107
.gear/predownloaded-development/vendor/aes/src/armv8/hazmat.rs
vendored
Normal file
107
.gear/predownloaded-development/vendor/aes/src/armv8/hazmat.rs
vendored
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
//! Low-level "hazmat" AES functions: ARMv8 Cryptography Extensions support.
|
||||
//!
|
||||
//! Note: this isn't actually used in the `Aes128`/`Aes192`/`Aes256`
|
||||
//! implementations in this crate, but instead provides raw AES-NI accelerated
|
||||
//! access to the AES round function gated under the `hazmat` crate feature.
|
||||
|
||||
use crate::{Block, Block8};
|
||||
use core::arch::aarch64::*;
|
||||
|
||||
// Stable "polyfills" for unstable core::arch::aarch64 intrinsics
|
||||
use super::intrinsics::{vaesdq_u8, vaeseq_u8, vaesimcq_u8, vaesmcq_u8};
|
||||
|
||||
/// AES cipher (encrypt) round function.
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[target_feature(enable = "aes")]
|
||||
pub(crate) unsafe fn cipher_round(block: &mut Block, round_key: &Block) {
|
||||
let b = vld1q_u8(block.as_ptr());
|
||||
let k = vld1q_u8(round_key.as_ptr());
|
||||
|
||||
// AES single round encryption (all-zero round key, deferred until the end)
|
||||
let mut state = vaeseq_u8(b, vdupq_n_u8(0));
|
||||
|
||||
// AES mix columns (the `vaeseq_u8` instruction otherwise omits this step)
|
||||
state = vaesmcq_u8(state);
|
||||
|
||||
// AES add round key (bitwise XOR)
|
||||
state = veorq_u8(state, k);
|
||||
|
||||
vst1q_u8(block.as_mut_ptr(), state);
|
||||
}
|
||||
|
||||
/// AES cipher (encrypt) round function: parallel version.
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[target_feature(enable = "aes")]
|
||||
pub(crate) unsafe fn cipher_round_par(blocks: &mut Block8, round_keys: &Block8) {
|
||||
for i in 0..8 {
|
||||
let mut state = vld1q_u8(blocks[i].as_ptr());
|
||||
|
||||
// AES single round encryption
|
||||
state = vaeseq_u8(state, vdupq_n_u8(0));
|
||||
|
||||
// AES mix columns
|
||||
state = vaesmcq_u8(state);
|
||||
|
||||
// AES add round key (bitwise XOR)
|
||||
state = veorq_u8(state, vld1q_u8(round_keys[i].as_ptr()));
|
||||
|
||||
vst1q_u8(blocks[i].as_mut_ptr(), state);
|
||||
}
|
||||
}
|
||||
|
||||
/// AES equivalent inverse cipher (decrypt) round function.
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[target_feature(enable = "aes")]
|
||||
pub(crate) unsafe fn equiv_inv_cipher_round(block: &mut Block, round_key: &Block) {
|
||||
let b = vld1q_u8(block.as_ptr());
|
||||
let k = vld1q_u8(round_key.as_ptr());
|
||||
|
||||
// AES single round decryption (all-zero round key, deferred until the end)
|
||||
let mut state = vaesdq_u8(b, vdupq_n_u8(0));
|
||||
|
||||
// AES inverse mix columns (the `vaesdq_u8` instruction otherwise omits this step)
|
||||
state = vaesimcq_u8(state);
|
||||
|
||||
// AES add round key (bitwise XOR)
|
||||
state = veorq_u8(state, k);
|
||||
|
||||
vst1q_u8(block.as_mut_ptr(), state);
|
||||
}
|
||||
|
||||
/// AES equivalent inverse cipher (decrypt) round function: parallel version.
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[target_feature(enable = "aes")]
|
||||
pub(crate) unsafe fn equiv_inv_cipher_round_par(blocks: &mut Block8, round_keys: &Block8) {
|
||||
for i in 0..8 {
|
||||
let mut state = vld1q_u8(blocks[i].as_ptr());
|
||||
|
||||
// AES single round decryption (all-zero round key, deferred until the end)
|
||||
state = vaesdq_u8(state, vdupq_n_u8(0));
|
||||
|
||||
// AES inverse mix columns (the `vaesdq_u8` instruction otherwise omits this step)
|
||||
state = vaesimcq_u8(state);
|
||||
|
||||
// AES add round key (bitwise XOR)
|
||||
state = veorq_u8(state, vld1q_u8(round_keys[i].as_ptr()));
|
||||
|
||||
vst1q_u8(blocks[i].as_mut_ptr(), state);
|
||||
}
|
||||
}
|
||||
|
||||
/// AES mix columns function.
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[target_feature(enable = "aes")]
|
||||
pub(crate) unsafe fn mix_columns(block: &mut Block) {
|
||||
let b = vld1q_u8(block.as_ptr());
|
||||
let out = vaesmcq_u8(b);
|
||||
vst1q_u8(block.as_mut_ptr(), out);
|
||||
}
|
||||
|
||||
/// AES inverse mix columns function.
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[target_feature(enable = "aes")]
|
||||
pub(crate) unsafe fn inv_mix_columns(block: &mut Block) {
|
||||
let b = vld1q_u8(block.as_ptr());
|
||||
let out = vaesimcq_u8(b);
|
||||
vst1q_u8(block.as_mut_ptr(), out);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue