1use phf_generator::HashState;
7use phf_shared::PhfHash;
8use proc_macro::TokenStream;
9use quote::quote;
10use std::collections::HashSet;
11use std::hash::Hasher;
12use syn::parse::{self, Parse, ParseStream};
13use syn::punctuated::Punctuated;
14use syn::{parse_macro_input, Error, Expr, ExprLit, Lit, Token, UnOp};
15#[cfg(feature = "uncased")]
16use uncased_::Uncased;
17#[cfg(feature = "unicase")]
18use unicase_::{Ascii, UniCase};
19
20#[derive(Hash, PartialEq, Eq, Clone)]
21enum ParsedKey {
22 Str(String),
23 Binary(Vec<u8>),
24 Char(char),
25 I8(i8),
26 I16(i16),
27 I32(i32),
28 I64(i64),
29 I128(i128),
30 Isize(isize),
31 U8(u8),
32 U16(u16),
33 U32(u32),
34 U64(u64),
35 U128(u128),
36 Usize(usize),
37 Bool(bool),
38 #[cfg(feature = "unicase")]
39 UniCase(UniCase<String>),
40 #[cfg(feature = "unicase")]
41 UniCaseAscii(Ascii<String>),
42 #[cfg(feature = "uncased")]
43 Uncased(Uncased<'static>),
44}
45
46impl PhfHash for ParsedKey {
47 fn phf_hash<H>(&self, state: &mut H)
48 where
49 H: Hasher,
50 {
51 match self {
52 ParsedKey::Str(s) => s.phf_hash(state),
53 ParsedKey::Binary(s) => s.phf_hash(state),
54 ParsedKey::Char(s) => s.phf_hash(state),
55 ParsedKey::I8(s) => s.phf_hash(state),
56 ParsedKey::I16(s) => s.phf_hash(state),
57 ParsedKey::I32(s) => s.phf_hash(state),
58 ParsedKey::I64(s) => s.phf_hash(state),
59 ParsedKey::I128(s) => s.phf_hash(state),
60 ParsedKey::Isize(s) => s.phf_hash(state),
61 ParsedKey::U8(s) => s.phf_hash(state),
62 ParsedKey::U16(s) => s.phf_hash(state),
63 ParsedKey::U32(s) => s.phf_hash(state),
64 ParsedKey::U64(s) => s.phf_hash(state),
65 ParsedKey::U128(s) => s.phf_hash(state),
66 ParsedKey::Usize(s) => s.phf_hash(state),
67 ParsedKey::Bool(s) => s.phf_hash(state),
68 #[cfg(feature = "unicase")]
69 ParsedKey::UniCase(s) => s.phf_hash(state),
70 #[cfg(feature = "unicase")]
71 ParsedKey::UniCaseAscii(s) => s.phf_hash(state),
72 #[cfg(feature = "uncased")]
73 ParsedKey::Uncased(s) => s.phf_hash(state),
74 }
75 }
76}
77
78impl ParsedKey {
79 fn from_expr(expr: &Expr) -> Option<ParsedKey> {
80 match expr {
81 Expr::Lit(lit) => match &lit.lit {
82 Lit::Str(s) => Some(ParsedKey::Str(s.value())),
83 Lit::ByteStr(s) => Some(ParsedKey::Binary(s.value())),
84 Lit::Byte(s) => Some(ParsedKey::U8(s.value())),
85 Lit::Char(s) => Some(ParsedKey::Char(s.value())),
86 Lit::Int(s) => match s.suffix() {
87 "i8" => Some(ParsedKey::I8(s.base10_parse::<u8>().unwrap() as i8)),
91 "i16" => Some(ParsedKey::I16(s.base10_parse::<u16>().unwrap() as i16)),
92 "i32" => Some(ParsedKey::I32(s.base10_parse::<u32>().unwrap() as i32)),
93 "i64" => Some(ParsedKey::I64(s.base10_parse::<u64>().unwrap() as i64)),
94 "i128" => Some(ParsedKey::I128(s.base10_parse::<u128>().unwrap() as i128)),
95 "isize" => Some(ParsedKey::Isize(s.base10_parse::<usize>().unwrap() as isize)),
96 "u8" => Some(ParsedKey::U8(s.base10_parse::<u8>().unwrap())),
97 "u16" => Some(ParsedKey::U16(s.base10_parse::<u16>().unwrap())),
98 "u32" => Some(ParsedKey::U32(s.base10_parse::<u32>().unwrap())),
99 "u64" => Some(ParsedKey::U64(s.base10_parse::<u64>().unwrap())),
100 "u128" => Some(ParsedKey::U128(s.base10_parse::<u128>().unwrap())),
101 "usize" => Some(ParsedKey::Usize(s.base10_parse::<usize>().unwrap())),
102 _ => None,
103 },
104 Lit::Bool(s) => Some(ParsedKey::Bool(s.value)),
105 _ => None,
106 },
107 Expr::Array(array) => {
108 let mut buf = vec![];
109 for expr in &array.elems {
110 match expr {
111 Expr::Lit(lit) => match &lit.lit {
112 Lit::Int(s) => match s.suffix() {
113 "u8" | "" => buf.push(s.base10_parse::<u8>().unwrap()),
114 _ => return None,
115 },
116 _ => return None,
117 },
118 _ => return None,
119 }
120 }
121 Some(ParsedKey::Binary(buf))
122 }
123 Expr::Unary(unary) => {
124 macro_rules! try_negate (
128 ($val:expr) => {if $val < 0 { $val } else { -$val }}
129 );
130
131 match unary.op {
132 UnOp::Neg(_) => match ParsedKey::from_expr(&unary.expr)? {
133 ParsedKey::I8(v) => Some(ParsedKey::I8(try_negate!(v))),
134 ParsedKey::I16(v) => Some(ParsedKey::I16(try_negate!(v))),
135 ParsedKey::I32(v) => Some(ParsedKey::I32(try_negate!(v))),
136 ParsedKey::I64(v) => Some(ParsedKey::I64(try_negate!(v))),
137 ParsedKey::I128(v) => Some(ParsedKey::I128(try_negate!(v))),
138 ParsedKey::Isize(v) => Some(ParsedKey::Isize(try_negate!(v))),
139 _ => None,
140 },
141 UnOp::Deref(_) => {
142 let mut expr = &*unary.expr;
143 while let Expr::Group(group) = expr {
144 expr = &*group.expr;
145 }
146 match expr {
147 Expr::Lit(ExprLit {
148 lit: Lit::ByteStr(s),
149 ..
150 }) => Some(ParsedKey::Binary(s.value())),
151 _ => None,
152 }
153 }
154 _ => None,
155 }
156 }
157 Expr::Group(group) => ParsedKey::from_expr(&group.expr),
158 Expr::Call(call) if call.args.len() == 1 => {
159 let last;
160 let last_ahead;
161
162 if let Expr::Path(ep) = call.func.as_ref() {
163 let mut segments = ep.path.segments.iter();
164 last = segments.next_back()?.ident.to_string();
165 last_ahead = segments.next_back()?.ident.to_string();
166 } else {
167 return None;
168 }
169
170 let mut arg = call.args.first().unwrap();
171
172 while let Expr::Group(group) = arg {
173 arg = &group.expr;
174 }
175
176 let _value = match arg {
177 Expr::Lit(ExprLit {
178 attrs: _,
179 lit: Lit::Str(s),
180 }) => s.value(),
181 _ => {
182 return None;
183 }
184 };
185
186 match (&*last_ahead, &*last) {
187 #[cfg(feature = "unicase")]
188 ("UniCase", "unicode") => Some(ParsedKey::UniCase(UniCase::unicode(_value))),
189 #[cfg(feature = "unicase")]
190 ("UniCase", "ascii") => Some(ParsedKey::UniCase(UniCase::ascii(_value))),
191 #[cfg(feature = "unicase")]
192 ("Ascii", "new") => Some(ParsedKey::UniCaseAscii(Ascii::new(_value))),
193 #[cfg(feature = "uncased")]
194 ("UncasedStr", "new") => Some(ParsedKey::Uncased(Uncased::new(_value))),
195 _ => None,
196 }
197 }
198 _ => None,
199 }
200 }
201}
202
203struct Key {
204 parsed: ParsedKey,
205 expr: Expr,
206}
207
208impl PhfHash for Key {
209 fn phf_hash<H>(&self, state: &mut H)
210 where
211 H: Hasher,
212 {
213 self.parsed.phf_hash(state)
214 }
215}
216
217impl Parse for Key {
218 fn parse(input: ParseStream<'_>) -> parse::Result<Key> {
219 let expr = input.parse()?;
220 let parsed = ParsedKey::from_expr(&expr)
221 .ok_or_else(|| Error::new_spanned(&expr, "unsupported key expression"))?;
222
223 Ok(Key { parsed, expr })
224 }
225}
226
227struct Entry {
228 key: Key,
229 value: Expr,
230}
231
232impl PhfHash for Entry {
233 fn phf_hash<H>(&self, state: &mut H)
234 where
235 H: Hasher,
236 {
237 self.key.phf_hash(state)
238 }
239}
240
241impl Parse for Entry {
242 fn parse(input: ParseStream<'_>) -> parse::Result<Entry> {
243 let key = input.parse()?;
244 input.parse::<Token![=>]>()?;
245 let value = input.parse()?;
246 Ok(Entry { key, value })
247 }
248}
249
250struct Map(Vec<Entry>);
251
252impl Parse for Map {
253 fn parse(input: ParseStream<'_>) -> parse::Result<Map> {
254 let parsed = Punctuated::<Entry, Token![,]>::parse_terminated(input)?;
255 let map = parsed.into_iter().collect::<Vec<_>>();
256 check_duplicates(&map)?;
257 Ok(Map(map))
258 }
259}
260
261struct Set(Vec<Entry>);
262
263impl Parse for Set {
264 fn parse(input: ParseStream<'_>) -> parse::Result<Set> {
265 let parsed = Punctuated::<Key, Token![,]>::parse_terminated(input)?;
266 let set = parsed
267 .into_iter()
268 .map(|key| Entry {
269 key,
270 value: syn::parse_str("()").unwrap(),
271 })
272 .collect::<Vec<_>>();
273 check_duplicates(&set)?;
274 Ok(Set(set))
275 }
276}
277
278fn check_duplicates(entries: &[Entry]) -> parse::Result<()> {
279 let mut keys = HashSet::new();
280 for entry in entries {
281 if !keys.insert(&entry.key.parsed) {
282 return Err(Error::new_spanned(&entry.key.expr, "duplicate key"));
283 }
284 }
285 Ok(())
286}
287
288fn build_map(entries: &[Entry], state: HashState) -> proc_macro2::TokenStream {
289 let key = state.key;
290 let disps = state.disps.iter().map(|&(d1, d2)| quote!((#d1, #d2)));
291 let entries = state.map.iter().map(|&idx| {
292 let key = &entries[idx].key.expr;
293 let value = &entries[idx].value;
294 quote!((#key, #value))
295 });
296
297 quote! {
298 phf::Map {
299 key: #key,
300 disps: &[#(#disps),*],
301 entries: &[#(#entries),*],
302 }
303 }
304}
305
306fn build_ordered_map(entries: &[Entry], state: HashState) -> proc_macro2::TokenStream {
307 let key = state.key;
308 let disps = state.disps.iter().map(|&(d1, d2)| quote!((#d1, #d2)));
309 let idxs = state.map.iter().map(|idx| quote!(#idx));
310 let entries = entries.iter().map(|entry| {
311 let key = &entry.key.expr;
312 let value = &entry.value;
313 quote!((#key, #value))
314 });
315
316 quote! {
317 phf::OrderedMap {
318 key: #key,
319 disps: &[#(#disps),*],
320 idxs: &[#(#idxs),*],
321 entries: &[#(#entries),*],
322 }
323 }
324}
325
326#[proc_macro]
327pub fn phf_map(input: TokenStream) -> TokenStream {
328 let map = parse_macro_input!(input as Map);
329 let state = phf_generator::generate_hash(&map.0);
330
331 build_map(&map.0, state).into()
332}
333
334#[proc_macro]
335pub fn phf_set(input: TokenStream) -> TokenStream {
336 let set = parse_macro_input!(input as Set);
337 let state = phf_generator::generate_hash(&set.0);
338
339 let map = build_map(&set.0, state);
340 quote!(phf::Set { map: #map }).into()
341}
342
343#[proc_macro]
344pub fn phf_ordered_map(input: TokenStream) -> TokenStream {
345 let map = parse_macro_input!(input as Map);
346 let state = phf_generator::generate_hash(&map.0);
347
348 build_ordered_map(&map.0, state).into()
349}
350
351#[proc_macro]
352pub fn phf_ordered_set(input: TokenStream) -> TokenStream {
353 let set = parse_macro_input!(input as Set);
354 let state = phf_generator::generate_hash(&set.0);
355
356 let map = build_ordered_map(&set.0, state);
357 quote!(phf::OrderedSet { map: #map }).into()
358}