phf_macros-0.8.0/Cargo.toml.orig010064400017500001750000000012001355143646600147560ustar0000000000000000[package] name = "phf_macros" version = "0.8.0" authors = ["Steven Fackler "] edition = "2018" license = "MIT" description = "Macros to generate types in the phf crate" repository = "https://github.com/sfackler/rust-phf" [lib] proc-macro = true [dependencies] syn = { version = "1", features = ["full"] } quote = "1" proc-macro2 = "1" proc-macro-hack = "0.5.4" phf_generator = { version = "0.8.0", path = "../phf_generator" } phf_shared = { version = "0.8.0", path = "../phf_shared" } [dev-dependencies] trybuild = "1.0" phf = { version = "0.8", path = "../phf", features = ["macros", "unicase"] } unicase = "2.4.0" phf_macros-0.8.0/Cargo.toml0000644000000023140000000000000112170ustar00# 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] edition = "2018" name = "phf_macros" version = "0.8.0" authors = ["Steven Fackler "] description = "Macros to generate types in the phf crate" license = "MIT" repository = "https://github.com/sfackler/rust-phf" [lib] proc-macro = true [dependencies.phf_generator] version = "0.8.0" [dependencies.phf_shared] version = "0.8.0" [dependencies.proc-macro-hack] version = "0.5.4" [dependencies.proc-macro2] version = "1" [dependencies.quote] version = "1" [dependencies.syn] version = "1" features = ["full"] [dev-dependencies.phf] version = "0.8" features = ["macros", "unicase"] [dev-dependencies.trybuild] version = "1.0" [dev-dependencies.unicase] version = "2.4.0" phf_macros-0.8.0/benches/bench.rs010064400017500001750000000057141351315677500151410ustar0000000000000000#![feature(test)] extern crate test; mod map { use std::collections::{BTreeMap, HashMap}; use test::Bencher; use phf::phf_map; macro_rules! map_and_match { ($map:ident, $f:ident, $($key:expr => $value:expr,)+) => { static $map: phf::Map<&'static str, usize> = phf_map! { $($key => $value),+ }; fn $f(key: &str) -> Option { match key { $($key => Some($value),)+ _ => None } } } } map_and_match! { MAP, match_get, "apple" => 0, "banana" => 1, "carrot" => 2, "doughnut" => 3, "eggplant" => 4, "frankincene" => 5, "grapes" => 6, "haggis" => 7, "ice cream" => 8, "jelly beans" => 9, "kaffir lime leaves" => 10, "lemonade" => 11, "mashmallows" => 12, "nectarines" => 13, "oranges" => 14, "pineapples" => 15, "quinoa" => 16, "rosemary" => 17, "sourdough" => 18, "tomatoes" => 19, "unleavened bread" => 20, "vanilla" => 21, "watermelon" => 22, "xinomavro grapes" => 23, "yogurt" => 24, "zucchini" => 25, } #[bench] fn bench_match_some(b: &mut Bencher) { b.iter(|| { assert_eq!(match_get("zucchini").unwrap(), 25); }) } #[bench] fn bench_match_none(b: &mut Bencher) { b.iter(|| { assert_eq!(match_get("potato"), None); }) } #[bench] fn bench_btreemap_some(b: &mut Bencher) { let mut map = BTreeMap::new(); for (key, value) in MAP.entries() { map.insert(*key, *value); } b.iter(|| { assert_eq!(map.get("zucchini").unwrap(), &25); }) } #[bench] fn bench_hashmap_some(b: &mut Bencher) { let mut map = HashMap::new(); for (key, value) in MAP.entries() { map.insert(*key, *value); } b.iter(|| { assert_eq!(map.get("zucchini").unwrap(), &25); }) } #[bench] fn bench_phf_some(b: &mut Bencher) { b.iter(|| { assert_eq!(MAP.get("zucchini").unwrap(), &25); }) } #[bench] fn bench_btreemap_none(b: &mut Bencher) { let mut map = BTreeMap::new(); for (key, value) in MAP.entries() { map.insert(*key, *value); } b.iter(|| { assert_eq!(map.get("potato"), None); }) } #[bench] fn bench_hashmap_none(b: &mut Bencher) { let mut map = HashMap::new(); for (key, value) in MAP.entries() { map.insert(*key, *value); } b.iter(|| { assert_eq!(map.get("potato"), None); }) } #[bench] fn bench_phf_none(b: &mut Bencher) { b.iter(|| { assert_eq!(MAP.get("potato"), None); }) } } phf_macros-0.8.0/src/lib.rs010064400017500001750000000176101355141571300137760ustar0000000000000000extern crate proc_macro; use phf_generator::HashState; use phf_shared::PhfHash; use proc_macro::TokenStream; use quote::quote; use std::collections::HashSet; use std::hash::Hasher; use syn::parse::{self, Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::{parse_macro_input, Error, Expr, Lit, Token, UnOp}; #[derive(Hash, PartialEq, Eq, Clone)] enum ParsedKey { Str(String), Binary(Vec), Char(char), I8(i8), I16(i16), I32(i32), I64(i64), I128(i128), U8(u8), U16(u16), U32(u32), U64(u64), U128(u128), Bool(bool), } impl PhfHash for ParsedKey { fn phf_hash(&self, state: &mut H) where H: Hasher, { match self { ParsedKey::Str(s) => s.phf_hash(state), ParsedKey::Binary(s) => s.phf_hash(state), ParsedKey::Char(s) => s.phf_hash(state), ParsedKey::I8(s) => s.phf_hash(state), ParsedKey::I16(s) => s.phf_hash(state), ParsedKey::I32(s) => s.phf_hash(state), ParsedKey::I64(s) => s.phf_hash(state), ParsedKey::I128(s) => s.phf_hash(state), ParsedKey::U8(s) => s.phf_hash(state), ParsedKey::U16(s) => s.phf_hash(state), ParsedKey::U32(s) => s.phf_hash(state), ParsedKey::U64(s) => s.phf_hash(state), ParsedKey::U128(s) => s.phf_hash(state), ParsedKey::Bool(s) => s.phf_hash(state), } } } impl ParsedKey { fn from_expr(expr: &Expr) -> Option { match expr { Expr::Lit(lit) => match &lit.lit { Lit::Str(s) => Some(ParsedKey::Str(s.value())), Lit::ByteStr(s) => Some(ParsedKey::Binary(s.value())), Lit::Byte(s) => Some(ParsedKey::U8(s.value())), Lit::Char(s) => Some(ParsedKey::Char(s.value())), Lit::Int(s) => match s.suffix() { // we've lost the sign at this point, so `-128i8` looks like `128i8`, // which doesn't fit in an `i8`; parse it as a `u8` and cast (to `0i8`), // which is handled below, by `Unary` "i8" => Some(ParsedKey::I8(s.base10_parse::().unwrap() as i8)), "i16" => Some(ParsedKey::I16(s.base10_parse::().unwrap() as i16)), "i32" => Some(ParsedKey::I32(s.base10_parse::().unwrap() as i32)), "i64" => Some(ParsedKey::I64(s.base10_parse::().unwrap() as i64)), "i128" => Some(ParsedKey::I128(s.base10_parse::().unwrap() as i128)), "u8" => Some(ParsedKey::U8(s.base10_parse::().unwrap())), "u16" => Some(ParsedKey::U16(s.base10_parse::().unwrap())), "u32" => Some(ParsedKey::U32(s.base10_parse::().unwrap())), "u64" => Some(ParsedKey::U64(s.base10_parse::().unwrap())), "u128" => Some(ParsedKey::U128(s.base10_parse::().unwrap())), _ => None, }, Lit::Bool(s) => Some(ParsedKey::Bool(s.value)), _ => None, }, Expr::Array(array) => { let mut buf = vec![]; for expr in &array.elems { match expr { Expr::Lit(lit) => match &lit.lit { Lit::Int(s) => match s.suffix() { "u8" | "" => buf.push(s.base10_parse::().unwrap()), _ => return None, }, _ => return None, }, _ => return None, } } Some(ParsedKey::Binary(buf)) } Expr::Unary(unary) => { // if we received an integer literal (always unsigned) greater than i__::max_value() // then casting it to a signed integer type of the same width will negate it to // the same absolute value so we don't need to negate it here macro_rules! try_negate ( ($val:expr) => {if $val < 0 { $val } else { -$val }} ); match unary.op { UnOp::Neg(_) => match ParsedKey::from_expr(&unary.expr)? { ParsedKey::I8(v) => Some(ParsedKey::I8(try_negate!(v))), ParsedKey::I16(v) => Some(ParsedKey::I16(try_negate!(v))), ParsedKey::I32(v) => Some(ParsedKey::I32(try_negate!(v))), ParsedKey::I64(v) => Some(ParsedKey::I64(try_negate!(v))), ParsedKey::I128(v) => Some(ParsedKey::I128(try_negate!(v))), _ => None, }, _ => None, } } Expr::Group(group) => ParsedKey::from_expr(&group.expr), _ => None, } } } struct Key { parsed: ParsedKey, expr: Expr, } impl PhfHash for Key { fn phf_hash(&self, state: &mut H) where H: Hasher, { self.parsed.phf_hash(state) } } impl Parse for Key { fn parse(input: ParseStream) -> parse::Result { let expr = input.parse()?; let parsed = ParsedKey::from_expr(&expr) .ok_or_else(|| Error::new_spanned(&expr, "unsupported key expression"))?; Ok(Key { parsed, expr }) } } struct Entry { key: Key, value: Expr, } impl PhfHash for Entry { fn phf_hash(&self, state: &mut H) where H: Hasher, { self.key.phf_hash(state) } } impl Parse for Entry { fn parse(input: ParseStream) -> parse::Result { let key = input.parse()?; input.parse::]>()?; let value = input.parse()?; Ok(Entry { key, value }) } } struct Map(Vec); impl Parse for Map { fn parse(input: ParseStream) -> parse::Result { let parsed = Punctuated::::parse_terminated(input)?; let map = parsed.into_iter().collect::>(); check_duplicates(&map)?; Ok(Map(map)) } } struct Set(Vec); impl Parse for Set { fn parse(input: ParseStream) -> parse::Result { let parsed = Punctuated::::parse_terminated(input)?; let set = parsed .into_iter() .map(|key| Entry { key, value: syn::parse_str("()").unwrap(), }) .collect::>(); check_duplicates(&set)?; Ok(Set(set)) } } fn check_duplicates(entries: &[Entry]) -> parse::Result<()> { let mut keys = HashSet::new(); for entry in entries { if !keys.insert(&entry.key.parsed) { return Err(Error::new_spanned(&entry.key.expr, "duplicate key")); } } Ok(()) } fn build_map(entries: &[Entry], state: HashState) -> proc_macro2::TokenStream { let key = state.key; let disps = state.disps.iter().map(|&(d1, d2)| quote!((#d1, #d2))); let entries = state.map.iter().map(|&idx| { let key = &entries[idx].key.expr; let value = &entries[idx].value; quote!((#key, #value)) }); quote! { phf::Map { key: #key, disps: phf::Slice::Static(&[#(#disps),*]), entries: phf::Slice::Static(&[#(#entries),*]), } } } #[::proc_macro_hack::proc_macro_hack] pub fn phf_map(input: TokenStream) -> TokenStream { let map = parse_macro_input!(input as Map); let state = phf_generator::generate_hash(&map.0); build_map(&map.0, state).into() } #[::proc_macro_hack::proc_macro_hack] pub fn phf_set(input: TokenStream) -> TokenStream { let set = parse_macro_input!(input as Set); let state = phf_generator::generate_hash(&set.0); let map = build_map(&set.0, state); quote!(phf::Set { map: #map }).into() } phf_macros-0.8.0/tests/compile-fail-unicase/equivalent-keys.rs010064400017500001750000000004161355143624500227160ustar0000000000000000use unicase::UniCase; use phf::phf_map; static MAP: phf::Map, isize> = phf_map!( //~ ERROR duplicate key UniCase("FOO") UniCase("FOO") => 42, //~ NOTE one occurrence here UniCase("foo") => 42, //~ NOTE one occurrence here ); fn main() {} phf_macros-0.8.0/tests/compile-fail-unicase/equivalent-keys.stderr010064400017500001750000000002311355143624500235700ustar0000000000000000error: unsupported key expression --> $DIR/equivalent-keys.rs:5:5 | 5 | UniCase("FOO") => 42, //~ NOTE one occurrence here | ^^^^^^^^^^^^^^ phf_macros-0.8.0/tests/compile-fail/bad-syntax.rs010064400017500001750000000002141355143624500202110ustar0000000000000000use phf::phf_map; static MAP: phf::Map = phf_map! { Signature:: => //~ ERROR expected identifier () }; fn main() {} phf_macros-0.8.0/tests/compile-fail/bad-syntax.stderr010064400017500001750000000001571355143624500210760ustar0000000000000000error: expected identifier --> $DIR/bad-syntax.rs:5:5 | 5 | => //~ ERROR expected identifier | ^^ phf_macros-0.8.0/tests/compiletest.rs010064400017500001750000000005301351413764300161260ustar0000000000000000#[test] #[ignore] // compiler error message format is different between 1.32.0 and nightly fn compile_test_unicase() { let t = trybuild::TestCases::new(); t.compile_fail("tests/compile-fail-unicase/*.rs"); } #[test] #[ignore] fn compile_fail() { let t = trybuild::TestCases::new(); t.compile_fail("tests/compile-fail/*.rs"); } phf_macros-0.8.0/tests/test.rs010064400017500001750000000200101351764006500145500ustar0000000000000000mod map { use std::collections::{HashMap, HashSet}; use phf::phf_map; #[allow(dead_code)] static TRAILING_COMMA: phf::Map<&'static str, isize> = phf_map!( "foo" => 10, ); #[allow(dead_code)] static NO_TRAILING_COMMA: phf::Map<&'static str, isize> = phf_map!( "foo" => 10 ); #[allow(dead_code)] static BYTE_STRING_KEY: phf::Map<&'static [u8], &'static str> = phf_map!( b"camembert" => "delicious", ); #[test] fn test_two() { static MAP: phf::Map<&'static str, isize> = phf_map!( "foo" => 10, "bar" => 11, ); assert!(Some(&10) == MAP.get(&("foo"))); assert!(Some(&11) == MAP.get(&("bar"))); assert_eq!(None, MAP.get(&("asdf"))); assert_eq!(2, MAP.len()); } #[test] fn test_entries() { static MAP: phf::Map<&'static str, isize> = phf_map!( "foo" => 10, "bar" => 11, ); let hash = MAP.entries().map(|(&k, &v)| (k, v)).collect::>(); assert!(Some(&10) == hash.get(&("foo"))); assert!(Some(&11) == hash.get(&("bar"))); assert_eq!(2, hash.len()); } #[test] fn test_keys() { static MAP: phf::Map<&'static str, isize> = phf_map!( "foo" => 10, "bar" => 11, ); let hash = MAP.keys().map(|&e| e).collect::>(); assert!(hash.contains(&("foo"))); assert!(hash.contains(&("bar"))); assert_eq!(2, hash.len()); } #[test] fn test_values() { static MAP: phf::Map<&'static str, isize> = phf_map!( "foo" => 10, "bar" => 11, ); let hash = MAP.values().map(|&e| e).collect::>(); assert!(hash.contains(&10)); assert!(hash.contains(&11)); assert_eq!(2, hash.len()); } #[test] fn test_large() { static MAP: phf::Map<&'static str, isize> = phf_map!( "a" => 0, "b" => 1, "c" => 2, "d" => 3, "e" => 4, "f" => 5, "g" => 6, "h" => 7, "i" => 8, "j" => 9, "k" => 10, "l" => 11, "m" => 12, "n" => 13, "o" => 14, "p" => 15, "q" => 16, "r" => 17, "s" => 18, "t" => 19, "u" => 20, "v" => 21, "w" => 22, "x" => 23, "y" => 24, "z" => 25, ); assert!(MAP.get(&("a")) == Some(&0)); } #[test] fn test_non_static_str_key() { static MAP: phf::Map<&'static str, isize> = phf_map!( "a" => 0, ); assert_eq!(Some(&0), MAP.get(&*"a".to_string())); } #[test] fn test_index_ok() { static MAP: phf::Map<&'static str, isize> = phf_map!( "a" => 0, ); assert_eq!(0, MAP["a"]); } #[test] #[should_panic] fn test_index_fail() { static MAP: phf::Map<&'static str, isize> = phf_map!( "a" => 0, ); MAP["b"]; } macro_rules! test_key_type( ($t:ty, $($k:expr => $v:expr),+) => ({ static MAP: phf::Map<$t, isize> = phf_map! { $($k => $v),+ }; $( assert_eq!(Some(&$v), MAP.get(&$k)); )+ }) ); #[test] fn test_array_vals() { static MAP: phf::Map<&'static str, [u8; 3]> = phf_map!( "a" => [0u8, 1, 2], ); assert_eq!(Some(&[0u8, 1, 2]), MAP.get(&("a"))); } #[test] fn test_array_keys() { static MAP: phf::Map<[u8; 2], isize> = phf_map!( [0u8, 1] => 0, [2, 3u8] => 1, [4, 5] => 2, ); assert_eq!(Some(&0), MAP.get(&[0u8, 1u8])); } #[test] fn test_byte_keys() { test_key_type!(u8, b'a' => 0, b'b' => 1); } #[test] fn test_char_keys() { test_key_type!(char, 'a' => 0, 'b' => 1); } #[test] fn test_i8_keys() { test_key_type!(i8, 0i8 => 0, 1i8 => 1, 127i8 => 2, -128i8 => 3); } #[test] fn test_i16_keys() { test_key_type!(i16, 0i16 => 0, 1i16 => 1, 32767i16 => 2, -32768i16 => 3); } #[test] fn test_i32_keys() { test_key_type!(i32, 0i32 => 0, 1i32 => 1, 2147483647i32 => 2, -2147483648i32 => 3); } #[test] fn test_i64_keys() { test_key_type!(i64, 0i64 => 0, 1i64 => 1, -9223372036854775808i64 => 2); } #[test] fn test_i128_keys() { test_key_type!( i128, 0i128 => 0, 1i128 => 1, // `syn` handles literals larger than 64-bit differently 170141183460469231731687303715884105727i128 => 2, -170141183460469231731687303715884105727i128 => 3 ); } #[test] fn test_u8_keys() { test_key_type!(u8, 0u8 => 0, 1u8 => 1, 255u8 => 2); } #[test] fn test_u16_keys() { test_key_type!(u16, 0u16 => 0, 1u16 => 1, 65535u16 => 2); } #[test] fn test_u32_keys() { test_key_type!(u32, 0u32 => 0, 1u32 => 1, 4294967295u32 => 2); } #[test] fn test_u64_keys() { test_key_type!(u64, 0u64 => 0, 1u64 => 1, 18446744073709551615u64 => 2); } #[test] fn test_u128_keys() { test_key_type!( u128, 0u128 => 0, 1u128 => 1, 340282366920938463463374607431768211455u128 => 2 ); } #[test] fn test_bool_keys() { test_key_type!(bool, false => 0, true => 1); } #[test] fn test_into_iterator() { static MAP: phf::Map<&'static str, isize> = phf_map!( "foo" => 10, ); for (k, v) in &MAP { assert_eq!(&"foo", k); assert_eq!(&10, v) } } #[cfg(feature = "unicase_support")] #[test] fn test_unicase() { use unicase::UniCase; static MAP: phf::Map, isize> = phf_map!( UniCase("FOO") => 10, UniCase("Bar") => 11, ); assert!(Some(&10) == MAP.get(&UniCase("FOo"))); assert!(Some(&11) == MAP.get(&UniCase("bar"))); assert_eq!(None, MAP.get(&UniCase("asdf"))); } #[cfg(feature = "unicase_support")] #[test] fn test_unicase_alt() { use unicase; static MAP: phf::Map, isize> = phf_map!( unicase::UniCase("FOO") => 10, unicase::UniCase("Bar") => 11, ); assert!(Some(&10) == MAP.get(&unicase::UniCase("FOo"))); assert!(Some(&11) == MAP.get(&unicase::UniCase("bar"))); assert_eq!(None, MAP.get(&unicase::UniCase("asdf"))); } } mod set { use std::collections::HashSet; use phf::phf_set; #[allow(dead_code)] static TRAILING_COMMA: phf::Set<&'static str> = phf_set! { "foo", }; #[allow(dead_code)] static NO_TRAILING_COMMA: phf::Set<&'static str> = phf_set! { "foo" }; #[test] fn test_two() { static SET: phf::Set<&'static str> = phf_set! { "hello", "world", }; assert!(SET.contains(&"hello")); assert!(SET.contains(&"world")); assert!(!SET.contains(&"foo")); assert_eq!(2, SET.len()); } #[test] fn test_iter() { static SET: phf::Set<&'static str> = phf_set! { "hello", "world", }; let set = SET.iter().map(|e| *e).collect::>(); assert!(set.contains(&"hello")); assert!(set.contains(&"world")); assert_eq!(2, set.len()); } #[test] fn test_non_static_str_contains() { static SET: phf::Set<&'static str> = phf_set! { "hello", "world", }; assert!(SET.contains(&*"hello".to_string())); } #[test] fn test_into_iterator() { static SET: phf::Set<&'static str> = phf_set! { "hello", }; for e in &SET { assert_eq!(&"hello", e); } } } phf_macros-0.8.0/.cargo_vcs_info.json0000644000000001120000000000000132130ustar00{ "git": { "sha1": "81c7cc5b48649108428671d3b8ad151f6fbdb359" } }