multiversx_sc/abi/type_abi.rs
1use super::*;
2use alloc::{format, string::ToString, vec::Vec};
3
4/// Implemented for all types that can end up in the ABI:
5/// - argument types,
6/// - result types,
7/// - event log arguments
8/// - etc.
9///
10/// Will be automatically implemented for struct ad enum types via the `#[type_abi]` annotation.
11pub trait TypeAbi: TypeAbiFrom<Self> {
12 type Unmanaged;
13
14 fn type_names() -> TypeNames {
15 TypeNames {
16 abi: Self::type_name(),
17 rust: Self::type_name_rust(),
18 specific: Self::type_name_specific(),
19 }
20 }
21
22 /// The type name, as it shows up in the ABI.
23 fn type_name() -> TypeName {
24 core::any::type_name::<Self>().into()
25 }
26
27 /// The type name as it shows up in Rust code. Used for proxies.
28 ///
29 /// Does not get saved into the ABI, but is used for code generation.
30 fn type_name_rust() -> TypeName {
31 core::any::type_name::<Self>().into()
32 }
33
34 /// Specific name to be optionally added to the ABI.
35 ///
36 /// Added to allow adding more type information to the ABI, in a backwards compatible manner.
37 /// This is important, since we currently do not encode the original Rust type information.
38 fn type_name_specific() -> Option<TypeName> {
39 None
40 }
41
42 /// A type can provide more than its own name.
43 /// For instance, a struct can also provide the descriptions of the type of its fields.
44 /// TypeAbi doesn't care for the exact accumulator type,
45 /// which is abstracted by the TypeDescriptionContainer trait.
46 fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
47 let type_names = Self::type_names();
48 accumulator.insert(
49 type_names,
50 TypeDescription {
51 docs: Vec::new(),
52 names: Self::type_names(),
53 contents: TypeContents::NotSpecified,
54 macro_attributes: Vec::new(),
55 },
56 );
57 }
58
59 #[doc(hidden)]
60 fn is_variadic() -> bool {
61 false
62 }
63
64 /// Method that provides output ABIs directly.
65 /// All types should return a single output, since Rust only allows for single method results
66 /// (even if it is a multi-output, live MultiResultVec),
67 /// however, MultiResultX when top-level can be seen as multiple endpoint results.
68 /// This method gives it an opportunity to dissolve into its components.
69 /// Should only be overridden by framework types.
70 /// Output names are optionally provided in contracts via the `output_name` method attribute.
71 #[doc(hidden)]
72 fn output_abis(output_names: &[&'static str]) -> OutputAbis {
73 let mut result = Vec::with_capacity(1);
74 let output_name = if !output_names.is_empty() {
75 output_names[0]
76 } else {
77 ""
78 };
79 result.push(OutputAbi {
80 output_name: output_name.to_string(),
81 type_names: Self::type_names(),
82 multi_result: Self::is_variadic(),
83 });
84 result
85 }
86}
87
88pub fn type_name_variadic<T: TypeAbi>() -> TypeName {
89 format!("variadic<{}>", T::type_name())
90}
91
92pub fn type_name_multi_value_encoded<T: TypeAbi>() -> TypeName {
93 format!("MultiValueEncoded<$API, {}>", T::type_name_rust())
94}
95
96pub fn type_name_optional<T: TypeAbi>() -> TypeName {
97 let mut repr = TypeName::from("optional<");
98 repr.push_str(T::type_name().as_str());
99 repr.push('>');
100 repr
101}