@@ -16,13 +16,127 @@ 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
+ match variant. field_list ( ) {
46
+ // => match self { Self::Name { x } => Self::Name { x: x.clone() } }
47
+ Some ( ast:: FieldList :: RecordFieldList ( list) ) => {
48
+ let mut pats = vec ! [ ] ;
49
+ let mut fields = vec ! [ ] ;
50
+ for field in list. fields ( ) {
51
+ let field_name = field. name ( ) ?;
52
+ let pat = make:: ident_pat ( false , false , field_name. clone ( ) ) ;
53
+ pats. push ( pat. into ( ) ) ;
54
+
55
+ let path = make:: ext:: ident_path ( & field_name. to_string ( ) ) ;
56
+ let method_call = gen_clone_call ( make:: expr_path ( path) ) ;
57
+ let name_ref = make:: name_ref ( & field_name. to_string ( ) ) ;
58
+ let field = make:: record_expr_field ( name_ref, Some ( method_call) ) ;
59
+ fields. push ( field) ;
60
+ }
61
+ let pat = make:: record_pat ( variant_name. clone ( ) , pats. into_iter ( ) ) ;
62
+ let fields = make:: record_expr_field_list ( fields) ;
63
+ let record_expr = make:: record_expr ( variant_name, fields) . into ( ) ;
64
+ arms. push ( make:: match_arm ( Some ( pat. into ( ) ) , None , record_expr) ) ;
65
+ }
66
+
67
+ // => match self { Self::Name(arg1) => Self::Name(arg1.clone()) }
68
+ Some ( ast:: FieldList :: TupleFieldList ( list) ) => {
69
+ let mut pats = vec ! [ ] ;
70
+ let mut fields = vec ! [ ] ;
71
+ for ( i, _) in list. fields ( ) . enumerate ( ) {
72
+ let field_name = format ! ( "arg{}" , i) ;
73
+ let pat = make:: ident_pat ( false , false , make:: name ( & field_name) ) ;
74
+ pats. push ( pat. into ( ) ) ;
75
+
76
+ let f_path = make:: expr_path ( make:: ext:: ident_path ( & field_name) ) ;
77
+ fields. push ( gen_clone_call ( f_path) ) ;
78
+ }
79
+ let pat = make:: tuple_struct_pat ( variant_name. clone ( ) , pats. into_iter ( ) ) ;
80
+ let struct_name = make:: expr_path ( variant_name) ;
81
+ let tuple_expr = make:: expr_call ( struct_name, make:: arg_list ( fields) ) ;
82
+ arms. push ( make:: match_arm ( Some ( pat. into ( ) ) , None , tuple_expr) ) ;
83
+ }
84
+
85
+ // => match self { Self::Name => Self::Name }
86
+ None => {
87
+ let pattern = make:: path_pat ( variant_name. clone ( ) ) ;
88
+ let variant_expr = make:: expr_path ( variant_name) ;
89
+ arms. push ( make:: match_arm ( Some ( pattern. into ( ) ) , None , variant_expr) ) ;
90
+ }
91
+ }
92
+ }
93
+
94
+ let match_target = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
95
+ let list = make:: match_arm_list ( arms) . indent ( ast:: edit:: IndentLevel ( 1 ) ) ;
96
+ make:: expr_match ( match_target, list)
97
+ }
98
+ ast:: Adt :: Struct ( strukt) => {
99
+ match strukt. field_list ( ) {
100
+ // => Self { name: self.name.clone() }
101
+ Some ( ast:: FieldList :: RecordFieldList ( field_list) ) => {
102
+ let mut fields = vec ! [ ] ;
103
+ for field in field_list. fields ( ) {
104
+ let base = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
105
+ let target = make:: expr_field ( base, & field. name ( ) ?. to_string ( ) ) ;
106
+ let method_call = gen_clone_call ( target) ;
107
+ let name_ref = make:: name_ref ( & field. name ( ) ?. to_string ( ) ) ;
108
+ let field = make:: record_expr_field ( name_ref, Some ( method_call) ) ;
109
+ fields. push ( field) ;
110
+ }
111
+ let struct_name = make:: ext:: ident_path ( "Self" ) ;
112
+ let fields = make:: record_expr_field_list ( fields) ;
113
+ make:: record_expr ( struct_name, fields) . into ( )
114
+ }
115
+ // => Self(self.0.clone(), self.1.clone())
116
+ Some ( ast:: FieldList :: TupleFieldList ( field_list) ) => {
117
+ let mut fields = vec ! [ ] ;
118
+ for ( i, _) in field_list. fields ( ) . enumerate ( ) {
119
+ let f_path = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
120
+ let target = make:: expr_field ( f_path, & format ! ( "{}" , i) ) . into ( ) ;
121
+ fields. push ( gen_clone_call ( target) ) ;
122
+ }
123
+ let struct_name = make:: expr_path ( make:: ext:: ident_path ( "Self" ) ) ;
124
+ make:: expr_call ( struct_name, make:: arg_list ( fields) )
125
+ }
126
+ // => Self { }
127
+ None => {
128
+ let struct_name = make:: ext:: ident_path ( "Self" ) ;
129
+ let fields = make:: record_expr_field_list ( None ) ;
130
+ make:: record_expr ( struct_name, fields) . into ( )
131
+ }
132
+ }
133
+ }
134
+ } ;
135
+ let body = make:: block_expr ( None , Some ( expr) ) . indent ( ast:: edit:: IndentLevel ( 1 ) ) ;
136
+ ted:: replace ( func. body ( ) ?. syntax ( ) , body. clone_for_update ( ) . syntax ( ) ) ;
137
+ Some ( ( ) )
138
+ }
139
+
26
140
/// Generate a `Debug` impl based on the fields and members of the target type.
27
141
fn gen_debug_impl ( adt : & ast:: Adt , func : & ast:: Fn ) -> Option < ( ) > {
28
142
let annotated_name = adt. name ( ) ?;
@@ -88,10 +202,10 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
88
202
Some ( ast:: FieldList :: TupleFieldList ( field_list) ) => {
89
203
let method = make:: name_ref ( "debug_tuple" ) ;
90
204
let mut expr = make:: expr_method_call ( target, method, args) ;
91
- for ( idx , _) in field_list. fields ( ) . enumerate ( ) {
205
+ for ( i , _) in field_list. fields ( ) . enumerate ( ) {
92
206
let f_path = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
93
207
let f_path = make:: expr_ref ( f_path, false ) ;
94
- let f_path = make:: expr_field ( f_path, & format ! ( "{}" , idx ) ) . into ( ) ;
208
+ let f_path = make:: expr_field ( f_path, & format ! ( "{}" , i ) ) . into ( ) ;
95
209
let method = make:: name_ref ( "field" ) ;
96
210
expr = make:: expr_method_call ( expr, method, make:: arg_list ( Some ( f_path) ) ) ;
97
211
}
@@ -182,7 +296,7 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
182
296
make:: block_expr ( Some ( stmt) , None ) . indent ( ast:: edit:: IndentLevel ( 1 ) )
183
297
}
184
298
ast:: Adt :: Struct ( strukt) => match strukt. field_list ( ) {
185
- // => self.<field>.hash(state);*
299
+ // => self.<field>.hash(state);
186
300
Some ( ast:: FieldList :: RecordFieldList ( field_list) ) => {
187
301
let mut stmts = vec ! [ ] ;
188
302
for field in field_list. fields ( ) {
@@ -193,7 +307,7 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
193
307
make:: block_expr ( stmts, None ) . indent ( ast:: edit:: IndentLevel ( 1 ) )
194
308
}
195
309
196
- // => self.<field_index>.hash(state);*
310
+ // => self.<field_index>.hash(state);
197
311
Some ( ast:: FieldList :: TupleFieldList ( field_list) ) => {
198
312
let mut stmts = vec ! [ ] ;
199
313
for ( i, _) in field_list. fields ( ) . enumerate ( ) {
0 commit comments