1use proc_macro::TokenStream;
2
3mod assertions;
4mod config;
5mod errors;
6mod handler;
7mod store;
8
9#[proc_macro_attribute]
10pub fn map(args: TokenStream, item: TokenStream) -> TokenStream {
11 let mut keep_empty_output = false;
12 match args.to_string().as_str() {
13 "" => {}
14 "keep_empty_output" => keep_empty_output = true,
15 _ => panic!("Invalid argument '{}' for map macro", args),
16 }
17 handler::main(item.into(), config::ModuleType::Map, keep_empty_output).into()
18}
19
20#[proc_macro_attribute]
21pub fn store(args: TokenStream, item: TokenStream) -> TokenStream {
22 let mut keep_empty_output = false;
23 match args.to_string().as_str() {
24 "" => {}
25 "keep_empty_output" => keep_empty_output = true,
26 _ => panic!("Invalid argument '{}' for store macro", args),
27 }
28 handler::main(item.into(), config::ModuleType::Store, keep_empty_output).into()
29}
30
31#[proc_macro_derive(StoreWriter)]
33pub fn derive(input: TokenStream) -> TokenStream {
34 store::main(input)
35}
36
37#[cfg(test)]
38mod test {
39 use crate::{assertions::assert_ast_eq, config::ModuleType, handler::main};
40 use quote::quote;
41
42 #[test]
43 fn test_map_plain() {
44 let item = quote! {
45 fn map_transfers(blk: eth::Block) -> pb::Custom {
46 unimplemented!("do something");
47 }
48 };
49
50 assert_ast_eq(
51 main(item, ModuleType::Map, true).into(),
52 quote! {
53 #[no_mangle]
54 pub extern "C" fn map_transfers(blk_ptr: *mut u8, blk_len: usize) {
55 substreams::register_panic_hook();
56 let func = || -> pb::Custom {
57 let blk: eth::Block = substreams::proto::decode_ptr(blk_ptr, blk_len)
58 .unwrap_or_else(|_| panic!("Unable to decode Protobuf data ({} bytes) to '{}' message's struct", blk_len, stringify!(eth::Block)));
59 let result = {
60 unimplemented!("do something");
61 };
62 result
63 };
64 let result = func();
65 substreams::output(result);
66 }
67 },
68 );
69 }
70
71 #[test]
72 fn test_map_mut() {
73 let item = quote! {
74 fn map_transfers(mut blk: eth::Block) -> pb::Custom {
75 unimplemented!("do something");
76 }
77 };
78
79 assert_ast_eq(
80 main(item, ModuleType::Map, true).into(),
81 quote! {
82 #[no_mangle]
83 pub extern "C" fn map_transfers(blk_ptr: *mut u8, blk_len: usize) {
84 substreams::register_panic_hook();
85 let func = || -> pb::Custom {
86 let mut blk: eth::Block = substreams::proto::decode_ptr(blk_ptr, blk_len)
87 .unwrap_or_else(|_| panic!("Unable to decode Protobuf data ({} bytes) to '{}' message's struct", blk_len, stringify!(eth::Block)));
88 let result = {
89 unimplemented!("do something");
90 };
91 result
92 };
93 let result = func();
94 substreams::output(result);
95 }
96 },
97 );
98 }
99
100 #[test]
101 fn test_map_option() {
102 let item = quote! {
103 fn map_transfers(blk: eth::Block) -> Option<pb::Custom> {
104 unimplemented!("do something");
105 }
106 };
107
108 assert_ast_eq(
109 main(item, ModuleType::Map, true).into(),
110 quote! {
111 #[no_mangle]
112 pub extern "C" fn map_transfers(blk_ptr: *mut u8, blk_len: usize) {
113 substreams::register_panic_hook();
114 let func = || -> Option<pb::Custom> {
115 let blk: eth::Block = substreams::proto::decode_ptr(blk_ptr, blk_len)
116 .unwrap_or_else(|_| panic!("Unable to decode Protobuf data ({} bytes) to '{}' message's struct", blk_len, stringify!(eth::Block)));
117 let result = { unimplemented!("do something"); };
118 result
119 };
120
121 let result = func();
122 if let Some(value) = result {
123 substreams::output(value);
124 }
125 }
126 },
127 );
128 }
129
130 #[test]
131 fn test_map_result() {
132 let item = quote! {
133 fn map_transfers(blk: eth::Block) -> Result<pb::Custom> {
134 unimplemented!("do something");
135 }
136 };
137
138 assert_ast_eq(
139 main(item, ModuleType::Map, true).into(),
140 quote! {
141 #[no_mangle]
142 pub extern "C" fn map_transfers(blk_ptr: *mut u8, blk_len: usize) {
143 substreams::register_panic_hook();
144 let func = || -> Result<pb::Custom> {
145 let blk: eth::Block = substreams::proto::decode_ptr(blk_ptr, blk_len)
146 .unwrap_or_else(|_| panic!("Unable to decode Protobuf data ({} bytes) to '{}' message's struct", blk_len, stringify!(eth::Block)));
147 let result = { unimplemented!("do something"); };
148 result
149 };
150
151 let result = func();
152 if result.is_err() {
153 panic!("{:?}", result.unwrap_err())
154 }
155 substreams::output(result.expect("already checked that result is not an error"));
156 }
157 },
158 );
159 }
160
161 #[test]
162 fn test_map_result_option() {
163 let item = quote! {
164 fn map_transfers(blk: eth::Block) -> Result<Option<pb::Custom>> {
165 unimplemented!("do something");
166 }
167 };
168
169 assert_ast_eq(
170 main(item.clone(), ModuleType::Map, true).into(),
171 quote! {
172 #[no_mangle]
173 pub extern "C" fn map_transfers(blk_ptr: *mut u8, blk_len: usize) {
174 substreams::register_panic_hook();
175 let func = || -> Result<Option<pb::Custom> > {
176 let blk: eth::Block = substreams::proto::decode_ptr(blk_ptr, blk_len)
177 .unwrap_or_else(|_| panic!("Unable to decode Protobuf data ({} bytes) to '{}' message's struct", blk_len, stringify!(eth::Block)));
178 let result = { unimplemented!("do something"); };
179 result
180 };
181
182 let result = func();
183 if result.is_err() {
184 panic!("{:?}", result.unwrap_err())
185 }
186 if let Some(inner) = result.expect("already checked that result is not an error") {
187 substreams::output(inner);
188 }
189 }
190 },
191 );
192
193 assert_ast_eq(
194 main(item, ModuleType::Map, false).into(),
195 quote! {
196 #[no_mangle]
197 pub extern "C" fn map_transfers(blk_ptr: *mut u8, blk_len: usize) {
198 substreams::register_panic_hook();
199 let func = || -> Result<Option<pb::Custom> > {
200 let blk: eth::Block = substreams::proto::decode_ptr(blk_ptr, blk_len)
201 .unwrap_or_else(|_| panic!("Unable to decode Protobuf data ({} bytes) to '{}' message's struct", blk_len, stringify!(eth::Block)));
202 let result = { unimplemented!("do something"); };
203 result
204 };
205
206 substreams :: skip_empty_output () ;
207 let result = func();
208 if result.is_err() {
209 panic!("{:?}", result.unwrap_err())
210 }
211 if let Some(inner) = result.expect("already checked that result is not an error") {
212 substreams::output(inner);
213 }
214 }
215 },
216 );
217 }
218
219 #[test]
220 fn test_store_result_option() {
221 let item = quote! {
222 fn store_values(blk: eth::Block, store: StoreAddInt64) {
223 unimplemented!("do something");
224 }
225 };
226
227 assert_ast_eq(
228 main(item.clone(), ModuleType::Store, true).into(),
229 quote! {
230 #[no_mangle]
231 pub extern "C" fn store_values(blk_ptr: *mut u8, blk_len: usize) {
232 substreams::register_panic_hook();
233 let blk: eth::Block = substreams::proto::decode_ptr(blk_ptr, blk_len)
234 .unwrap_or_else(|_|
235 panic!(
236 "Unable to decode Protobuf data ({} bytes) to '{}' message's struct",
237 blk_len, stringify!(eth::Block)
238 )
239 );
240 let store: StoreAddInt64 = StoreAddInt64::new();
241 let result = {
242 unimplemented!("do something");
243 };
244 result
245 }
246 },
247 );
248
249 assert_ast_eq(
250 main(item, ModuleType::Store, false).into(),
251 quote! {
252 #[no_mangle]
253 pub extern "C" fn store_values(blk_ptr: *mut u8, blk_len: usize) {
254 substreams::register_panic_hook();
255 let blk: eth::Block = substreams::proto::decode_ptr(blk_ptr, blk_len)
256 .unwrap_or_else(|_|
257 panic!(
258 "Unable to decode Protobuf data ({} bytes) to '{}' message's struct",
259 blk_len, stringify!(eth::Block)
260 )
261 );
262 let store: StoreAddInt64 = StoreAddInt64::new();
263 substreams :: skip_empty_output () ;
264 let result = {
265 unimplemented!("do something");
266 };
267 result
268 }
269 },
270 );
271 }
272}