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
use super::*;
use alloc::{format, string::ToString, vec::Vec};
/// Implemented for all types that can end up in the ABI:
/// - argument types,
/// - result types,
/// - event log arguments
/// - etc.
///
/// Will be automatically implemented for struct ad enum types via the `#[type_abi]` annotation.
pub trait TypeAbi: TypeAbiFrom<Self> {
type Unmanaged;
fn type_names() -> TypeNames {
TypeNames {
abi: Self::type_name(),
rust: Self::type_name_rust(),
specific: Self::type_name_specific(),
}
}
/// The type name, as it shows up in the ABI.
fn type_name() -> TypeName {
core::any::type_name::<Self>().into()
}
/// The type name as it shows up in Rust code. Used for proxies.
///
/// Does not get saved into the ABI, but is used for code generation.
fn type_name_rust() -> TypeName {
core::any::type_name::<Self>().into()
}
/// Specific name to be optionally added to the ABI.
///
/// Added to allow adding more type information to the ABI, in a backwards compatible manner.
/// This is important, since we currently do not encode the original Rust type information.
fn type_name_specific() -> Option<TypeName> {
None
}
/// A type can provide more than its own name.
/// For instance, a struct can also provide the descriptions of the type of its fields.
/// TypeAbi doesn't care for the exact accumulator type,
/// which is abstracted by the TypeDescriptionContainer trait.
fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
let type_names = Self::type_names();
accumulator.insert(
type_names,
TypeDescription {
docs: Vec::new(),
names: Self::type_names(),
contents: TypeContents::NotSpecified,
macro_attributes: Vec::new(),
},
);
}
#[doc(hidden)]
fn is_variadic() -> bool {
false
}
/// Method that provides output ABIs directly.
/// All types should return a single output, since Rust only allows for single method results
/// (even if it is a multi-output, live MultiResultVec),
/// however, MultiResultX when top-level can be seen as multiple endpoint results.
/// This method gives it an opportunity to dissolve into its components.
/// Should only be overridden by framework types.
/// Output names are optionally provided in contracts via the `output_name` method attribute.
#[doc(hidden)]
fn output_abis(output_names: &[&'static str]) -> OutputAbis {
let mut result = Vec::with_capacity(1);
let output_name = if !output_names.is_empty() {
output_names[0]
} else {
""
};
result.push(OutputAbi {
output_name: output_name.to_string(),
type_names: Self::type_names(),
multi_result: Self::is_variadic(),
});
result
}
}
pub fn type_name_variadic<T: TypeAbi>() -> TypeName {
format!("variadic<{}>", T::type_name())
}
pub fn type_name_multi_value_encoded<T: TypeAbi>() -> TypeName {
format!("MultiValueEncoded<$API, {}>", T::type_name_rust())
}
pub fn type_name_optional<T: TypeAbi>() -> TypeName {
let mut repr = TypeName::from("optional<");
repr.push_str(T::type_name().as_str());
repr.push('>');
repr
}