@@ -6,8 +6,8 @@ use syn::{
66 parse:: { Parse , ParseStream , Parser } ,
77 punctuated:: Punctuated ,
88 token:: Comma ,
9- ExprClosure , Field , Fields , Generics , Ident , Index , Meta , Result , Token ,
10- Type , Variant , Visibility , WhereClause ,
9+ ExprClosure , Field , Fields , GenericParam , Generics , Ident , Index , Meta ,
10+ Result , Token , Type , TypeParam , Variant , Visibility , WhereClause ,
1111} ;
1212
1313#[ proc_macro_error]
@@ -26,6 +26,103 @@ pub fn derive_patch(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
2626 . into ( )
2727}
2828
29+ /// Removes all constraints from generics arguments list.
30+ ///
31+ /// # Example
32+ ///
33+ /// ```rust,ignore
34+ /// struct Data<
35+ /// 'a,
36+ /// T1: ToString + PatchField,
37+ /// T2: PatchField,
38+ /// T3: 'static + PatchField,
39+ /// T4,
40+ /// >
41+ /// where
42+ /// T3: ToString,
43+ /// T4: ToString + PatchField,
44+ /// {
45+ /// data1: &'a T1,
46+ /// data2: T2,
47+ /// data3: T3,
48+ /// data4: T4,
49+ /// }
50+ /// ```
51+ ///
52+ /// Fort the struct above the `[syn::DeriveInput::parse]` will return the instance of [syn::Generics]
53+ /// which will conceptually look like this
54+ ///
55+ /// ```text
56+ /// Generics:
57+ /// params:
58+ /// [
59+ /// 'a,
60+ /// T1: ToString + PatchField,
61+ /// T2: PatchField,
62+ /// T3: 'static + PatchField,
63+ /// T4,
64+ /// ]
65+ /// where_clause:
66+ /// [
67+ /// T3: ToString,
68+ /// T4: ToString + PatchField,
69+ /// ]
70+ /// ```
71+ ///
72+ /// This method would return a new instance of [syn::Generics] which will conceptually look like this
73+ ///
74+ /// ```text
75+ /// Generics:
76+ /// params:
77+ /// [
78+ /// 'a,
79+ /// T1,
80+ /// T2,
81+ /// T3,
82+ /// T4,
83+ /// ]
84+ /// where_clause:
85+ /// []
86+ /// ```
87+ ///
88+ /// This is useful when you want to use a generic arguments list for `impl` sections for type definitions.
89+ fn remove_constraint_from_generics ( generics : & Generics ) -> Generics {
90+ let mut new_generics = generics. clone ( ) ;
91+
92+ // remove contraints directly placed in the generic arguments list
93+ //
94+ // For generics for `struct A<T: MyTrait>` the `T: MyTrait` becomes `T`
95+ for param in new_generics. params . iter_mut ( ) {
96+ match param {
97+ GenericParam :: Lifetime ( lifetime) => {
98+ lifetime. bounds . clear ( ) ; // remove bounds
99+ lifetime. colon_token = None ;
100+ }
101+ GenericParam :: Type ( type_param) => {
102+ type_param. bounds . clear ( ) ; // remove bounds
103+ type_param. colon_token = None ;
104+ type_param. eq_token = None ;
105+ type_param. default = None ;
106+ }
107+ GenericParam :: Const ( const_param) => {
108+ // replaces const generic with type param without bounds which is basically an `ident` token
109+ * param = GenericParam :: Type ( TypeParam {
110+ attrs : const_param. attrs . clone ( ) ,
111+ ident : const_param. ident . clone ( ) ,
112+ colon_token : None ,
113+ bounds : Punctuated :: new ( ) ,
114+ eq_token : None ,
115+ default : None ,
116+ } ) ;
117+ }
118+ }
119+ }
120+
121+ new_generics. where_clause = None ; // remove where clause
122+
123+ new_generics
124+ }
125+
29126struct Model {
30127 vis : Visibility ,
31128 name : Ident ,
@@ -111,7 +208,9 @@ impl ToTokens for Model {
111208 } = & self ;
112209 let any_store_field = Ident :: new ( "AnyStoreField" , Span :: call_site ( ) ) ;
113210 let trait_name = Ident :: new ( & format ! ( "{name}StoreFields" ) , name. span ( ) ) ;
211+ let clear_generics = remove_constraint_from_generics ( generics) ;
114212 let params = & generics. params ;
213+ let clear_params = & clear_generics. params ;
115214 let generics_with_orig = quote ! { <#any_store_field, #params> } ;
116215 let where_with_orig = {
117216 generics
@@ -124,17 +223,22 @@ impl ToTokens for Model {
124223 } = & w;
125224 quote ! {
126225 #where_token
127- #any_store_field: #library_path:: StoreField <Value = #name #generics >,
226+ #any_store_field: #library_path:: StoreField <Value = #name < #clear_params > >,
128227 #predicates
129228 }
130229 } )
131- . unwrap_or_else ( || quote ! { where #any_store_field: #library_path:: StoreField <Value = #name #generics > } )
230+ . unwrap_or_else ( || quote ! { where #any_store_field: #library_path:: StoreField <Value = #name < #clear_params > > } )
132231 } ;
133232
134233 // define an extension trait that matches this struct
135234 // and implement that trait for all StoreFields
136- let ( trait_fields, read_fields) : ( Vec < _ > , Vec < _ > ) =
137- ty. to_field_data ( & library_path, generics, & any_store_field, name) ;
235+ let ( trait_fields, read_fields) : ( Vec < _ > , Vec < _ > ) = ty. to_field_data (
236+ & library_path,
237+ generics,
238+ & clear_generics,
239+ & any_store_field,
240+ name,
241+ ) ;
138242
139243 // read access
140244 tokens. extend ( quote ! {
@@ -144,7 +248,7 @@ impl ToTokens for Model {
144248 #( #trait_fields) *
145249 }
146250
147- impl #generics_with_orig #trait_name <AnyStoreField , #params > for AnyStoreField
251+ impl #generics_with_orig #trait_name <AnyStoreField , #clear_params > for AnyStoreField
148252 #where_with_orig
149253 {
150254 #( #read_fields) *
@@ -158,6 +262,7 @@ impl ModelTy {
158262 & self ,
159263 library_path : & TokenStream ,
160264 generics : & Generics ,
265+ clear_generics : & Generics ,
161266 any_store_field : & Ident ,
162267 name : & Ident ,
163268 ) -> ( Vec < TokenStream > , Vec < TokenStream > ) {
@@ -204,6 +309,7 @@ impl ModelTy {
204309 library_path,
205310 ident. as_ref ( ) ,
206311 generics,
312+ clear_generics,
207313 any_store_field,
208314 name,
209315 ty,
@@ -215,6 +321,7 @@ impl ModelTy {
215321 library_path,
216322 ident. as_ref ( ) ,
217323 generics,
324+ clear_generics,
218325 any_store_field,
219326 name,
220327 ty,
@@ -233,6 +340,7 @@ impl ModelTy {
233340 library_path,
234341 ident,
235342 generics,
343+ clear_generics,
236344 any_store_field,
237345 name,
238346 fields,
@@ -242,6 +350,7 @@ impl ModelTy {
242350 library_path,
243351 ident,
244352 generics,
353+ clear_generics,
245354 any_store_field,
246355 name,
247356 fields,
@@ -260,7 +369,8 @@ fn field_to_tokens(
260369 modes : Option < & [ SubfieldMode ] > ,
261370 library_path : & proc_macro2:: TokenStream ,
262371 orig_ident : Option < & Ident > ,
263- generics : & Generics ,
372+ _generics : & Generics ,
373+ clear_generics : & Generics ,
264374 any_store_field : & Ident ,
265375 name : & Ident ,
266376 ty : & Type ,
@@ -285,7 +395,7 @@ fn field_to_tokens(
285395 SubfieldMode :: Keyed ( keyed_by, key_ty) => {
286396 let signature = quote ! {
287397 #[ track_caller]
288- fn #ident( self ) -> #library_path:: KeyedSubfield <#any_store_field, #name #generics , #key_ty, #ty>
398+ fn #ident( self ) -> #library_path:: KeyedSubfield <#any_store_field, #name #clear_generics , #key_ty, #ty>
289399 } ;
290400 return if include_body {
291401 quote ! {
@@ -318,7 +428,7 @@ fn field_to_tokens(
318428 // default subfield
319429 if include_body {
320430 quote ! {
321- fn #ident( self ) -> #library_path:: Subfield <#any_store_field, #name #generics , #ty> {
431+ fn #ident( self ) -> #library_path:: Subfield <#any_store_field, #name #clear_generics , #ty> {
322432 #library_path:: Subfield :: new(
323433 self ,
324434 #idx. into( ) ,
@@ -329,7 +439,7 @@ fn field_to_tokens(
329439 }
330440 } else {
331441 quote ! {
332- fn #ident( self ) -> #library_path:: Subfield <#any_store_field, #name #generics , #ty>;
442+ fn #ident( self ) -> #library_path:: Subfield <#any_store_field, #name #clear_generics , #ty>;
333443 }
334444 }
335445}
@@ -339,7 +449,8 @@ fn variant_to_tokens(
339449 include_body : bool ,
340450 library_path : & proc_macro2:: TokenStream ,
341451 ident : & Ident ,
342- generics : & Generics ,
452+ _generics : & Generics ,
453+ clear_generics : & Generics ,
343454 any_store_field : & Ident ,
344455 name : & Ident ,
345456 fields : & Fields ,
@@ -408,7 +519,7 @@ fn variant_to_tokens(
408519 // default subfield
409520 if include_body {
410521 quote ! {
411- fn #combined_ident( self ) -> Option <#library_path:: Subfield <#any_store_field, #name #generics , #field_ty>> {
522+ fn #combined_ident( self ) -> Option <#library_path:: Subfield <#any_store_field, #name #clear_generics , #field_ty>> {
412523 #library_path:: StoreField :: track_field( & self ) ;
413524 let reader = #library_path:: StoreField :: reader( & self ) ;
414525 let matches = reader
@@ -440,7 +551,7 @@ fn variant_to_tokens(
440551 }
441552 } else {
442553 quote ! {
443- fn #combined_ident( self ) -> Option <#library_path:: Subfield <#any_store_field, #name #generics , #field_ty>>;
554+ fn #combined_ident( self ) -> Option <#library_path:: Subfield <#any_store_field, #name #clear_generics , #field_ty>>;
444555 }
445556 }
446557 } ) ) ;
@@ -491,7 +602,7 @@ fn variant_to_tokens(
491602 // default subfield
492603 if include_body {
493604 quote ! {
494- fn #combined_ident( self ) -> Option <#library_path:: Subfield <#any_store_field, #name #generics , #field_ty>> {
605+ fn #combined_ident( self ) -> Option <#library_path:: Subfield <#any_store_field, #name #clear_generics , #field_ty>> {
495606 #library_path:: StoreField :: track_field( & self ) ;
496607 let reader = #library_path:: StoreField :: reader( & self ) ;
497608 let matches = reader
@@ -523,7 +634,7 @@ fn variant_to_tokens(
523634 }
524635 } else {
525636 quote ! {
526- fn #combined_ident( self ) -> Option <#library_path:: Subfield <#any_store_field, #name #generics , #field_ty>>;
637+ fn #combined_ident( self ) -> Option <#library_path:: Subfield <#any_store_field, #name #clear_generics , #field_ty>>;
527638 }
528639 }
529640 } ) ) ;
@@ -665,9 +776,14 @@ impl ToTokens for PatchModel {
665776 }
666777 } ;
667778
779+ let clear_generics = remove_constraint_from_generics ( generics) ;
780+ let params = clear_generics. params ;
781+ let where_clause = & generics. where_clause ;
782+
668783 // read access
669784 tokens. extend ( quote ! {
670- impl #library_path:: PatchField for #name #generics
785+ impl #generics #library_path:: PatchField for #name <#params>
786+ #where_clause
671787 {
672788 fn patch_field(
673789 & mut self ,
0 commit comments