diff --git a/phf/Cargo.toml b/phf/Cargo.toml index c2d40a98..aeca3585 100644 --- a/phf/Cargo.toml +++ b/phf/Cargo.toml @@ -18,7 +18,7 @@ test = false [features] default = ["std"] std = ["phf_shared/std"] -uncased = ["phf_shared/uncased"] +uncased = ["phf_macros?/uncased", "phf_shared/uncased"] unicase = ["phf_macros?/unicase", "phf_shared/unicase"] macros = ["phf_macros"] diff --git a/phf/examples/uncased-example/Cargo.toml b/phf/examples/uncased-example/Cargo.toml new file mode 100644 index 00000000..18bd390e --- /dev/null +++ b/phf/examples/uncased-example/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "unicase-example" +version = "0.1.0" +edition = "2021" +rust-version = "1.61" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +phf = { version = "^0.11.2", features = ["macros", "uncased"] } +uncased = "0.9.7" diff --git a/phf/examples/uncased-example/src/main.rs b/phf/examples/uncased-example/src/main.rs new file mode 100644 index 00000000..ee28ce46 --- /dev/null +++ b/phf/examples/uncased-example/src/main.rs @@ -0,0 +1,9 @@ +use phf::phf_map; +use uncased::UncasedStr; + +pub static MAP: phf::Map<&'static UncasedStr, isize> = phf_map!( + UncasedStr::new("Foo") => 0, + UncasedStr::new("Bar") => 1, +); + +fn main() {} diff --git a/phf_codegen/test/Cargo.toml b/phf_codegen/test/Cargo.toml index 1c98a25e..8ab2feed 100644 --- a/phf_codegen/test/Cargo.toml +++ b/phf_codegen/test/Cargo.toml @@ -7,10 +7,10 @@ edition = "2021" [dependencies] phf = { version = "^0.11.2", features = ["uncased", "unicase"] } -uncased = { version = "0.9.6", default-features = false } +uncased = { version = "0.9.7", default-features = false } unicase = "2.4.0" [build-dependencies] phf_codegen = { version = "^0.11.2", path = ".." } unicase = "2.4.0" -uncased = { version = "0.9.6", default-features = false } +uncased = { version = "0.9.7", default-features = false } diff --git a/phf_macros/Cargo.toml b/phf_macros/Cargo.toml index 921d3e60..eb1f8059 100644 --- a/phf_macros/Cargo.toml +++ b/phf_macros/Cargo.toml @@ -15,12 +15,14 @@ proc-macro = true [features] unicase = ["unicase_", "phf_shared/unicase"] +uncased = ["uncased_", "phf_shared/uncased"] [dependencies] syn = { version = "2", features = ["full"] } quote = "1" proc-macro2 = "1" unicase_ = { package = "unicase", version = "2.4.0", optional = true } +uncased_ = { package = "uncased", version = "0.9.7", optional = true } phf_generator = "0.11.1" phf_shared = { version = "^0.11.2", default-features = false } diff --git a/phf_macros/src/lib.rs b/phf_macros/src/lib.rs index a033036e..8db0f8a1 100644 --- a/phf_macros/src/lib.rs +++ b/phf_macros/src/lib.rs @@ -12,6 +12,8 @@ use std::hash::Hasher; use syn::parse::{self, Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::{parse_macro_input, Error, Expr, ExprLit, Lit, Token, UnOp}; +#[cfg(feature = "uncased")] +use uncased_::Uncased; #[cfg(feature = "unicase")] use unicase_::UniCase; @@ -33,6 +35,8 @@ enum ParsedKey { Bool(bool), #[cfg(feature = "unicase")] UniCase(UniCase), + #[cfg(feature = "uncased")] + Uncased(Uncased<'static>), } impl PhfHash for ParsedKey { @@ -57,6 +61,8 @@ impl PhfHash for ParsedKey { ParsedKey::Bool(s) => s.phf_hash(state), #[cfg(feature = "unicase")] ParsedKey::UniCase(s) => s.phf_hash(state), + #[cfg(feature = "uncased")] + ParsedKey::Uncased(s) => s.phf_hash(state), } } } @@ -138,34 +144,42 @@ impl ParsedKey { } } Expr::Group(group) => ParsedKey::from_expr(&group.expr), - #[cfg(feature = "unicase")] - Expr::Call(call) => { + Expr::Call(call) if call.args.len() == 1 => { + let last; + let last_ahead; + if let Expr::Path(ep) = call.func.as_ref() { - let segments = &mut ep.path.segments.iter().rev(); - let last = &segments.next()?.ident; - let last_ahead = &segments.next()?.ident; - let is_unicode = last_ahead == "UniCase" && last == "unicode"; - let is_ascii = last_ahead == "UniCase" && last == "ascii"; - if call.args.len() == 1 && (is_unicode || is_ascii) { - if let Some(Expr::Lit(ExprLit { - attrs: _, - lit: Lit::Str(s), - })) = call.args.first() - { - let v = if is_unicode { - UniCase::unicode(s.value()) - } else { - UniCase::ascii(s.value()) - }; - Some(ParsedKey::UniCase(v)) - } else { - None - } - } else { - None - } + let mut segments = ep.path.segments.iter(); + last = segments.next_back()?.ident.to_string(); + last_ahead = segments.next_back()?.ident.to_string(); } else { - None + return None; + } + + let mut arg = call.args.first().unwrap(); + + while let Expr::Group(group) = arg { + arg = &group.expr; + } + + let _value = match arg { + Expr::Lit(ExprLit { + attrs: _, + lit: Lit::Str(s), + }) => s.value(), + _ => { + return None; + } + }; + + match (&*last_ahead, &*last) { + #[cfg(feature = "unicase")] + ("UniCase", "unicode") => Some(ParsedKey::UniCase(UniCase::unicode(_value))), + #[cfg(feature = "unicase")] + ("UniCase", "ascii") => Some(ParsedKey::UniCase(UniCase::ascii(_value))), + #[cfg(feature = "uncased")] + ("UncasedStr", "new") => Some(ParsedKey::Uncased(Uncased::new(_value))), + _ => None, } } _ => None, diff --git a/phf_macros_tests/Cargo.toml b/phf_macros_tests/Cargo.toml index dd38f82c..e4ef387d 100644 --- a/phf_macros_tests/Cargo.toml +++ b/phf_macros_tests/Cargo.toml @@ -14,5 +14,6 @@ categories = ["data-structures"] [dev-dependencies] trybuild = "1.0" phf = { version = "0.11", features = ["macros"] } -phf_macros = { version = "0.11", features = ["unicase"] } +phf_macros = { version = "0.11", features = ["unicase", "uncased"] } unicase = "2.4.0" +uncased = "0.9.7" diff --git a/phf_macros_tests/tests/compile-fail-uncased/equivalent-keys.rs b/phf_macros_tests/tests/compile-fail-uncased/equivalent-keys.rs new file mode 100644 index 00000000..b7101b17 --- /dev/null +++ b/phf_macros_tests/tests/compile-fail-uncased/equivalent-keys.rs @@ -0,0 +1,9 @@ +use phf::phf_map; +use uncased::UncasedStr; + +static MAP: phf::Map<&'static UncasedStr, isize> = phf_map!( + UncasedStr::new("FOO") => 42, + UncasedStr::new("foo") => 42, //~ ERROR duplicate key UncasedStr("FOO") +); + +fn main() {} diff --git a/phf_macros_tests/tests/compile-fail-uncased/equivalent-keys.stderr b/phf_macros_tests/tests/compile-fail-uncased/equivalent-keys.stderr new file mode 100644 index 00000000..077c569e --- /dev/null +++ b/phf_macros_tests/tests/compile-fail-uncased/equivalent-keys.stderr @@ -0,0 +1,5 @@ +error: duplicate key + --> tests/compile-fail-uncased/equivalent-keys.rs:6:5 + | +6 | UncasedStr::new("foo") => 42, //~ ERROR duplicate key UncasedStr("FOO") + | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/phf_macros_tests/tests/test.rs b/phf_macros_tests/tests/test.rs index 7123753f..68ff486e 100644 --- a/phf_macros_tests/tests/test.rs +++ b/phf_macros_tests/tests/test.rs @@ -256,6 +256,18 @@ mod map { assert!(Some(&11) == MAP.get(&UniCase::new("bar"))); assert_eq!(None, MAP.get(&UniCase::new("asdf"))); } + + #[test] + fn test_uncased() { + use uncased::UncasedStr; + static MAP: phf::Map<&'static UncasedStr, isize> = phf_map!( + UncasedStr::new("FOO") => 10, + UncasedStr::new("Bar") => 11, + ); + assert!(Some(&10) == MAP.get("FOo".into())); + assert!(Some(&11) == MAP.get("bar".into())); + assert_eq!(None, MAP.get("asdf".into())); + } } mod set { diff --git a/phf_macros_tests/tests/trybuild.rs b/phf_macros_tests/tests/trybuild.rs index 8e80715c..a15c4065 100644 --- a/phf_macros_tests/tests/trybuild.rs +++ b/phf_macros_tests/tests/trybuild.rs @@ -9,6 +9,13 @@ fn compile_test_unicase() { t.compile_fail("tests/compile-fail-unicase/*.rs"); } +#[test] +#[ignore] +fn compile_test_uncased() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/compile-fail-uncased/*.rs"); +} + #[test] #[ignore] fn compile_fail() {