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}