Skip to main content

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}