reborrow_derive/
lib.rs

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}