shallowclone_derive/
lib.rs1mod attributes;
2mod gen_impl;
3mod target_type;
4
5use gen_impl::gen_impl;
6use proc_macro::TokenStream;
7use proc_macro_error::proc_macro_error;
8use quote::quote;
9use syn::parse_macro_input;
10use syn::{DeriveInput, GenericParam};
11use target_type::get_target_type;
12
13#[derive(Debug, PartialEq, Eq, Clone, Copy)]
14enum DeriveType {
15 ShallowClone,
16 MakeOwned,
17}
18
19#[proc_macro_error]
20#[proc_macro_derive(ShallowClone, attributes(shallowclone))]
21pub fn derive_shallowclone(input: TokenStream) -> TokenStream {
22 derive(input, DeriveType::ShallowClone)
23}
24
25#[proc_macro_error]
26#[proc_macro_derive(MakeOwned, attributes(makeowned))]
27pub fn derive_makeowned(input: TokenStream) -> TokenStream {
28 derive(input, DeriveType::MakeOwned)
29}
30
31fn derive(input: TokenStream, derive_type: DeriveType) -> TokenStream {
32 let input = parse_macro_input!(input as DeriveInput);
33
34 let ident = &input.ident;
35
36 let target_type = match derive_type {
37 DeriveType::ShallowClone => get_target_type(&input, derive_type),
38 DeriveType::MakeOwned => get_target_type(&input, derive_type),
39 };
40
41 let (_, type_generics, where_clause) = input.generics.split_for_impl();
47
48 let mut impl_generics = Vec::new();
49 let mut extra_bounds = Vec::new();
50 for generic in &input.generics.params {
51 let skip = attributes::is_generic_skipped(derive_type, generic);
52
53 match generic {
54 GenericParam::Lifetime(lifetime_param) => {
55 let lifetime = &lifetime_param.lifetime;
56 let bounds = &lifetime_param.bounds;
57
58 impl_generics.push(quote! { #lifetime: #bounds });
59
60 if !skip && derive_type == DeriveType::ShallowClone {
61 extra_bounds.push(quote! { #lifetime: 'shallowclone });
62 }
63 }
64 GenericParam::Type(type_param) => {
65 let name = &type_param.ident;
66 let bounds = &type_param.bounds;
67
68 impl_generics.push(quote! { #name: #bounds });
69
70 if skip {
71 if derive_type == DeriveType::MakeOwned {
72 extra_bounds.push(quote! { #name: 'static });
73 }
74 } else {
75 match derive_type {
76 DeriveType::ShallowClone => {
77 extra_bounds.push(quote! { #name: ShallowClone<'shallowclone> });
78 }
79 DeriveType::MakeOwned => {
80 let orig_bounds = &type_param.bounds;
83
84 extra_bounds.push(quote! { #name: MakeOwned });
85 extra_bounds.push(quote! { <#name as MakeOwned>::Owned: #orig_bounds });
86 }
87 }
88 }
89 }
90 GenericParam::Const(const_param) => {
91 let name = &const_param.ident;
92 let ty = &const_param.ty;
93
94 impl_generics.push(quote! { const #name: #ty });
95 }
96 }
97 }
98
99 if derive_type == DeriveType::MakeOwned {
100 let generics = input.generics.params.iter().map(|param| match param {
113 GenericParam::Lifetime(_) => quote! { 'any },
114 GenericParam::Type(t) => {
115 let ident = &t.ident;
116 quote! { #ident }
117 }
118 GenericParam::Const(c) => {
119 let ident = &c.ident;
120 quote! { #ident }
121 }
122 });
123 extra_bounds.push(quote! { for<'any> #ident <#(#generics),*>: Clone });
124 }
125
126 let where_clause = where_clause
134 .map(|c| quote! { #c })
135 .unwrap_or(quote! { where });
136 let where_clause = quote! {
137 #where_clause
138 #(#extra_bounds),*
139 };
140
141 let impl_code = gen_impl(derive_type, &input);
142
143 match derive_type {
144 DeriveType::ShallowClone => quote! {
145 impl<'shallowclone, #(#impl_generics),*> ShallowClone<'shallowclone> for #ident #type_generics
146 #where_clause {
147 type Target = #target_type;
148
149 fn shallow_clone(&'shallowclone self) -> <Self as ShallowClone<'shallowclone>>::Target {
150 #impl_code
151 }
152 }
153 },
154 DeriveType::MakeOwned => quote! {
155 impl<#(#impl_generics),*> MakeOwned for #ident #type_generics
156 #where_clause {
157 type Owned = #target_type;
158
159 fn make_owned(self) -> <Self as MakeOwned>::Owned {
160 #impl_code
161 }
162 }
163 },
164 }
165 .into()
166}