1extern crate proc_macro;
2
3use proc_macro::{TokenStream};
4
5use syn::{DeriveInput, Attribute, Type};
6use quote::quote;
7use syn::parse::{Parse, ParseBuffer};
8use syn::Token;
9
10struct TypeList {
11 paths: Vec<Type>
12}
13
14impl Parse for TypeList {
15 fn parse(input: &ParseBuffer) -> syn::Result<Self> {
16 let content;
17 let mut res = vec![];
18 syn::parenthesized!(content in input);
19 loop {
20 res.push(content.parse()?);
21 if content.peek(Token![,]) {
22 let _: Token![,] = content.parse()?;
23 } else {
24 break;
25 }
26 }
27 Ok(Self {
28 paths: res
29 })
30 }
31}
32
33#[proc_macro_derive(ProcessDispatch, attributes(dispatch))]
34pub fn my_derive(_input: TokenStream) -> TokenStream {
35 let mut i: DeriveInput = syn::parse(_input).unwrap();
36 let attr: Attribute = i.attrs.pop().unwrap();
37 let paths = if attr.path.get_ident().map(|i| i.to_string()).as_deref() == Some("dispatch") {
38 let list: TypeList = syn::parse2(attr.tokens).unwrap();
39 list.paths
40 } else {
41 panic!("Missing paths")
42 };
43 let messages = paths.into_iter().map(|p| {
44 let id = quote! { #p::ID };
45 let block = quote! {
46 {
47 let msg = <#p as Service>::read(data).map_err(|_| quix::derive::DispatchError::Format);
48 Box::pin(async move {
49 let res = addr.send(msg?).await.map_err(|_| quix::derive::DispatchError::MailboxRemote)?;
50 let mut buf = quix::derive::BytesMut::new();
51 <#p as Service>::write_result(&res, &mut buf).map_err(|_| quix::derive::DispatchError::Format)?;
52 Ok(buf.freeze())
53 })
54 }
55 };
56
57 quote! { #id => #block }
58 });
59
60
61 let dispatch = quote! {
62 match method {
63 #(#messages),*
64 _ => {
65 Box::pin(async move { Err(quix::derive::DispatchError::DispatchRemote)})
66 }
67 }
68 };
69
70 let name = i.ident;
71
72 let dispatcher = quote! {
73 pub struct LocalDispatcher { addr: actix::WeakAddr<#name> }
74 impl quix::derive::Dispatcher for LocalDispatcher {
75 fn dispatch(&self, method: u64, data: quix::derive::Bytes) -> quix::derive::BoxFuture<'static, Result<quix::derive::Bytes, quix::derive::DispatchError>> {
76 use quix::derive::Service;
77 let addr = self.addr.upgrade().unwrap().clone();
78 #dispatch
79 }
80 }
81 Box::new(LocalDispatcher { addr })
82 };
83
84 let tokens = quote! {
85 impl quix::derive::ProcessDispatch for #name {
86 fn make_dispatcher(addr: actix::WeakAddr<Self>) -> Box<dyn quix::derive::Dispatcher> {
87 #dispatcher
88 }
89 }
90 };
91
92 tokens.into()
93}