Skip to main content

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 the
42    /// host 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}
396
397impl const TryFrom<u8> for IoTypeMetadataKind {
398    type Error = ();
399
400    #[inline]
401    fn try_from(byte: u8) -> Result<Self, Self::Error> {
402        Ok(match byte {
403            0 => Self::Unit,
404            1 => Self::Bool,
405            2 => Self::U8,
406            3 => Self::U16,
407            4 => Self::U32,
408            5 => Self::U64,
409            6 => Self::U128,
410            7 => Self::I8,
411            8 => Self::I16,
412            9 => Self::I32,
413            10 => Self::I64,
414            11 => Self::I128,
415            12 => Self::Struct,
416            13 => Self::Struct0,
417            14 => Self::Struct1,
418            15 => Self::Struct2,
419            16 => Self::Struct3,
420            17 => Self::Struct4,
421            18 => Self::Struct5,
422            19 => Self::Struct6,
423            20 => Self::Struct7,
424            21 => Self::Struct8,
425            22 => Self::Struct9,
426            23 => Self::Struct10,
427            24 => Self::TupleStruct,
428            25 => Self::TupleStruct1,
429            26 => Self::TupleStruct2,
430            27 => Self::TupleStruct3,
431            28 => Self::TupleStruct4,
432            29 => Self::TupleStruct5,
433            30 => Self::TupleStruct6,
434            31 => Self::TupleStruct7,
435            32 => Self::TupleStruct8,
436            33 => Self::TupleStruct9,
437            34 => Self::TupleStruct10,
438            35 => Self::Enum,
439            36 => Self::Enum1,
440            37 => Self::Enum2,
441            38 => Self::Enum3,
442            39 => Self::Enum4,
443            40 => Self::Enum5,
444            41 => Self::Enum6,
445            42 => Self::Enum7,
446            43 => Self::Enum8,
447            44 => Self::Enum9,
448            45 => Self::Enum10,
449            46 => Self::EnumNoFields,
450            47 => Self::EnumNoFields1,
451            48 => Self::EnumNoFields2,
452            49 => Self::EnumNoFields3,
453            50 => Self::EnumNoFields4,
454            51 => Self::EnumNoFields5,
455            52 => Self::EnumNoFields6,
456            53 => Self::EnumNoFields7,
457            54 => Self::EnumNoFields8,
458            55 => Self::EnumNoFields9,
459            56 => Self::EnumNoFields10,
460            57 => Self::Array8b,
461            58 => Self::Array16b,
462            59 => Self::Array32b,
463            60 => Self::ArrayU8x8,
464            61 => Self::ArrayU8x16,
465            62 => Self::ArrayU8x32,
466            63 => Self::ArrayU8x64,
467            64 => Self::ArrayU8x128,
468            65 => Self::ArrayU8x256,
469            66 => Self::ArrayU8x512,
470            67 => Self::ArrayU8x1024,
471            68 => Self::ArrayU8x2028,
472            69 => Self::ArrayU8x4096,
473            70 => Self::VariableBytes8b,
474            71 => Self::VariableBytes16b,
475            72 => Self::VariableBytes32b,
476            73 => Self::VariableBytes0,
477            74 => Self::VariableBytes512,
478            75 => Self::VariableBytes1024,
479            76 => Self::VariableBytes2028,
480            77 => Self::VariableBytes4096,
481            78 => Self::VariableBytes8192,
482            79 => Self::VariableBytes16384,
483            80 => Self::VariableBytes32768,
484            81 => Self::VariableBytes65536,
485            82 => Self::VariableBytes131072,
486            83 => Self::VariableBytes262144,
487            84 => Self::VariableBytes524288,
488            85 => Self::VariableBytes1048576,
489            86 => Self::VariableElements8b,
490            87 => Self::VariableElements16b,
491            88 => Self::VariableElements32b,
492            89 => Self::VariableElements0,
493            90 => Self::FixedCapacityBytes8b,
494            91 => Self::FixedCapacityBytes16b,
495            92 => Self::FixedCapacityString8b,
496            93 => Self::FixedCapacityString16b,
497            94 => Self::Unaligned,
498            _ => {
499                return Err(());
500            }
501        })
502    }
503}
504
505impl IoTypeMetadataKind {
506    // TODO: Create wrapper type for metadata bytes and move this method there
507    /// Produce compact metadata.
508    ///
509    /// Compact metadata retains the shape, but throws some details. Specifically, the following
510    /// transformations are applied to metadata:
511    /// * Struct names, enum names and enum variant names are removed (replaced with zero bytes
512    ///   names)
513    /// * Structs and enum variants are turned into tuple variants (removing field names)
514    ///
515    /// This is typically called by higher-level functions and doesn't need to be used directly.
516    ///
517    /// This function takes an `input` that starts with metadata defined in [`IoTypeMetadataKind`]
518    /// and `output` where compact metadata must be written. Since input might have other data past
519    /// the data structure to be processed, the remainder of input and output are returned to the
520    /// caller.
521    ///
522    /// Unexpected metadata kind results in `None` being returned.
523    #[inline]
524    pub const fn compact<'i, 'o>(
525        input: &'i [u8],
526        output: &'o mut [u8],
527    ) -> Option<(&'i [u8], &'o mut [u8])> {
528        compact_metadata(input, output)
529    }
530
531    // TODO: Create wrapper type for metadata bytes and move this method there
532    /// Decode type name.
533    ///
534    /// Expected to be UTF-8, but must be parsed before printed as text, which is somewhat costly.
535    #[inline]
536    pub const fn type_name(metadata: &[u8]) -> Option<&[u8]> {
537        type_name(metadata)
538    }
539
540    // TODO: Create wrapper type for metadata bytes and move this method there
541    /// Decode type, return its recommended capacity that should be allocated by the host.
542    ///
543    /// If actual data is larger, it will be passed down to the guest as it is, if smaller than host
544    /// should allocate recommended capacity for guest anyway.
545    ///
546    /// Returns type details and whatever slice of bytes from `input` that is left after
547    /// type decoding.
548    #[inline]
549    pub const fn type_details(metadata: &[u8]) -> Option<(IoTypeDetails, &[u8])> {
550        decode_type_details(metadata)
551    }
552}