borderless_sdk_macros/
lib.rs1use agent::AgentArgs;
2use proc_macro::TokenStream;
3use quote::quote;
4use syn::{parse_macro_input, Item, ItemMod};
5
6mod action;
7mod agent;
8mod contract;
9mod schedule;
10mod sink;
11mod state;
12mod utils;
13
14#[proc_macro_attribute]
19pub fn contract(_attrs: TokenStream, input: TokenStream) -> TokenStream {
20 let module = parse_macro_input!(input as ItemMod);
21
22 if module.content.is_none() {
24 return syn::Error::new_spanned(
25 module,
26 "Macro can only be implemented on modules that have some content",
27 )
28 .to_compile_error()
29 .into();
30 }
31 let (brace, mut items) = module.content.unwrap();
32
33 let new_tokens = match contract::parse_module_content(brace.span.join(), &items, &module.ident)
35 {
36 Ok(tokens) => tokens,
37 Err(e) => return e.to_compile_error().into(),
38 };
39
40 items.push(Item::Verbatim(new_tokens));
42
43 match module.vis {
45 syn::Visibility::Public(_) => (),
46 _ => {
47 let tokens =
48 syn::Error::new_spanned(module.mod_token, "Contract module must be public")
49 .to_compile_error();
50 items.push(Item::Verbatim(tokens));
51 }
52 }
53
54 let wasm_exports = contract::generate_wasm_exports(&module.ident);
55
56 let new_module = ItemMod {
58 attrs: module.attrs,
59 vis: module.vis,
60 unsafety: module.unsafety,
61 mod_token: module.mod_token,
62 ident: module.ident,
63 content: Some((brace, items)),
64 semi: module.semi,
65 };
66
67 quote! {
69 #new_module
70 #wasm_exports
71 }
72 .into()
73}
74
75#[proc_macro_attribute]
76pub fn agent(attrs: TokenStream, input: TokenStream) -> TokenStream {
77 let module = parse_macro_input!(input as ItemMod);
78 let parsed_attrs = syn::parse_macro_input!(attrs as AgentArgs);
79
80 if module.content.is_none() {
82 return syn::Error::new_spanned(
83 module,
84 "Macro can only be implemented on modules that have some content",
85 )
86 .to_compile_error()
87 .into();
88 }
89 let (brace, mut items) = module.content.unwrap();
90
91 let use_ws = parsed_attrs.websocket.unwrap_or_default();
93
94 let new_tokens = match agent::parse_module_content(brace.span.join(), &items, use_ws) {
96 Ok(tokens) => tokens,
97 Err(e) => return e.to_compile_error().into(),
98 };
99
100 items.push(Item::Verbatim(new_tokens));
102
103 match module.vis {
105 syn::Visibility::Public(_) => (),
106 _ => {
107 let tokens = syn::Error::new_spanned(module.mod_token, "Agent module must be public")
108 .to_compile_error();
109 items.push(Item::Verbatim(tokens));
110 }
111 }
112
113 let wasm_exports = agent::generate_wasm_exports(&module.ident);
114
115 let wasm_ws_exports = if use_ws {
117 agent::generate_ws_wasm_exports(&module.ident)
118 } else {
119 quote! {}
120 };
121
122 let new_module = ItemMod {
124 attrs: module.attrs,
125 vis: module.vis,
126 unsafety: module.unsafety,
127 mod_token: module.mod_token,
128 ident: module.ident,
129 content: Some((brace, items)),
130 semi: module.semi,
131 };
132
133 quote! {
135 #new_module
136 #wasm_exports
137 #wasm_ws_exports
138 }
139 .into()
140}
141
142#[proc_macro_derive(State)]
143pub fn derive_contract_state(input: TokenStream) -> TokenStream {
144 let input = parse_macro_input!(input);
145 let output = state::impl_state(input);
146
147 match output {
148 syn::Result::Ok(token_stream) => token_stream,
149 syn::Result::Err(err) => err.to_compile_error(),
150 }
151 .into()
152}
153
154#[proc_macro_derive(NamedSink)]
155pub fn derive_named_sink(input: TokenStream) -> TokenStream {
156 let input = parse_macro_input!(input);
157 let output = sink::impl_named_sink(input);
158
159 match output {
160 syn::Result::Ok(token_stream) => token_stream,
161 syn::Result::Err(err) => err.to_compile_error(),
162 }
163 .into()
164}
165
166#[proc_macro_attribute]
167pub fn action(_attrs: TokenStream, input: TokenStream) -> TokenStream {
168 input
169}
170
171#[proc_macro_attribute]
172pub fn schedule(_attrs: TokenStream, input: TokenStream) -> TokenStream {
173 input
174}