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