diff --git a/Cargo.lock b/Cargo.lock index c59c903ec..a3543618a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -302,6 +302,8 @@ dependencies = [ "lazy_static", "libc", "nix 0.23.1", + "phf", + "phf_codegen", "pretty_assertions", "rand", "regex", @@ -1347,6 +1349,44 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + [[package]] name = "pkg-config" version = "0.3.24" @@ -1758,6 +1798,12 @@ dependencies = [ "libc", ] +[[package]] +name = "siphasher" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e" + [[package]] name = "smallvec" version = "1.8.0" diff --git a/Cargo.toml b/Cargo.toml index 5364b8448..e9fbe42fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -247,6 +247,7 @@ test = [ "uu_test" ] [dependencies] clap = { version = "3.0", features = ["wrap_help", "cargo"] } clap_complete = "3.0" +phf = "0.10.1" lazy_static = { version="1.3" } textwrap = { version="0.14", features=["terminal_size"] } uucore = { version=">=0.0.11", package="uucore", path="src/uucore" } @@ -387,6 +388,9 @@ nix = "0.23.1" rust-users = { version="0.10", package="users" } unix_socket = "0.5.0" +[build-dependencies] +phf_codegen = "0.10.0" + [[bin]] name = "coreutils" path = "src/bin/coreutils.rs" diff --git a/build.rs b/build.rs index ecff0f707..a8a6fb421 100644 --- a/build.rs +++ b/build.rs @@ -12,9 +12,9 @@ pub fn main() { println!("cargo:rustc-cfg=build={:?}", profile); } - let env_feature_prefix: &str = "CARGO_FEATURE_"; - let feature_prefix: &str = "feat_"; - let override_prefix: &str = "uu_"; + const ENV_FEATURE_PREFIX: &str = "CARGO_FEATURE_"; + const FEATURE_PREFIX: &str = "feat_"; + const OVERRIDE_PREFIX: &str = "uu_"; let out_dir = env::var("OUT_DIR").unwrap(); // println!("cargo:warning=out_dir={}", out_dir); @@ -25,16 +25,16 @@ pub fn main() { let mut crates = Vec::new(); for (key, val) in env::vars() { - if val == "1" && key.starts_with(env_feature_prefix) { - let krate = key[env_feature_prefix.len()..].to_lowercase(); + if val == "1" && key.starts_with(ENV_FEATURE_PREFIX) { + let krate = key[ENV_FEATURE_PREFIX.len()..].to_lowercase(); match krate.as_ref() { "default" | "macos" | "unix" | "windows" | "selinux" => continue, // common/standard feature names "nightly" | "test_unimplemented" => continue, // crate-local custom features "test" => continue, // over-ridden with 'uu_test' to avoid collision with rust core crate 'test' - s if s.starts_with(feature_prefix) => continue, // crate feature sets + s if s.starts_with(FEATURE_PREFIX) => continue, // crate feature sets _ => {} // util feature name } - crates.push(krate.to_string()); + crates.push(krate); } } crates.sort(); @@ -43,33 +43,23 @@ pub fn main() { let mut tf = File::create(Path::new(&out_dir).join("test_modules.rs")).unwrap(); mf.write_all( - "type UtilityMap = HashMap<&'static str, (fn(T) -> i32, fn() -> App<'static>)>;\n\ + "type UtilityMap = phf::Map<&'static str, (fn(T) -> i32, fn() -> App<'static>)>;\n\ \n\ - fn util_map() -> UtilityMap {\n\ - \t#[allow(unused_mut)]\n\ - \t#[allow(clippy::let_and_return)]\n\ - \tlet mut map = UtilityMap::new();\n\ - " - .as_bytes(), + fn util_map() -> UtilityMap {\n" + .as_bytes(), ) .unwrap(); + let mut phf_map = phf_codegen::Map::::new(); for krate in crates { + let map_value = format!("({krate}::uumain, {krate}::uu_app)", krate = krate); match krate.as_ref() { // 'test' is named uu_test to avoid collision with rust core crate 'test'. // It can also be invoked by name '[' for the '[ expr ] syntax'. "uu_test" => { - mf.write_all( - format!( - "\ - \tmap.insert(\"test\", ({krate}::uumain, {krate}::uu_app));\n\ - \t\tmap.insert(\"[\", ({krate}::uumain, {krate}::uu_app));\n\ - ", - krate = krate - ) - .as_bytes(), - ) - .unwrap(); + phf_map.entry(String::from("test"), &map_value); + phf_map.entry(String::from("["), &map_value); + tf.write_all( format!( "#[path=\"{dir}/test_test.rs\"]\nmod test_test;\n", @@ -79,20 +69,12 @@ pub fn main() { ) .unwrap() } - k if k.starts_with(override_prefix) => { - mf.write_all( - format!( - "\tmap.insert(\"{k}\", ({krate}::uumain, {krate}::uu_app));\n", - k = &krate[override_prefix.len()..], - krate = krate - ) - .as_bytes(), - ) - .unwrap(); + k if k.starts_with(OVERRIDE_PREFIX) => { + phf_map.entry(String::from(&krate[OVERRIDE_PREFIX.len()..]), &map_value); tf.write_all( format!( "#[path=\"{dir}/test_{k}.rs\"]\nmod test_{k};\n", - k = &krate[override_prefix.len()..], + k = &krate[OVERRIDE_PREFIX.len()..], dir = util_tests_dir, ) .as_bytes(), @@ -100,14 +82,10 @@ pub fn main() { .unwrap() } "false" | "true" => { - mf.write_all( - format!( - "\tmap.insert(\"{krate}\", (r#{krate}::uumain, r#{krate}::uu_app));\n", - krate = krate - ) - .as_bytes(), - ) - .unwrap(); + phf_map.entry( + String::from(&krate), + &format!("(r#{krate}::uumain, r#{krate}::uu_app)", krate = krate), + ); tf.write_all( format!( "#[path=\"{dir}/test_{krate}.rs\"]\nmod test_{krate};\n", @@ -119,29 +97,25 @@ pub fn main() { .unwrap() } "hashsum" => { - mf.write_all( - format!( - "\ - \tmap.insert(\"{krate}\", ({krate}::uumain, {krate}::uu_app_custom));\n\ - \t\tmap.insert(\"md5sum\", ({krate}::uumain, {krate}::uu_app_common));\n\ - \t\tmap.insert(\"sha1sum\", ({krate}::uumain, {krate}::uu_app_common));\n\ - \t\tmap.insert(\"sha224sum\", ({krate}::uumain, {krate}::uu_app_common));\n\ - \t\tmap.insert(\"sha256sum\", ({krate}::uumain, {krate}::uu_app_common));\n\ - \t\tmap.insert(\"sha384sum\", ({krate}::uumain, {krate}::uu_app_common));\n\ - \t\tmap.insert(\"sha512sum\", ({krate}::uumain, {krate}::uu_app_common));\n\ - \t\tmap.insert(\"sha3sum\", ({krate}::uumain, {krate}::uu_app_common));\n\ - \t\tmap.insert(\"sha3-224sum\", ({krate}::uumain, {krate}::uu_app_common));\n\ - \t\tmap.insert(\"sha3-256sum\", ({krate}::uumain, {krate}::uu_app_common));\n\ - \t\tmap.insert(\"sha3-384sum\", ({krate}::uumain, {krate}::uu_app_common));\n\ - \t\tmap.insert(\"sha3-512sum\", ({krate}::uumain, {krate}::uu_app_common));\n\ - \t\tmap.insert(\"shake128sum\", ({krate}::uumain, {krate}::uu_app_common));\n\ - \t\tmap.insert(\"shake256sum\", ({krate}::uumain, {krate}::uu_app_common));\n\ - ", - krate = krate - ) - .as_bytes(), - ) - .unwrap(); + phf_map.entry( + String::from(&krate), + &format!("({krate}::uumain, {krate}::uu_app_custom)", krate = krate), + ); + + let map_value = format!("({krate}::uumain, {krate}::uu_app_common)", krate = krate); + phf_map.entry(String::from("md5sum"), &map_value); + phf_map.entry(String::from("sha1sum"), &map_value); + phf_map.entry(String::from("sha224sum"), &map_value); + phf_map.entry(String::from("sha256sum"), &map_value); + phf_map.entry(String::from("sha384sum"), &map_value); + phf_map.entry(String::from("sha512sum"), &map_value); + phf_map.entry(String::from("sha3sum"), &map_value); + phf_map.entry(String::from("sha3-224sum"), &map_value); + phf_map.entry(String::from("sha3-256sum"), &map_value); + phf_map.entry(String::from("sha3-384sum"), &map_value); + phf_map.entry(String::from("sha3-512sum"), &map_value); + phf_map.entry(String::from("shake128sum"), &map_value); + phf_map.entry(String::from("shake256sum"), &map_value); tf.write_all( format!( "#[path=\"{dir}/test_{krate}.rs\"]\nmod test_{krate};\n", @@ -153,14 +127,7 @@ pub fn main() { .unwrap() } _ => { - mf.write_all( - format!( - "\tmap.insert(\"{krate}\", ({krate}::uumain, {krate}::uu_app));\n", - krate = krate - ) - .as_bytes(), - ) - .unwrap(); + phf_map.entry(String::from(&krate), &map_value); tf.write_all( format!( "#[path=\"{dir}/test_{krate}.rs\"]\nmod test_{krate};\n", @@ -173,8 +140,8 @@ pub fn main() { } } } - - mf.write_all(b"map\n}\n").unwrap(); + write!(mf, "{}", phf_map.build()).unwrap(); + mf.write_all(b"\n}\n").unwrap(); mf.flush().unwrap(); tf.flush().unwrap(); diff --git a/src/bin/coreutils.rs b/src/bin/coreutils.rs index e83b6f697..41b12e6a7 100644 --- a/src/bin/coreutils.rs +++ b/src/bin/coreutils.rs @@ -8,7 +8,6 @@ use clap::{App, Arg}; use clap_complete::Shell; use std::cmp; -use std::collections::hash_map::HashMap; use std::ffi::OsStr; use std::ffi::OsString; use std::io::{self, Write}; @@ -171,7 +170,7 @@ fn gen_completions( fn gen_coreutils_app(util_map: UtilityMap) -> App<'static> { let mut app = App::new("coreutils"); - for (_, (_, sub_app)) in util_map { + for (_, (_, sub_app)) in &util_map { app = app.subcommand(sub_app()); } app diff --git a/src/bin/uudoc.rs b/src/bin/uudoc.rs index 38e8a0323..b8a64d08c 100644 --- a/src/bin/uudoc.rs +++ b/src/bin/uudoc.rs @@ -4,7 +4,6 @@ // file that was distributed with this source code. use clap::App; -use std::collections::hash_map::HashMap; use std::ffi::OsString; use std::fs::File; use std::io::{self, Write}; @@ -32,7 +31,7 @@ fn main() -> io::Result<()> { * [Multi-call binary](multicall.md)\n", ); - let mut utils = utils.iter().collect::>(); + let mut utils = utils.entries().collect::>(); utils.sort(); for (&name, (_, app)) in utils { if name == "[" {