netsim_embed_macros/
lib.rs

1use proc_macro::TokenStream;
2
3#[proc_macro_attribute]
4pub fn machine(_attrs: TokenStream, fun: TokenStream) -> TokenStream {
5    let f = syn::parse_macro_input!(fun as syn::ItemFn);
6
7    assert!(
8        f.attrs.is_empty(),
9        "netsim_embed::machine cannot have any attribute"
10    );
11    assert!(
12        f.sig.constness.is_none(),
13        "netsim_embed::machine cannot be const"
14    );
15    assert!(
16        f.sig.asyncness.is_none(),
17        "netsim_embed::machine cannot be async"
18    );
19    assert!(
20        f.sig.unsafety.is_none(),
21        "netsim_embed::machine cannot be unsafe"
22    );
23    assert!(
24        f.sig.abi.is_none(),
25        "netsim_embed::machine cannot have an abi defined"
26    );
27    assert!(
28        f.sig.generics.params.is_empty(),
29        "netsim_embed::machine cannot be generic"
30    );
31    assert!(
32        f.sig.inputs.len() == 1,
33        "netsim_embed::machine must take exactly one argument"
34    );
35    assert!(
36        f.sig.variadic.is_none(),
37        "netsim_embed::machine cannot be variadic"
38    );
39    assert!(
40        matches!(f.sig.output, syn::ReturnType::Default),
41        "netsim_embed::machine must not declare a return type"
42    );
43
44    let input = match &f.sig.inputs.first().unwrap() {
45        syn::FnArg::Typed(input) => input,
46        _ => panic!("netsim_embed::machine must be a freestanding function"),
47    };
48    assert!(
49        input.attrs.is_empty(),
50        "netsim_embed::machine's only argument must not have any attributes attached"
51    );
52
53    let f_vis = f.vis;
54    let f_ident = f.sig.ident;
55    let input_ty = &input.ty;
56    let id: u128 = rand::random();
57    let input_pat = &input.pat;
58    let f_block = f.block;
59
60    TokenStream::from(quote::quote! {
61        #[allow(non_camel_case_types)]
62        #f_vis struct #f_ident ;
63
64        impl netsim_embed::MachineFn for #f_ident {
65            type Arg = #input_ty ;
66
67            fn id() -> u128 {
68                #id
69            }
70
71            fn call(#input_pat: #input_ty) #f_block
72        }
73    })
74}