1extern crate fxhash;
2extern crate proc_macro;
3#[macro_use]
4extern crate quote;
5extern crate syn;
6
7use proc_macro::TokenStream;
8
9mod builder;
10use builder::Builder;
11
12type Key<'a> = syn::Lit;
13type Value<'a> = &'a str;
14
15const LEADING: &str = "enum __StaticMap__ {\n A =\n static_map!(@ zero";
16const TRAILING: &str = "),\n}";
17
18fn trim(input: &str) -> &str {
19 assert!(input.starts_with(LEADING));
20 assert!(input.ends_with(TRAILING));
21
22 let (_, input) = input.split_at(LEADING.len());
23 let (input, _) = input.split_at(input.len() - TRAILING.len());
24 input.trim()
25}
26
27#[proc_macro_derive(StaticMapMacro)]
28pub fn static_map_macro(input: TokenStream) -> TokenStream {
29 let s = input.to_string();
30 let result = build_static_map(trim(&s));
31
32 let wrapper = quote! {
33 macro_rules! __static_map__construct_map {
34 () => ( #result )
35 }
36 };
37
38 wrapper.parse().unwrap()
39}
40
41fn build_static_map(input: &str) -> quote::Tokens {
42 let mut tt = input.split('@');
45
46 let default_value = tt.next().unwrap();
49
50 let count = input.chars().filter(|&c| c == '@').count();
52 let mut builder = Builder::with_capacity(count);
53
54 let mut pair = tt
56 .next()
57 .expect("staticmap! requires at least one key/value pair")
58 .split('?');
59
60 let default_key = syn::parse::lit(pair.next().unwrap()).expect("failed to parse key type");
61 let value = pair.next().unwrap();
62 builder.insert(default_key.clone(), value);
63
64 for pair in tt {
65 let mut pair = pair.split('?');
66
67 let key = syn::parse::lit(pair.next().unwrap()).expect("failed to parse key type");
69 let value = pair.next().unwrap();
70 builder.insert(key, value);
71 }
72
73 builder.build(lit_default(&default_key), default_value)
74}
75
76fn lit_default(lit: &syn::Lit) -> syn::Lit {
77 use syn::Lit::*;
78 use syn::Lit;
79
80 match *lit {
81 Str(_, _) => Lit::from(""),
82 Byte(_) => Lit::from(0u8),
83 Char(_) => Lit::from(0 as char),
84 Int(_, ty) => {
85 use syn::IntTy::*;
86 use syn::IntTy;
87 match ty {
88 Isize => Lit::from(0isize),
89 I8 => Lit::from(0i8),
90 I16 => Lit::from(0i16),
91 I32 => Lit::from(0i32),
92 I64 => Lit::from(0i64),
93 Usize => Lit::from(0usize),
94 U8 => Lit::from(0u8),
95 U16 => Lit::from(0u16),
96 U32 => Lit::from(0u32),
97 U64 => Lit::from(0u64),
98 Unsuffixed => Lit::Int(0, IntTy::Unsuffixed),
99 }
100 },
101 ref lit => panic!("staticmap! unsupported key type `{:?}`", lit),
102 }
103}