blob: 8988012c0f3dd7335d6cecb3820cc9e3ff196b0c [file] [log] [blame]
David Tolnayfbc46692020-11-27 11:33:29 -08001use crate::syntax::{Enum, Struct, Trait};
David Tolnay2c24e5c2020-11-27 12:47:41 -08002use proc_macro2::{Span, TokenStream};
David Tolnayd8ad9702020-11-27 12:43:59 -08003use quote::{quote, quote_spanned, ToTokens};
4
5pub fn expand_struct(strct: &Struct) -> TokenStream {
David Tolnayd8ad9702020-11-27 12:43:59 -08006 let mut expanded = TokenStream::new();
7
David Tolnay2c24e5c2020-11-27 12:47:41 -08008 for derive in &strct.derives {
9 let span = derive.span;
10 match derive.what {
11 Trait::Copy => expanded.extend(struct_copy(strct, span)),
12 Trait::Clone => expanded.extend(struct_clone(strct, span)),
13 }
14 }
15
16 expanded
17}
18
David Tolnayfbc46692020-11-27 11:33:29 -080019pub fn expand_enum(enm: &Enum) -> TokenStream {
20 let mut expanded = TokenStream::new();
21 let mut has_copy = false;
22 let mut has_clone = false;
23
24 for derive in &enm.derives {
25 let span = derive.span;
26 match derive.what {
27 Trait::Copy => {
28 expanded.extend(enum_copy(enm, span));
29 has_copy = true;
30 }
31 Trait::Clone => {
32 expanded.extend(enum_clone(enm, span));
33 has_clone = true;
34 }
35 }
36 }
37
38 let span = enm.name.rust.span();
39 if !has_copy {
40 expanded.extend(enum_copy(enm, span));
41 }
42 if !has_clone {
43 expanded.extend(enum_clone(enm, span));
44 }
45
46 expanded
47}
48
David Tolnay2c24e5c2020-11-27 12:47:41 -080049fn struct_copy(strct: &Struct, span: Span) -> TokenStream {
50 let ident = &strct.name.rust;
51
52 quote_spanned! {span=>
53 impl ::std::marker::Copy for #ident {}
54 }
55}
56
57fn struct_clone(strct: &Struct, span: Span) -> TokenStream {
58 let ident = &strct.name.rust;
59
David Tolnayd8ad9702020-11-27 12:43:59 -080060 let is_copy = strct
61 .derives
62 .iter()
63 .any(|derive| derive.what == Trait::Copy);
64
David Tolnay2c24e5c2020-11-27 12:47:41 -080065 let body = if is_copy {
66 quote!(*self)
67 } else {
68 let fields = strct.fields.iter().map(|field| &field.ident);
69 let values = strct.fields.iter().map(|field| {
70 let ident = &field.ident;
71 let ty = field.ty.to_token_stream();
72 let span = ty.into_iter().last().unwrap().span();
73 quote_spanned!(span=> &self.#ident)
74 });
75 quote_spanned!(span=> #ident {
76 #(#fields: ::std::clone::Clone::clone(#values),)*
77 })
78 };
79
80 quote_spanned! {span=>
81 impl ::std::clone::Clone for #ident {
82 fn clone(&self) -> Self {
83 #body
David Tolnayd8ad9702020-11-27 12:43:59 -080084 }
85 }
86 }
David Tolnayd8ad9702020-11-27 12:43:59 -080087}
David Tolnayfbc46692020-11-27 11:33:29 -080088
89fn enum_copy(enm: &Enum, span: Span) -> TokenStream {
90 let ident = &enm.name.rust;
91
92 quote_spanned! {span=>
93 impl ::std::marker::Copy for #ident {}
94 }
95}
96
97fn enum_clone(enm: &Enum, span: Span) -> TokenStream {
98 let ident = &enm.name.rust;
99
100 quote_spanned! {span=>
101 impl ::std::clone::Clone for #ident {
102 fn clone(&self) -> Self {
103 *self
104 }
105 }
106 }
107}