fuels_core/codec/
abi_decoder.rs

1mod bounded_decoder;
2mod decode_as_debug_str;
3
4use std::io::Read;
5
6use crate::{
7    codec::abi_decoder::{
8        bounded_decoder::BoundedDecoder, decode_as_debug_str::decode_as_debug_str,
9    },
10    types::{errors::Result, param_types::ParamType, Token},
11};
12
13#[derive(Debug, Clone, Copy)]
14pub struct DecoderConfig {
15    /// Entering a struct, array, tuple, enum or vector increases the depth. Decoding will fail if
16    /// the current depth becomes greater than `max_depth` configured here.
17    pub max_depth: usize,
18    /// Every decoded Token will increase the token count. Decoding will fail if the current
19    /// token count becomes greater than `max_tokens` configured here.
20    pub max_tokens: usize,
21}
22
23// ANCHOR: default_decoder_config
24impl Default for DecoderConfig {
25    fn default() -> Self {
26        Self {
27            max_depth: 45,
28            max_tokens: 10_000,
29        }
30    }
31}
32// ANCHOR_END: default_decoder_config
33
34#[derive(Default)]
35pub struct ABIDecoder {
36    pub config: DecoderConfig,
37}
38
39impl ABIDecoder {
40    pub fn new(config: DecoderConfig) -> Self {
41        Self { config }
42    }
43
44    /// Decodes `bytes` following the schema described in `param_type` into its respective `Token`.
45    ///
46    /// # Arguments
47    ///
48    /// * `param_type`: The `ParamType` of the type we expect is encoded
49    ///                  inside `bytes`.
50    /// * `bytes`:       The bytes to be used in the decoding process.
51    /// # Examples
52    ///
53    /// ```
54    /// use fuels_core::codec::ABIDecoder;
55    /// use fuels_core::traits::Tokenizable;
56    /// use fuels_core::types::param_types::ParamType;
57    ///
58    /// let decoder = ABIDecoder::default();
59    ///
60    /// let token = decoder.decode(&ParamType::U64,  [0, 0, 0, 0, 0, 0, 0, 7].as_slice()).unwrap();
61    ///
62    /// assert_eq!(u64::from_token(token).unwrap(), 7u64);
63    /// ```
64    pub fn decode(&self, param_type: &ParamType, mut bytes: impl Read) -> Result<Token> {
65        BoundedDecoder::new(self.config).decode(param_type, &mut bytes)
66    }
67
68    /// Same as `decode` but decodes multiple `ParamType`s in one go.
69    /// # Examples
70    /// ```
71    /// use fuels_core::codec::ABIDecoder;
72    /// use fuels_core::types::param_types::ParamType;
73    /// use fuels_core::types::Token;
74    ///
75    /// let decoder = ABIDecoder::default();
76    /// let data = [7, 8];
77    ///
78    /// let tokens = decoder.decode_multiple(&[ParamType::U8, ParamType::U8], data.as_slice()).unwrap();
79    ///
80    /// assert_eq!(tokens, vec![Token::U8(7), Token::U8(8)]);
81    /// ```
82    pub fn decode_multiple(
83        &self,
84        param_types: &[ParamType],
85        mut bytes: impl Read,
86    ) -> Result<Vec<Token>> {
87        BoundedDecoder::new(self.config).decode_multiple(param_types, &mut bytes)
88    }
89
90    /// Decodes `bytes` following the schema described in `param_type` into its respective debug
91    /// string.
92    ///
93    /// # Arguments
94    ///
95    /// * `param_type`: The `ParamType` of the type we expect is encoded
96    ///                  inside `bytes`.
97    /// * `bytes`:       The bytes to be used in the decoding process.
98    /// # Examples
99    ///
100    /// ```
101    /// use fuels_core::codec::ABIDecoder;
102    /// use fuels_core::types::param_types::ParamType;
103    ///
104    /// let decoder = ABIDecoder::default();
105    ///
106    /// let debug_string = decoder.decode_as_debug_str(&ParamType::U64,  [0, 0, 0, 0, 0, 0, 0, 7].as_slice()).unwrap();
107    /// let expected_value = 7u64;
108    ///
109    /// assert_eq!(debug_string, format!("{expected_value}"));
110    /// ```
111    pub fn decode_as_debug_str(
112        &self,
113        param_type: &ParamType,
114        mut bytes: impl Read,
115    ) -> Result<String> {
116        let token = BoundedDecoder::new(self.config).decode(param_type, &mut bytes)?;
117        decode_as_debug_str(param_type, &token)
118    }
119
120    pub fn decode_multiple_as_debug_str(
121        &self,
122        param_types: &[ParamType],
123        mut bytes: impl Read,
124    ) -> Result<Vec<String>> {
125        let token = BoundedDecoder::new(self.config).decode_multiple(param_types, &mut bytes)?;
126        token
127            .into_iter()
128            .zip(param_types)
129            .map(|(token, param_type)| decode_as_debug_str(param_type, &token))
130            .collect()
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use std::vec;
137
138    use ParamType::*;
139
140    use super::*;
141    use crate::{
142        constants::WORD_SIZE,
143        to_named,
144        traits::Parameterize,
145        types::{errors::Error, param_types::EnumVariants, StaticStringToken, U256},
146    };
147
148    #[test]
149    fn decode_multiple_uint() -> Result<()> {
150        let types = vec![
151            ParamType::U8,
152            ParamType::U16,
153            ParamType::U32,
154            ParamType::U64,
155            ParamType::U128,
156            ParamType::U256,
157        ];
158
159        let data = [
160            255, // u8
161            255, 255, // u16
162            255, 255, 255, 255, // u32
163            255, 255, 255, 255, 255, 255, 255, 255, // u64
164            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
165            255, // u128
166            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
167            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // u256
168        ];
169
170        let decoded = ABIDecoder::default().decode_multiple(&types, data.as_slice())?;
171
172        let expected = vec![
173            Token::U8(u8::MAX),
174            Token::U16(u16::MAX),
175            Token::U32(u32::MAX),
176            Token::U64(u64::MAX),
177            Token::U128(u128::MAX),
178            Token::U256(U256::MAX),
179        ];
180        assert_eq!(decoded, expected);
181
182        Ok(())
183    }
184
185    #[test]
186    fn decode_bool() -> Result<()> {
187        let types = vec![ParamType::Bool, ParamType::Bool];
188        let data = [1, 0];
189
190        let decoded = ABIDecoder::default().decode_multiple(&types, data.as_slice())?;
191
192        let expected = vec![Token::Bool(true), Token::Bool(false)];
193
194        assert_eq!(decoded, expected);
195
196        Ok(())
197    }
198
199    #[test]
200    fn decode_b256() -> Result<()> {
201        let data = [
202            213, 87, 156, 70, 223, 204, 127, 24, 32, 112, 19, 230, 91, 68, 228, 203, 78, 44, 34,
203            152, 244, 172, 69, 123, 168, 248, 39, 67, 243, 30, 147, 11,
204        ];
205
206        let decoded = ABIDecoder::default().decode(&ParamType::B256, data.as_slice())?;
207
208        assert_eq!(decoded, Token::B256(data));
209
210        Ok(())
211    }
212
213    #[test]
214    fn decode_string_array() -> Result<()> {
215        let types = vec![ParamType::StringArray(23), ParamType::StringArray(5)];
216        let data = [
217            84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 102, 117, 108, 108, 32, 115, 101, 110,
218            116, 101, 110, 99, 101, //This is a full sentence
219            72, 101, 108, 108, 111, // Hello
220        ];
221
222        let decoded = ABIDecoder::default().decode_multiple(&types, data.as_slice())?;
223
224        let expected = vec![
225            Token::StringArray(StaticStringToken::new(
226                "This is a full sentence".into(),
227                Some(23),
228            )),
229            Token::StringArray(StaticStringToken::new("Hello".into(), Some(5))),
230        ];
231
232        assert_eq!(decoded, expected);
233
234        Ok(())
235    }
236
237    #[test]
238    fn decode_string_slice() -> Result<()> {
239        let data = [
240            0, 0, 0, 0, 0, 0, 0, 23, // [length]
241            84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 102, 117, 108, 108, 32, 115, 101, 110,
242            116, 101, 110, 99, 101, //This is a full sentence
243        ];
244
245        let decoded = ABIDecoder::default().decode(&ParamType::StringSlice, data.as_slice())?;
246
247        let expected = Token::StringSlice(StaticStringToken::new(
248            "This is a full sentence".into(),
249            None,
250        ));
251
252        assert_eq!(decoded, expected);
253
254        Ok(())
255    }
256
257    #[test]
258    fn decode_string() -> Result<()> {
259        let data = [
260            0, 0, 0, 0, 0, 0, 0, 23, // [length]
261            84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 102, 117, 108, 108, 32, 115, 101, 110,
262            116, 101, 110, 99, 101, //This is a full sentence
263        ];
264
265        let decoded = ABIDecoder::default().decode(&ParamType::String, data.as_slice())?;
266
267        let expected = Token::String("This is a full sentence".to_string());
268
269        assert_eq!(decoded, expected);
270
271        Ok(())
272    }
273
274    #[test]
275    fn decode_tuple() -> Result<()> {
276        let param_type = ParamType::Tuple(vec![ParamType::U32, ParamType::Bool]);
277        let data = [
278            0, 0, 0, 255, //u32
279            1,   //bool
280        ];
281
282        let result = ABIDecoder::default().decode(&param_type, data.as_slice())?;
283
284        let expected = Token::Tuple(vec![Token::U32(255), Token::Bool(true)]);
285
286        assert_eq!(result, expected);
287
288        Ok(())
289    }
290
291    #[test]
292    fn decode_array() -> Result<()> {
293        let types = vec![ParamType::Array(Box::new(ParamType::U8), 2)];
294        let data = [255, 42];
295
296        let decoded = ABIDecoder::default().decode_multiple(&types, data.as_slice())?;
297
298        let expected = vec![Token::Array(vec![Token::U8(255), Token::U8(42)])];
299        assert_eq!(decoded, expected);
300
301        Ok(())
302    }
303
304    #[test]
305    fn decode_struct() -> Result<()> {
306        // struct MyStruct {
307        //     foo: u8,
308        //     bar: bool,
309        // }
310
311        let data = [1, 1];
312
313        let param_type = ParamType::Struct {
314            name: "".to_string(),
315            fields: to_named(&[ParamType::U8, ParamType::Bool]),
316            generics: vec![],
317        };
318
319        let decoded = ABIDecoder::default().decode(&param_type, data.as_slice())?;
320
321        let expected = Token::Struct(vec![Token::U8(1), Token::Bool(true)]);
322
323        assert_eq!(decoded, expected);
324
325        Ok(())
326    }
327
328    #[test]
329    fn decode_bytes() -> Result<()> {
330        let data = [0, 0, 0, 0, 0, 0, 0, 7, 255, 0, 1, 2, 3, 4, 5];
331
332        let decoded = ABIDecoder::default().decode(&ParamType::Bytes, data.as_slice())?;
333
334        let expected = Token::Bytes([255, 0, 1, 2, 3, 4, 5].to_vec());
335
336        assert_eq!(decoded, expected);
337
338        Ok(())
339    }
340
341    #[test]
342    fn decode_raw_slice() -> Result<()> {
343        let data = [0, 0, 0, 0, 0, 0, 0, 7, 255, 0, 1, 2, 3, 4, 5];
344
345        let decoded = ABIDecoder::default().decode(&ParamType::RawSlice, data.as_slice())?;
346
347        let expected = Token::RawSlice([255, 0, 1, 2, 3, 4, 5].to_vec());
348
349        assert_eq!(decoded, expected);
350
351        Ok(())
352    }
353
354    #[test]
355    fn decode_enum() -> Result<()> {
356        // enum MyEnum {
357        //     x: u32,
358        //     y: bool,
359        // }
360
361        let types = to_named(&[ParamType::U32, ParamType::Bool]);
362        let inner_enum_types = EnumVariants::new(types)?;
363        let types = vec![ParamType::Enum {
364            name: "".to_string(),
365            enum_variants: inner_enum_types.clone(),
366            generics: vec![],
367        }];
368
369        let data = [
370            0, 0, 0, 0, 0, 0, 0, 0, // discriminant
371            0, 0, 0, 42, // u32
372        ];
373
374        let decoded = ABIDecoder::default().decode_multiple(&types, data.as_slice())?;
375
376        let expected = vec![Token::Enum(Box::new((0, Token::U32(42), inner_enum_types)))];
377        assert_eq!(decoded, expected);
378
379        Ok(())
380    }
381
382    #[test]
383    fn decode_nested_struct() -> Result<()> {
384        // struct Foo {
385        //     x: u16,
386        //     y: Bar,
387        // }
388        //
389        // struct Bar {
390        //     a: bool,
391        //     b: u8[2],
392        // }
393
394        let fields = to_named(&[
395            ParamType::U16,
396            ParamType::Struct {
397                name: "".to_string(),
398                fields: to_named(&[
399                    ParamType::Bool,
400                    ParamType::Array(Box::new(ParamType::U8), 2),
401                ]),
402                generics: vec![],
403            },
404        ]);
405        let nested_struct = ParamType::Struct {
406            name: "".to_string(),
407            fields,
408            generics: vec![],
409        };
410
411        let data = [0, 10, 1, 1, 2];
412
413        let decoded = ABIDecoder::default().decode(&nested_struct, data.as_slice())?;
414
415        let my_nested_struct = vec![
416            Token::U16(10),
417            Token::Struct(vec![
418                Token::Bool(true),
419                Token::Array(vec![Token::U8(1), Token::U8(2)]),
420            ]),
421        ];
422
423        assert_eq!(decoded, Token::Struct(my_nested_struct));
424
425        Ok(())
426    }
427
428    #[test]
429    fn decode_comprehensive() -> Result<()> {
430        // struct Foo {
431        //     x: u16,
432        //     y: Bar,
433        // }
434        //
435        // struct Bar {
436        //     a: bool,
437        //     b: u8[2],
438        // }
439
440        // fn: long_function(Foo,u8[2],b256,str[3],str)
441
442        // Parameters
443        let fields = to_named(&[
444            ParamType::U16,
445            ParamType::Struct {
446                name: "".to_string(),
447                fields: to_named(&[
448                    ParamType::Bool,
449                    ParamType::Array(Box::new(ParamType::U8), 2),
450                ]),
451                generics: vec![],
452            },
453        ]);
454        let nested_struct = ParamType::Struct {
455            name: "".to_string(),
456            fields,
457            generics: vec![],
458        };
459
460        let u8_arr = ParamType::Array(Box::new(ParamType::U8), 2);
461        let b256 = ParamType::B256;
462
463        let types = [nested_struct, u8_arr, b256];
464
465        let bytes = [
466            0, 10, // u16
467            1,  // bool
468            1, 2, // array[u8;2]
469            1, 2, // array[u8;2]
470            213, 87, 156, 70, 223, 204, 127, 24, 32, 112, 19, 230, 91, 68, 228, 203, 78, 44, 34,
471            152, 244, 172, 69, 123, 168, 248, 39, 67, 243, 30, 147, 11, // b256
472        ];
473
474        let decoded = ABIDecoder::default().decode_multiple(&types, bytes.as_slice())?;
475
476        // Expected tokens
477        let foo = Token::Struct(vec![
478            Token::U16(10),
479            Token::Struct(vec![
480                Token::Bool(true),
481                Token::Array(vec![Token::U8(1), Token::U8(2)]),
482            ]),
483        ]);
484
485        let u8_arr = Token::Array(vec![Token::U8(1), Token::U8(2)]);
486
487        let b256 = Token::B256([
488            213, 87, 156, 70, 223, 204, 127, 24, 32, 112, 19, 230, 91, 68, 228, 203, 78, 44, 34,
489            152, 244, 172, 69, 123, 168, 248, 39, 67, 243, 30, 147, 11,
490        ]);
491
492        let expected: Vec<Token> = vec![foo, u8_arr, b256];
493
494        assert_eq!(decoded, expected);
495
496        Ok(())
497    }
498
499    #[test]
500    fn enums_with_all_unit_variants_are_decoded_from_one_word() -> Result<()> {
501        let data = [0, 0, 0, 0, 0, 0, 0, 1];
502        let types = to_named(&[ParamType::Unit, ParamType::Unit]);
503        let enum_variants = EnumVariants::new(types)?;
504        let enum_w_only_units = ParamType::Enum {
505            name: "".to_string(),
506            enum_variants: enum_variants.clone(),
507            generics: vec![],
508        };
509
510        let result = ABIDecoder::default().decode(&enum_w_only_units, data.as_slice())?;
511
512        let expected_enum = Token::Enum(Box::new((1, Token::Unit, enum_variants)));
513        assert_eq!(result, expected_enum);
514
515        Ok(())
516    }
517
518    #[test]
519    fn out_of_bounds_discriminant_is_detected() -> Result<()> {
520        let data = [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2];
521        let types = to_named(&[ParamType::U64]);
522        let enum_variants = EnumVariants::new(types)?;
523        let enum_type = ParamType::Enum {
524            name: "".to_string(),
525            enum_variants,
526            generics: vec![],
527        };
528
529        let result = ABIDecoder::default().decode(&enum_type, data.as_slice());
530
531        let error = result.expect_err("should have resulted in an error");
532
533        let expected_msg = "discriminant `1` doesn't point to any variant: ";
534        assert!(matches!(error, Error::Other(str) if str.starts_with(expected_msg)));
535
536        Ok(())
537    }
538
539    #[test]
540    pub fn division_by_zero() {
541        let param_type = Vec::<[u16; 0]>::param_type();
542        let result = ABIDecoder::default().decode(&param_type, [].as_slice());
543        assert!(matches!(result, Err(Error::IO(_))));
544    }
545
546    #[test]
547    pub fn multiply_overflow_enum() {
548        let result = ABIDecoder::default().decode(
549            &Enum {
550                name: "".to_string(),
551                enum_variants: EnumVariants::new(to_named(&[
552                    Array(Box::new(Array(Box::new(RawSlice), 8)), usize::MAX),
553                    B256,
554                    B256,
555                    B256,
556                    B256,
557                    B256,
558                    B256,
559                    B256,
560                    B256,
561                    B256,
562                    B256,
563                ]))
564                .unwrap(),
565                generics: vec![U16],
566            },
567            [].as_slice(),
568        );
569
570        assert!(matches!(result, Err(Error::IO(_))));
571    }
572
573    #[test]
574    pub fn multiply_overflow_arith() {
575        let mut param_type: ParamType = U16;
576        for _ in 0..50 {
577            param_type = Array(Box::new(param_type), 8);
578        }
579        let result = ABIDecoder::default().decode(
580            &Enum {
581                name: "".to_string(),
582                enum_variants: EnumVariants::new(to_named(&[param_type])).unwrap(),
583                generics: vec![U16],
584            },
585            [].as_slice(),
586        );
587        assert!(matches!(result, Err(Error::IO(_))));
588    }
589
590    #[test]
591    pub fn capacity_overflow() {
592        let result = ABIDecoder::default().decode(
593            &Array(Box::new(Array(Box::new(Tuple(vec![])), usize::MAX)), 1),
594            [].as_slice(),
595        );
596        assert!(matches!(result, Err(Error::Codec(_))));
597    }
598
599    #[test]
600    pub fn stack_overflow() {
601        let mut param_type: ParamType = U16;
602        for _ in 0..13500 {
603            param_type = Vector(Box::new(param_type));
604        }
605        let result = ABIDecoder::default().decode(&param_type, [].as_slice());
606        assert!(matches!(result, Err(Error::IO(_))));
607    }
608
609    #[test]
610    pub fn capacity_malloc() {
611        let param_type = Array(Box::new(U8), usize::MAX);
612        let result = ABIDecoder::default().decode(&param_type, [].as_slice());
613        assert!(matches!(result, Err(Error::IO(_))));
614    }
615
616    #[test]
617    fn max_depth_surpassed() {
618        const MAX_DEPTH: usize = 2;
619        let config = DecoderConfig {
620            max_depth: MAX_DEPTH,
621            ..Default::default()
622        };
623        let msg = format!("depth limit `{MAX_DEPTH}` reached while decoding. Try increasing it");
624        // for each nested enum so that it may read the discriminant
625        let data = [0; MAX_DEPTH * WORD_SIZE];
626
627        [nested_struct, nested_enum, nested_tuple, nested_array]
628            .iter()
629            .map(|fun| fun(MAX_DEPTH + 1))
630            .for_each(|param_type| {
631                assert_decoding_failed_w_data(config, &param_type, &msg, data.as_slice());
632            })
633    }
634
635    #[test]
636    fn depth_is_not_reached() {
637        const MAX_DEPTH: usize = 3;
638        const ACTUAL_DEPTH: usize = MAX_DEPTH - 1;
639
640        // enough data to decode 2*ACTUAL_DEPTH enums (discriminant + u8 = 2*WORD_SIZE)
641        let data = [0; 2 * ACTUAL_DEPTH * (WORD_SIZE * 2)];
642        let config = DecoderConfig {
643            max_depth: MAX_DEPTH,
644            ..Default::default()
645        };
646
647        [nested_struct, nested_enum, nested_tuple, nested_array]
648            .into_iter()
649            .map(|fun| fun(ACTUAL_DEPTH))
650            .map(|param_type| {
651                // Wrapping everything in a structure so that we may check whether the depth is
652                // decremented after finishing every struct field.
653                ParamType::Struct {
654                    name: "".to_string(),
655                    fields: to_named(&[param_type.clone(), param_type]),
656                    generics: vec![],
657                }
658            })
659            .for_each(|param_type| {
660                ABIDecoder::new(config)
661                    .decode(&param_type, data.as_slice())
662                    .unwrap();
663            })
664    }
665
666    #[test]
667    fn too_many_tokens() {
668        let config = DecoderConfig {
669            max_tokens: 3,
670            ..Default::default()
671        };
672        {
673            let data = [0; 3 * WORD_SIZE];
674            let inner_param_types = vec![ParamType::U64; 3];
675            for param_type in [
676                ParamType::Struct {
677                    name: "".to_string(),
678                    fields: to_named(&inner_param_types),
679                    generics: vec![],
680                },
681                ParamType::Tuple(inner_param_types.clone()),
682                ParamType::Array(Box::new(ParamType::U64), 3),
683            ] {
684                assert_decoding_failed_w_data(
685                    config,
686                    &param_type,
687                    "token limit `3` reached while decoding. Try increasing it",
688                    &data,
689                );
690            }
691        }
692        {
693            let data = [0, 0, 0, 0, 0, 0, 0, 3, 1, 2, 3];
694
695            assert_decoding_failed_w_data(
696                config,
697                &ParamType::Vector(Box::new(ParamType::U8)),
698                "token limit `3` reached while decoding. Try increasing it",
699                &data,
700            );
701        }
702    }
703
704    #[test]
705    fn token_count_is_being_reset_between_decodings() {
706        // given
707        let config = DecoderConfig {
708            max_tokens: 3,
709            ..Default::default()
710        };
711
712        let param_type = ParamType::Array(Box::new(ParamType::StringArray(0)), 2);
713
714        let decoder = ABIDecoder::new(config);
715        decoder.decode(&param_type, [].as_slice()).unwrap();
716
717        // when
718        let result = decoder.decode(&param_type, [].as_slice());
719
720        // then
721        result.expect("element count to be reset");
722    }
723
724    fn assert_decoding_failed_w_data(
725        config: DecoderConfig,
726        param_type: &ParamType,
727        msg: &str,
728        data: &[u8],
729    ) {
730        let decoder = ABIDecoder::new(config);
731
732        let err = decoder.decode(param_type, data);
733
734        let Err(Error::Codec(actual_msg)) = err else {
735            panic!("expected a `Codec` error. Got: `{err:?}`");
736        };
737
738        assert_eq!(actual_msg, msg);
739    }
740
741    fn nested_struct(depth: usize) -> ParamType {
742        let fields = if depth == 1 {
743            vec![]
744        } else {
745            to_named(&[nested_struct(depth - 1)])
746        };
747
748        ParamType::Struct {
749            name: "".to_string(),
750            fields,
751            generics: vec![],
752        }
753    }
754
755    fn nested_enum(depth: usize) -> ParamType {
756        let fields = if depth == 1 {
757            to_named(&[ParamType::U8])
758        } else {
759            to_named(&[nested_enum(depth - 1)])
760        };
761
762        ParamType::Enum {
763            name: "".to_string(),
764            enum_variants: EnumVariants::new(fields).unwrap(),
765            generics: vec![],
766        }
767    }
768
769    fn nested_array(depth: usize) -> ParamType {
770        let field = if depth == 1 {
771            ParamType::U8
772        } else {
773            nested_array(depth - 1)
774        };
775
776        ParamType::Array(Box::new(field), 1)
777    }
778
779    fn nested_tuple(depth: usize) -> ParamType {
780        let fields = if depth == 1 {
781            vec![ParamType::U8]
782        } else {
783            vec![nested_tuple(depth - 1)]
784        };
785
786        ParamType::Tuple(fields)
787    }
788}