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    #[inline(always)]
51    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`
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    /// Arrays with up to 2^8 encoded as follows:
263    /// * 1 byte number of elements
264    /// * Recursive metadata of contained type
265    Array8b,
266    /// Array `[T; N]` with up to 2^16 elements.
267    ///
268    /// Arrays with up to 2^16 encoded as follows:
269    /// * 2 bytes number of elements (little-endian)
270    /// * Recursive metadata of contained type
271    Array16b,
272    /// Array `[T; N]` with up to 2^32 elements.
273    ///
274    /// Arrays with up to 2^32 encoded as follows:
275    /// * 4 bytes number of elements (little-endian)
276    /// * Recursive metadata of 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    /// Variable bytes with up to 2^8 bytes 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    /// Variable bytes with up to 2^16 bytes 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    /// Variable bytes with up to 2^8 bytes 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    /// Variable elements with up to 2^8 elements encoded as follows:
342    /// * 1 byte recommended allocation in bytes
343    VariableElements8b,
344    /// Variable elements with up to 2^16 elements recommended allocation.
345    ///
346    /// Variable elements with up to 2^16 elements encoded as follows:
347    /// * 2 bytes recommended allocation in elements (little-endian)
348    VariableElements16b,
349    /// Variable elements with up to 2^32 elements recommended allocation.
350    ///
351    /// Variable elements with up to 2^8 elements encoded as follows:
352    /// * 4 bytes recommended allocation in elements (little-endian)
353    VariableElements32b,
354    /// Compact alias [`VariableElements<0, T>`](crate::variable_elements::VariableElements)
355    VariableElements0,
356    /// Address of a contract.
357    ///
358    /// Internally `u128` with `8` byte alignment
359    Address = 128,
360    /// Balance of a token.
361    ///
362    /// Internally `u128` with `8` byte alignment
363    Balance,
364}
365
366impl IoTypeMetadataKind {
367    // TODO: Implement `TryFrom` once it is available in const environment
368    /// Try to create an instance from its `u8` representation
369    pub const fn try_from_u8(byte: u8) -> Option<Self> {
370        Some(match byte {
371            0 => Self::Unit,
372            1 => Self::Bool,
373            2 => Self::U8,
374            3 => Self::U16,
375            4 => Self::U32,
376            5 => Self::U64,
377            6 => Self::U128,
378            7 => Self::I8,
379            8 => Self::I16,
380            9 => Self::I32,
381            10 => Self::I64,
382            11 => Self::I128,
383            12 => Self::Struct,
384            13 => Self::Struct0,
385            14 => Self::Struct1,
386            15 => Self::Struct2,
387            16 => Self::Struct3,
388            17 => Self::Struct4,
389            18 => Self::Struct5,
390            19 => Self::Struct6,
391            20 => Self::Struct7,
392            21 => Self::Struct8,
393            22 => Self::Struct9,
394            23 => Self::Struct10,
395            24 => Self::TupleStruct,
396            25 => Self::TupleStruct1,
397            26 => Self::TupleStruct2,
398            27 => Self::TupleStruct3,
399            28 => Self::TupleStruct4,
400            29 => Self::TupleStruct5,
401            30 => Self::TupleStruct6,
402            31 => Self::TupleStruct7,
403            32 => Self::TupleStruct8,
404            33 => Self::TupleStruct9,
405            34 => Self::TupleStruct10,
406            35 => Self::Enum,
407            36 => Self::Enum1,
408            37 => Self::Enum2,
409            38 => Self::Enum3,
410            39 => Self::Enum4,
411            40 => Self::Enum5,
412            41 => Self::Enum6,
413            42 => Self::Enum7,
414            43 => Self::Enum8,
415            44 => Self::Enum9,
416            45 => Self::Enum10,
417            46 => Self::EnumNoFields,
418            47 => Self::EnumNoFields1,
419            48 => Self::EnumNoFields2,
420            49 => Self::EnumNoFields3,
421            50 => Self::EnumNoFields4,
422            51 => Self::EnumNoFields5,
423            52 => Self::EnumNoFields6,
424            53 => Self::EnumNoFields7,
425            54 => Self::EnumNoFields8,
426            55 => Self::EnumNoFields9,
427            56 => Self::EnumNoFields10,
428            57 => Self::Array8b,
429            58 => Self::Array16b,
430            59 => Self::Array32b,
431            60 => Self::ArrayU8x8,
432            61 => Self::ArrayU8x16,
433            62 => Self::ArrayU8x32,
434            63 => Self::ArrayU8x64,
435            64 => Self::ArrayU8x128,
436            65 => Self::ArrayU8x256,
437            66 => Self::ArrayU8x512,
438            67 => Self::ArrayU8x1024,
439            68 => Self::ArrayU8x2028,
440            69 => Self::ArrayU8x4096,
441            70 => Self::VariableBytes8b,
442            71 => Self::VariableBytes16b,
443            72 => Self::VariableBytes32b,
444            73 => Self::VariableBytes0,
445            74 => Self::VariableBytes512,
446            75 => Self::VariableBytes1024,
447            76 => Self::VariableBytes2028,
448            77 => Self::VariableBytes4096,
449            78 => Self::VariableBytes8192,
450            79 => Self::VariableBytes16384,
451            80 => Self::VariableBytes32768,
452            81 => Self::VariableBytes65536,
453            82 => Self::VariableBytes131072,
454            83 => Self::VariableBytes262144,
455            84 => Self::VariableBytes524288,
456            85 => Self::VariableBytes1048576,
457            86 => Self::VariableElements8b,
458            87 => Self::VariableElements16b,
459            88 => Self::VariableElements32b,
460            89 => Self::VariableElements0,
461            128 => Self::Address,
462            129 => Self::Balance,
463            _ => {
464                return None;
465            }
466        })
467    }
468
469    // TODO: Create wrapper type for metadata bytes and move this method there
470    /// Produce compact metadata.
471    ///
472    /// Compact metadata retains the shape, but throws some details. Specifically, the following
473    /// transformations are applied to metadata:
474    /// * Struct names, enum names and enum variant names are removed (replaced with zero bytes
475    ///   names)
476    /// * Structs and enum variants are turned into tuple variants (removing field names)
477    ///
478    /// This is typically called by higher-level functions and doesn't need to be used directly.
479    ///
480    /// This function takes an `input` that starts with metadata defined in [`IoTypeMetadataKind`]
481    /// and `output` where compact metadata must be written. Since input might have other data past
482    /// the data structure to be processed, the remainder of input and output are returned to the
483    /// caller.
484    ///
485    /// Unexpected metadata kind results in `None` being returned.
486    pub const fn compact<'i, 'o>(
487        input: &'i [u8],
488        output: &'o mut [u8],
489    ) -> Option<(&'i [u8], &'o mut [u8])> {
490        compact_metadata(input, output)
491    }
492
493    // TODO: Create wrapper type for metadata bytes and move this method there
494    /// Decode type name
495    pub const fn type_name(metadata: &[u8]) -> Option<&str> {
496        type_name(metadata)
497    }
498
499    // TODO: Create wrapper type for metadata bytes and move this method there
500    /// Decode type, return its recommended capacity that should be allocated by the host.
501    ///
502    /// If actual data is larger, it will be passed down to the guest as it is, if smaller than host
503    /// should allocate recommended capacity for guest anyway.
504    ///
505    /// Returns type details and whatever slice of bytes from `input` that is left after
506    /// type decoding.
507    #[inline(always)]
508    pub const fn type_details(metadata: &[u8]) -> Option<(IoTypeDetails, &[u8])> {
509        decode_type_details(metadata)
510    }
511}