ab_contracts_io_type/
metadata.rs

1mod compact;
2#[cfg(test)]
3mod tests;
4mod type_details;
5mod type_name;
6
7use crate::metadata::compact::compact_metadata;
8use crate::metadata::type_details::decode_type_details;
9use crate::metadata::type_name::type_name;
10use core::num::NonZeroU8;
11
12/// Max capacity for metadata bytes used in fixed size buffers
13pub const MAX_METADATA_CAPACITY: usize = 8192;
14
15/// Concatenates metadata sources.
16///
17/// Returns both a scratch memory and number of bytes in it that correspond to metadata
18pub const fn concat_metadata_sources(sources: &[&[u8]]) -> ([u8; MAX_METADATA_CAPACITY], usize) {
19    let mut metadata_scratch = [0u8; MAX_METADATA_CAPACITY];
20    // TODO: Use `as_mut_slice` once stabilized: https://github.com/rust-lang/rust/issues/133333
21    let mut remainder: &mut [u8] = &mut metadata_scratch;
22
23    // For loops are not yet usable in const environment
24    let mut i = 0;
25    while i < sources.len() {
26        let source = sources[i];
27        let target;
28        (target, remainder) = remainder.split_at_mut(source.len());
29        target.copy_from_slice(source);
30        i += 1;
31    }
32
33    let remainder_len = remainder.len();
34    let size = metadata_scratch.len() - remainder_len;
35    (metadata_scratch, size)
36}
37
38#[derive(Debug, Copy, Clone)]
39pub struct IoTypeDetails {
40    /// Recommended capacity that must be allocated by the host.
41    ///
42    /// If actual data is larger, it will be passed down to the guest as it is, if smaller than host
43    /// must allocate the recommended capacity for guest anyway.
44    pub recommended_capacity: u32,
45    /// Alignment of the type
46    pub alignment: NonZeroU8,
47}
48
49impl IoTypeDetails {
50    /// Create an instance for regular bytes (alignment 1)
51    #[inline(always)]
52    pub const fn bytes(recommended_capacity: u32) -> Self {
53        Self {
54            recommended_capacity,
55            alignment: NonZeroU8::new(1).expect("Not zero; qed"),
56        }
57    }
58}
59
60/// Metadata types contained in [`TrivialType::METADATA`] and [`IoType::METADATA`].
61///
62/// Metadata encoding consists of this enum variant treated as `u8` followed by optional metadata
63/// encoding rules specific to metadata type variant (see variant's description).
64///
65/// This metadata is enough to fully reconstruct the hierarchy of the type to generate language
66/// bindings, auto-generate UI forms, etc.
67///
68/// [`TrivialType::METADATA`]: crate::trivial_type::TrivialType::METADATA
69/// [`IoType::METADATA`]: crate::IoType::METADATA
70#[derive(Debug, Copy, Clone, Eq, PartialEq)]
71#[repr(u8)]
72pub enum IoTypeMetadataKind {
73    /// `()`
74    Unit,
75    /// `bool`
76    Bool,
77    /// `u8`
78    U8,
79    /// `u16`
80    U16,
81    /// `u32`
82    U32,
83    /// `u64`
84    U64,
85    /// `u128`
86    U128,
87    /// `i8`
88    I8,
89    /// `i16`
90    I16,
91    /// `i32`
92    I32,
93    /// `i64`
94    I64,
95    /// `i128`
96    I128,
97    /// `struct S {..}`
98    ///
99    /// Structs with named fields are encoded af follows:
100    /// * Length of struct name in bytes (u8)
101    /// * Struct name as UTF-8 bytes
102    /// * Number of fields (u8)
103    ///
104    /// Each field is encoded follows:
105    /// * Length of the field name in bytes (u8)
106    /// * Field name as UTF-8 bytes
107    /// * Recursive metadata of the field's type
108    Struct,
109    /// Similar to [`Self::Struct`], but for exactly `0` struct fields and thus skips number of
110    /// fields after struct name
111    Struct0,
112    /// Similar to [`Self::Struct`], but for exactly `1` struct fields and thus skips number of
113    /// fields after struct name
114    Struct1,
115    /// Similar to [`Self::Struct`], but for exactly `2` struct fields and thus skips number of
116    /// fields after struct name
117    Struct2,
118    /// Similar to [`Self::Struct`], but for exactly `3` struct fields and thus skips number of
119    /// fields after struct name
120    Struct3,
121    /// Similar to [`Self::Struct`], but for exactly `4` struct fields and thus skips number of
122    /// fields after struct name
123    Struct4,
124    /// Similar to [`Self::Struct`], but for exactly `5` struct fields and thus skips number of
125    /// fields after struct name
126    Struct5,
127    /// Similar to [`Self::Struct`], but for exactly `6` struct fields and thus skips number of
128    /// fields after struct name
129    Struct6,
130    /// Similar to [`Self::Struct`], but for exactly `7` struct fields and thus skips number of
131    /// fields after struct name
132    Struct7,
133    /// Similar to [`Self::Struct`], but for exactly `8` struct fields and thus skips number of
134    /// fields after struct name
135    Struct8,
136    /// Similar to [`Self::Struct`], but for exactly `9` struct fields and thus skips number of
137    /// fields after struct name
138    Struct9,
139    /// Similar to [`Self::Struct`], but for exactly `10` struct fields and thus skips number of
140    /// fields after struct name
141    Struct10,
142    /// `struct S(..);`
143    ///
144    /// Tuple structs are encoded af follows:
145    /// * Length of struct name in bytes (u8)
146    /// * Struct name as UTF-8 bytes
147    /// * Number of fields (u8)
148    ///
149    /// Each field is encoded follows:
150    /// * Recursive metadata of the field's type
151    TupleStruct,
152    /// Similar to [`Self::TupleStruct`], but for exactly `1` struct fields and thus skips number of
153    /// fields after struct name
154    TupleStruct1,
155    /// Similar to [`Self::TupleStruct`], but for exactly `2` struct fields and thus skips number of
156    /// fields after struct name
157    TupleStruct2,
158    /// Similar to [`Self::TupleStruct`], but for exactly `3` struct fields and thus skips number of
159    /// fields after struct name
160    TupleStruct3,
161    /// Similar to [`Self::TupleStruct`], but for exactly `4` struct fields and thus skips number of
162    /// fields after struct name
163    TupleStruct4,
164    /// Similar to [`Self::TupleStruct`], but for exactly `5` struct fields and thus skips number of
165    /// fields after struct name
166    TupleStruct5,
167    /// Similar to [`Self::TupleStruct`], but for exactly `6` struct fields and thus skips number of
168    /// fields after struct name
169    TupleStruct6,
170    /// Similar to [`Self::TupleStruct`], but for exactly `7` struct fields and thus skips number of
171    /// fields after struct name
172    TupleStruct7,
173    /// Similar to [`Self::TupleStruct`], but for exactly `8` struct fields and thus skips number of
174    /// fields after struct name
175    TupleStruct8,
176    /// Similar to [`Self::TupleStruct`], but for exactly `9` struct fields and thus skips number of
177    /// fields after struct name
178    TupleStruct9,
179    /// Similar to [`Self::TupleStruct`], but for exactly `10` struct fields and thus skips number
180    /// of fields after struct name
181    TupleStruct10,
182    /// `enum E { Variant {..} }`
183    ///
184    /// Enums with variants that have fields are encoded as follows:
185    /// * Length of enum name in bytes (u8)
186    /// * Enum name as UTF-8 bytes
187    /// * Number of variants (u8)
188    /// * Each enum variant as if it was a struct with fields, see [`Self::Struct`] for details
189    Enum,
190    /// Similar to [`Self::Enum`], but for exactly `1` enum variants and thus skips number of
191    /// variants after enum name
192    Enum1,
193    /// Similar to [`Self::Enum`], but for exactly `2` enum variants and thus skips number of
194    /// variants after enum name
195    Enum2,
196    /// Similar to [`Self::Enum`], but for exactly `3` enum variants and thus skips number of
197    /// variants after enum name
198    Enum3,
199    /// Similar to [`Self::Enum`], but for exactly `4` enum variants and thus skips number of
200    /// variants after enum name
201    Enum4,
202    /// Similar to [`Self::Enum`], but for exactly `5` enum variants and thus skips number of
203    /// variants after enum name
204    Enum5,
205    /// Similar to [`Self::Enum`], but for exactly `6` enum variants and thus skips number of
206    /// variants after enum name
207    Enum6,
208    /// Similar to [`Self::Enum`], but for exactly `7` enum variants and thus skips number of
209    /// variants after enum name
210    Enum7,
211    /// Similar to [`Self::Enum`], but for exactly `8` enum variants and thus skips number of
212    /// variants after enum name
213    Enum8,
214    /// Similar to [`Self::Enum`], but for exactly `9` enum variants and thus skips number of
215    /// variants after enum name
216    Enum9,
217    /// Similar to [`Self::Enum`], but for exactly `10` enum variants and thus skips number of
218    /// variants after enum name
219    Enum10,
220    /// `enum E { A, B }`
221    ///
222    /// Enums with variants that have no fields are encoded as follows:
223    /// * Length of enum name in bytes (u8)
224    /// * Enum name as UTF-8 bytes
225    /// * Number of variants (u8)
226    ///
227    /// Each enum variant is encoded follows:
228    /// * Length of the variant name in bytes (u8)
229    /// * Variant name as UTF-8 bytes
230    EnumNoFields,
231    /// Similar to [`Self::EnumNoFields`], but for exactly `1` enum variants and thus skips number
232    /// of variants after enum name
233    EnumNoFields1,
234    /// Similar to [`Self::EnumNoFields`], but for exactly `2` enum variants and thus skips number
235    /// of variants after enum name
236    EnumNoFields2,
237    /// Similar to [`Self::EnumNoFields`], but for exactly `3` enum variants and thus skips number
238    /// of variants after enum name
239    EnumNoFields3,
240    /// Similar to [`Self::EnumNoFields`], but for exactly `4` enum variants and thus skips number
241    /// of variants after enum name
242    EnumNoFields4,
243    /// Similar to [`Self::EnumNoFields`], but for exactly `5` enum variants and thus skips number
244    /// of variants after enum name
245    EnumNoFields5,
246    /// Similar to [`Self::EnumNoFields`], but for exactly `6` enum variants and thus skips number
247    /// of variants after enum name
248    EnumNoFields6,
249    /// Similar to [`Self::EnumNoFields`], but for exactly `7` enum variants and thus skips number
250    /// of variants after enum name
251    EnumNoFields7,
252    /// Similar to [`Self::EnumNoFields`], but for exactly `8` enum variants and thus skips number
253    /// of variants after enum name
254    EnumNoFields8,
255    /// Similar to [`Self::EnumNoFields`], but for exactly `9` enum variants and thus skips number
256    /// of variants after enum name
257    EnumNoFields9,
258    /// Similar to [`Self::EnumNoFields`], but for exactly `10` enum variants and thus skips number
259    /// of variants after enum name
260    EnumNoFields10,
261    /// Array `[T; N]` with up to 2^8 elements.
262    ///
263    /// Arrays with up to 2^8 encoded as follows:
264    /// * 1 byte number of elements
265    /// * Recursive metadata of contained type
266    Array8b,
267    /// Array `[T; N]` with up to 2^16 elements.
268    ///
269    /// Arrays with up to 2^16 encoded as follows:
270    /// * 2 bytes number of elements (little-endian)
271    /// * Recursive metadata of contained type
272    Array16b,
273    /// Array `[T; N]` with up to 2^32 elements.
274    ///
275    /// Arrays with up to 2^32 encoded as follows:
276    /// * 4 bytes number of elements (little-endian)
277    /// * Recursive metadata of contained type
278    Array32b,
279    /// Compact alias for `[u8; 8]`
280    ArrayU8x8,
281    /// Compact alias for `[u8; 16]`
282    ArrayU8x16,
283    /// Compact alias for `[u8; 32]`
284    ArrayU8x32,
285    /// Compact alias for `[u8; 64]`
286    ArrayU8x64,
287    /// Compact alias for `[u8; 128]`
288    ArrayU8x128,
289    /// Compact alias for `[u8; 256]`
290    ArrayU8x256,
291    /// Compact alias for `[u8; 512]`
292    ArrayU8x512,
293    /// Compact alias for `[u8; 1024]`
294    ArrayU8x1024,
295    /// Compact alias for `[u8; 2028]`
296    ArrayU8x2028,
297    /// Compact alias for `[u8; 4096]`
298    ArrayU8x4096,
299    /// Variable bytes with up to 2^8 bytes recommended allocation.
300    ///
301    /// Variable bytes with up to 2^8 bytes encoded as follows:
302    /// * 1 byte recommended allocation in bytes
303    VariableBytes8b,
304    /// Variable bytes with up to 2^16 bytes recommended allocation.
305    ///
306    /// Variable bytes with up to 2^16 bytes encoded as follows:
307    /// * 2 bytes recommended allocation in bytes (little-endian)
308    VariableBytes16b,
309    /// Variable bytes with up to 2^32 bytes recommended allocation.
310    ///
311    /// Variable bytes with up to 2^8 bytes encoded as follows:
312    /// * 4 bytes recommended allocation in bytes (little-endian)
313    VariableBytes32b,
314    /// Compact alias [`VariableBytes<0>`](crate::variable_bytes::VariableBytes)
315    VariableBytes0,
316    /// Compact alias [`VariableBytes<512>`](crate::variable_bytes::VariableBytes)
317    VariableBytes512,
318    /// Compact alias [`VariableBytes<1024>`](crate::variable_bytes::VariableBytes)
319    VariableBytes1024,
320    /// Compact alias [`VariableBytes<2028>`](crate::variable_bytes::VariableBytes)
321    VariableBytes2028,
322    /// Compact alias [`VariableBytes<4096>`](crate::variable_bytes::VariableBytes)
323    VariableBytes4096,
324    /// Compact alias [`VariableBytes<8192>`](crate::variable_bytes::VariableBytes)
325    VariableBytes8192,
326    /// Compact alias [`VariableBytes<16384>`](crate::variable_bytes::VariableBytes)
327    VariableBytes16384,
328    /// Compact alias [`VariableBytes<32768>`](crate::variable_bytes::VariableBytes)
329    VariableBytes32768,
330    /// Compact alias [`VariableBytes<65536>`](crate::variable_bytes::VariableBytes)
331    VariableBytes65536,
332    /// Compact alias [`VariableBytes<131072>`](crate::variable_bytes::VariableBytes)
333    VariableBytes131072,
334    /// Compact alias [`VariableBytes<262144>`](crate::variable_bytes::VariableBytes)
335    VariableBytes262144,
336    /// Compact alias [`VariableBytes<524288>`](crate::variable_bytes::VariableBytes)
337    VariableBytes524288,
338    /// Compact alias [`VariableBytes<1048576>`](crate::variable_bytes::VariableBytes)
339    VariableBytes1048576,
340    /// Variable elements with up to 2^8 elements recommended allocation.
341    ///
342    /// Variable elements with up to 2^8 elements encoded as follows:
343    /// * 1 byte recommended allocation in bytes
344    VariableElements8b,
345    /// Variable elements with up to 2^16 elements recommended allocation.
346    ///
347    /// Variable elements with up to 2^16 elements encoded as follows:
348    /// * 2 bytes recommended allocation in elements (little-endian)
349    VariableElements16b,
350    /// Variable elements with up to 2^32 elements recommended allocation.
351    ///
352    /// Variable elements with up to 2^8 elements encoded as follows:
353    /// * 4 bytes recommended allocation in elements (little-endian)
354    VariableElements32b,
355    /// Compact alias [`VariableElements<0, T>`](crate::variable_elements::VariableElements)
356    VariableElements0,
357    /// Address of a contract.
358    ///
359    /// Internally `u128` with `8` byte alignment
360    Address = 128,
361    /// Balance of a token.
362    ///
363    /// Internally `u128` with `8` byte alignment
364    Balance,
365}
366
367impl IoTypeMetadataKind {
368    // TODO: Implement `TryFrom` once it is available in const environment
369    /// Try to create an instance from its `u8` representation
370    #[inline]
371    pub const fn try_from_u8(byte: u8) -> Option<Self> {
372        Some(match byte {
373            0 => Self::Unit,
374            1 => Self::Bool,
375            2 => Self::U8,
376            3 => Self::U16,
377            4 => Self::U32,
378            5 => Self::U64,
379            6 => Self::U128,
380            7 => Self::I8,
381            8 => Self::I16,
382            9 => Self::I32,
383            10 => Self::I64,
384            11 => Self::I128,
385            12 => Self::Struct,
386            13 => Self::Struct0,
387            14 => Self::Struct1,
388            15 => Self::Struct2,
389            16 => Self::Struct3,
390            17 => Self::Struct4,
391            18 => Self::Struct5,
392            19 => Self::Struct6,
393            20 => Self::Struct7,
394            21 => Self::Struct8,
395            22 => Self::Struct9,
396            23 => Self::Struct10,
397            24 => Self::TupleStruct,
398            25 => Self::TupleStruct1,
399            26 => Self::TupleStruct2,
400            27 => Self::TupleStruct3,
401            28 => Self::TupleStruct4,
402            29 => Self::TupleStruct5,
403            30 => Self::TupleStruct6,
404            31 => Self::TupleStruct7,
405            32 => Self::TupleStruct8,
406            33 => Self::TupleStruct9,
407            34 => Self::TupleStruct10,
408            35 => Self::Enum,
409            36 => Self::Enum1,
410            37 => Self::Enum2,
411            38 => Self::Enum3,
412            39 => Self::Enum4,
413            40 => Self::Enum5,
414            41 => Self::Enum6,
415            42 => Self::Enum7,
416            43 => Self::Enum8,
417            44 => Self::Enum9,
418            45 => Self::Enum10,
419            46 => Self::EnumNoFields,
420            47 => Self::EnumNoFields1,
421            48 => Self::EnumNoFields2,
422            49 => Self::EnumNoFields3,
423            50 => Self::EnumNoFields4,
424            51 => Self::EnumNoFields5,
425            52 => Self::EnumNoFields6,
426            53 => Self::EnumNoFields7,
427            54 => Self::EnumNoFields8,
428            55 => Self::EnumNoFields9,
429            56 => Self::EnumNoFields10,
430            57 => Self::Array8b,
431            58 => Self::Array16b,
432            59 => Self::Array32b,
433            60 => Self::ArrayU8x8,
434            61 => Self::ArrayU8x16,
435            62 => Self::ArrayU8x32,
436            63 => Self::ArrayU8x64,
437            64 => Self::ArrayU8x128,
438            65 => Self::ArrayU8x256,
439            66 => Self::ArrayU8x512,
440            67 => Self::ArrayU8x1024,
441            68 => Self::ArrayU8x2028,
442            69 => Self::ArrayU8x4096,
443            70 => Self::VariableBytes8b,
444            71 => Self::VariableBytes16b,
445            72 => Self::VariableBytes32b,
446            73 => Self::VariableBytes0,
447            74 => Self::VariableBytes512,
448            75 => Self::VariableBytes1024,
449            76 => Self::VariableBytes2028,
450            77 => Self::VariableBytes4096,
451            78 => Self::VariableBytes8192,
452            79 => Self::VariableBytes16384,
453            80 => Self::VariableBytes32768,
454            81 => Self::VariableBytes65536,
455            82 => Self::VariableBytes131072,
456            83 => Self::VariableBytes262144,
457            84 => Self::VariableBytes524288,
458            85 => Self::VariableBytes1048576,
459            86 => Self::VariableElements8b,
460            87 => Self::VariableElements16b,
461            88 => Self::VariableElements32b,
462            89 => Self::VariableElements0,
463            128 => Self::Address,
464            129 => Self::Balance,
465            _ => {
466                return None;
467            }
468        })
469    }
470
471    // TODO: Create wrapper type for metadata bytes and move this method there
472    /// Produce compact metadata.
473    ///
474    /// Compact metadata retains the shape, but throws some details. Specifically, the following
475    /// transformations are applied to metadata:
476    /// * Struct names, enum names and enum variant names are removed (replaced with zero bytes
477    ///   names)
478    /// * Structs and enum variants are turned into tuple variants (removing field names)
479    ///
480    /// This is typically called by higher-level functions and doesn't need to be used directly.
481    ///
482    /// This function takes an `input` that starts with metadata defined in [`IoTypeMetadataKind`]
483    /// and `output` where compact metadata must be written. Since input might have other data past
484    /// the data structure to be processed, the remainder of input and output are returned to the
485    /// caller.
486    ///
487    /// Unexpected metadata kind results in `None` being returned.
488    #[inline]
489    pub const fn compact<'i, 'o>(
490        input: &'i [u8],
491        output: &'o mut [u8],
492    ) -> Option<(&'i [u8], &'o mut [u8])> {
493        compact_metadata(input, output)
494    }
495
496    // TODO: Create wrapper type for metadata bytes and move this method there
497    /// Decode type name.
498    ///
499    /// Expected to be UTF-8, but must be parsed before printed as text, which is somewhat costly.
500    #[inline]
501    pub const fn type_name(metadata: &[u8]) -> Option<&[u8]> {
502        type_name(metadata)
503    }
504
505    // TODO: Create wrapper type for metadata bytes and move this method there
506    /// Decode type, return its recommended capacity that should be allocated by the host.
507    ///
508    /// If actual data is larger, it will be passed down to the guest as it is, if smaller than host
509    /// should allocate recommended capacity for guest anyway.
510    ///
511    /// Returns type details and whatever slice of bytes from `input` that is left after
512    /// type decoding.
513    #[inline]
514    pub const fn type_details(metadata: &[u8]) -> Option<(IoTypeDetails, &[u8])> {
515        decode_type_details(metadata)
516    }
517}