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 let input = parse_macro_input!(item as ItemFn);
14
15 impl_event_handler(&input)
17}
18
19fn impl_event_handler(ast: &ItemFn) -> TokenStream {
20 let ItemFn{sig, block, ..} = ast;
22 let Signature {ident, inputs, ..} = sig;
23 let ident_string = ident.to_string();
26 let ident_span = ident.span();
27 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 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 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 let input = parse_macro_input!(item as ItemFn);
79
80 impl_command_handler(&input)
82}
83
84fn impl_command_handler(ast: &ItemFn) -> TokenStream {
85 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 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 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 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 let input = parse_macro_input!(item as ItemFn);
143
144 impl_event_sourcing_handler(&input)
146}
147
148fn impl_event_sourcing_handler(ast: &ItemFn) -> TokenStream {
149 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 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 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 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 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 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 let input = parse_macro_input!(item as ItemFn);
264
265 impl_query_handler(&input)
267}
268
269fn impl_query_handler(ast: &ItemFn) -> TokenStream {
270 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 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 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 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}