1#![allow(unused_imports)]
2use std::env::args;
3
4use proc_macro::{self, TokenStream as ts1};
5use quote::{quote, quote_spanned, format_ident};
6use syn::{Attribute, ItemFn, Meta, MetaNameValue, ReturnType, TraitItem};
7use syn::{
8 parse_macro_input, DeriveInput, Generics, ImplItem, Data, Fields,
9 spanned::Spanned, Index, Ident, GenericParam, parse_quote, ItemImpl, token::Trait, ItemTrait
10};
11use proc_macro2::TokenStream as ts2;
12use synstructure::{AddBounds, Structure};
13
14fn derive_as_ref(mut structure: Structure<'_>) -> ts2 {
15 structure
16 .underscore_const(true)
17 .add_bounds(AddBounds::None)
18 .gen_impl(quote! {
19 gen impl ::core::convert::AsRef<Self> for @Self {
20 fn as_ref(&self) -> &Self {
21 &self
22 }
23 }
24 })
25}
26synstructure::decl_derive!([AsRef] => derive_as_ref);
27
28
29#[proc_macro_attribute]
30pub fn ta_derive(_metadata: ts1, input: ts1) -> ts1 {
31 let input_token: ts2 = input.into();
32 let output = quote! {
33 #[derive(Debug, Clone, Serialize, Deserialize, AsRef)]
34 #input_token
35 };
36 output.into()
37}
38
39#[proc_macro_attribute]
40pub fn ta_derive2(_metadata: ts1, input: ts1) -> ts1 {
41 let input_token: ts2 = input.into();
42 let output = quote! {
43 #[derive(PathDebug, Clone, Serialize, Deserialize, AsRef)]
44 #input_token
45 };
46 output.into()
47}
48
49#[proc_macro_attribute]
50pub fn clone_trait(_metadata: ts1, input: ts1) -> ts1 {
51 let input_token: ItemTrait = syn::parse(input).unwrap();
52 let name = input_token.ident.clone();
53 let name_str = name.to_string();
54 let name_to_box = format_ident!("{}_box", name_str.to_lowercase());
55 let type_ident = format_ident!("{}Box", name_str);
56 let visi = input_token.vis;
57 let item = input_token.items.into_iter();
58 let attrs = input_token.attrs.into_iter();
59 let gener = input_token.generics;
60 let output = quote! {
61 #[typetag::serde(tag = #name_str)]
62 #(#attrs)*
63 #visi trait #name #gener: DynClone + Send + Sync + std::fmt::Debug + 'static {
64 #(#item)*
65 fn #name_to_box(&self) -> Box<dyn #name>
66 where
67 Self: Clone,
68 {
69 Box::new(self.clone())
70 }
71 }
72 clone_trait_object!(#gener #name #gener);
73 impl PartialEq for Box<dyn #name> {
74 fn eq(&self, other: &Self) -> bool {
75 format!("{:?}", self) == format!("{:?}", other)
76 }
77 }
78 pub type #type_ident = Box<dyn #name>;
79 };
80 proc_macro::TokenStream::from(output)
81}
82
83#[proc_macro_derive(PathDebug)]
120pub fn path_debug(input: ts1) -> ts1 {
121 let ast: DeriveInput = syn::parse(input).unwrap();
122 let name = ast.ident.clone();
123 let b = get_fields_name(&ast.ident, &ast.data);
124 let generics = add_trait_bounds(ast.generics);
125 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
126 let output = quote! {
127 impl #impl_generics std::fmt::Debug for #name #ty_generics #where_clause {
128 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129 f
130 #b
131 .finish()
132 }
133 }
134
135 };
136 proc_macro::TokenStream::from(output)
137}
138
139
140fn add_trait_bounds(mut generics: Generics) -> Generics {
141 for param in &mut generics.params {
142 if let GenericParam::Type(ref mut type_param) = *param {
143 type_param.bounds.push(parse_quote!(std::fmt::Debug));
144 }
145 }
146 generics
147}
148
149fn get_fields_name(type_name: &Ident, data: &Data) -> ts2 {
150 let type_string = type_name.to_string();
151 match *data {
152 Data::Struct(ref data) => {
153 match data.fields {
154 Fields::Named(ref fields) => {
155 let recurse = fields.named.iter().map(|f| {
156 let name = &f.ident;
157 let name_string = name.as_ref().map_or_else(String::default, |v| v.to_string());
158 quote! { field(#name_string, &self.#name) }
159 });
160 quote! {
161 .debug_struct(&format!("{}::{}", module_path!().split("::").last().unwrap(), #type_string))
162 #(.#recurse)*
163 }
164 }
165 Fields::Unnamed(ref fields) => {
166 let recurse = fields.unnamed.iter().enumerate().map(|(i, _f)| {
167 let index = Index::from(i);
168 quote! { field(&self.#index) }
169 });
170 quote! {
171 .debug_tuple(&format!("{}::{}", module_path!().split("::").last().unwrap(), #type_string))
172 #(.#recurse)*
173 }
174 }
175 Fields::Unit => {
176 quote! {
177 .debug_struct(&format!("{}::{}", module_path!().split("::").last().unwrap(), #type_string))
178 }
179 }
180 }
181 }
182 Data::Enum(_) | Data::Union(_) => unimplemented!(),
183 }
184}
185
186#[proc_macro_attribute]
187pub fn lazy_init(attr: ts1, item: ts1) -> ts1 {
188 let input = parse_macro_input!(item as ItemTrait);
189 let di_expr = parse_macro_input!(attr as syn::Expr);
190
191 let trait_name = &input.ident;
192 let mut methods = quote!{};
193
194 for item in input.items.clone() {
195 if let TraitItem::Fn(trait_item_fn) = item {
196 let fn_name = trait_item_fn.sig.ident;
197 let fn_name_lazy = format_ident!("{}_lazy", fn_name);
198 let ReturnType::Type(_, return_type) = trait_item_fn.sig.output else { panic!("return type") };
199 methods.extend(quote! {
200 fn #fn_name_lazy(&self) -> #return_type {
201 let mut cond_fn: Option<#return_type> = None;
202 Box::new(move |data| {
203 cond_fn.get_or_insert_with(|| self.#fn_name(#di_expr))(data)
204 })
205 }
206 });
207 break;
208 }
209 }
210
211 let items = &input.items;
212 let attrs = &input.attrs;
213
214 let expanded = quote! {
215 #(#attrs)*
216 pub trait #trait_name {
217 #(#items)*
218 #methods
219 }
220 };
221 ts1::from(expanded)
222}