netsim_embed_macros/
lib.rs1use 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}