@@ -16,13 +16,83 @@ pub(crate) fn gen_trait_fn_body(
1616 adt : & ast:: Adt ,
1717) -> Option < ( ) > {
1818 match trait_path. segment ( ) ?. name_ref ( ) ?. text ( ) . as_str ( ) {
19+ "Clone" => gen_clone_impl ( adt, func) ,
1920 "Debug" => gen_debug_impl ( adt, func) ,
2021 "Default" => gen_default_impl ( adt, func) ,
2122 "Hash" => gen_hash_impl ( adt, func) ,
2223 _ => None ,
2324 }
2425}
2526
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+
2696/// Generate a `Debug` impl based on the fields and members of the target type.
2797fn gen_debug_impl ( adt : & ast:: Adt , func : & ast:: Fn ) -> Option < ( ) > {
2898 let annotated_name = adt. name ( ) ?;
@@ -88,10 +158,10 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
88158 Some ( ast:: FieldList :: TupleFieldList ( field_list) ) => {
89159 let method = make:: name_ref ( "debug_tuple" ) ;
90160 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 ( ) {
92162 let f_path = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
93163 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 ( ) ;
95165 let method = make:: name_ref ( "field" ) ;
96166 expr = make:: expr_method_call ( expr, method, make:: arg_list ( Some ( f_path) ) ) ;
97167 }
@@ -182,7 +252,7 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
182252 make:: block_expr ( Some ( stmt) , None ) . indent ( ast:: edit:: IndentLevel ( 1 ) )
183253 }
184254 ast:: Adt :: Struct ( strukt) => match strukt. field_list ( ) {
185- // => self.<field>.hash(state);*
255+ // => self.<field>.hash(state);
186256 Some ( ast:: FieldList :: RecordFieldList ( field_list) ) => {
187257 let mut stmts = vec ! [ ] ;
188258 for field in field_list. fields ( ) {
@@ -193,7 +263,7 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
193263 make:: block_expr ( stmts, None ) . indent ( ast:: edit:: IndentLevel ( 1 ) )
194264 }
195265
196- // => self.<field_index>.hash(state);*
266+ // => self.<field_index>.hash(state);
197267 Some ( ast:: FieldList :: TupleFieldList ( field_list) ) => {
198268 let mut stmts = vec ! [ ] ;
199269 for ( i, _) in field_list. fields ( ) . enumerate ( ) {
0 commit comments