1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
extern crate proc_macro;
use syn::spanned::Spanned;
use syn::Data::{Enum, Struct};
use syn::GenericParam;
use syn::{parse_macro_input, DeriveInput, Fields};
extern crate proc_quote;
use proc_quote::quote;
#[proc_macro_derive(TryClone)]
pub fn derive_try_clone(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let impl_generic = input.generics.clone();
let generic = input.generics.params.into_iter().map(|x| match x {
GenericParam::Type(type_param) => type_param.ident,
_ => panic!("unhandled generic param"),
});
let expanded = match input.data {
Struct(datastruct) => {
let all_names = match datastruct.fields {
Fields::Named(fields) => {
let fields = fields.named.iter().map(|x| x.ident.clone());
quote!(Self {#( #fields: fallible_collections::TryClone::try_clone(&self.#fields)?, )*})
}
Fields::Unit => quote!(Self),
Fields::Unnamed(fields) => {
let fields = (0..fields.unnamed.len()).map(|i| syn::Index::from(i));
quote!(Self(#(self.#fields.try_clone()?,)*))
}
};
quote!(
impl#impl_generic fallible_collections::TryClone for #name<#(#generic),*> {
fn try_clone(&self) -> core::result::Result<Self,alloc::collections::TryReserveError> {
Ok(
#all_names
)
}
}
)
}
Enum(datastruct) => {
let all_names = datastruct.variants.iter().map(|x| match &x.fields {
Fields::Unit => {
let variant = x.ident.clone();
quote!(#name::#variant => #name::#variant,)
}
Fields::Unnamed(fields) => {
let fields = (0..fields.unnamed.len()).map(|i| {
let mut ident = [0];
syn::Ident::new(
((('a' as u8) + i as u8) as char).encode_utf8(&mut ident),
x.span(),
)
});
let fields_clone = fields.clone();
let variant = x.ident.clone();
quote!(#name::#variant(#(#fields,)*) => #name::#variant(#(#fields_clone.try_clone()?,)*),)
}
Fields::Named(fields) => {
let fields = fields.named.iter().map(|x| x.ident.clone());
let fields_clone = fields.clone();
let fields_clone2 = fields.clone();
let variant = x.ident.clone();
quote!(#name::#variant{#(#fields,)*} => #name::#variant{#(#fields_clone2: #fields_clone.try_clone()?,)*},)
}
});
quote!(
impl fallible_collections::TryClone for #name {
fn try_clone(&self) -> core::result::Result<Self,alloc::collections::TryReserveError> {
Ok(
match self {
#( #all_names )*
}
)
}
}
)
}
_ => panic!("bad"),
};
proc_macro::TokenStream::from(expanded)
}