@@ -44,32 +44,31 @@ pub fn max_len(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
44
44
tokens. as_str ( ) . parse ( ) . unwrap ( )
45
45
}
46
46
47
- /// On `struct $Name($ValueType)`, add a new static method
48
- /// `fn map() -> &'static ::phf::Map<&'static str, $ValueType>`.
49
- /// The map’s content is given as:
50
- /// `#[cssparser__phf_map__kv_pairs(key = "…", value = "…", key = "…", value = "…")]`.
51
- /// Keys are ASCII-lowercased.
52
- #[ proc_macro_derive( cssparser__phf_map,
53
- attributes( cssparser__phf_map__kv_pairs) ) ]
47
+ /// ```
48
+ /// impl $Name {
49
+ /// fn map() -> &'static ::phf::Map<&'static str, $ValueType> { … }
50
+ /// }
51
+ /// ```
52
+ ///
53
+ /// Map keys are ASCII-lowercased.
54
+ #[ proc_macro_derive( cssparser__phf_map) ]
54
55
pub fn phf_map ( input : proc_macro:: TokenStream ) -> proc_macro:: TokenStream {
55
56
let input = syn:: parse_macro_input ( & input. to_string ( ) ) . unwrap ( ) ;
56
57
let name = & input. ident ;
57
- let value_type = match input. body {
58
- syn:: Body :: Struct ( syn:: VariantData :: Tuple ( ref fields) ) if fields. len ( ) == 1 => {
59
- & fields[ 0 ] . ty
60
- }
61
- _ => panic ! ( "expected tuple struct newtype, got {:?}" , input. body)
62
- } ;
63
-
64
- let pairs: Vec < _ > = list_attr ( & input, "cssparser__phf_map__kv_pairs" ) . chunks ( 2 ) . map ( |chunk| {
65
- let key = sub_attr_value ( & chunk[ 0 ] , "key" ) ;
66
- let value = sub_attr_value ( & chunk[ 1 ] , "value" ) ;
67
- ( key. to_ascii_lowercase ( ) , value)
58
+ let token_trees = find_smuggled_tokens ( & input) ;
59
+ let value_type = & token_trees[ 0 ] ;
60
+ let pairs: Vec < _ > = token_trees[ 1 ..] . chunks ( 2 ) . map ( |chunk| {
61
+ let key = match chunk[ 0 ] {
62
+ syn:: TokenTree :: Token ( syn:: Token :: Literal ( syn:: Lit :: Str ( ref string, _) ) ) => string,
63
+ _ => panic ! ( "expected string literal, got {:?}" , chunk[ 0 ] )
64
+ } ;
65
+ let value = & chunk[ 1 ] ;
66
+ ( key. to_ascii_lowercase ( ) , quote ! ( #value) . to_string ( ) )
68
67
} ) . collect ( ) ;
69
68
70
69
let mut map = phf_codegen:: Map :: new ( ) ;
71
- for & ( ref key, value) in & pairs {
72
- map. entry ( & * * key, value) ;
70
+ for & ( ref key, ref value) in & pairs {
71
+ map. entry ( & * * key, & * * value) ;
73
72
}
74
73
75
74
let mut initializer_bytes = Vec :: < u8 > :: new ( ) ;
@@ -90,6 +89,42 @@ pub fn phf_map(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
90
89
tokens. as_str ( ) . parse ( ) . unwrap ( )
91
90
}
92
91
92
+ /// Return the `…` part in:
93
+ ///
94
+ /// ```rust
95
+ /// enum $Name {
96
+ /// Input = (0, stringify!(…)).0
97
+ /// }
98
+ /// ```
99
+ fn find_smuggled_tokens ( input : & syn:: DeriveInput ) -> & [ syn:: TokenTree ] {
100
+ let discriminant = match input. body {
101
+ syn:: Body :: Enum ( ref variants) if variants. len ( ) == 1 => & variants[ 0 ] . discriminant ,
102
+ _ => panic ! ( "expected single-variant enum, got {:?}" , input. body)
103
+ } ;
104
+ let tuple = match * discriminant {
105
+ Some ( syn:: ConstExpr :: Other ( syn:: Expr { node : syn:: ExprKind :: TupField ( ref t, 0 ) , .. } ) ) => t,
106
+ _ => panic ! ( "expected a discriminant like tuple.0, got {:?}" , discriminant)
107
+ } ;
108
+ let expr = match * * tuple {
109
+ syn:: Expr { node : syn:: ExprKind :: Tup ( ref values) , .. } if values. len ( ) == 2 => & values[ 1 ] ,
110
+ _ => panic ! ( "expected non-empty tuple, got {:?}" , tuple)
111
+ } ;
112
+ let macro_args = match * expr {
113
+ syn:: Expr { node : syn:: ExprKind :: Mac (
114
+ syn:: Mac { ref tts, path : syn:: Path { global : false , ref segments } }
115
+ ) , .. }
116
+ if segments. len ( ) == 1
117
+ && segments[ 0 ] == syn:: PathSegment :: from ( "stringify" )
118
+ && tts. len ( ) == 1
119
+ => & tts[ 0 ] ,
120
+ _ => panic ! ( "expected a stringify!(…) macro, got {:?}" , expr)
121
+ } ;
122
+ match * macro_args {
123
+ syn:: TokenTree :: Delimited ( syn:: Delimited { ref tts, delim : syn:: DelimToken :: Paren } ) => tts,
124
+ _ => panic ! ( "expected (…) parentheses, got {:?}" , macro_args)
125
+ }
126
+ }
127
+
93
128
/// Panic if the first attribute isn’t `#[foo(…)]` with the given name,
94
129
/// or return the parameters.
95
130
fn list_attr < ' a > ( input : & ' a syn:: DeriveInput , expected_name : & str ) -> & ' a [ syn:: NestedMetaItem ] {
0 commit comments