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