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}