@@ -209,11 +209,11 @@ use proc_macro::TokenStream;
209209use proc_macro2:: TokenStream as TokenStream2 ;
210210use proc_macro_error2:: { abort, abort_call_site, proc_macro_error} ;
211211use syn:: {
212- parse_macro_input, punctuated:: Punctuated , spanned:: Spanned , Attribute , Data , DataStruct ,
213- DeriveInput , Fields , Meta , Token ,
212+ parse_macro_input, parse_str , punctuated:: Punctuated , spanned:: Spanned , Attribute , Data ,
213+ DataStruct , DeriveInput , Fields , ItemImpl , Meta , Token ,
214214} ;
215215
216- use crate :: generate:: { GenMode , GenParams } ;
216+ use crate :: generate:: { expr_to_string , GenMode , GenParams } ;
217217
218218mod generate;
219219
@@ -272,21 +272,47 @@ pub fn with_setters(input: TokenStream) -> TokenStream {
272272}
273273
274274fn make_params ( attrs : & [ Attribute ] , mode : GenMode ) -> GenParams {
275+ let mut impl_attrs = vec ! [ ] ;
275276 GenParams {
276277 mode,
277- global_attr : attrs. iter ( ) . filter_map ( |v| parse_attr ( v, mode) ) . last ( ) ,
278+ global_attr : attrs
279+ . iter ( )
280+ . filter_map ( |v| {
281+ let ( attr, impl_attrs_exist) = parse_attr ( v, mode, true ) ;
282+ if let Some ( Meta :: NameValue ( code) ) = & impl_attrs_exist {
283+ match expr_to_string ( & code. value ) {
284+ Some ( code_str) => {
285+ match parse_str :: < ItemImpl > ( & format ! ( "{} impl _ {{}}" , code_str) ) {
286+ Ok ( parsed_impl) => impl_attrs. extend ( parsed_impl. attrs ) ,
287+ Err ( _) => abort ! (
288+ code. value. span( ) ,
289+ "Syntax error, expected attributes like #[..]."
290+ ) ,
291+ }
292+ }
293+ None => abort ! ( code. value. span( ) , "Expected string." ) ,
294+ }
295+ }
296+ attr
297+ } )
298+ . last ( ) ,
299+ impl_attrs,
278300 }
279301}
280302
281- fn parse_attr ( attr : & Attribute , mode : GenMode ) -> Option < Meta > {
303+ fn parse_attr (
304+ attr : & Attribute ,
305+ mode : GenMode ,
306+ globally_called : bool ,
307+ ) -> ( Option < Meta > , Option < Meta > ) {
282308 if attr. path ( ) . is_ident ( "getset" ) {
283309 let meta_list = match attr. parse_args_with ( Punctuated :: < Meta , Token ! [ , ] > :: parse_terminated)
284310 {
285311 Ok ( list) => list,
286312 Err ( e) => abort ! ( attr. span( ) , "Failed to parse getset attribute: {}" , e) ,
287313 } ;
288314
289- let ( last, skip, mut collected) = meta_list
315+ let ( last, skip, impl_attrs , mut collected) = meta_list
290316 . into_iter ( )
291317 . inspect ( |meta| {
292318 if !( meta. path ( ) . is_ident ( "get" )
@@ -295,21 +321,24 @@ fn parse_attr(attr: &Attribute, mode: GenMode) -> Option<Meta> {
295321 || meta. path ( ) . is_ident ( "get_mut" )
296322 || meta. path ( ) . is_ident ( "set" )
297323 || meta. path ( ) . is_ident ( "set_with" )
298- || meta. path ( ) . is_ident ( "skip" ) )
324+ || meta. path ( ) . is_ident ( "skip" )
325+ || ( meta. path ( ) . is_ident ( "impl_attrs" ) && globally_called) )
299326 {
300327 abort ! ( meta. path( ) . span( ) , "unknown setter or getter" )
301328 }
302329 } )
303330 . fold (
304- ( None , None , Vec :: new ( ) ) ,
305- |( last, skip, mut collected) , meta| {
331+ ( None , None , None , Vec :: new ( ) ) ,
332+ |( last, skip, impl_attrs , mut collected) , meta| {
306333 if meta. path ( ) . is_ident ( mode. name ( ) ) {
307- ( Some ( meta) , skip, collected)
334+ ( Some ( meta) , skip, impl_attrs , collected)
308335 } else if meta. path ( ) . is_ident ( "skip" ) {
309- ( last, Some ( meta) , collected)
336+ ( last, Some ( meta) , impl_attrs, collected)
337+ } else if meta. path ( ) . is_ident ( "impl_attrs" ) {
338+ ( last, skip, Some ( meta) , collected)
310339 } else {
311340 collected. push ( meta) ;
312- ( last, skip, collected)
341+ ( last, skip, impl_attrs , collected)
313342 }
314343 } ,
315344 ) ;
@@ -318,26 +347,27 @@ fn parse_attr(attr: &Attribute, mode: GenMode) -> Option<Meta> {
318347 // Check if there is any setter or getter used with skip, which is
319348 // forbidden.
320349 if last. is_none ( ) && collected. is_empty ( ) {
321- skip
350+ ( skip, impl_attrs )
322351 } else {
323352 abort ! (
324353 last. or_else( || collected. pop( ) ) . unwrap( ) . path( ) . span( ) ,
325354 "use of setters and getters with skip is invalid"
326355 ) ;
327356 }
328357 } else {
329- last
358+ ( last, impl_attrs )
330359 }
331360 } else if attr. path ( ) . is_ident ( mode. name ( ) ) {
332361 // If skip is not used, return the last occurrence of matching
333362 // setter/getter, if there is any.
334- attr. meta . clone ( ) . into ( )
363+ ( attr. meta . clone ( ) . into ( ) , None )
335364 } else {
336- None
365+ ( None , None )
337366 }
338367}
339368
340369fn produce ( ast : & DeriveInput , params : & GenParams ) -> TokenStream2 {
370+ let impl_attrs = & params. impl_attrs ;
341371 let name = & ast. ident ;
342372 let generics = & ast. generics ;
343373 let ( impl_generics, ty_generics, where_clause) = generics. split_for_impl ( ) ;
@@ -354,6 +384,7 @@ fn produce(ast: &DeriveInput, params: &GenParams) -> TokenStream2 {
354384 let generated = generate:: implement_for_unnamed ( field, params) ;
355385
356386 quote ! {
387+ #( #impl_attrs) *
357388 impl #impl_generics #name #ty_generics #where_clause {
358389 #generated
359390 }
@@ -362,6 +393,7 @@ fn produce(ast: &DeriveInput, params: &GenParams) -> TokenStream2 {
362393 let generated = fields. iter ( ) . map ( |f| generate:: implement ( f, params) ) ;
363394
364395 quote ! {
396+ #( #impl_attrs) *
365397 impl #impl_generics #name #ty_generics #where_clause {
366398 #( #generated) *
367399 }
0 commit comments