1mod info;
2
3use serde::Serialize;
4use serde::Deserialize;
5use scale_info::{IntoPortable, Registry, form::PortableForm, TypeDefPrimitive};
6use scale_info::form::{Form, MetaForm};
7use serde::de::DeserializeOwned;
8use strum::{EnumString, Display, EnumIter, IntoEnumIterator};
9use crate::info::generate_abi_type;
10
11#[derive(Serialize, Deserialize)]
13pub struct ABI {
14 pub contract: ContractMeta<PortableForm>,
15 pub methods: Vec<MethodInfo<PortableForm>>,
16 pub types: Vec<ABIType<PortableForm>>,
17}
18
19impl ABI {
20 pub fn new(meta: ContractMeta, methods: Vec<MethodInfo>) -> ABI {
21 let mut registry = Registry::new();
22 ABI {
24 contract: meta.into_portable(&mut registry),
25 methods: methods
26 .into_iter()
27 .map(|method| method.into_portable(&mut registry))
28 .collect::<Vec<_>>(),
29 types: generate_abi_type(registry),
30 }
31 }
32}
33
34
35#[derive(Serialize, Deserialize)]
36#[serde(bound(
37serialize = "F::Type: Serialize, F::String: Serialize",
38deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
39))]
40pub struct ContractMeta<F: Form = MetaForm> {
41 pub name: String,
42 pub constructor: ConstructorSpec<F>,
43}
44
45impl IntoPortable for ContractMeta {
46 type Output = ContractMeta<PortableForm>;
47
48 fn into_portable(self, registry: &mut Registry) -> Self::Output {
49 ContractMeta {
50 name: self.name,
51 constructor: ConstructorSpec {
52 input: self
53 .constructor
54 .input
55 .into_iter()
56 .map(|info| info.into_portable(registry))
57 .collect::<Vec<_>>()
58 },
59 }
60 }
61}
62
63#[derive(Serialize, Deserialize)]
64pub struct MutexField {
65 pub field_name: String,
66 pub field_id: i32,
67 pub parallel_index: Vec<i32>,
68}
69
70#[derive(Serialize, Deserialize)]
71pub struct MutexCall {
72 pub address_index: i32,
73 pub address: String,
74 pub methods: Vec<String>,
75 pub cns_name: String,
76 pub cns_index: i32,
77}
78
79#[derive(Serialize, Deserialize)]
80#[serde(bound(
81serialize = "F::Type: Serialize, F::String: Serialize",
82deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
83))]
84pub struct MethodInfo<F: Form = MetaForm> {
85 pub name: String,
86 pub input: Vec<TypeInfo<F>>,
87 pub output: Vec<TypeInfo<F>>,
88 pub parallel_level: i32,
89 pub mutex_fields: Vec<MutexField>,
90 pub mutex_calls: Vec<MutexCall>,
91 pub method_calls: Vec<String>,
92}
93
94impl IntoPortable for MethodInfo {
95 type Output = MethodInfo<PortableForm>;
96
97 fn into_portable(self, registry: &mut Registry) -> Self::Output {
98 MethodInfo {
99 name: self.name,
100 input: self
101 .input
102 .into_iter()
103 .map(|info| info.into_portable(registry))
104 .collect::<Vec<_>>(),
105 output: self
106 .output
107 .into_iter()
108 .map(|info| info.into_portable(registry))
109 .collect::<Vec<_>>(),
110 parallel_level: self.parallel_level,
111 mutex_fields: self.mutex_fields
112 .into_iter()
113 .map(|x| { x.into() })
114 .collect::<Vec<_>>(),
115 mutex_calls: self.mutex_calls
116 .into_iter()
117 .map(|x| { x.into() })
118 .collect::<Vec<_>>(),
119 method_calls: self.method_calls,
120 }
121 }
122}
123
124#[derive(Serialize, Deserialize)]
125#[serde(bound(
126serialize = "F::Type: Serialize, F::String: Serialize",
127deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
128))]
129pub struct ConstructorSpec<F: Form = MetaForm> {
130 pub input: Vec<TypeInfo<F>>,
131}
132
133#[derive(Serialize, Deserialize)]
135#[serde(bound(
136serialize = "F::Type: Serialize, F::String: Serialize",
137deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
138))]
139pub struct TypeInfo<F: Form = MetaForm> {
140 pub type_id: F::Type,
141}
142
143impl IntoPortable for TypeInfo {
144 type Output = TypeInfo<PortableForm>;
145
146 fn into_portable(self, registry: &mut Registry) -> Self::Output {
147 TypeInfo {
148 type_id: registry.register_type(&self.type_id),
149 }
150 }
151}
152
153#[derive(Serialize, Deserialize)]
154#[serde(bound(
155serialize = "F::Type: Serialize, F::String: Serialize",
156deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
157))]
158#[serde(rename(serialize = "types"))]
159pub struct ABIType<F: Form = MetaForm> {
160 #[serde(rename(serialize = "id"))]
161 pub type_id: u32,
162 #[serde(rename(serialize = "type"))]
163 pub tp: TypeEnum,
164 #[serde(skip_serializing_if = "Option::is_none")]
165 pub fields: Option<Vec<TypeInfo<F>>>,
166 #[serde(skip_serializing_if = "Option::is_none")]
167 pub primitive: Option<String>,
168 #[serde(skip_serializing_if = "Option::is_none")]
169 pub array_len: Option<u32>,
170 #[serde(skip_serializing_if = "Option::is_none")]
171 pub variants: Option<Vec<Vec<TypeInfo<F>>>>,
172}
173
174#[derive(Serialize, Deserialize)]
175#[serde(rename_all(serialize = "lowercase"))]
176pub enum TypeEnum {
177 Primitive,
178 Struct,
179 Vec,
180 Array,
181 Tuple,
182 Enum,
183}
184
185#[derive(EnumString, Display, EnumIter, Debug, PartialEq)]
186pub enum PrimitiveType {
187 #[strum(serialize = "bool")]
189 Bool,
190 #[strum(serialize = "char")]
192 Char,
193 #[strum(serialize = "str")]
195 Str,
196 #[strum(serialize = "u8")]
198 U8,
199 #[strum(serialize = "u16")]
201 U16,
202 #[strum(serialize = "u32")]
204 U32,
205 #[strum(serialize = "u64")]
207 U64,
208 #[strum(serialize = "u128")]
210 U128,
211 #[strum(serialize = "u256")]
213 U256,
214 #[strum(serialize = "i8")]
216 I8,
217 #[strum(serialize = "i16")]
219 I16,
220 #[strum(serialize = "i32")]
222 I32,
223 #[strum(serialize = "i64")]
225 I64,
226 #[strum(serialize = "i128")]
228 I128,
229 #[strum(serialize = "i256")]
231 I256,
232}
233
234impl PrimitiveType {
235 pub fn to_primitive_type(tp: &TypeDefPrimitive) -> Self {
236 match tp {
237 TypeDefPrimitive::Bool => PrimitiveType::Bool,
238 TypeDefPrimitive::Char => PrimitiveType::Char,
239 TypeDefPrimitive::Str => PrimitiveType::Str,
240 TypeDefPrimitive::U8 => PrimitiveType::U8,
241 TypeDefPrimitive::U16 => PrimitiveType::U16,
242 TypeDefPrimitive::U32 => PrimitiveType::U32,
243 TypeDefPrimitive::U64 => PrimitiveType::U64,
244 TypeDefPrimitive::U128 => PrimitiveType::U128,
245 TypeDefPrimitive::U256 => PrimitiveType::U256,
246 TypeDefPrimitive::I8 => PrimitiveType::I8,
247 TypeDefPrimitive::I16 => PrimitiveType::I16,
248 TypeDefPrimitive::I32 => PrimitiveType::I32,
249 TypeDefPrimitive::I64 => PrimitiveType::I64,
250 TypeDefPrimitive::I128 => PrimitiveType::I128,
251 TypeDefPrimitive::I256 => PrimitiveType::I256,
252 }
253 }
254
255 pub fn is_primitive_type(type_name: &str) -> bool {
256 for tp in PrimitiveType::iter() {
257 if tp.to_string() == type_name {
258 return true;
259 }
260 }
261 false
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 #![allow(dead_code)]
268
269 use crate::{ContractMeta, ConstructorSpec, MethodInfo, TypeInfo as ABITypeInfo, ABI, MutexField};
270 use scale_info::meta_type;
271 use scale_info::TypeInfo;
272
273 #[derive(TypeInfo)]
274 pub struct Student {
275 id: u32,
276 name: String,
277 list: Vec<Vec<String>>,
278 }
279
280
281 #[derive(TypeInfo)]
282 pub struct Info {
283 ages: Vec<[Student; 10]>,
284 }
285
286 #[test]
287 fn test_abi_serialized_null() {
288 let meta = ContractMeta {
289 name: "MyContract".to_string(),
290 constructor: ConstructorSpec {
291 input: vec![]
292 },
293 };
294 let methods = vec![];
295 let abi = ABI::new(meta, methods);
296 let json = serde_json::to_string_pretty(&abi).unwrap();
297 println!("{}", json);
298 assert_eq!(
299 json,
300 r#"{
301 "contract": {
302 "name": "MyContract",
303 "constructor": {
304 "input": []
305 }
306 },
307 "methods": [],
308 "types": []
309}"#);
310 }
311
312 #[derive(TypeInfo)]
313 enum IpAddr {
314 V4(u32, (u32, u32)),
315 V6(u32),
316 }
317
318 #[test]
319 fn test_abi_serialized_normal() {
320 let meta = ContractMeta {
321 name: "MyContract".to_string(),
322 constructor: ConstructorSpec {
323 input: vec![]
324 },
325 };
326
327 let methods = vec![
328 MethodInfo {
329 name: "add".to_string(),
330 input: vec![
331 ABITypeInfo {
332 type_id: meta_type::<u64>(),
334 }
335 ],
336 output: vec![
337 ABITypeInfo {
338 type_id: meta_type::<u64>(),
340 }
341 ],
342 parallel_level: 0,
343 mutex_fields: vec![],
344 method_calls: vec![],
345 mutex_calls: vec![],
346
347 },
348 MethodInfo {
349 name: "make_student".to_string(),
350 input: vec![
351 ABITypeInfo {
352 type_id: meta_type::<Student>(),
354 },
355 ABITypeInfo {
356 type_id: meta_type::<Info>(),
358 },
359 ],
360 output: vec![
361 ABITypeInfo {
362 type_id: meta_type::<u64>(),
364 }
365 ],
366 parallel_level: 0,
367 mutex_fields: vec![],
368 method_calls: vec![],
369 mutex_calls: vec![],
370
371 },
372 MethodInfo {
373 name: "testTuple".to_string(),
374 input: vec![
375 ABITypeInfo {
376 type_id: meta_type::<(u32, u32)>()
377 }
378 ],
379 output: vec![
380 ABITypeInfo {
381 type_id: meta_type::<IpAddr>()
382 },
383 ABITypeInfo {
384 type_id: meta_type::<Option<u32>>()
385 },
386 ],
387 parallel_level: 0,
388 mutex_fields: vec![
389 MutexField { field_name: "".to_string(), parallel_index: vec![1, 2], field_id: 1 }
390 ],
391 method_calls: vec![],
392 mutex_calls: vec![],
393
394 },
395 ];
396
397 let abi = ABI::new(meta, methods);
398 let json = serde_json::to_string_pretty(&abi);
399 println!("{}", json.unwrap())
400 }
401
402 #[test]
403 fn test_meta_type() {
404 use scale_info::TypeInfo as Tp2;
405
406 let a = vec![
407 meta_type::<String>(),
408 meta_type::<&String>(),
409 meta_type::<&str>(),
410 meta_type::<&'static str>(),
411 meta_type::<bool>(),
412 meta_type::<&bool>(),
413 meta_type::<Box<bool>>(),
414 meta_type::<i128>(),
415 meta_type::<Student>(),
416 meta_type::<&Student>(),
417 ];
418
419 for tp in a {
420 println!("{:?}", tp.type_info().type_def())
421 }
422 println!("{:?}", <u32 as Tp2>::type_info().type_def())
423 }
424
425 #[test]
426 fn test1() {
427 let a = "Hello, world";
428 a.to_string().trim().trim_matches('\"').split(',').for_each(|x| {
429 println!("{}", x.trim())
430 })
431 }
432}