phf_macros/
lib.rs

1//! A set of macros to generate Rust source for PHF data structures at compile time.
2//! See [the `phf` crate's documentation][phf] for details.
3//!
4//! [phf]: https://docs.rs/phf
5
6use 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                    // we've lost the sign at this point, so `-128i8` looks like `128i8`,
88                    // which doesn't fit in an `i8`; parse it as a `u8` and cast (to `0i8`),
89                    // which is handled below, by `Unary`
90                    "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                // if we received an integer literal (always unsigned) greater than i__::max_value()
125                // then casting it to a signed integer type of the same width will negate it to
126                // the same absolute value so we don't need to negate it here
127                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}