@@ -13,6 +13,7 @@ const ATTRIBUTE: &str = "attribute";
1313const SKIP : & str = "skip" ;
1414const ADDABLE : & str = "addable" ;
1515const ADD : & str = "add" ;
16+ const NESTING : & str = "nesting" ;
1617
1718pub ( crate ) struct Patch {
1819 visibility : syn:: Visibility ,
@@ -38,6 +39,8 @@ struct Field {
3839 retyped : bool ,
3940 #[ cfg( feature = "op" ) ]
4041 addable : Addable ,
42+ #[ cfg( feature = "nesting" ) ]
43+ nesting : bool ,
4144}
4245
4346impl Patch {
@@ -56,20 +59,60 @@ impl Patch {
5659 . iter ( )
5760 . map ( |f| f. to_token_stream ( ) )
5861 . collect :: < Result < Vec < _ > > > ( ) ?;
62+
63+ #[ cfg( not( feature = "nesting" ) ) ]
5964 let field_names = fields. iter ( ) . map ( |f| f. ident . as_ref ( ) ) . collect :: < Vec < _ > > ( ) ;
65+ #[ cfg( feature = "nesting" ) ]
66+ let field_names = fields
67+ . iter ( )
68+ . filter ( |f| !f. nesting )
69+ . map ( |f| f. ident . as_ref ( ) ) . collect :: < Vec < _ > > ( ) ;
6070
71+ #[ cfg( not( feature = "nesting" ) ) ]
6172 let renamed_field_names = fields
6273 . iter ( )
6374 . filter ( |f| f. retyped )
6475 . map ( |f| f. ident . as_ref ( ) )
6576 . collect :: < Vec < _ > > ( ) ;
77+ #[ cfg( feature = "nesting" ) ]
78+ let renamed_field_names = fields
79+ . iter ( )
80+ . filter ( |f| f. retyped && !f. nesting )
81+ . map ( |f| f. ident . as_ref ( ) )
82+ . collect :: < Vec < _ > > ( ) ;
6683
84+ #[ cfg( not( feature = "nesting" ) ) ]
6785 let original_field_names = fields
6886 . iter ( )
6987 . filter ( |f| !f. retyped )
7088 . map ( |f| f. ident . as_ref ( ) )
7189 . collect :: < Vec < _ > > ( ) ;
7290
91+ #[ cfg( feature = "nesting" ) ]
92+ let original_field_names = fields
93+ . iter ( )
94+ . filter ( |f| !f. retyped && !f. nesting )
95+ . map ( |f| f. ident . as_ref ( ) )
96+ . collect :: < Vec < _ > > ( ) ;
97+
98+ #[ cfg( not( feature = "nesting" ) ) ]
99+ let nesting_field_names: Vec < String > = Vec :: new ( ) ;
100+ #[ cfg( not( feature = "nesting" ) ) ]
101+ let nesting_field_types: Vec < Type > = Vec :: new ( ) ;
102+
103+ #[ cfg( feature = "nesting" ) ]
104+ let nesting_field_names = fields
105+ . iter ( )
106+ . filter ( |f| f. nesting )
107+ . map ( |f| f. ident . as_ref ( ) )
108+ . collect :: < Vec < _ > > ( ) ;
109+ #[ cfg( feature = "nesting" ) ]
110+ let nesting_field_types = fields
111+ . iter ( )
112+ . filter ( |f| f. nesting )
113+ . map ( |f| f. ty . clone ( ) )
114+ . collect :: < Vec < _ > > ( ) ;
115+
73116 let mapped_attributes = attributes
74117 . iter ( )
75118 . map ( |a| {
@@ -119,6 +162,9 @@ impl Patch {
119162 #(
120163 #original_field_names: other. #original_field_names. or( self . #original_field_names) ,
121164 ) *
165+ #(
166+ #nesting_field_names: other. #nesting_field_names. apply( self . #nesting_field_names) ,
167+ ) *
122168 }
123169 }
124170 }
@@ -252,6 +298,9 @@ impl Patch {
252298 self . #original_field_names = v;
253299 }
254300 ) *
301+ #(
302+ self . #nesting_field_names. apply( patch. #nesting_field_names) ;
303+ ) *
255304 }
256305
257306 fn into_patch( self ) -> #name #generics {
@@ -262,6 +311,9 @@ impl Patch {
262311 #(
263312 #original_field_names: Some ( self . #original_field_names) ,
264313 ) *
314+ #(
315+ #nesting_field_names: self . #nesting_field_names. into_patch( ) ,
316+ ) *
265317 }
266318 }
267319
@@ -283,6 +335,9 @@ impl Patch {
283335 None
284336 } ,
285337 ) *
338+ #(
339+ #nesting_field_names: self . #nesting_field_names. into_patch_by_diff( previous_struct. #nesting_field_names) ,
340+ ) *
286341 }
287342 }
288343
@@ -291,6 +346,9 @@ impl Patch {
291346 #(
292347 #field_names: None ,
293348 ) *
349+ #(
350+ #nesting_field_names: #nesting_field_types:: new_empty_patch( ) ,
351+ ) *
294352 }
295353 }
296354 }
@@ -403,6 +461,8 @@ impl Field {
403461 ident,
404462 ty,
405463 attributes,
464+ #[ cfg( feature = "nesting" ) ]
465+ nesting,
406466 ..
407467 } = self ;
408468
@@ -415,14 +475,48 @@ impl Field {
415475 } )
416476 . collect :: < Vec < _ > > ( ) ;
417477 match ident {
478+ #[ cfg( not( feature = "nesting" ) ) ]
418479 Some ( ident) => Ok ( quote ! {
419480 #( #attributes) *
420481 pub #ident: Option <#ty>,
421482 } ) ,
483+ #[ cfg( feature = "nesting" ) ]
484+ Some ( ident) => {
485+ if * nesting {
486+ // TODO handle rename
487+ let patch_type = syn:: Ident :: new ( & format ! ( "{}Patch" , & ty. to_token_stream( ) ) , Span :: call_site ( ) ) ;
488+ Ok ( quote ! {
489+ #( #attributes) *
490+ pub #ident: #patch_type,
491+ } )
492+ } else {
493+ Ok ( quote ! {
494+ #( #attributes) *
495+ pub #ident: Option <#ty>,
496+ } )
497+ }
498+ } ,
499+ #[ cfg( not( feature = "nesting" ) ) ]
422500 None => Ok ( quote ! {
423501 #( #attributes) *
424502 pub Option <#ty>,
425503 } ) ,
504+ #[ cfg( feature = "nesting" ) ]
505+ None => {
506+ if * nesting {
507+ // TODO handle rename
508+ let patch_type = syn:: Ident :: new ( & format ! ( "{}Patch" , & ty. to_token_stream( ) ) , Span :: call_site ( ) ) ;
509+ Ok ( quote ! {
510+ #( #attributes) *
511+ pub #patch_type,
512+ } )
513+ } else {
514+ Ok ( quote ! {
515+ #( #attributes) *
516+ pub Option <#ty>,
517+ } )
518+ }
519+ } ,
426520 }
427521 }
428522
@@ -438,6 +532,8 @@ impl Field {
438532
439533 #[ cfg( feature = "op" ) ]
440534 let mut addable = Addable :: Disable ;
535+ #[ cfg( feature = "nesting" ) ]
536+ let mut nesting = false ;
441537
442538 for attr in attrs {
443539 if attr. path ( ) . to_string ( ) . as_str ( ) != PATCH {
@@ -491,6 +587,16 @@ impl Field {
491587 ADD => {
492588 return Err ( syn:: Error :: new ( ident. span ( ) , "`add` needs `op` feature" ) ) ;
493589 }
590+ #[ cfg( feature = "nesting" ) ]
591+ NESTING => {
592+ // #[patch(nesting)]
593+ nesting = true ;
594+ }
595+ #[ cfg( not( feature = "nesting" ) ) ]
596+ NESTING => {
597+ return Err (
598+ meta. error ( "#[patch(nesting)] only work with `nesting` feature" ) ) ;
599+ }
494600 _ => {
495601 return Err ( meta. error ( format_args ! (
496602 "unknown patch field attribute `{}`" ,
@@ -512,6 +618,8 @@ impl Field {
512618 attributes,
513619 #[ cfg( feature = "op" ) ]
514620 addable,
621+ #[ cfg( feature = "nesting" ) ]
622+ nesting,
515623 } ) )
516624 }
517625}
0 commit comments