1use quote::quote;
2use syn::{DeriveInput, GenericParam, Lifetime, LifetimeDef};
3
4#[proc_macro_derive(ReborrowCopyTraits)]
5pub fn derive_reborrow_copy(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
6 let input = syn::parse_macro_input!(input as DeriveInput);
7
8 let name = &input.ident;
9
10 let reborrowed_lifetime = &LifetimeDef::new(Lifetime::new(
11 "'__reborrow_lifetime",
12 proc_macro2::Span::call_site(),
13 ));
14
15 let mut target_ty_generics = input.generics.clone();
16 for lt in target_ty_generics.lifetimes_mut() {
17 *lt = reborrowed_lifetime.clone();
18 }
19 let target_ty_generics = target_ty_generics.split_for_impl().1;
20 let mut impl_generics = input.generics.clone();
21 impl_generics
22 .params
23 .insert(0, GenericParam::Lifetime(reborrowed_lifetime.clone()));
24 let impl_generics = impl_generics.split_for_impl().0;
25
26 let (orig_impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
27
28 let expanded = quote! {
29 impl #orig_impl_generics ::core::marker::Copy for #name #ty_generics
30 #where_clause {}
31
32 impl #orig_impl_generics ::core::clone::Clone for #name #ty_generics
33 #where_clause
34 {
35 #[inline]
36 fn clone(&self) -> Self {
37 *self
38 }
39 }
40
41 impl #orig_impl_generics ::reborrow::IntoConst for #name #ty_generics
42 #where_clause
43 {
44 type Target = #name #ty_generics;
45
46 #[inline]
47 fn into_const(self) -> <Self as ::reborrow::IntoConst>::Target {
48 self
49 }
50 }
51
52 impl #impl_generics ::reborrow::ReborrowMut<'__reborrow_lifetime> for #name #ty_generics
53 #where_clause
54 {
55 type Target = #name #target_ty_generics;
56
57 #[inline]
58 fn rb_mut(&'__reborrow_lifetime mut self) -> <Self as ::reborrow::ReborrowMut>::Target {
59 *self
60 }
61 }
62
63 impl #impl_generics ::reborrow::Reborrow<'__reborrow_lifetime> for #name #ty_generics
64 #where_clause
65 {
66 type Target = #name #target_ty_generics;
67
68 #[inline]
69 fn rb(&'__reborrow_lifetime self) -> <Self as ::reborrow::Reborrow>::Target {
70 *self
71 }
72 }
73
74 impl #impl_generics ::reborrow::AsGeneralizedMut<
75 '__reborrow_lifetime,
76 <Self as ::reborrow::ReborrowMut<'__reborrow_lifetime>>::Target,
77 > for #name #ty_generics
78 #where_clause
79 {
80 #[inline]
81 fn as_generalized_mut(&'__reborrow_lifetime mut self) -> <Self as ::reborrow::ReborrowMut<'__reborrow_lifetime>>::Target {
82 *self
83 }
84 }
85
86 impl #impl_generics ::reborrow::AsGeneralizedRef<
87 '__reborrow_lifetime,
88 <Self as ::reborrow::Reborrow<'__reborrow_lifetime>>::Target,
89 > for #name #ty_generics
90 #where_clause
91 {
92 #[inline]
93 fn as_generalized_ref(&'__reborrow_lifetime self) -> <Self as ::reborrow::Reborrow<'__reborrow_lifetime>>::Target {
94 *self
95 }
96 }
97 };
98
99 expanded.into()
100}
101
102#[proc_macro_derive(ReborrowTraits, attributes(reborrow, Const))]
103pub fn derive_reborrow(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
104 let input = syn::parse_macro_input!(input as DeriveInput);
105
106 let const_name = input
107 .attrs
108 .iter()
109 .find(|&attr| {
110 let segments = &attr.path.segments;
111 if let Some(syn::PathSegment {
112 ident,
113 arguments: syn::PathArguments::None,
114 }) = segments.first()
115 {
116 ident.to_string() == "Const"
117 } else {
118 false
119 }
120 })
121 .unwrap_or_else(|| panic!("Const reborrowed type must be specified."));
122
123 let const_name = const_name.tokens.clone();
124 let const_name = *syn::parse2::<syn::TypeParen>(const_name).unwrap().elem;
125
126 let name = &input.ident;
127
128 let reborrowed_lifetime = &LifetimeDef::new(Lifetime::new(
129 "'__reborrow_lifetime",
130 proc_macro2::Span::call_site(),
131 ));
132
133 let mut target_ty_generics = input.generics.clone();
134 for lt in target_ty_generics.lifetimes_mut() {
135 *lt = reborrowed_lifetime.clone();
136 }
137 let target_ty_generics = target_ty_generics.split_for_impl().1;
138
139 let mut impl_generics = input.generics.clone();
140 impl_generics
141 .params
142 .insert(0, GenericParam::Lifetime(reborrowed_lifetime.clone()));
143 let impl_generics = impl_generics.split_for_impl().0;
144
145 let (orig_impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
146
147 let (rb_mut, rb, into_const) = {
148 let data = input.data;
149
150 match data {
151 syn::Data::Struct(s) => match s.fields {
152 syn::Fields::Named(f) => {
153 let names: Vec<_> = f.named.iter().map(|f| &f.ident).collect();
154 let (f0, f1, f2) = unzip3(
155 f.named
156 .iter()
157 .enumerate()
158 .map(|(i, f)| reborrow_exprs(i, f.clone())),
159 );
160
161 (
162 quote! { #name:: #target_ty_generics { #(#names: #f0,)* } },
163 quote! { #const_name:: #target_ty_generics { #(#names: #f1,)* } },
164 quote! { #const_name:: #ty_generics { #(#names: #f2,)* } },
165 )
166 }
167 syn::Fields::Unnamed(f) => {
168 let (f0, f1, f2) = unzip3(
169 f.unnamed
170 .iter()
171 .enumerate()
172 .map(|(i, f)| reborrow_exprs(i, f.clone())),
173 );
174
175 (
176 quote! { #name:: #target_ty_generics ( #(#f0,)* ) },
177 quote! { #const_name:: #target_ty_generics ( #(#f1,)* ) },
178 quote! { #const_name:: #ty_generics ( #(#f2,)* ) },
179 )
180 }
181 syn::Fields::Unit => (
182 quote! { #name:: #target_ty_generics },
183 quote! { #const_name:: #target_ty_generics },
184 quote! { #const_name:: #target_ty_generics },
185 ),
186 },
187 syn::Data::Enum(_) => panic!("reborrow-derive does not support enums."),
188 syn::Data::Union(_) => panic!("reborrow-derive does not support unions."),
189 }
190 };
191
192 let expanded = quote! {
193 impl #orig_impl_generics ::reborrow::IntoConst for #name #ty_generics
194 #where_clause
195 {
196 type Target = #const_name #ty_generics;
197
198 #[inline]
199 fn into_const(self) -> <Self as ::reborrow::IntoConst>::Target {
200 #into_const
201 }
202 }
203
204 impl #impl_generics ::reborrow::ReborrowMut<'__reborrow_lifetime> for #name #ty_generics
205 #where_clause
206 {
207 type Target = #name #target_ty_generics;
208
209 #[inline]
210 fn rb_mut(&'__reborrow_lifetime mut self) -> <Self as ::reborrow::ReborrowMut>::Target {
211 #rb_mut
212 }
213 }
214
215 impl #impl_generics ::reborrow::Reborrow<'__reborrow_lifetime> for #name #ty_generics
216 #where_clause
217 {
218 type Target = #const_name #target_ty_generics;
219
220 #[inline]
221 fn rb(&'__reborrow_lifetime self) -> <Self as ::reborrow::Reborrow>::Target {
222 #rb
223 }
224 }
225
226 impl #impl_generics ::reborrow::AsGeneralizedMut<
227 '__reborrow_lifetime,
228 <Self as ::reborrow::ReborrowMut<'__reborrow_lifetime>>::Target,
229 > for #name #ty_generics
230 #where_clause
231 {
232 #[inline]
233 fn as_generalized_mut(&'__reborrow_lifetime mut self) -> <Self as ::reborrow::ReborrowMut<'__reborrow_lifetime>>::Target {
234 <Self as ::reborrow::ReborrowMut>::rb_mut(self)
235 }
236 }
237
238 impl #impl_generics ::reborrow::AsGeneralizedRef<
239 '__reborrow_lifetime,
240 <Self as ::reborrow::Reborrow<'__reborrow_lifetime>>::Target,
241 > for #name #ty_generics
242 #where_clause
243 {
244 #[inline]
245 fn as_generalized_ref(&'__reborrow_lifetime self) -> <Self as ::reborrow::Reborrow<'__reborrow_lifetime>>::Target {
246 <Self as ::reborrow::Reborrow>::rb(self)
247 }
248 }
249 };
250
251 expanded.into()
252}
253
254fn unzip3<A, B, C, I: Iterator<Item = (A, B, C)>>(iter: I) -> (Vec<A>, Vec<B>, Vec<C>) {
255 let mut v0 = Vec::new();
256 let mut v1 = Vec::new();
257 let mut v2 = Vec::new();
258 for (a, b, c) in iter {
259 v0.push(a);
260 v1.push(b);
261 v2.push(c);
262 }
263 (v0, v1, v2)
264}
265
266fn reborrow_exprs(
267 idx: usize,
268 f: syn::Field,
269) -> (
270 proc_macro2::TokenStream,
271 proc_macro2::TokenStream,
272 proc_macro2::TokenStream,
273) {
274 let is_reborrowable = f
275 .attrs
276 .iter()
277 .find(|&attr| {
278 let segments = &attr.path.segments;
279 if let Some(syn::PathSegment {
280 ident,
281 arguments: syn::PathArguments::None,
282 }) = segments.first()
283 {
284 ident.to_string() == "reborrow"
285 } else {
286 false
287 }
288 })
289 .is_some();
290
291 let idx = syn::Index::from(idx);
292
293 let expr = f
294 .ident
295 .map(|ident| quote! { self.#ident })
296 .unwrap_or(quote! { self.#idx });
297
298 if !is_reborrowable {
299 (quote! {#expr}, quote! {#expr}, quote! {#expr})
300 } else {
301 let ty = f.ty;
302 (
303 quote! { <#ty as ::reborrow::ReborrowMut>::rb_mut(&mut #expr) },
304 quote! { <#ty as ::reborrow::Reborrow>::rb(&#expr) },
305 quote! { <#ty as ::reborrow::IntoConst>::into_const(#expr) },
306 )
307 }
308}