Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Macro support for uncased #309

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion phf/Cargo.toml
Expand Up @@ -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"]

Expand Down
11 changes: 11 additions & 0 deletions 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"
9 changes: 9 additions & 0 deletions 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() {}
4 changes: 2 additions & 2 deletions phf_codegen/test/Cargo.toml
Expand Up @@ -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 }
2 changes: 2 additions & 0 deletions phf_macros/Cargo.toml
Expand Up @@ -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 }
66 changes: 40 additions & 26 deletions phf_macros/src/lib.rs
Expand Up @@ -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;

Expand All @@ -33,6 +35,8 @@ enum ParsedKey {
Bool(bool),
#[cfg(feature = "unicase")]
UniCase(UniCase<String>),
#[cfg(feature = "uncased")]
Uncased(Uncased<'static>),
}

impl PhfHash for ParsedKey {
Expand All @@ -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),
}
}
}
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion phf_macros_tests/Cargo.toml
Expand Up @@ -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"
@@ -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() {}
@@ -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")
| ^^^^^^^^^^^^^^^^^^^^^^
12 changes: 12 additions & 0 deletions phf_macros_tests/tests/test.rs
Expand Up @@ -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 {
Expand Down
7 changes: 7 additions & 0 deletions phf_macros_tests/tests/trybuild.rs
Expand Up @@ -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() {
Expand Down