1 //! This example shows how to do struct and field parsing using darling. 2 3 #[macro_use] 4 extern crate darling; 5 extern crate proc_macro2; 6 #[macro_use] 7 extern crate quote; 8 extern crate syn; 9 10 use darling::ast; 11 use darling::FromDeriveInput; 12 use proc_macro2::TokenStream; 13 use quote::ToTokens; 14 use syn::parse_str; 15 16 /// A speaking volume. Deriving `FromMeta` will cause this to be usable 17 /// as a string value for a meta-item key. 18 #[derive(Debug, Clone, Copy, FromMeta)] 19 #[darling(default)] 20 enum Volume { 21 Normal, 22 Whisper, 23 Shout, 24 } 25 26 impl Default for Volume { 27 fn default() -> Self { 28 Volume::Normal 29 } 30 } 31 32 /// Support parsing from a full derive input. Unlike FromMeta, this isn't 33 /// composable; each darling-dependent crate should have its own struct to handle 34 /// when its trait is derived. 35 #[derive(Debug, FromDeriveInput)] 36 // This line says that we want to process all attributes declared with `my_trait`, 37 // and that darling should panic if this receiver is given an enum. 38 #[darling(attributes(my_trait), supports(struct_any))] 39 struct MyInputReceiver { 40 /// The struct ident. 41 ident: syn::Ident, 42 43 /// The type's generics. You'll need these any time your trait is expected 44 /// to work with types that declare generics. 45 generics: syn::Generics, 46 47 /// Receives the body of the struct or enum. We don't care about 48 /// struct fields because we previously told darling we only accept structs. 49 data: ast::Data<(), MyFieldReceiver>, 50 51 /// The Input Receiver demands a volume, so use `Volume::Normal` if the 52 /// caller doesn't provide one. 53 #[darling(default)] 54 volume: Volume, 55 } 56 57 impl ToTokens for MyInputReceiver { 58 fn to_tokens(&self, tokens: &mut TokenStream) { 59 let MyInputReceiver { 60 ref ident, 61 ref generics, 62 ref data, 63 volume, 64 } = *self; 65 66 let (imp, ty, wher) = generics.split_for_impl(); 67 let fields = data 68 .as_ref() 69 .take_struct() 70 .expect("Should never be enum") 71 .fields; 72 73 // Generate the format string which shows each field and its name 74 let fmt_string = fields 75 .iter() 76 .enumerate() 77 .map(|(i, f)| { 78 // We have to preformat the ident in this case so we can fall back 79 // to the field index for unnamed fields. It's not easy to read, 80 // unfortunately. 81 format!( 82 "{} = {{}}", 83 f.ident 84 .as_ref() 85 .map(|v| format!("{}", v)) 86 .unwrap_or_else(|| format!("{}", i)) 87 ) 88 }) 89 .collect::<Vec<_>>() 90 .join(", "); 91 92 // Generate the actual values to fill the format string. 93 let field_list = fields 94 .into_iter() 95 .enumerate() 96 .map(|(i, f)| { 97 let field_volume = f.volume.unwrap_or(volume); 98 99 // This works with named or indexed fields, so we'll fall back to the index so we can 100 // write the output as a key-value pair. 101 let field_ident = f.ident 102 .as_ref() 103 .map(|v| quote!(#v)) 104 .unwrap_or_else(|| quote!(#i)); 105 106 match field_volume { 107 Volume::Normal => quote!(self.#field_ident), 108 Volume::Shout => { 109 quote!(::std::string::ToString::to_string(&self.#field_ident).to_uppercase()) 110 } 111 Volume::Whisper => { 112 quote!(::std::string::ToString::to_string(&self.#field_ident).to_lowercase()) 113 } 114 } 115 }) 116 .collect::<Vec<_>>(); 117 118 tokens.extend(quote! { 119 impl #imp Speak for #ident #ty #wher { 120 fn speak(&self, writer: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 121 write!(#fmt_string, #(#field_list),*) 122 } 123 } 124 }); 125 } 126 } 127 128 #[derive(Debug, FromField)] 129 #[darling(attributes(my_trait))] 130 struct MyFieldReceiver { 131 /// Get the ident of the field. For fields in tuple or newtype structs or 132 /// enum bodies, this can be `None`. 133 ident: Option<syn::Ident>, 134 135 /// This magic field name pulls the type from the input. 136 ty: syn::Type, 137 138 /// We declare this as an `Option` so that during tokenization we can write 139 /// `field.volume.unwrap_or(derive_input.volume)` to facilitate field-level 140 /// overrides of struct-level settings. 141 #[darling(default)] 142 volume: Option<Volume>, 143 } 144 145 fn main() { 146 let input = r#"#[derive(MyTrait)] 147 #[my_trait(volume = "shout")] 148 pub struct Foo { 149 #[my_trait(volume = "whisper")] 150 bar: bool, 151 152 baz: i64, 153 }"#; 154 155 let parsed = parse_str(input).unwrap(); 156 let receiver = MyInputReceiver::from_derive_input(&parsed).unwrap(); 157 let tokens = quote!(#receiver); 158 159 println!( 160 r#" 161 INPUT: 162 163 {} 164 165 PARSED AS: 166 167 {:?} 168 169 EMITS: 170 171 {} 172 "#, 173 input, receiver, tokens 174 ); 175 } 176