atomic_struct/
lib.rs

1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::{Fields, ItemStruct, parse_macro_input};
4
5#[proc_macro_attribute]
6pub fn atomic_struct(_attr: TokenStream, item: TokenStream) -> TokenStream {
7    let input = parse_macro_input!(item as ItemStruct);
8    let struct_name = &input.ident;
9    let struct_vis = &input.vis;
10
11    let struct_attrs = &input.attrs;
12    let mut atomic_fields = Vec::new();
13    let mut getters_setters = Vec::new();
14    let mut constructor_params = Vec::new();
15    let mut constructor_inits = Vec::new();
16
17    if let Fields::Named(fields) = &input.fields {
18        for field in &fields.named {
19            let fname = field.ident.as_ref().unwrap();
20            let fty = &field.ty;
21            let attrs = &field.attrs;
22            let vis = &field.vis;
23            let doc_attrs: Vec<_> = field
24                .attrs
25                .iter()
26                .filter(|attr| attr.path().is_ident("doc"))
27                .collect();
28
29            // Field as AtomicMember
30            atomic_fields.push(quote! {
31                #(#attrs)*
32                #fname: atomic_struct_core::AtomicMember<#fty>
33            });
34
35            // Construktor-Parameter
36            constructor_params.push(quote! {
37                #fname: #fty
38            });
39
40            // Construktor-Init
41            constructor_inits.push(quote! {
42                #fname: atomic_struct_core::AtomicMember::new(#fname)
43            });
44
45            // Getter
46            let get_name = format_ident!("get_{}", fname);
47            getters_setters.push(quote! {
48                #(#doc_attrs)*
49                #vis async fn #get_name(&self) -> #fty {
50                    self.#fname.get().await
51                }
52            });
53
54            // Setter
55            let set_name = format_ident!("set_{}", fname);
56            getters_setters.push(quote! {
57                #(#doc_attrs)*
58                #vis async fn #set_name(&self, new_val: #fty) {
59                    self.#fname.set(new_val).await
60                }
61            });
62        }
63    }
64
65
66    // create the expanded struct with atomic fields and methods
67    let expanded = quote! {
68        #(#struct_attrs)*
69        #struct_vis struct #struct_name {
70            #(#atomic_fields),*
71        }
72
73        impl #struct_name {
74            #struct_vis fn new(#(#constructor_params),*) -> Self {
75                Self {
76                    #(#constructor_inits),*
77                }
78            }
79
80            #(#getters_setters)*
81        }
82    };
83
84    expanded.into()
85}