@@ -16,13 +16,83 @@ pub(crate) fn gen_trait_fn_body(
16
16
adt : & ast:: Adt ,
17
17
) -> Option < ( ) > {
18
18
match trait_path. segment ( ) ?. name_ref ( ) ?. text ( ) . as_str ( ) {
19
+ "Clone" => gen_clone_impl ( adt, func) ,
19
20
"Debug" => gen_debug_impl ( adt, func) ,
20
21
"Default" => gen_default_impl ( adt, func) ,
21
22
"Hash" => gen_hash_impl ( adt, func) ,
22
23
_ => None ,
23
24
}
24
25
}
25
26
27
+ /// Generate a `Clone` impl based on the fields and members of the target type.
28
+ fn gen_clone_impl ( adt : & ast:: Adt , func : & ast:: Fn ) -> Option < ( ) > {
29
+ fn gen_clone_call ( target : ast:: Expr ) -> ast:: Expr {
30
+ let method = make:: name_ref ( "clone" ) ;
31
+ make:: expr_method_call ( target, method, make:: arg_list ( None ) )
32
+ }
33
+ let expr = match adt {
34
+ // `Clone` cannot be derived for unions, so no default impl can be provided.
35
+ ast:: Adt :: Union ( _) => return None ,
36
+ ast:: Adt :: Enum ( enum_) => {
37
+ let list = enum_. variant_list ( ) ?;
38
+ let mut arms = vec ! [ ] ;
39
+ for variant in list. variants ( ) {
40
+ let name = variant. name ( ) ?;
41
+ let left = make:: ext:: ident_path ( "Self" ) ;
42
+ let right = make:: ext:: ident_path ( & format ! ( "{}" , name) ) ;
43
+ let variant_name = make:: path_concat ( left, right) ;
44
+
45
+ let pattern = make:: path_pat ( variant_name. clone ( ) ) ;
46
+ let variant_expr = make:: expr_path ( variant_name) ;
47
+ arms. push ( make:: match_arm ( Some ( pattern. into ( ) ) , None , variant_expr) ) ;
48
+ }
49
+
50
+ let match_target = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
51
+ let list = make:: match_arm_list ( arms) . indent ( ast:: edit:: IndentLevel ( 1 ) ) ;
52
+ make:: expr_match ( match_target, list)
53
+ }
54
+ ast:: Adt :: Struct ( strukt) => {
55
+ match strukt. field_list ( ) {
56
+ // => Self { name: self.name.clone() }
57
+ Some ( ast:: FieldList :: RecordFieldList ( field_list) ) => {
58
+ let mut fields = vec ! [ ] ;
59
+ for field in field_list. fields ( ) {
60
+ let base = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
61
+ let target = make:: expr_field ( base, & field. name ( ) ?. to_string ( ) ) ;
62
+ let method_call = gen_clone_call ( target) ;
63
+ let name_ref = make:: name_ref ( & field. name ( ) ?. to_string ( ) ) ;
64
+ let field = make:: record_expr_field ( name_ref, Some ( method_call) ) ;
65
+ fields. push ( field) ;
66
+ }
67
+ let struct_name = make:: ext:: ident_path ( "Self" ) ;
68
+ let fields = make:: record_expr_field_list ( fields) ;
69
+ make:: record_expr ( struct_name, fields) . into ( )
70
+ }
71
+ // => Self(self.0.clone(), self.1.clone())
72
+ Some ( ast:: FieldList :: TupleFieldList ( field_list) ) => {
73
+ let mut fields = vec ! [ ] ;
74
+ for ( i, _) in field_list. fields ( ) . enumerate ( ) {
75
+ let f_path = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
76
+ let target = make:: expr_field ( f_path, & format ! ( "{}" , i) ) . into ( ) ;
77
+ fields. push ( gen_clone_call ( target) ) ;
78
+ }
79
+ let struct_name = make:: expr_path ( make:: ext:: ident_path ( "Self" ) ) ;
80
+ make:: expr_call ( struct_name, make:: arg_list ( fields) )
81
+ }
82
+ // => Self { }
83
+ None => {
84
+ let struct_name = make:: ext:: ident_path ( "Self" ) ;
85
+ let fields = make:: record_expr_field_list ( None ) ;
86
+ make:: record_expr ( struct_name, fields) . into ( )
87
+ }
88
+ }
89
+ }
90
+ } ;
91
+ let body = make:: block_expr ( None , Some ( expr) ) . indent ( ast:: edit:: IndentLevel ( 1 ) ) ;
92
+ ted:: replace ( func. body ( ) ?. syntax ( ) , body. clone_for_update ( ) . syntax ( ) ) ;
93
+ Some ( ( ) )
94
+ }
95
+
26
96
/// Generate a `Debug` impl based on the fields and members of the target type.
27
97
fn gen_debug_impl ( adt : & ast:: Adt , func : & ast:: Fn ) -> Option < ( ) > {
28
98
let annotated_name = adt. name ( ) ?;
@@ -88,10 +158,10 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
88
158
Some ( ast:: FieldList :: TupleFieldList ( field_list) ) => {
89
159
let method = make:: name_ref ( "debug_tuple" ) ;
90
160
let mut expr = make:: expr_method_call ( target, method, args) ;
91
- for ( idx , _) in field_list. fields ( ) . enumerate ( ) {
161
+ for ( i , _) in field_list. fields ( ) . enumerate ( ) {
92
162
let f_path = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
93
163
let f_path = make:: expr_ref ( f_path, false ) ;
94
- let f_path = make:: expr_field ( f_path, & format ! ( "{}" , idx ) ) . into ( ) ;
164
+ let f_path = make:: expr_field ( f_path, & format ! ( "{}" , i ) ) . into ( ) ;
95
165
let method = make:: name_ref ( "field" ) ;
96
166
expr = make:: expr_method_call ( expr, method, make:: arg_list ( Some ( f_path) ) ) ;
97
167
}
@@ -182,7 +252,7 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
182
252
make:: block_expr ( Some ( stmt) , None ) . indent ( ast:: edit:: IndentLevel ( 1 ) )
183
253
}
184
254
ast:: Adt :: Struct ( strukt) => match strukt. field_list ( ) {
185
- // => self.<field>.hash(state);*
255
+ // => self.<field>.hash(state);
186
256
Some ( ast:: FieldList :: RecordFieldList ( field_list) ) => {
187
257
let mut stmts = vec ! [ ] ;
188
258
for field in field_list. fields ( ) {
@@ -193,7 +263,7 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
193
263
make:: block_expr ( stmts, None ) . indent ( ast:: edit:: IndentLevel ( 1 ) )
194
264
}
195
265
196
- // => self.<field_index>.hash(state);*
266
+ // => self.<field_index>.hash(state);
197
267
Some ( ast:: FieldList :: TupleFieldList ( field_list) ) => {
198
268
let mut stmts = vec ! [ ] ;
199
269
for ( i, _) in field_list. fields ( ) . enumerate ( ) {
0 commit comments