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}