@@ -11,8 +11,8 @@ use crate::{
11
11
use proc_macro2:: { Span , TokenStream } ;
12
12
use quote:: { format_ident, quote, ToTokens } ;
13
13
use syn:: {
14
- parse2, parse_quote, punctuated:: Punctuated , Data , DeriveInput , Error , Index , Member , Result ,
15
- Token , Type ,
14
+ parse2, parse_quote, punctuated:: Punctuated , Data , DeriveInput , Error , GenericArgument ,
15
+ GenericParam , Index , Lifetime , Member , PathArguments , Result , Token , TypePath ,
16
16
} ;
17
17
18
18
pub fn derive ( node : & DeriveInput ) -> Result < TokenStream > {
@@ -417,11 +417,11 @@ fn struct_main_code_block(input: &Struct, ctx: &ImplContext) -> TokenStream {
417
417
Kind :: OwnedInto | Kind :: RefInto => {
418
418
let dst = if ctx. struct_attr . ty . nameless_tuple || ctx. has_post_init {
419
419
TokenStream :: new ( )
420
- } else if let Ok ( Type :: Path ( mut path) ) = parse2 :: < Type > ( ctx. dst_ty . clone ( ) ) {
420
+ } else if let Ok ( mut path) = parse2 :: < TypePath > ( ctx. dst_ty . clone ( ) ) {
421
421
// In this case we want to transform something like `mod1::mod2::Entity<T>` to `mod1::mod2::Entity`.
422
422
// So set all segments arguments to None.
423
423
path. path . segments . iter_mut ( ) . for_each ( |segment| {
424
- segment. arguments = syn :: PathArguments :: None ;
424
+ segment. arguments = PathArguments :: None ;
425
425
} ) ;
426
426
path. to_token_stream ( )
427
427
} else {
@@ -1442,29 +1442,70 @@ struct QuoteTraitParams<'a> {
1442
1442
}
1443
1443
1444
1444
fn get_quote_trait_params < ' a > ( input : & DataType , ctx : & ' a ImplContext ) -> QuoteTraitParams < ' a > {
1445
- // If there is at least one lifetime in generics,we add a new lifetime `'o2o` and add a bound `'o2o: 'a + 'b`.
1446
1445
let generics = input. get_generics ( ) ;
1447
- let ( gens_impl, where_clause, r) = if ctx. kind . is_ref ( ) && generics. lifetimes ( ) . next ( ) . is_some ( )
1448
- {
1449
- let lifetimes: Vec < _ > = generics
1450
- . lifetimes ( )
1451
- . map ( |params| params. lifetime . clone ( ) )
1452
- . collect ( ) ;
1446
+ let mut generics_impl = generics. clone ( ) ;
1447
+ let mut lifetimes: Vec < Lifetime > = vec ! [ ] ;
1448
+
1449
+ if let Ok ( dst_ty) = parse2 :: < syn:: TypePath > ( ctx. dst_ty . clone ( ) ) {
1450
+ // The idea is to check if all lifetimes of the dst are included in the input generics or not.
1451
+ // If not, we will add the missing ones to the input generics.
1452
+
1453
+ let dst_generics = match & dst_ty. path . segments . last ( ) . unwrap ( ) . arguments {
1454
+ PathArguments :: None => syn:: punctuated:: Punctuated :: new ( ) ,
1455
+ PathArguments :: AngleBracketed ( args) => args. args . clone ( ) ,
1456
+ PathArguments :: Parenthesized ( _) => {
1457
+ unimplemented ! ( "Only Struct<T> syntax is supported" )
1458
+ }
1459
+ } ;
1460
+
1461
+ for dst_generic in dst_generics {
1462
+ if let GenericArgument :: Lifetime ( arg) = & dst_generic {
1463
+ lifetimes. push ( parse_quote ! ( #dst_generic) ) ;
1464
+ if generics. params . iter ( ) . all ( |param| {
1465
+ if let GenericParam :: Lifetime ( param) = param {
1466
+ & param. lifetime != arg
1467
+ } else {
1468
+ // Skip any other generic param
1469
+ false
1470
+ }
1471
+ } ) {
1472
+ generics_impl. params . push ( parse_quote ! ( #dst_generic) ) ;
1473
+ }
1474
+ }
1475
+ }
1476
+ }
1453
1477
1454
- let mut generics = generics. clone ( ) ;
1455
- generics. params . push ( parse_quote ! ( ' o2o) ) ;
1478
+ // If there is at least one lifetime in generics, we add a new lifetime `'o2o` and add a bound `'o2o: 'a + 'b`.
1479
+ let ( gens_impl, where_clause, r) = if ctx. kind . is_ref ( ) {
1480
+ // If lifetime is empty, we assume that lifetime generics come from the other structure (src <-> dst).
1481
+ let lifetimes: Vec < _ > = if lifetimes. is_empty ( ) {
1482
+ generics
1483
+ . lifetimes ( )
1484
+ . map ( |params| params. lifetime . clone ( ) )
1485
+ . collect ( )
1486
+ } else {
1487
+ lifetimes
1488
+ } ;
1456
1489
1457
1490
let mut where_clause = input
1458
1491
. get_attrs ( )
1459
1492
. where_attr ( & ctx. struct_attr . ty )
1460
- . map ( |x| x. where_clause . clone ( ) )
1461
- . unwrap_or_default ( ) ;
1462
- where_clause. push ( parse_quote ! ( ' o2o: #( #lifetimes ) +* ) ) ;
1493
+ . map ( |x| x. where_clause . clone ( ) ) ;
1494
+
1495
+ let r = if !lifetimes. is_empty ( ) {
1496
+ generics_impl. params . push ( parse_quote ! ( ' o2o) ) ;
1497
+ let mut where_clause_punctuated = where_clause. unwrap_or_default ( ) ;
1498
+ where_clause_punctuated. push ( parse_quote ! ( ' o2o: #( #lifetimes ) +* ) ) ;
1499
+ where_clause = Some ( where_clause_punctuated) ;
1500
+ Some ( quote ! ( & ' o2o) )
1501
+ } else {
1502
+ Some ( quote ! ( & ) )
1503
+ } ;
1463
1504
1464
1505
(
1465
- generics . to_token_stream ( ) ,
1466
- Some ( quote ! ( where #where_clause) ) ,
1467
- Some ( quote ! ( & ' o2o ) ) ,
1506
+ generics_impl . to_token_stream ( ) ,
1507
+ where_clause . map ( |where_clause| quote ! ( where #where_clause) ) ,
1508
+ r ,
1468
1509
)
1469
1510
} else {
1470
1511
(
0 commit comments