warcmutex/lib.rs
1use proc_macro::TokenStream;
2use proc_macro2::Ident;
3use quote::{quote, ToTokens};
4use syn::{parse_macro_input, parse_quote, DeriveInput, ImplItem, ItemImpl, Visibility, Field, ItemMod, Item, ItemStruct, parse_str};
5use util::{field_helpers::extract_fields, mod_helpers::{get_type_name, has_warcmutex_attribute}};
6
7use crate::util::impl_block_helpers::{
8 change_block_method, get_impl_type_name, remove_pub_from_impl_item,
9 transform_method_return_type,
10};
11
12mod util;
13
14#[proc_macro_attribute]
15pub fn warcmutex(_ : TokenStream, input : TokenStream) -> TokenStream{
16 //obtem do o módulo
17 let item: Item = parse_macro_input!(input as Item);
18 match item {
19 Item::Impl(item_impl) => extend_impl(item_impl).into(),
20 Item::Mod(sub_mod) => extend_mod(sub_mod).into(),
21 Item::Struct(item_struct ) => extend_struct(item_struct).into(),
22 _ => panic!("This macro can only be used in structs, impl Blocks and mods!"),
23 }
24}
25
26fn extend_mod(item_mod : ItemMod) -> TokenStream{
27 let mut tokens = format!("{} mod {}",item_mod.vis.into_token_stream().to_string(),item_mod.ident.to_string());
28 tokens += "{";
29 for item in item_mod.content.unwrap().1.iter(){
30 if !has_warcmutex_attribute(&item){
31 match item.clone() {
32 Item::Impl(item_impl) => tokens += &extend_impl(item_impl.clone()).to_string(),
33 Item::Mod(sub_mod) => tokens += &extend_mod(sub_mod.clone()).to_string(),
34 Item::Struct(item_struct ) => tokens += &extend_struct(item_struct.clone()).to_string(),
35 _ => tokens += &item.into_token_stream().to_string(),
36 }
37 }
38 }
39 tokens += "}";
40 let output : proc_macro2::TokenStream = parse_str(&tokens).unwrap();
41 //println!(">>Mod>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n {} <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",output);
42 output.into()
43}
44
45fn extend_struct(item_struct : ItemStruct) -> TokenStream{
46
47 let input: DeriveInput = parse_quote! {
48 #item_struct
49 };
50 let vis = &input.vis;
51 let field_names = extract_fields(&input);
52 // Gere um TokenStream contendo apenas os nomes dos campos impl Iterator<Item = TokenStream>
53 let field_tokens = field_names.iter().map(|field_name| {
54 let new_field_name = if let Visibility::Public(_) = field_name.vis{
55 Field{
56 attrs: field_name.attrs.clone(),
57 vis: Visibility::Inherited,
58 mutability: field_name.mutability.clone(),
59 ident: field_name.ident.clone(),
60 colon_token: field_name.colon_token,
61 ty: field_name.ty.clone(),
62 }
63 }else{
64 field_name.clone()
65 };
66 quote! { #new_field_name }
67 });
68 // Clone the struct name identifier and assign a new name
69 let original_struct_name = input.ident.clone();
70 let base_name = original_struct_name.to_string()+"Base";
71 let base_name : Ident = parse_str(&base_name).unwrap();
72
73 // Generate the transformed struct definition
74 let transformed_struct = quote! {
75 pub struct #base_name {
76 // Fields remain intact
77 #(#field_tokens),*
78 }
79 };
80 // Generate the second struct definition
81 let secund_struct = quote! {
82 #vis struct #original_struct_name {
83 // New field named 'base' of type 'Arc<Base>'
84 base: std::sync::Arc<std::sync::Mutex<#base_name>>,
85 }
86 };
87
88 let lock_impl: ItemImpl = parse_quote!(
89 impl #original_struct_name{
90 pub fn lock(&mut self) -> LockResult<MutexGuard<'_, #base_name>> {
91 self.base.lock()
92 }
93 }
94 );
95
96 let clone_impl: ItemImpl = parse_quote!(
97 impl Clone for #original_struct_name{
98 fn clone(&self) -> Self {
99 Self { base: self.base.clone() }
100 }
101 }
102 );
103
104 let send_impl: ItemImpl = parse_quote!(
105 unsafe impl Send for #original_struct_name{}
106 );
107
108 let sync_impl: ItemImpl = parse_quote!(
109 unsafe impl Sync for #original_struct_name{}
110 );
111
112 // Combine the transformed struct and the original struct into the output tokens
113 let output = quote! {
114 use std::sync::Arc;
115 use std::sync::Mutex;
116 use std::sync::LockResult;
117 use std::sync::MutexGuard;
118 #transformed_struct
119 #secund_struct
120 #lock_impl
121 #clone_impl
122 #send_impl
123 #sync_impl
124 };
125 // Return the generated code as a TokenStream
126 //println!(">>Struct>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n {} <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",output);
127 output.into()
128}
129
130fn extend_impl(item_impl : ItemImpl) -> TokenStream{
131 let original_name = item_impl.self_ty.clone();
132 let original_name_str = get_type_name( original_name.clone()).expect("Could not get type name.");
133 let base_name_str = original_name_str+"Base";
134 let base_name : Ident = parse_str(&base_name_str).unwrap();
135
136 // Obter todos os itens de implementação
137 let mut original_impl_items = item_impl.items.clone();
138 original_impl_items
139 .iter_mut()
140 .for_each(|ii| transform_method_return_type(ii, get_impl_type_name(&item_impl).unwrap()));
141 let first_self_ty = parse_quote!(#base_name);
142 let sencund_self_ty = parse_quote!(#original_name);
143
144 let mut first_impl_items: Vec<ImplItem> = vec![];
145 let mut secund_impl_items: Vec<ImplItem> = vec![];
146 for original_impl_item in original_impl_items {
147 if let Some(item) = change_block_method(&original_impl_item,base_name_str.clone()) {
148 secund_impl_items.push(item);
149 let mut modificated_impl_item = original_impl_item.clone();
150 remove_pub_from_impl_item(&mut modificated_impl_item);
151 first_impl_items.push(modificated_impl_item);
152 } else {
153 first_impl_items.push(original_impl_item.clone());
154 }
155 }
156
157 let secund_impl_block = ItemImpl {
158 attrs: item_impl.attrs.clone(),
159 defaultness: item_impl.defaultness,
160 unsafety: item_impl.unsafety,
161 impl_token: item_impl.impl_token,
162 generics: item_impl.generics.clone(),
163 trait_: item_impl.trait_.clone(),
164 self_ty: sencund_self_ty,
165 brace_token: item_impl.brace_token,
166 items: secund_impl_items,
167 };
168 // Crie um novo bloco impl com o nome modificado do tipo
169 let renamed_impl_block = ItemImpl {
170 attrs: item_impl.attrs,
171 defaultness: item_impl.defaultness,
172 unsafety: item_impl.unsafety,
173 impl_token: item_impl.impl_token,
174 generics: item_impl.generics,
175 trait_: item_impl.trait_,
176 self_ty: first_self_ty,
177 brace_token: item_impl.brace_token,
178 items: first_impl_items,
179 };
180 // Retorne o código modificado como TokenStream
181 let output = quote! {
182 #renamed_impl_block
183 #secund_impl_block
184 };
185 //println!(">>Impl>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n {} <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",output);
186 output.into()
187}
188
189/*#[proc_macro_attribute]
190pub fn warcmutex_struct(_: TokenStream, input: TokenStream) -> TokenStream {
191 // Parse the input tokens into a syntax tree
192 let input = parse_macro_input!(input as DeriveInput);
193 let vis = &input.vis;
194 let field_names = extract_fields(&input);
195 // Gere um TokenStream contendo apenas os nomes dos campos impl Iterator<Item = TokenStream>
196 let field_tokens = field_names.iter().map(|field_name| {
197 let new_field_name = if let Visibility::Public(_) = field_name.vis{
198 Field{
199 attrs: field_name.attrs.clone(),
200 vis: Visibility::Inherited,
201 mutability: field_name.mutability.clone(),
202 ident: field_name.ident.clone(),
203 colon_token: field_name.colon_token,
204 ty: field_name.ty.clone(),
205 }
206 }else{
207 field_name.clone()
208 };
209 quote! { #new_field_name }
210 });
211 // Clone the struct name identifier and assign a new name
212 let original_struct_name = input.ident.clone();
213
214 // Generate the transformed struct definition
215 let transformed_struct = quote! {
216 pub struct Base {
217 // Fields remain intact
218 #(#field_tokens),*
219 }
220 };
221 // Generate the second struct definition
222 let secund_struct = quote! {
223 #vis struct #original_struct_name {
224 // New field named 'base' of type 'Arc<Base>'
225 base: std::sync::Arc<std::sync::Mutex<Base>>,
226 }
227 };
228
229 let lock_impl: ItemImpl = parse_quote!(
230 impl #original_struct_name{
231 pub fn lock(&mut self) -> LockResult<MutexGuard<'_, Base>> {
232 self.base.lock()
233 }
234 }
235 );
236
237 // Combine the transformed struct and the original struct into the output tokens
238 let output = quote! {
239 use std::sync::Arc;
240 use std::sync::Mutex;
241 use std::sync::LockResult;
242 use std::sync::MutexGuard;
243 #transformed_struct
244 #secund_struct
245 #lock_impl
246 };
247 // Return the generated code as a TokenStream
248 output.into()
249}
250
251#[proc_macro_attribute]
252pub fn warcmutex_impl(_: TokenStream, input: TokenStream) -> TokenStream {
253 // Parse o nome original do bloco impl
254 // Parse o input como um ItemImpl
255 let impl_block = parse_macro_input!(input as ItemImpl);
256 let original_name = impl_block.self_ty.clone();
257
258 // Obter todos os itens de implementação
259 let mut original_impl_items = impl_block.items.clone();
260 original_impl_items
261 .iter_mut()
262 .for_each(|ii| transform_method_return_type(ii, get_impl_type_name(&impl_block).unwrap()));
263 let first_self_ty = parse_quote!(Base);
264 let sencund_self_ty = parse_quote!(#original_name);
265
266 let mut first_impl_items: Vec<ImplItem> = vec![];
267 let mut secund_impl_items: Vec<ImplItem> = vec![];
268 for original_impl_item in original_impl_items {
269 if let Some(item) = change_block_method(&original_impl_item) {
270 secund_impl_items.push(item);
271 let mut modificated_impl_item = original_impl_item.clone();
272 remove_pub_from_impl_item(&mut modificated_impl_item);
273 first_impl_items.push(modificated_impl_item);
274 } else {
275 first_impl_items.push(original_impl_item.clone());
276 }
277 }
278
279 let secund_impl_block = ItemImpl {
280 attrs: impl_block.attrs.clone(),
281 defaultness: impl_block.defaultness,
282 unsafety: impl_block.unsafety,
283 impl_token: impl_block.impl_token,
284 generics: impl_block.generics.clone(),
285 trait_: impl_block.trait_.clone(),
286 self_ty: sencund_self_ty,
287 brace_token: impl_block.brace_token,
288 items: secund_impl_items,
289 };
290 // Crie um novo bloco impl com o nome modificado do tipo
291 let renamed_impl_block = ItemImpl {
292 attrs: impl_block.attrs,
293 defaultness: impl_block.defaultness,
294 unsafety: impl_block.unsafety,
295 impl_token: impl_block.impl_token,
296 generics: impl_block.generics,
297 trait_: impl_block.trait_,
298 self_ty: first_self_ty,
299 brace_token: impl_block.brace_token,
300 items: first_impl_items,
301 };
302 // Retorne o código modificado como TokenStream
303 let output = quote! {
304 #renamed_impl_block
305 #secund_impl_block
306 };
307
308 /*println!(
309 ">>>>>>>>>>>>>> resultado impl >>>>>>>>>>>>>>> \n{}\n <<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>",
310 output.to_string()
311 );*/
312
313 output.into()
314}
315*/