1#[macro_use]
2extern crate quote;
3
4macro_rules! format_ident {
5 ($ident:expr, $fstr:expr) => {
6 syn::Ident::new(&format!($fstr, $ident), $ident.span())
7 };
8}
9
10pub struct Contract {
11 pub trait_name: proc_macro2::Ident,
12 pub endpoint_name: proc_macro2::Ident,
13 pub client_name: proc_macro2::Ident,
14 pub struct_name: proc_macro2::Ident,
15 pub method_sigs: Vec<proc_macro2::TokenStream>,
16 pub method_impls: Vec<proc_macro2::TokenStream>,
17}
18
19impl Contract {
20 pub fn new(contract_trait: &syn::ItemTrait) -> Self {
21 let (method_sigs, method_impls) = split_contract_trait(&contract_trait);
22 Contract {
23 trait_name: format_ident!(contract_trait.ident, "{}"),
24 endpoint_name: format_ident!(contract_trait.ident, "{}Endpoint"),
25 client_name: format_ident!(contract_trait.ident, "{}Client"),
26 struct_name: format_ident!(contract_trait.ident, "{}Inst"),
27 method_sigs: method_sigs,
28 method_impls: method_impls,
29 }
30 }
31}
32
33fn split_contract_trait(
34 contract_trait: &syn::ItemTrait,
35) -> (Vec<proc_macro2::TokenStream>, Vec<proc_macro2::TokenStream>) {
36 contract_trait
37 .items
38 .iter()
39 .filter_map(|itm| match itm {
40 syn::TraitItem::Method(m) => {
41 let msig = &m.sig;
42 let bad_self_ref = format!(
43 "ABI function `{}` must have `&mut self` as its first argument.",
44 msig.ident.to_string()
45 );
46 match msig.decl.inputs[0] {
47 syn::FnArg::SelfRef(ref selfref) => {
48 if selfref.mutability.is_none() {
49 panic!(bad_self_ref)
50 }
51 }
52 _ => panic!(bad_self_ref),
53 }
54
55 let mattrs = &m.attrs;
56 let sig = quote! {
57 #(#mattrs)*
58 #msig;
59 };
60
61 let body = match m.default {
62 Some(ref mbody) => {
63 quote! { #msig { #mbody } }
64 }
65 None => quote! {},
66 };
67
68 Some((sig, body))
69 }
70 _ => None,
71 })
72 .unzip()
73}