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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use heck::CamelCase;
use proc_macro2::TokenStream as TokenStream2;
use quote::{quote, ToTokens};
use syn::{
parse::{Parse, ParseStream, Result as ParseResult},
Block, FnArg, Ident, ItemFn, LitStr, Signature,
};
pub struct ActionArgs {
name: Option<LitStr>,
}
impl Parse for ActionArgs {
fn parse(input: ParseStream) -> ParseResult<Self> {
let name = input.parse::<Option<LitStr>>()?;
Ok(Self { name })
}
}
pub struct ActionFn {
sig: Signature,
block: Box<Block>,
args: ActionArgs,
}
impl ActionFn {
pub fn new(args: ActionArgs, item: ItemFn) -> Self {
Self {
sig: item.sig,
block: item.block,
args,
}
}
pub fn struct_ident(&self) -> Ident {
let name = self.sig.ident.to_string().as_str().to_camel_case();
Ident::new(&name, self.sig.ident.span())
}
pub fn action_name(&self) -> LitStr {
if let Some(lit) = &self.args.name {
lit.clone()
} else {
LitStr::new(
self.sig.ident.to_string().as_str(),
self.sig.ident.span(),
)
}
}
}
impl ToTokens for ActionFn {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let inputs = &self.sig.inputs;
let mut struct_fields = quote!();
let mut assign_args = quote!();
for input in inputs.iter() {
match input {
FnArg::Typed(input) => {
let pat = &input.pat;
let ty = &input.ty;
let ty_str = quote!(#ty).to_string();
let serde_attr = if ty_str == "bool" {
quote!(
#[cfg_attr(
feature = "serde",
serde(
deserialize_with = "::eosio::bool_from_u8",
serialize_with = "::eosio::bool_to_u8"
)
)]
)
} else {
quote!()
};
struct_fields = quote! {
#struct_fields
#serde_attr
pub #pat: #ty,
};
assign_args = quote! {
#assign_args
let #pat = self.#pat;
};
}
_ => unimplemented!(),
}
}
let block = &self.block;
let struct_ident = self.struct_ident();
let type_ident = &self.sig.ident;
let action_name = self.action_name();
let expanded = quote! {
#[derive(Clone, eosio::Read, eosio::Write, eosio::NumBytes)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
pub struct #struct_ident {
#struct_fields
}
#[allow(non_camel_case_types)]
pub type #type_ident = #struct_ident;
#[automatically_derived]
impl eosio::ActionFn for #struct_ident {
const NAME: eosio::ActionName = eosio::ActionName::new(eosio::n!(#action_name));
fn call(self) {
#assign_args
#block
}
}
};
expanded.to_tokens(tokens);
}
}