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}