Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add support for uncased
uncased is an ASCII-only case insensitive comparison library like
UniCase, but it has better support for being used in a map.

Specifically, UniCase does not support the Borrow trait (see
seanmonstar/unicase#22), so the type

    phf::Map<UniCase<&'static str>, _>

only supports lookups with static string literals, which has limited
usefulness.

By contrast, the the equivalent uncased construction

    phf::Map<&'static Uncased, _>

*does* support lookups with non-static strings.
  • Loading branch information
benesch committed Jun 16, 2021
1 parent 711e9aa commit 2a6087f
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 3 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Expand Up @@ -13,10 +13,10 @@ jobs:
fail-fast: false
matrix:
# MSRV and nightly
version: [1.40.0, nightly]
version: [1.46.0, nightly]
steps:
- uses: actions/checkout@v2

- name: Set toolchain
run: |
rustup set profile minimal
Expand Down
1 change: 1 addition & 0 deletions phf/Cargo.toml
Expand Up @@ -15,6 +15,7 @@ test = false
[features]
default = ["std"]
std = ["phf_shared/std"]
uncased = ["phf_shared/uncased"]
unicase = ["phf_shared/unicase"]
macros = [
"phf_macros",
Expand Down
4 changes: 3 additions & 1 deletion phf_codegen/test/Cargo.toml
Expand Up @@ -6,9 +6,11 @@ build = "build.rs"
edition = "2018"

[dependencies]
phf = { version = "0.8", features = ["unicase"] }
phf = { version = "0.8", features = ["uncased", "unicase"] }
uncased = { version = "0.9.6", default-features = false }
unicase = "2.4.0"

[build-dependencies]
phf_codegen = "0.8"
unicase = "2.4.0"
uncased = { version = "0.9.6", default-features = false }
10 changes: 10 additions & 0 deletions phf_codegen/test/build.rs
Expand Up @@ -6,6 +6,7 @@ use std::fs::File;
use std::io::{self, BufWriter, Write};
use std::path::Path;

use uncased::UncasedStr;
use unicase::UniCase;

fn main() -> io::Result<()> {
Expand Down Expand Up @@ -71,6 +72,15 @@ fn main() -> io::Result<()> {
.build()
)?;

write!(
&mut file,
"static UNCASED_MAP: ::phf::Map<&'static ::uncased::UncasedStr, &'static str> = \n{};",
phf_codegen::Map::new()
.entry(UncasedStr::new("abc"), "\"a\"")
.entry(UncasedStr::new("DEF"), "\"b\"")
.build()
)?;

//u32 is used here purely for a type that impls `Hash+PhfHash+Eq+fmt::Debug`, but is not required for the empty test itself
writeln!(&mut file,
"static EMPTY: ::phf::Map<u32, u32> = \n{};",
Expand Down
9 changes: 9 additions & 0 deletions phf_codegen/test/src/lib.rs
@@ -1,5 +1,6 @@
#[cfg(test)]
mod test {
use uncased::UncasedStr;
use unicase::UniCase;

include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
Expand Down Expand Up @@ -61,6 +62,14 @@ mod test {
assert_eq!("b", UNICASE_MAP[&UniCase::new(&*local_str_3)]);
}

#[test]
fn uncased_map() {
assert_eq!("a", UNCASED_MAP[&UncasedStr::new("AbC")]);
assert_eq!("a", UNCASED_MAP[&UncasedStr::new("abc")]);
assert_eq!("b", UNCASED_MAP[&UncasedStr::new("DEf")]);
assert!(!UNCASED_MAP.contains_key(&UncasedStr::new("XyZ")));
}

#[test]
fn array_keys() {
assert_eq!(0, ARRAY_KEYS[b"foo"]);
Expand Down
1 change: 1 addition & 0 deletions phf_shared/Cargo.toml
Expand Up @@ -19,3 +19,4 @@ std = []
[dependencies]
siphasher = "0.3"
unicase = { version = "2.4.0", optional = true }
uncased = { version = "0.9.6", optional = true, default-features = false }
27 changes: 27 additions & 0 deletions phf_shared/src/lib.rs
Expand Up @@ -276,6 +276,33 @@ impl<'b, 'a: 'b, S: ?Sized + 'a> PhfBorrow<unicase::UniCase<&'b S>> for unicase:
}
}

#[cfg(feature = "uncased")]
impl PhfHash for uncased::UncasedStr {
#[inline]
fn phf_hash<H: Hasher>(&self, state: &mut H) {
self.hash(state)
}
}

#[cfg(feature = "uncased")]
impl FmtConst for uncased::UncasedStr {
fn fmt_const(&self, f: &mut fmt::Formatter) -> fmt::Result {
// transmute is not stable in const fns (rust-lang/rust#53605), so
// `UncasedStr::new` can't be a const fn itself, but we can inline the
// call to transmute here in the meantime.
f.write_str("unsafe { ::std::mem::transmute::<&'static str, &'static UncasedStr>(")?;
self.as_str().fmt_const(f)?;
f.write_str(") }")
}
}

#[cfg(feature = "uncased")]
impl PhfBorrow<uncased::UncasedStr> for &uncased::UncasedStr {
fn borrow(&self) -> &uncased::UncasedStr {
self
}
}

macro_rules! sip_impl (
(le $t:ty) => (
impl PhfHash for $t {
Expand Down

0 comments on commit 2a6087f

Please sign in to comment.