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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
use crate::info_extractor::arg_info::{ArgInfo, BindgenArgType};
use crate::info_extractor::serializer_attr::SerializerAttr;
use crate::info_extractor::SerializerType;
use quote::ToTokens;
use syn::export::Span;
use syn::spanned::Spanned;
use syn::{Attribute, Error, FnArg, Ident, Receiver, ReturnType, Signature};
pub struct AttrSigInfo {
pub ident: Ident,
pub non_bindgen_attrs: Vec<Attribute>,
pub args: Vec<ArgInfo>,
pub is_init: bool,
pub is_payable: bool,
pub input_serializer: SerializerType,
pub is_view: bool,
pub result_serializer: SerializerType,
pub receiver: Option<Receiver>,
pub returns: ReturnType,
pub original_sig: Signature,
}
impl AttrSigInfo {
pub fn new(
original_attrs: &mut Vec<Attribute>,
original_sig: &mut Signature,
) -> syn::Result<Self> {
if original_sig.asyncness.is_some() {
return Err(Error::new(
original_sig.span(),
"Contract API is not allowed to be async.",
));
}
if original_sig.abi.is_some() {
return Err(Error::new(
original_sig.span(),
"Contract API is not allowed to have binary interface.",
));
}
if original_sig.variadic.is_some() {
return Err(Error::new(
original_sig.span(),
"Contract API is not allowed to have variadic arguments.",
));
}
let ident = original_sig.ident.clone();
let mut non_bindgen_attrs = vec![];
let mut args = vec![];
let mut is_init = false;
let mut is_payable = false;
let mut result_serializer = SerializerType::JSON;
let mut payable_attr = None;
for attr in original_attrs.iter() {
let attr_str = attr.path.to_token_stream().to_string();
match attr_str.as_str() {
"init" => {
is_init = true;
}
"payable" => {
payable_attr = Some(attr);
is_payable = true;
}
"result_serializer" => {
let serializer: SerializerAttr = syn::parse2(attr.tokens.clone())?;
result_serializer = serializer.serializer_type;
}
_ => {
non_bindgen_attrs.push((*attr).clone());
}
}
}
let mut receiver = None;
for fn_arg in &mut original_sig.inputs {
match fn_arg {
FnArg::Receiver(r) => receiver = Some((*r).clone()),
FnArg::Typed(pat_typed) => {
args.push(ArgInfo::new(pat_typed)?);
}
}
}
let is_view = if let Some(ref receiver) = receiver {
receiver.mutability.is_none()
} else {
!is_init
};
if let Some(payable_attr) = payable_attr {
if is_view {
return Err(Error::new(
payable_attr.span(),
"Payable method must be mutable (not view)",
));
}
}
original_attrs.retain(|attr| {
let attr_str = attr.path.to_token_stream().to_string();
attr_str != "init" && attr_str != "result_serializer" && attr_str != "payable"
});
let returns = original_sig.output.clone();
let mut result = Self {
ident,
non_bindgen_attrs,
args,
input_serializer: SerializerType::JSON,
is_init,
is_payable,
is_view,
result_serializer,
receiver,
returns,
original_sig: original_sig.clone(),
};
let input_serializer =
if result.input_args().all(|arg: &ArgInfo| arg.serializer_ty == SerializerType::JSON) {
SerializerType::JSON
} else if result.input_args().all(|arg| arg.serializer_ty == SerializerType::Borsh) {
SerializerType::Borsh
} else {
return Err(Error::new(
Span::call_site(),
format!("Input arguments should be all of the same serialization type."),
));
};
result.input_serializer = input_serializer;
Ok(result)
}
pub fn input_args(&self) -> impl Iterator<Item = &ArgInfo> {
self.args.iter().filter(|arg| match arg.bindgen_ty {
BindgenArgType::Regular => true,
_ => false,
})
}
}