@@ -44,6 +44,9 @@ struct Options {
4444
4545 #[ darling( default = "Options::default_async_local" ) ]
4646 async_local : bool ,
47+
48+ #[ darling( default = "Options::default_generic" ) ]
49+ generic : bool ,
4750}
4851
4952impl Options {
@@ -54,6 +57,10 @@ impl Options {
5457 fn default_async_local ( ) -> bool {
5558 false
5659 }
60+
61+ fn default_generic ( ) -> bool {
62+ false
63+ }
5764}
5865
5966struct Args {
@@ -176,6 +183,8 @@ fn try_async_trait_fn_rewrite(args: &Args, body: &Block) -> Option<TokenStream2>
176183fn wrap_with_span ( args : & Args , block : TokenStream2 ) -> TokenStream2 {
177184 let apply_fn = if args. options . async_local {
178185 quote ! ( apply_local)
186+ } else if args. options . generic {
187+ quote ! ( apply_generic)
179188 } else {
180189 quote ! ( apply)
181190 } ;
@@ -321,6 +330,38 @@ mod tests {
321330 assert_eq ! ( actual, expected) ;
322331 }
323332
333+ #[ test]
334+ fn expand_async_fn_generic ( ) {
335+ let args = parse_attr ! {
336+ #[ span_fn( "async_span" , generic = true ) ]
337+ } ;
338+
339+ let item_fn = parse_quote ! {
340+ async fn do_async( ) -> io:: Result <String > {
341+ do_something_else( ) . await ;
342+
343+ Ok ( "foo" . into( ) )
344+ }
345+ } ;
346+
347+ let actual = expand_from_parsed ( args, item_fn) . to_string ( ) ;
348+
349+ let expected = code_str ! {
350+ async fn do_async<>( ) -> io:: Result <String > {
351+ :: foundations:: telemetry:: tracing:: span( "async_span" )
352+ . into_context( )
353+ . apply_generic( async move { {
354+ do_something_else( ) . await ;
355+
356+ Ok ( "foo" . into( ) )
357+ } } )
358+ . await
359+ }
360+ } ;
361+
362+ assert_eq ! ( actual, expected) ;
363+ }
364+
324365 #[ test]
325366 fn expand_async_trait_fn ( ) {
326367 let args = parse_attr ! {
@@ -453,6 +494,72 @@ mod tests {
453494 assert_eq ! ( actual, expected) ;
454495 }
455496
497+ #[ test]
498+ fn expand_async_trait_fn_generic ( ) {
499+ let args = parse_attr ! {
500+ #[ span_fn( "async_trait_span" , generic = true ) ]
501+ } ;
502+
503+ let item_fn = parse_quote ! {
504+ fn test<' life0, ' async_trait>(
505+ & ' life0 self ,
506+ ) -> :: core:: pin:: Pin <
507+ Box <dyn :: core:: future:: Future <Output = String > + :: core:: marker:: Send + ' async_trait>
508+ >
509+ where
510+ ' life0: ' async_trait,
511+ Self : ' async_trait,
512+ {
513+ Box :: pin( async move {
514+ if let :: core:: option:: Option :: Some ( __ret) = :: core:: option:: Option :: None :: <String > {
515+ return __ret;
516+ }
517+ let __self = self ;
518+ let __ret: String = {
519+ __self. do_something_else( ) . await ;
520+ "foo" . into( )
521+ } ;
522+ #[ allow( unreachable_code) ]
523+ __ret
524+ } )
525+ }
526+ } ;
527+
528+ let actual = expand_from_parsed ( args, item_fn) . to_string ( ) ;
529+
530+ let expected = code_str ! {
531+ fn test<' life0, ' async_trait>(
532+ & ' life0 self ,
533+ ) -> :: core:: pin:: Pin <
534+ Box <dyn :: core:: future:: Future <Output = String > + :: core:: marker:: Send + ' async_trait>
535+ >
536+ where
537+ ' life0: ' async_trait,
538+ Self : ' async_trait,
539+ {
540+ Box :: pin( async move {
541+ :: foundations:: telemetry:: tracing:: span( "async_trait_span" )
542+ . into_context( )
543+ . apply_generic( async move {
544+ if let :: core:: option:: Option :: Some ( __ret) = :: core:: option:: Option :: None :: <String > {
545+ return __ret;
546+ }
547+ let __self = self ;
548+ let __ret: String = {
549+ __self. do_something_else( ) . await ;
550+ "foo" . into( )
551+ } ;
552+ #[ allow( unreachable_code) ]
553+ __ret
554+ } )
555+ . await
556+ } )
557+ }
558+ } ;
559+
560+ assert_eq ! ( actual, expected) ;
561+ }
562+
456563 #[ test]
457564 fn expand_structure_with_crate_path ( ) {
458565 let args = parse_attr ! {
0 commit comments