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