ab_io_type/metadata/
compact.rs

1use crate::metadata::IoTypeMetadataKind;
2
3/// This macro is necessary to reduce boilerplate due to lack of `?` in const environment
4macro_rules! forward_option {
5    ($expr:expr) => {{
6        let Some(result) = $expr else {
7            return None;
8        };
9        result
10    }};
11}
12
13pub(super) const fn compact_metadata<'i, 'o>(
14    mut input: &'i [u8],
15    mut output: &'o mut [u8],
16) -> Option<(&'i [u8], &'o mut [u8])> {
17    if input.is_empty() || output.is_empty() {
18        return None;
19    }
20
21    let kind = forward_option!(IoTypeMetadataKind::try_from_u8(input[0]));
22
23    match kind {
24        IoTypeMetadataKind::Unit
25        | IoTypeMetadataKind::Bool
26        | IoTypeMetadataKind::U8
27        | IoTypeMetadataKind::U16
28        | IoTypeMetadataKind::U32
29        | IoTypeMetadataKind::U64
30        | IoTypeMetadataKind::U128
31        | IoTypeMetadataKind::I8
32        | IoTypeMetadataKind::I16
33        | IoTypeMetadataKind::I32
34        | IoTypeMetadataKind::I64
35        | IoTypeMetadataKind::I128 => copy_n_bytes(input, output, 1),
36        IoTypeMetadataKind::Struct => {
37            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
38            compact_struct(input, output, None, false)
39        }
40        IoTypeMetadataKind::Struct0 => {
41            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
42            compact_struct(input, output, Some(0), false)
43        }
44        IoTypeMetadataKind::Struct1 => {
45            // Convert struct with field names to tuple struct
46            output[0] = IoTypeMetadataKind::TupleStruct1 as u8;
47            (input, output) = forward_option!(skip_n_bytes_io(input, output, 1));
48            compact_struct(input, output, Some(1), false)
49        }
50        IoTypeMetadataKind::Struct2 => {
51            // Convert struct with field names to tuple struct
52            output[0] = IoTypeMetadataKind::TupleStruct2 as u8;
53            (input, output) = forward_option!(skip_n_bytes_io(input, output, 1));
54            compact_struct(input, output, Some(2), false)
55        }
56        IoTypeMetadataKind::Struct3 => {
57            // Convert struct with field names to tuple struct
58            output[0] = IoTypeMetadataKind::TupleStruct3 as u8;
59            (input, output) = forward_option!(skip_n_bytes_io(input, output, 1));
60            compact_struct(input, output, Some(3), false)
61        }
62        IoTypeMetadataKind::Struct4 => {
63            // Convert struct with field names to tuple struct
64            output[0] = IoTypeMetadataKind::TupleStruct4 as u8;
65            (input, output) = forward_option!(skip_n_bytes_io(input, output, 1));
66            compact_struct(input, output, Some(4), false)
67        }
68        IoTypeMetadataKind::Struct5 => {
69            // Convert struct with field names to tuple struct
70            output[0] = IoTypeMetadataKind::TupleStruct5 as u8;
71            (input, output) = forward_option!(skip_n_bytes_io(input, output, 1));
72            compact_struct(input, output, Some(5), false)
73        }
74        IoTypeMetadataKind::Struct6 => {
75            // Convert struct with field names to tuple struct
76            output[0] = IoTypeMetadataKind::TupleStruct6 as u8;
77            (input, output) = forward_option!(skip_n_bytes_io(input, output, 1));
78            compact_struct(input, output, Some(6), false)
79        }
80        IoTypeMetadataKind::Struct7 => {
81            // Convert struct with field names to tuple struct
82            output[0] = IoTypeMetadataKind::TupleStruct7 as u8;
83            (input, output) = forward_option!(skip_n_bytes_io(input, output, 1));
84            compact_struct(input, output, Some(7), false)
85        }
86        IoTypeMetadataKind::Struct8 => {
87            // Convert struct with field names to tuple struct
88            output[0] = IoTypeMetadataKind::TupleStruct8 as u8;
89            (input, output) = forward_option!(skip_n_bytes_io(input, output, 1));
90            compact_struct(input, output, Some(8), false)
91        }
92        IoTypeMetadataKind::Struct9 => {
93            // Convert struct with field names to tuple struct
94            output[0] = IoTypeMetadataKind::TupleStruct9 as u8;
95            (input, output) = forward_option!(skip_n_bytes_io(input, output, 1));
96            compact_struct(input, output, Some(9), false)
97        }
98        IoTypeMetadataKind::Struct10 => {
99            // Convert struct with field names to tuple struct
100            output[0] = IoTypeMetadataKind::TupleStruct10 as u8;
101            (input, output) = forward_option!(skip_n_bytes_io(input, output, 1));
102            compact_struct(input, output, Some(10), false)
103        }
104        IoTypeMetadataKind::TupleStruct => {
105            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
106            compact_struct(input, output, None, true)
107        }
108        IoTypeMetadataKind::TupleStruct1 => {
109            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
110            compact_struct(input, output, Some(1), true)
111        }
112        IoTypeMetadataKind::TupleStruct2 => {
113            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
114            compact_struct(input, output, Some(2), true)
115        }
116        IoTypeMetadataKind::TupleStruct3 => {
117            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
118            compact_struct(input, output, Some(3), true)
119        }
120        IoTypeMetadataKind::TupleStruct4 => {
121            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
122            compact_struct(input, output, Some(4), true)
123        }
124        IoTypeMetadataKind::TupleStruct5 => {
125            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
126            compact_struct(input, output, Some(5), true)
127        }
128        IoTypeMetadataKind::TupleStruct6 => {
129            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
130            compact_struct(input, output, Some(6), true)
131        }
132        IoTypeMetadataKind::TupleStruct7 => {
133            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
134            compact_struct(input, output, Some(7), true)
135        }
136        IoTypeMetadataKind::TupleStruct8 => {
137            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
138            compact_struct(input, output, Some(8), true)
139        }
140        IoTypeMetadataKind::TupleStruct9 => {
141            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
142            compact_struct(input, output, Some(9), true)
143        }
144        IoTypeMetadataKind::TupleStruct10 => {
145            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
146            compact_struct(input, output, Some(10), true)
147        }
148        IoTypeMetadataKind::Enum => {
149            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
150            compact_enum(input, output, None, true)
151        }
152        IoTypeMetadataKind::Enum1 => {
153            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
154            compact_enum(input, output, Some(1), true)
155        }
156        IoTypeMetadataKind::Enum2 => {
157            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
158            compact_enum(input, output, Some(2), true)
159        }
160        IoTypeMetadataKind::Enum3 => {
161            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
162            compact_enum(input, output, Some(3), true)
163        }
164        IoTypeMetadataKind::Enum4 => {
165            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
166            compact_enum(input, output, Some(4), true)
167        }
168        IoTypeMetadataKind::Enum5 => {
169            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
170            compact_enum(input, output, Some(5), true)
171        }
172        IoTypeMetadataKind::Enum6 => {
173            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
174            compact_enum(input, output, Some(6), true)
175        }
176        IoTypeMetadataKind::Enum7 => {
177            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
178            compact_enum(input, output, Some(7), true)
179        }
180        IoTypeMetadataKind::Enum8 => {
181            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
182            compact_enum(input, output, Some(8), true)
183        }
184        IoTypeMetadataKind::Enum9 => {
185            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
186            compact_enum(input, output, Some(9), true)
187        }
188        IoTypeMetadataKind::Enum10 => {
189            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
190            compact_enum(input, output, Some(10), true)
191        }
192        IoTypeMetadataKind::EnumNoFields => {
193            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
194            compact_enum(input, output, None, false)
195        }
196        IoTypeMetadataKind::EnumNoFields1 => {
197            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
198            compact_enum(input, output, Some(1), false)
199        }
200        IoTypeMetadataKind::EnumNoFields2 => {
201            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
202            compact_enum(input, output, Some(2), false)
203        }
204        IoTypeMetadataKind::EnumNoFields3 => {
205            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
206            compact_enum(input, output, Some(3), false)
207        }
208        IoTypeMetadataKind::EnumNoFields4 => {
209            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
210            compact_enum(input, output, Some(4), false)
211        }
212        IoTypeMetadataKind::EnumNoFields5 => {
213            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
214            compact_enum(input, output, Some(5), false)
215        }
216        IoTypeMetadataKind::EnumNoFields6 => {
217            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
218            compact_enum(input, output, Some(6), false)
219        }
220        IoTypeMetadataKind::EnumNoFields7 => {
221            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
222            compact_enum(input, output, Some(7), false)
223        }
224        IoTypeMetadataKind::EnumNoFields8 => {
225            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
226            compact_enum(input, output, Some(8), false)
227        }
228        IoTypeMetadataKind::EnumNoFields9 => {
229            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
230            compact_enum(input, output, Some(9), false)
231        }
232        IoTypeMetadataKind::EnumNoFields10 => {
233            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
234            compact_enum(input, output, Some(10), false)
235        }
236        IoTypeMetadataKind::Array8b | IoTypeMetadataKind::VariableElements8b => {
237            (input, output) = forward_option!(copy_n_bytes(input, output, 1 + 1));
238            compact_metadata(input, output)
239        }
240        IoTypeMetadataKind::Array16b | IoTypeMetadataKind::VariableElements16b => {
241            (input, output) = forward_option!(copy_n_bytes(input, output, 1 + 2));
242            compact_metadata(input, output)
243        }
244        IoTypeMetadataKind::Array32b | IoTypeMetadataKind::VariableElements32b => {
245            (input, output) = forward_option!(copy_n_bytes(input, output, 1 + 4));
246            compact_metadata(input, output)
247        }
248        IoTypeMetadataKind::ArrayU8x8
249        | IoTypeMetadataKind::ArrayU8x16
250        | IoTypeMetadataKind::ArrayU8x32
251        | IoTypeMetadataKind::ArrayU8x64
252        | IoTypeMetadataKind::ArrayU8x128
253        | IoTypeMetadataKind::ArrayU8x256
254        | IoTypeMetadataKind::ArrayU8x512
255        | IoTypeMetadataKind::ArrayU8x1024
256        | IoTypeMetadataKind::ArrayU8x2028
257        | IoTypeMetadataKind::ArrayU8x4096 => copy_n_bytes(input, output, 1),
258        IoTypeMetadataKind::VariableBytes8b
259        | IoTypeMetadataKind::FixedCapacityBytes8b
260        | IoTypeMetadataKind::FixedCapacityString8b => copy_n_bytes(input, output, 1 + 1),
261        IoTypeMetadataKind::VariableBytes16b
262        | IoTypeMetadataKind::FixedCapacityBytes16b
263        | IoTypeMetadataKind::FixedCapacityString16b => copy_n_bytes(input, output, 1 + 2),
264        IoTypeMetadataKind::VariableBytes32b => copy_n_bytes(input, output, 1 + 4),
265        IoTypeMetadataKind::VariableBytes0
266        | IoTypeMetadataKind::VariableBytes512
267        | IoTypeMetadataKind::VariableBytes1024
268        | IoTypeMetadataKind::VariableBytes2028
269        | IoTypeMetadataKind::VariableBytes4096
270        | IoTypeMetadataKind::VariableBytes8192
271        | IoTypeMetadataKind::VariableBytes16384
272        | IoTypeMetadataKind::VariableBytes32768
273        | IoTypeMetadataKind::VariableBytes65536
274        | IoTypeMetadataKind::VariableBytes131072
275        | IoTypeMetadataKind::VariableBytes262144
276        | IoTypeMetadataKind::VariableBytes524288
277        | IoTypeMetadataKind::VariableBytes1048576 => copy_n_bytes(input, output, 1),
278        IoTypeMetadataKind::VariableElements0 => {
279            (input, output) = forward_option!(copy_n_bytes(input, output, 1));
280            compact_metadata(input, output)
281        }
282        IoTypeMetadataKind::Address | IoTypeMetadataKind::Balance => copy_n_bytes(input, output, 1),
283    }
284}
285
286const fn compact_struct<'i, 'o>(
287    mut input: &'i [u8],
288    mut output: &'o mut [u8],
289    arguments_count: Option<u8>,
290    tuple: bool,
291) -> Option<(&'i [u8], &'o mut [u8])> {
292    if input.is_empty() || output.is_empty() {
293        return None;
294    }
295
296    // Remove struct name
297    let struct_name_length = input[0] as usize;
298    output[0] = 0;
299    (input, output) = forward_option!(skip_n_bytes_io(input, output, 1));
300    input = forward_option!(skip_n_bytes(input, struct_name_length));
301
302    let mut arguments_count = if let Some(arguments_count) = arguments_count {
303        arguments_count
304    } else {
305        if input.is_empty() || output.is_empty() {
306            return None;
307        }
308
309        let arguments_count = input[0];
310        (input, output) = forward_option!(copy_n_bytes(input, output, 1));
311
312        arguments_count
313    };
314
315    // Compact arguments
316    while arguments_count > 0 {
317        if input.is_empty() || output.is_empty() {
318            return None;
319        }
320
321        // Remove field name if needed
322        if !tuple {
323            let field_name_length = input[0] as usize;
324            input = forward_option!(skip_n_bytes(input, 1 + field_name_length));
325        }
326
327        // Compact argument's type
328        (input, output) = forward_option!(compact_metadata(input, output));
329
330        arguments_count -= 1;
331    }
332
333    Some((input, output))
334}
335
336const fn compact_enum<'i, 'o>(
337    mut input: &'i [u8],
338    mut output: &'o mut [u8],
339    variant_count: Option<u8>,
340    has_fields: bool,
341) -> Option<(&'i [u8], &'o mut [u8])> {
342    if input.is_empty() || output.is_empty() {
343        return None;
344    }
345
346    // Remove enum name
347    let enum_name_length = input[0] as usize;
348    output[0] = 0;
349    (input, output) = forward_option!(skip_n_bytes_io(input, output, 1));
350    input = forward_option!(skip_n_bytes(input, enum_name_length));
351
352    let mut variant_count = if let Some(variant_count) = variant_count {
353        variant_count
354    } else {
355        if input.is_empty() || output.is_empty() {
356            return None;
357        }
358
359        let variant_count = input[0];
360        (input, output) = forward_option!(copy_n_bytes(input, output, 1));
361
362        variant_count
363    };
364
365    // Compact enum variants
366    while variant_count > 0 {
367        if input.is_empty() || output.is_empty() {
368            return None;
369        }
370
371        if has_fields {
372            // Compact variant as if it was a struct
373            (input, output) = forward_option!(compact_struct(input, output, None, false));
374        } else {
375            // Compact variant as if it was a struct without fields
376            (input, output) = forward_option!(compact_struct(input, output, Some(0), false));
377        }
378
379        variant_count -= 1;
380    }
381
382    Some((input, output))
383}
384
385/// Copies `n` bytes from input to output and returns both input and output after `n` bytes offset
386const fn copy_n_bytes<'i, 'o>(
387    mut input: &'i [u8],
388    mut output: &'o mut [u8],
389    n: usize,
390) -> Option<(&'i [u8], &'o mut [u8])> {
391    if n > input.len() || n > output.len() {
392        return None;
393    }
394
395    let source;
396    let target;
397    (source, input) = input.split_at(n);
398    (target, output) = output.split_at_mut(n);
399    target.copy_from_slice(source);
400
401    Some((input, output))
402}
403
404/// Skips `n` bytes and return remainder
405const fn skip_n_bytes(input: &[u8], n: usize) -> Option<&[u8]> {
406    if n > input.len() {
407        return None;
408    }
409
410    // `&input[n..]` not supported in const yet
411    Some(input.split_at(n).1)
412}
413
414/// Skips `n` bytes in input and output
415const fn skip_n_bytes_io<'i, 'o>(
416    mut input: &'i [u8],
417    mut output: &'o mut [u8],
418    n: usize,
419) -> Option<(&'i [u8], &'o mut [u8])> {
420    if n > input.len() || n > output.len() {
421        return None;
422    }
423
424    // `&input[n..]` not supported in const yet
425    input = input.split_at(n).1;
426    // `&mut output[n..]` not supported in const yet
427    output = output.split_at_mut(n).1;
428
429    Some((input, output))
430}