testnumbat_wasm/abi/
type_abi.rs

1use super::*;
2use alloc::{
3    boxed::Box,
4    string::{String, ToString},
5    vec::Vec,
6};
7
8pub trait TypeAbi {
9    fn type_name() -> String {
10        core::any::type_name::<Self>().into()
11    }
12
13    /// A type can provide more than its own description.
14    /// For instance, a struct can also provide the descriptions of the type of its fields.
15    /// TypeAbi doesn't care for the exact accumulator type,
16    /// which is abstracted by the TypeDescriptionContainer trait.
17    fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
18        let type_name = Self::type_name();
19        accumulator.insert(
20            type_name,
21            TypeDescription {
22                docs: &[],
23                name: Self::type_name(),
24                contents: TypeContents::NotSpecified,
25            },
26        );
27    }
28
29    #[doc(hidden)]
30    fn is_multi_arg_or_result() -> bool {
31        false
32    }
33
34    /// Method that provides output ABIs directly.
35    /// All types should return a single output, since Rust only allows for single method results
36    /// (even if it is a multi-output, live MultiResultVec),
37    /// however, MultiResultX when top-level can be seen as multiple endpoint results.
38    /// This method gives it an opportunity to dissolve into its components.
39    /// Should only be overridden by framework types.
40    /// Output names are optionally provided in contracts via the `output_name` method attribute.
41    #[doc(hidden)]
42    fn output_abis(output_names: &[&'static str]) -> Vec<OutputAbi> {
43        let mut result = Vec::with_capacity(1);
44        let output_name = if !output_names.is_empty() {
45            output_names[0]
46        } else {
47            ""
48        };
49        result.push(OutputAbi {
50            output_name,
51            type_name: Self::type_name(),
52            multi_result: Self::is_multi_arg_or_result(),
53        });
54        result
55    }
56}
57
58impl TypeAbi for () {
59    /// No another exception from the 1-type-1-output-abi rule:
60    /// the unit type produces no output.
61    fn output_abis(_output_names: &[&'static str]) -> Vec<OutputAbi> {
62        Vec::new()
63    }
64}
65
66impl<T: TypeAbi> TypeAbi for &T {
67    fn type_name() -> String {
68        T::type_name()
69    }
70
71    fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
72        T::provide_type_descriptions(accumulator);
73    }
74}
75
76impl<T: TypeAbi> TypeAbi for Box<T> {
77    fn type_name() -> String {
78        T::type_name()
79    }
80
81    fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
82        T::provide_type_descriptions(accumulator);
83    }
84}
85
86impl<T: TypeAbi> TypeAbi for &[T] {
87    fn type_name() -> String {
88        let t_name = T::type_name();
89        if t_name == "u8" {
90            return "bytes".into();
91        }
92        let mut repr = String::from("List<");
93        repr.push_str(t_name.as_str());
94        repr.push('>');
95        repr
96    }
97}
98
99impl<T: TypeAbi> TypeAbi for Vec<T> {
100    fn type_name() -> String {
101        <&[T]>::type_name()
102    }
103}
104
105impl<T: TypeAbi> TypeAbi for Box<[T]> {
106    fn type_name() -> String {
107        <&[T]>::type_name()
108    }
109}
110
111impl TypeAbi for String {
112    fn type_name() -> String {
113        "utf-8 string".into()
114    }
115}
116
117impl TypeAbi for &str {
118    fn type_name() -> String {
119        String::type_name()
120    }
121}
122
123impl TypeAbi for Box<str> {
124    fn type_name() -> String {
125        String::type_name()
126    }
127}
128
129macro_rules! type_abi_name_only {
130    ($ty:ty, $name:expr) => {
131        impl TypeAbi for $ty {
132            fn type_name() -> String {
133                String::from($name)
134            }
135
136            fn provide_type_descriptions<TDC: TypeDescriptionContainer>(_: &mut TDC) {}
137        }
138    };
139}
140
141type_abi_name_only!(u8, "u8");
142type_abi_name_only!(u16, "u16");
143type_abi_name_only!(u32, "u32");
144type_abi_name_only!(usize, "u32");
145type_abi_name_only!(u64, "u64");
146
147type_abi_name_only!(i8, "i8");
148type_abi_name_only!(i16, "i16");
149type_abi_name_only!(i32, "i32");
150type_abi_name_only!(isize, "i32");
151type_abi_name_only!(i64, "i64");
152
153type_abi_name_only!(core::num::NonZeroUsize, "NonZeroUsize");
154type_abi_name_only!(bool, "bool");
155
156impl<T: TypeAbi> TypeAbi for Option<T> {
157    fn type_name() -> String {
158        let mut repr = String::from("Option<");
159        repr.push_str(T::type_name().as_str());
160        repr.push('>');
161        repr
162    }
163
164    fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
165        T::provide_type_descriptions(accumulator);
166    }
167}
168
169impl<T: TypeAbi, E> TypeAbi for Result<T, E> {
170    fn type_name() -> String {
171        T::type_name()
172    }
173
174    /// Similar to the SCResult implementation.
175    fn output_abis(output_names: &[&'static str]) -> Vec<OutputAbi> {
176        T::output_abis(output_names)
177    }
178
179    fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
180        T::provide_type_descriptions(accumulator);
181    }
182}
183
184macro_rules! tuple_impls {
185    ($($len:expr => ($($n:tt $name:ident)+))+) => {
186        $(
187            impl<$($name),+> TypeAbi for ($($name,)+)
188            where
189                $($name: TypeAbi,)+
190            {
191				fn type_name() -> String {
192					let mut repr = String::from("tuple");
193					repr.push_str("<");
194					$(
195						if $n > 0 {
196							repr.push(',');
197						}
198						repr.push_str($name::type_name().as_str());
199                    )+
200					repr.push('>');
201					repr
202				}
203
204				fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
205					$(
206						$name::provide_type_descriptions(accumulator);
207                    )+
208				}
209            }
210        )+
211    }
212}
213
214tuple_impls! {
215    1  => (0 T0)
216    2  => (0 T0 1 T1)
217    3  => (0 T0 1 T1 2 T2)
218    4  => (0 T0 1 T1 2 T2 3 T3)
219    5  => (0 T0 1 T1 2 T2 3 T3 4 T4)
220    6  => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
221    7  => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
222    8  => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
223    9  => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
224    10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
225    11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
226    12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
227    13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12)
228    14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13)
229    15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14)
230    16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15)
231}
232
233impl<T: TypeAbi, const N: usize> TypeAbi for [T; N] {
234    fn type_name() -> String {
235        let mut repr = String::from("array");
236        repr.push_str(N.to_string().as_str());
237        repr.push('<');
238        repr.push_str(T::type_name().as_str());
239        repr.push('>');
240        repr
241    }
242
243    fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
244        T::provide_type_descriptions(accumulator);
245    }
246}