dendrite_macros/
lib.rs

1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use proc_macro2::Span;
5use quote::quote;
6use syn::{AngleBracketedGenericArguments, FnArg, GenericArgument, Ident, ItemFn, LitStr, Pat, PatIdent, Path, PathArguments, PathSegment, PatType, ReturnType, Signature, Type, TypePath, TypeReference, parse_macro_input, parse2};
7use syn::punctuated::Iter;
8
9#[proc_macro_attribute]
10pub fn event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
11    // Construct a representation of Rust code as a syntax tree
12    // that we can manipulate
13    let input = parse_macro_input!(item as ItemFn);
14
15    // Build the trait implementation
16    impl_event_handler(&input)
17}
18
19fn impl_event_handler(ast: &ItemFn) -> TokenStream {
20    // println!("AST: {:?}", ast);
21    let ItemFn{sig, block, ..} = ast;
22    let Signature {ident, inputs, ..} = sig;
23    // println!("Signature: {:?}", sig);
24
25    let ident_string = ident.to_string();
26    let ident_span = ident.span();
27    // println!("X: {:?}: {:?}: {:?}", ident, ident_string, ident_span);
28    let ident_tmp = Ident::new(&format!("{}_registry_type", ident_string), ident_span);
29    let ident_helper = Ident::new(&format!("{}_helper", ident_string), ident_span);
30
31    let mut arg_iter = inputs.iter();
32    let (event_arg_name, event_type) = split_argument(arg_iter.next().unwrap(), &ident_string, "event");
33    let (query_model_arg_name, query_model_type) = split_argument(arg_iter.next().unwrap(), &ident_string, "query model");
34    let metadata_arg = get_metadata_arg(&mut arg_iter, "event", "Event", ident_span);
35
36    let event_type_ident = get_type_ident(event_type, &ident_string, "event");
37    // println!("Event type ident: {:?}", event_type_ident);
38    let event_type_literal = LitStr::new(&event_type_ident.to_string(), event_type_ident.span());
39
40    let gen = quote! {
41        use dendrite::axon_utils::HandlerRegistry as #ident_tmp;
42
43        #[tonic::async_trait]
44        impl AsyncApplicableTo<#query_model_type, dendrite::axon_server::event::Event> for #event_type {
45            async fn apply_to(self, #metadata_arg, #query_model_arg_name: &mut #query_model_type) -> Result<()> {
46                let #event_arg_name = self;
47                debug!("Event type: {:?}", #event_type_literal);
48                #block
49            }
50
51            fn box_clone(&self) -> Box<dyn AsyncApplicableTo<#query_model_type,dendrite::axon_server::event::Event>> {
52                Box::from(#event_type::clone(self))
53            }
54        }
55
56        // register event handler with registry
57        fn #ident(registry: &mut dendrite::axon_utils::TheHandlerRegistry<#query_model_type,dendrite::axon_server::event::Event,Option<#query_model_type>>) -> Result<()> {
58            registry.insert(
59                #event_type_literal,
60                &#event_type::decode,
61                &(|c,m,p| Box::pin(#ident_helper(Box::from(c), m, p)))
62            )
63        }
64
65        async fn #ident_helper<T: AsyncApplicableTo<P,M>,M: Send + Clone,P: Clone>(event: Box<T>, metadata: M, projection: P) -> Result<()> {
66            let mut p = projection.clone();
67            event.apply_to(metadata, &mut p).await?;
68            Ok(())
69        }
70    };
71    gen.into()
72}
73
74#[proc_macro_attribute]
75pub fn command_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
76    // Construct a representation of Rust code as a syntax tree
77    // that we can manipulate
78    let input = parse_macro_input!(item as ItemFn);
79
80    // Build the trait implementation
81    impl_command_handler(&input)
82}
83
84fn impl_command_handler(ast: &ItemFn) -> TokenStream {
85    // println!("AST: {:?}", ast);
86    let ItemFn{sig, block, ..} = ast;
87    let Signature {ident, inputs, output, ..} = sig;
88
89    let ident_string = ident.to_string();
90    let ident_span = ident.span();
91    // println!("X: {:?}: {:?}: {:?}", ident, ident_string, ident_span);
92    let ident_tmp = Ident::new(&format!("{}_registry_type", ident_string), ident_span);
93    let ident_impl = Ident::new(&format!("{}_impl", ident_string), ident_span);
94
95    let mut arg_iter = inputs.iter();
96    let (command_arg_name, command_type) = split_argument(arg_iter.next().unwrap(), &ident_string, "command");
97    let (context_arg_name, context_type) = split_argument(arg_iter.next().unwrap(), &ident_string, "context");
98    let context_elem_type = get_elem_type_argument(context_type, &ident_string, "context");
99    let metadata_arg = get_metadata_arg(&mut arg_iter, "command", "Command", ident_span);
100
101    let command_type_ident = get_type_ident(command_type, &ident_string, "command");
102    // println!("Event type ident: {:?}", event_type_ident);
103    let command_type_literal = LitStr::new(&command_type_ident.to_string(), command_type_ident.span());
104
105    let (output_type, output_type_ident) = match output {
106        ReturnType::Type(_, t) => (t, get_return_type_ident(&**t, &ident_string, "result")),
107        _ => panic!("Missing output type: {:?}", ident)
108    };
109    let output_type_literal = LitStr::new(&output_type_ident.to_string(), output_type_ident.span());
110
111    let gen = quote! {
112        use dendrite::axon_utils::HandlerRegistry as #ident_tmp;
113
114        // register command handler with registry
115        fn #ident(registry: &mut dendrite::axon_utils::TheHandlerRegistry<std::sync::Arc<async_lock::Mutex<#context_elem_type>>,dendrite::axon_server::command::Command,dendrite::axon_utils::SerializedObject>) -> Result<()> {
116            registry.insert_with_output(
117                #command_type_literal,
118                &#command_type::decode,
119                &(|c,m,p| Box::pin(#ident_impl(c, m, p)))
120            )
121        }
122
123        async fn #ident_impl(#command_arg_name: #command_type, #metadata_arg, #context_arg_name: std::sync::Arc<async_lock::Mutex<#context_elem_type>>) -> Result<Option<SerializedObject>> {
124            let mut #context_arg_name = #context_arg_name.deref().lock().await;
125            debug!("Event type: {:?}", #command_type_literal);
126            let result : #output_type = #block;
127            let result: Option<Result<SerializedObject>> = result?.map(|r| dendrite::axon_utils::axon_serialize(#output_type_literal, &r));
128            match result {
129                Some(Ok(serialized)) => Ok(Some(serialized)),
130                Some(Err(e)) => Err(e),
131                None => Ok(None),
132            }
133        }
134    };
135    gen.into()
136}
137
138#[proc_macro_attribute]
139pub fn event_sourcing_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
140    // Construct a representation of Rust code as a syntax tree
141    // that we can manipulate
142    let input = parse_macro_input!(item as ItemFn);
143
144    // Build the trait implementation
145    impl_event_sourcing_handler(&input)
146}
147
148fn impl_event_sourcing_handler(ast: &ItemFn) -> TokenStream {
149    // println!("AST: {:?}", ast);
150    let ItemFn{sig, block, ..} = ast;
151    let Signature {ident, inputs, ..} = sig;
152
153    let ident_string = ident.to_string();
154    let ident_span = ident.span();
155    // println!("X: {:?}: {:?}: {:?}", ident, ident_string, ident_span);
156    let ident_helper = Ident::new(&format!("{}_helper", ident_string), ident_span);
157
158    let mut arg_iter = inputs.iter();
159    let (event_arg_name, event_type) = split_argument(arg_iter.next().unwrap(), &ident_string, "event");
160    let (projection_arg_name, projection_type) = split_argument(arg_iter.next().unwrap(), &ident_string, "projection");
161    let metadata_arg = get_metadata_arg(&mut arg_iter, "event", "Event", ident_span);
162
163    let event_type_ident = get_type_ident(event_type, &ident_string, "event");
164    // println!("Event type ident: {:?}", event_type_ident);
165    let event_type_literal = LitStr::new(&event_type_ident.to_string(), event_type_ident.span());
166
167    let gen = quote! {
168        #[tonic::async_trait]
169        impl dendrite::axon_utils::ApplicableTo<#projection_type,dendrite::axon_server::event::Event> for #event_type {
170            fn apply_to(self, #metadata_arg, #projection_arg_name: &mut #projection_type) -> Result<()> {
171                let #event_arg_name = self;
172                debug!("Event type: {:?}", #event_type_literal);
173                #block;
174                Ok(())
175            }
176
177            fn box_clone(&self) -> Box<dyn dendrite::axon_utils::ApplicableTo<#projection_type,dendrite::axon_server::event::Event>> {
178                Box::from(#event_type::clone(self))
179            }
180        }
181
182        // register event handler with registry
183        fn #ident(registry: &mut dendrite::axon_utils::TheHandlerRegistry<#projection_type,dendrite::axon_server::event::Event,#projection_type>) -> Result<()> {
184            registry.insert_with_output(
185                #event_type_literal,
186                &#event_type::decode,
187                &(|c,m,p| Box::pin(#ident_helper(Box::from(c), m, p)))
188            )
189        }
190
191        async fn #ident_helper<T: ApplicableTo<P,M>,M: Send + Clone,P: Clone>(event: Box<T>, metadata: M, projection: P) -> Result<Option<P>> {
192            let mut p = projection.clone();
193            event.apply_to(metadata, &mut p)?;
194            Ok(Some(p))
195        }
196    };
197    gen.into()
198}
199
200fn split_argument<'a>(argument: &'a FnArg, handler_name: &str, qualifier: &str) -> (&'a Ident, &'a Box<Type>) {
201    if let FnArg::Typed(PatType {pat, ty, ..}) = argument {
202        if let Pat::Ident(PatIdent {ref ident, ..}) = **pat {
203            return (ident, ty);
204        }
205    }
206    panic!("Can't parse argument: {:?}: {:?}", handler_name, qualifier)
207}
208
209fn get_elem_type_argument<'a>(argument: &'a Type, handler_name: &str, qualifier: &str) -> &'a Box<Type> {
210    // println!("Get elem type of: {:?}", argument);
211    if let Type::Reference(TypeReference { elem, .. }) = argument {
212        return elem;
213    }
214    panic!("Can't get element type of reference: {:?}: {:?}", handler_name, qualifier)
215}
216
217fn get_type_ident<'a>(ty: &'a Type, handler_name: &str, qualifier: &str) -> &'a Ident {
218    if let Type::Path(TypePath {path: Path {segments, ..},..}) = ty {
219        let last_segment = segments.last().unwrap();
220        return &last_segment.ident;
221    }
222    panic!("Can't get type identifier: {:?}: {:?}", handler_name, qualifier)
223}
224
225fn get_return_type_ident<'a>(ty: &'a Type, handler_name: &str, qualifier: &str) -> &'a Ident {
226    let ty = get_first_generic_type_argument(ty, handler_name, qualifier);
227    let ty = get_first_generic_type_argument(ty, handler_name, qualifier);
228    if let Type::Path(TypePath {path:Path {segments:arg_segments,..}, ..}) = ty {
229        let last_arg_segment = arg_segments.last().unwrap();
230        let PathSegment { ident, ..} = last_arg_segment;
231        return ident;
232    }
233    panic!("Can't get return type identifier: {:?}: {:?}", handler_name, qualifier)
234}
235
236fn get_first_generic_type_argument<'a>(ty: &'a Type, handler_name: &str, qualifier: &str) -> &'a Type {
237    // println!("Try to get first generic type argument: {:?}", ty);
238    if let Type::Path(TypePath { path: Path { segments, .. }, .. }) = ty {
239        let last_segment = segments.last().unwrap();
240        if let PathSegment { arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { args, .. }), .. } = last_segment {
241            if let Some(GenericArgument::Type(result)) = args.first() {
242                return result;
243            }
244        }
245    }
246    panic!("Can't get first generic type argument: {:?}: {:?}", handler_name, qualifier)
247}
248
249fn get_metadata_arg(arg_iter: &mut Iter<FnArg>, package_name: &str, type_name: &str, span: Span) -> FnArg {
250    arg_iter.next().map(Clone::clone).unwrap_or_else(|| {
251        let package_ident = Ident::new(package_name, span);
252        let type_ident = Ident::new(type_name, span);
253        let argument = quote! { _: dendrite::axon_server::#package_ident::#type_ident };
254        let arg: FnArg = parse2(argument).unwrap();
255        arg
256    })
257}
258
259#[proc_macro_attribute]
260pub fn query_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
261    // Construct a representation of Rust code as a syntax tree
262    // that we can manipulate
263    let input = parse_macro_input!(item as ItemFn);
264
265    // Build the trait implementation
266    impl_query_handler(&input)
267}
268
269fn impl_query_handler(ast: &ItemFn) -> TokenStream {
270    // println!("AST: {:?}", ast);
271    let ItemFn{sig, block, ..} = ast;
272    let Signature {ident, inputs, ..} = sig;
273
274    let ident_string = ident.to_string();
275    let ident_span = ident.span();
276    // println!("X: {:?}: {:?}: {:?}", ident, ident_string, ident_span);
277    let ident_tmp = Ident::new(&format!("{}_registry_type", ident_string), ident_span);
278    let ident_impl = Ident::new(&format!("{}_impl", ident_string), ident_span);
279
280    let mut arg_iter = inputs.iter();
281    let (event_arg_name, event_type) = split_argument(arg_iter.next().unwrap(), &ident_string, "event");
282    let (query_model_arg_name, query_model_type) = split_argument(arg_iter.next().unwrap(), &ident_string, "query model");
283    let metadata_arg = get_metadata_arg(&mut arg_iter, "query", "QueryRequest", ident_span);
284
285    let event_type_ident = get_type_ident(event_type, &ident_string, "event");
286    // println!("Event type ident: {:?}", event_type_ident);
287    let event_type_literal = LitStr::new(&event_type_ident.to_string(), event_type_ident.span());
288
289    let gen = quote! {
290        use dendrite::axon_utils::HandlerRegistry as #ident_tmp;
291
292        async fn #ident_impl(#event_arg_name: #event_type, #metadata_arg, #query_model_arg_name: #query_model_type) -> Result<Option<dendrite::axon_utils::QueryResult>> {
293            debug!("Event type: {:?}", #event_type_literal);
294            #block
295        }
296
297        // register event handler with registry
298        fn #ident(registry: &mut dendrite::axon_utils::TheHandlerRegistry<#query_model_type,dendrite::axon_server::query::QueryRequest,dendrite::axon_utils::QueryResult>) -> Result<()> {
299            registry.insert_with_output(
300                #event_type_literal,
301                &#event_type::decode,
302                &(|c,m,p| Box::pin(#ident_impl(c, m, p)))
303            )
304        }
305    };
306    gen.into()
307}