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*/