blob: 3010dc6c2b4d90bbd28785ff68bde1df85761e7e [file] [log] [blame]
David Tolnayd8ad9702020-11-27 12:43:59 -08001use crate::syntax::{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
19fn struct_copy(strct: &Struct, span: Span) -> TokenStream {
20 let ident = &strct.name.rust;
21
22 quote_spanned! {span=>
23 impl ::std::marker::Copy for #ident {}
24 }
25}
26
27fn struct_clone(strct: &Struct, span: Span) -> TokenStream {
28 let ident = &strct.name.rust;
29
David Tolnayd8ad9702020-11-27 12:43:59 -080030 let is_copy = strct
31 .derives
32 .iter()
33 .any(|derive| derive.what == Trait::Copy);
34
David Tolnay2c24e5c2020-11-27 12:47:41 -080035 let body = if is_copy {
36 quote!(*self)
37 } else {
38 let fields = strct.fields.iter().map(|field| &field.ident);
39 let values = strct.fields.iter().map(|field| {
40 let ident = &field.ident;
41 let ty = field.ty.to_token_stream();
42 let span = ty.into_iter().last().unwrap().span();
43 quote_spanned!(span=> &self.#ident)
44 });
45 quote_spanned!(span=> #ident {
46 #(#fields: ::std::clone::Clone::clone(#values),)*
47 })
48 };
49
50 quote_spanned! {span=>
51 impl ::std::clone::Clone for #ident {
52 fn clone(&self) -> Self {
53 #body
David Tolnayd8ad9702020-11-27 12:43:59 -080054 }
55 }
56 }
David Tolnayd8ad9702020-11-27 12:43:59 -080057}