simul_macro/
lib.rs

1use proc_macro::{Span, TokenStream};
2use quote::quote;
3use syn::{self, token, Field, Ident, Visibility};
4
5#[proc_macro_attribute]
6pub fn agent(attr: TokenStream, item: TokenStream) -> TokenStream {
7    let mut agent_struct = syn::parse_macro_input!(item as syn::ItemStruct);
8    let _ = syn::parse_macro_input!(attr as syn::parse::Nothing);
9
10    if let syn::Fields::Named(ref mut fields) = agent_struct.fields {
11        if fields.named.iter().all(|f| {
12            f.ident
13                .as_ref()
14                .map(|name| name != "state")
15                .unwrap_or(false)
16        }) {
17            fields.named.push(Field {
18                attrs: vec![],
19                vis: Visibility::Inherited,
20                ident: Some(Ident::new("state", Span::call_site().into())),
21                colon_token: Some(token::Colon {
22                    spans: [Span::call_site().into()],
23                }),
24                ty: syn::parse_str("simul::AgentState").expect("Failed to parse type"),
25                mutability: syn::FieldMutability::None,
26            });
27        }
28    }
29
30    let struct_name = &agent_struct.ident;
31    let common_agent_impl = quote! {
32        impl simul::AgentCommon for #struct_name {
33            fn state(&self) -> &AgentState {
34                &self.state
35            }
36
37            fn state_mut(&mut self) -> &mut AgentState {
38                &mut self.state
39            }
40        }
41    };
42
43    quote!(
44        #[derive(Clone, Debug)]
45        #agent_struct
46
47        #common_agent_impl
48    )
49    .into()
50}