fuels_types/
param_types.rs

1use std::{collections::HashMap, iter::zip};
2
3use fuel_abi_types::{
4    program_abi::{TypeApplication, TypeDeclaration},
5    utils::{extract_array_len, extract_generic_name, extract_str_len, has_tuple_format},
6};
7use itertools::chain;
8use strum_macros::EnumString;
9
10use crate::{
11    constants::WORD_SIZE,
12    enum_variants::EnumVariants,
13    errors::{error, Error, Result},
14};
15
16#[derive(Debug, Clone, EnumString, PartialEq, Eq, Default)]
17#[strum(ascii_case_insensitive)]
18pub enum ParamType {
19    #[default]
20    U8,
21    U16,
22    U32,
23    U64,
24    U128,
25    Bool,
26    B256,
27    // The Unit ParamType is used for unit variants in Enums. The corresponding type field is `()`,
28    // similar to Rust.
29    Unit,
30    Array(Box<ParamType>, usize),
31    Vector(Box<ParamType>),
32    #[strum(serialize = "str")]
33    String(usize),
34    #[strum(disabled)]
35    Struct {
36        fields: Vec<ParamType>,
37        generics: Vec<ParamType>,
38    },
39    #[strum(disabled)]
40    Enum {
41        variants: EnumVariants,
42        generics: Vec<ParamType>,
43    },
44    Tuple(Vec<ParamType>),
45    RawSlice,
46    Bytes,
47}
48
49pub enum ReturnLocation {
50    Return,
51    ReturnData,
52}
53
54impl ParamType {
55    // Depending on the type, the returned value will be stored
56    // either in `Return` or `ReturnData`.
57    pub fn get_return_location(&self) -> ReturnLocation {
58        match self {
59            Self::Unit | Self::U8 | Self::U16 | Self::U32 | Self::U64 | Self::Bool => {
60                ReturnLocation::Return
61            }
62
63            _ => ReturnLocation::ReturnData,
64        }
65    }
66
67    /// Given a [ParamType], return the number of elements of that [ParamType] that can fit in
68    /// `available_bytes`: it is the length of the corresponding heap type.
69    pub fn calculate_num_of_elements(
70        param_type: &ParamType,
71        available_bytes: usize,
72    ) -> Result<usize> {
73        let memory_size = param_type.compute_encoding_width() * WORD_SIZE;
74        let remainder = available_bytes % memory_size;
75        if remainder != 0 {
76            return Err(error!(
77                InvalidData,
78                "{remainder} extra bytes detected while decoding heap type"
79            ));
80        }
81        Ok(available_bytes / memory_size)
82    }
83
84    pub fn contains_nested_heap_types(&self) -> bool {
85        match &self {
86            ParamType::Vector(param_type) => param_type.uses_heap_types(),
87            ParamType::Bytes => false,
88            _ => self.uses_heap_types(),
89        }
90    }
91
92    fn uses_heap_types(&self) -> bool {
93        match &self {
94            ParamType::Vector(..) | ParamType::Bytes => true,
95            ParamType::Array(param_type, ..) => param_type.uses_heap_types(),
96            ParamType::Tuple(param_types, ..) => Self::any_nested_heap_types(param_types),
97            ParamType::Enum {
98                generics, variants, ..
99            } => {
100                let variants_types = variants.param_types();
101                Self::any_nested_heap_types(chain!(generics, variants_types))
102            }
103            ParamType::Struct {
104                fields, generics, ..
105            } => Self::any_nested_heap_types(chain!(fields, generics)),
106            _ => false,
107        }
108    }
109
110    fn any_nested_heap_types<'a>(param_types: impl IntoIterator<Item = &'a ParamType>) -> bool {
111        param_types
112            .into_iter()
113            .any(|param_type| param_type.uses_heap_types())
114    }
115
116    pub fn is_vm_heap_type(&self) -> bool {
117        matches!(self, ParamType::Vector(..) | ParamType::Bytes)
118    }
119
120    /// Compute the inner memory size of a containing heap type (`Bytes` or `Vec`s).
121    pub fn heap_inner_element_size(&self) -> Option<usize> {
122        match &self {
123            ParamType::Vector(inner_param_type) => {
124                Some(inner_param_type.compute_encoding_width() * WORD_SIZE)
125            }
126            // `Bytes` type is byte-packed in the VM, so it's the size of an u8
127            ParamType::Bytes => Some(std::mem::size_of::<u8>()),
128            _ => None,
129        }
130    }
131
132    /// Calculates the number of `WORD`s the VM expects this parameter to be encoded in.
133    pub fn compute_encoding_width(&self) -> usize {
134        const fn count_words(bytes: usize) -> usize {
135            let q = bytes / WORD_SIZE;
136            let r = bytes % WORD_SIZE;
137            match r == 0 {
138                true => q,
139                false => q + 1,
140            }
141        }
142
143        match &self {
144            ParamType::Unit
145            | ParamType::U8
146            | ParamType::U16
147            | ParamType::U32
148            | ParamType::U64
149            | ParamType::Bool => 1,
150            ParamType::U128 | ParamType::RawSlice => 2,
151            ParamType::Vector(_) | ParamType::Bytes => 3,
152            ParamType::B256 => 4,
153            ParamType::Array(param, count) => param.compute_encoding_width() * count,
154            ParamType::String(len) => count_words(*len),
155            ParamType::Struct { fields, .. } => fields
156                .iter()
157                .map(|param_type| param_type.compute_encoding_width())
158                .sum(),
159            ParamType::Enum { variants, .. } => variants.compute_encoding_width_of_enum(),
160            ParamType::Tuple(params) => params.iter().map(|p| p.compute_encoding_width()).sum(),
161        }
162    }
163
164    /// For when you need to convert a ABI JSON's TypeApplication into a ParamType.
165    ///
166    /// # Arguments
167    ///
168    /// * `type_application`: The TypeApplication you wish to convert into a ParamType
169    /// * `type_lookup`: A HashMap of TypeDeclarations mentioned in the
170    ///                  TypeApplication where the type id is the key.
171    pub fn try_from_type_application(
172        type_application: &TypeApplication,
173        type_lookup: &HashMap<usize, TypeDeclaration>,
174    ) -> Result<Self> {
175        Type::try_from(type_application, type_lookup)?.try_into()
176    }
177}
178
179#[derive(Debug, Clone)]
180struct Type {
181    type_field: String,
182    generic_params: Vec<Type>,
183    components: Vec<Type>,
184}
185
186impl Type {
187    /// Will recursively drill down the given generic parameters until all types are
188    /// resolved.
189    ///
190    /// # Arguments
191    ///
192    /// * `type_application`: the type we wish to resolve
193    /// * `types`: all types used in the function call
194    pub fn try_from(
195        type_application: &TypeApplication,
196        type_lookup: &HashMap<usize, TypeDeclaration>,
197    ) -> Result<Self> {
198        Self::resolve(type_application, type_lookup, &[])
199    }
200
201    fn resolve(
202        type_application: &TypeApplication,
203        type_lookup: &HashMap<usize, TypeDeclaration>,
204        parent_generic_params: &[(usize, Type)],
205    ) -> Result<Self> {
206        let type_declaration = type_lookup.get(&type_application.type_id).ok_or_else(|| {
207            error!(
208                InvalidData,
209                "type id {} not found in type lookup", type_application.type_id
210            )
211        })?;
212
213        if extract_generic_name(&type_declaration.type_field).is_some() {
214            let (_, generic_type) = parent_generic_params
215                .iter()
216                .find(|(id, _)| *id == type_application.type_id)
217                .ok_or_else(|| {
218                    error!(
219                        InvalidData,
220                        "type id {} not found in parent's generic parameters",
221                        type_application.type_id
222                    )
223                })?;
224
225            return Ok(generic_type.clone());
226        }
227
228        // Figure out what does the current type do with the inherited generic
229        // parameters and reestablish the mapping since the current type might have
230        // renamed the inherited generic parameters.
231        let generic_params_lookup = Self::determine_generics_for_type(
232            type_application,
233            type_lookup,
234            type_declaration,
235            parent_generic_params,
236        )?;
237
238        // Resolve the enclosed components (if any) with the newly resolved generic
239        // parameters.
240        let components = type_declaration
241            .components
242            .iter()
243            .flatten()
244            .map(|component| Self::resolve(component, type_lookup, &generic_params_lookup))
245            .collect::<Result<Vec<_>>>()?;
246
247        Ok(Type {
248            type_field: type_declaration.type_field.clone(),
249            components,
250            generic_params: generic_params_lookup
251                .into_iter()
252                .map(|(_, ty)| ty)
253                .collect(),
254        })
255    }
256
257    /// For the given type generates generic_type_id -> Type mapping describing to
258    /// which types generic parameters should be resolved.
259    ///
260    /// # Arguments
261    ///
262    /// * `type_application`: The type on which the generic parameters are defined.
263    /// * `types`: All types used.
264    /// * `parent_generic_params`: The generic parameters as inherited from the
265    ///                            enclosing type (a struct/enum/array etc.).
266    fn determine_generics_for_type(
267        type_application: &TypeApplication,
268        type_lookup: &HashMap<usize, TypeDeclaration>,
269        type_declaration: &TypeDeclaration,
270        parent_generic_params: &[(usize, Type)],
271    ) -> Result<Vec<(usize, Self)>> {
272        match &type_declaration.type_parameters {
273            // The presence of type_parameters indicates that the current type
274            // (a struct or an enum) defines some generic parameters (i.e. SomeStruct<T, K>).
275            Some(params) if !params.is_empty() => {
276                // Determine what Types the generics will resolve to.
277                let generic_params_from_current_type = type_application
278                    .type_arguments
279                    .iter()
280                    .flatten()
281                    .map(|ty| Self::resolve(ty, type_lookup, parent_generic_params))
282                    .collect::<Result<Vec<_>>>()?;
283
284                let generics_to_use = if !generic_params_from_current_type.is_empty() {
285                    generic_params_from_current_type
286                } else {
287                    // Types such as arrays and enums inherit and forward their
288                    // generic parameters, without declaring their own.
289                    parent_generic_params
290                        .iter()
291                        .map(|(_, ty)| ty)
292                        .cloned()
293                        .collect()
294                };
295
296                // All inherited but unused generic types are dropped. The rest are
297                // re-mapped to new type_ids since child types are free to rename
298                // the generic parameters as they see fit -- i.e.
299                // struct ParentStruct<T>{
300                //     b: ChildStruct<T>
301                // }
302                // struct ChildStruct<K> {
303                //     c: K
304                // }
305
306                Ok(zip(params.clone(), generics_to_use).collect())
307            }
308            _ => Ok(parent_generic_params.to_vec()),
309        }
310    }
311}
312
313impl TryFrom<Type> for ParamType {
314    type Error = Error;
315
316    fn try_from(value: Type) -> Result<Self> {
317        (&value).try_into()
318    }
319}
320
321impl TryFrom<&Type> for ParamType {
322    type Error = Error;
323
324    fn try_from(the_type: &Type) -> Result<Self> {
325        let matched_param_type = [
326            try_primitive,
327            try_array,
328            try_str,
329            try_tuple,
330            try_vector,
331            try_bytes,
332            try_raw_slice,
333            try_enum,
334            try_u128,
335            try_struct,
336        ]
337        .into_iter()
338        .map(|fun| fun(the_type))
339        .flat_map(|result| result.ok().flatten())
340        .next();
341
342        matched_param_type.map(Ok).unwrap_or_else(|| {
343            Err(error!(
344                InvalidType,
345                "Type {} couldn't be converted into a ParamType", the_type.type_field
346            ))
347        })
348    }
349}
350
351fn convert_into_param_types(coll: &[Type]) -> Result<Vec<ParamType>> {
352    coll.iter().map(ParamType::try_from).collect()
353}
354
355fn try_struct(the_type: &Type) -> Result<Option<ParamType>> {
356    let result = if has_struct_format(&the_type.type_field) {
357        let generics = param_types(&the_type.generic_params)?;
358
359        let fields = convert_into_param_types(&the_type.components)?;
360        Some(ParamType::Struct { fields, generics })
361    } else {
362        None
363    };
364
365    Ok(result)
366}
367
368fn has_struct_format(field: &str) -> bool {
369    field.starts_with("struct ")
370}
371
372fn try_vector(the_type: &Type) -> Result<Option<ParamType>> {
373    if !["struct std::vec::Vec", "struct Vec"].contains(&the_type.type_field.as_str()) {
374        return Ok(None);
375    }
376
377    if the_type.generic_params.len() != 1 {
378        return Err(error!(
379            InvalidType,
380            "Vec must have exactly one generic argument for its type. Found: {:?}",
381            the_type.generic_params
382        ));
383    }
384
385    let vec_elem_type = convert_into_param_types(&the_type.generic_params)?.remove(0);
386
387    Ok(Some(ParamType::Vector(Box::new(vec_elem_type))))
388}
389
390fn try_u128(the_type: &Type) -> Result<Option<ParamType>> {
391    Ok(["struct std::u128::U128", "struct U128"]
392        .contains(&the_type.type_field.as_str())
393        .then_some(ParamType::U128))
394}
395
396fn try_bytes(the_type: &Type) -> Result<Option<ParamType>> {
397    Ok(["struct std::bytes::Bytes", "struct Bytes"]
398        .contains(&the_type.type_field.as_str())
399        .then_some(ParamType::Bytes))
400}
401
402fn try_raw_slice(the_type: &Type) -> Result<Option<ParamType>> {
403    Ok((the_type.type_field == "raw untyped slice").then_some(ParamType::RawSlice))
404}
405
406fn try_enum(the_type: &Type) -> Result<Option<ParamType>> {
407    let field = &the_type.type_field;
408    let result = if field.starts_with("enum ") {
409        let generics = param_types(&the_type.generic_params)?;
410
411        let components = convert_into_param_types(&the_type.components)?;
412        let variants = EnumVariants::new(components)?;
413
414        Some(ParamType::Enum { variants, generics })
415    } else {
416        None
417    };
418
419    Ok(result)
420}
421
422fn try_tuple(the_type: &Type) -> Result<Option<ParamType>> {
423    let result = if has_tuple_format(&the_type.type_field) {
424        let tuple_elements = param_types(&the_type.components)?;
425        Some(ParamType::Tuple(tuple_elements))
426    } else {
427        None
428    };
429
430    Ok(result)
431}
432
433fn param_types(coll: &[Type]) -> Result<Vec<ParamType>> {
434    coll.iter().map(|e| e.try_into()).collect()
435}
436
437fn try_str(the_type: &Type) -> Result<Option<ParamType>> {
438    Ok(extract_str_len(&the_type.type_field).map(ParamType::String))
439}
440
441fn try_array(the_type: &Type) -> Result<Option<ParamType>> {
442    if let Some(len) = extract_array_len(&the_type.type_field) {
443        if the_type.components.len() != 1 {}
444
445        return match the_type.components.as_slice() {
446            [single_type] => {
447                let array_type = single_type.try_into()?;
448                Ok(Some(ParamType::Array(Box::new(array_type), len)))
449            }
450            _ => Err(error!(
451                InvalidType,
452                "An array must have elements of exactly one type. Array types: {:?}",
453                the_type.components
454            )),
455        };
456    }
457    Ok(None)
458}
459
460fn try_primitive(the_type: &Type) -> Result<Option<ParamType>> {
461    let result = match the_type.type_field.as_str() {
462        "bool" => Some(ParamType::Bool),
463        "u8" => Some(ParamType::U8),
464        "u16" => Some(ParamType::U16),
465        "u32" => Some(ParamType::U32),
466        "u64" => Some(ParamType::U64),
467        "b256" => Some(ParamType::B256),
468        "()" => Some(ParamType::Unit),
469        _ => None,
470    };
471
472    Ok(result)
473}
474
475#[cfg(test)]
476mod tests {
477    use super::*;
478    use crate::param_types::ParamType;
479
480    const WIDTH_OF_B256: usize = 4;
481    const WIDTH_OF_U32: usize = 1;
482    const WIDTH_OF_BOOL: usize = 1;
483
484    #[test]
485    fn array_size_dependent_on_num_of_elements() {
486        const NUM_ELEMENTS: usize = 11;
487        let param = ParamType::Array(Box::new(ParamType::B256), NUM_ELEMENTS);
488
489        let width = param.compute_encoding_width();
490
491        let expected = NUM_ELEMENTS * WIDTH_OF_B256;
492        assert_eq!(expected, width);
493    }
494
495    #[test]
496    fn string_size_dependent_on_num_of_elements() {
497        const NUM_ASCII_CHARS: usize = 9;
498        let param = ParamType::String(NUM_ASCII_CHARS);
499
500        let width = param.compute_encoding_width();
501
502        // 2 WORDS or 16 B are enough to fit 9 ascii chars
503        assert_eq!(2, width);
504    }
505
506    #[test]
507    fn structs_are_just_all_elements_combined() {
508        let inner_struct = ParamType::Struct {
509            fields: vec![ParamType::U32, ParamType::U32],
510            generics: vec![],
511        };
512
513        let a_struct = ParamType::Struct {
514            fields: vec![ParamType::B256, ParamType::Bool, inner_struct],
515            generics: vec![],
516        };
517
518        let width = a_struct.compute_encoding_width();
519
520        const INNER_STRUCT_WIDTH: usize = WIDTH_OF_U32 * 2;
521        const EXPECTED_WIDTH: usize = WIDTH_OF_B256 + WIDTH_OF_BOOL + INNER_STRUCT_WIDTH;
522        assert_eq!(EXPECTED_WIDTH, width);
523    }
524
525    #[test]
526    fn enums_are_as_big_as_their_biggest_variant_plus_a_word() -> Result<()> {
527        let fields = vec![ParamType::B256];
528        let inner_struct = ParamType::Struct {
529            fields,
530            generics: vec![],
531        };
532        let types = vec![ParamType::U32, inner_struct];
533        let param = ParamType::Enum {
534            variants: EnumVariants::new(types)?,
535            generics: vec![],
536        };
537
538        let width = param.compute_encoding_width();
539
540        const INNER_STRUCT_SIZE: usize = WIDTH_OF_B256;
541        const EXPECTED_WIDTH: usize = INNER_STRUCT_SIZE + 1;
542        assert_eq!(EXPECTED_WIDTH, width);
543        Ok(())
544    }
545
546    #[test]
547    fn tuples_are_just_all_elements_combined() {
548        let inner_tuple = ParamType::Tuple(vec![ParamType::B256]);
549        let param = ParamType::Tuple(vec![ParamType::U32, inner_tuple]);
550
551        let width = param.compute_encoding_width();
552
553        const INNER_TUPLE_WIDTH: usize = WIDTH_OF_B256;
554        const EXPECTED_WIDTH: usize = WIDTH_OF_U32 + INNER_TUPLE_WIDTH;
555        assert_eq!(EXPECTED_WIDTH, width);
556    }
557
558    #[test]
559    fn handles_simple_types() -> Result<()> {
560        let parse_param_type = |type_field: &str| {
561            let type_application = TypeApplication {
562                name: "".to_string(),
563                type_id: 0,
564                type_arguments: None,
565            };
566
567            let declarations = [TypeDeclaration {
568                type_id: 0,
569                type_field: type_field.to_string(),
570                components: None,
571                type_parameters: None,
572            }];
573
574            let type_lookup = declarations
575                .into_iter()
576                .map(|decl| (decl.type_id, decl))
577                .collect::<HashMap<_, _>>();
578
579            ParamType::try_from_type_application(&type_application, &type_lookup)
580        };
581
582        assert_eq!(parse_param_type("u8")?, ParamType::U8);
583        assert_eq!(parse_param_type("u16")?, ParamType::U16);
584        assert_eq!(parse_param_type("u32")?, ParamType::U32);
585        assert_eq!(parse_param_type("u64")?, ParamType::U64);
586        assert_eq!(parse_param_type("bool")?, ParamType::Bool);
587        assert_eq!(parse_param_type("b256")?, ParamType::B256);
588        assert_eq!(parse_param_type("()")?, ParamType::Unit);
589        assert_eq!(parse_param_type("str[21]")?, ParamType::String(21));
590
591        Ok(())
592    }
593
594    #[test]
595    fn handles_arrays() -> Result<()> {
596        // given
597        let type_application = TypeApplication {
598            name: "".to_string(),
599            type_id: 0,
600            type_arguments: None,
601        };
602
603        let declarations = [
604            TypeDeclaration {
605                type_id: 0,
606                type_field: "[_; 10]".to_string(),
607                components: Some(vec![TypeApplication {
608                    name: "__array_element".to_string(),
609                    type_id: 1,
610                    type_arguments: None,
611                }]),
612                type_parameters: None,
613            },
614            TypeDeclaration {
615                type_id: 1,
616                type_field: "u8".to_string(),
617                components: None,
618                type_parameters: None,
619            },
620        ];
621
622        let type_lookup = declarations
623            .into_iter()
624            .map(|decl| (decl.type_id, decl))
625            .collect::<HashMap<_, _>>();
626
627        // when
628        let result = ParamType::try_from_type_application(&type_application, &type_lookup)?;
629
630        // then
631        assert_eq!(result, ParamType::Array(Box::new(ParamType::U8), 10));
632
633        Ok(())
634    }
635
636    #[test]
637    fn handles_vectors() -> Result<()> {
638        // given
639        let declarations = [
640            TypeDeclaration {
641                type_id: 1,
642                type_field: "generic T".to_string(),
643                components: None,
644                type_parameters: None,
645            },
646            TypeDeclaration {
647                type_id: 2,
648                type_field: "raw untyped ptr".to_string(),
649                components: None,
650                type_parameters: None,
651            },
652            TypeDeclaration {
653                type_id: 3,
654                type_field: "struct std::vec::RawVec".to_string(),
655                components: Some(vec![
656                    TypeApplication {
657                        name: "ptr".to_string(),
658                        type_id: 2,
659                        type_arguments: None,
660                    },
661                    TypeApplication {
662                        name: "cap".to_string(),
663                        type_id: 5,
664                        type_arguments: None,
665                    },
666                ]),
667                type_parameters: Some(vec![1]),
668            },
669            TypeDeclaration {
670                type_id: 4,
671                type_field: "struct std::vec::Vec".to_string(),
672                components: Some(vec![
673                    TypeApplication {
674                        name: "buf".to_string(),
675                        type_id: 3,
676                        type_arguments: Some(vec![TypeApplication {
677                            name: "".to_string(),
678                            type_id: 1,
679                            type_arguments: None,
680                        }]),
681                    },
682                    TypeApplication {
683                        name: "len".to_string(),
684                        type_id: 5,
685                        type_arguments: None,
686                    },
687                ]),
688                type_parameters: Some(vec![1]),
689            },
690            TypeDeclaration {
691                type_id: 5,
692                type_field: "u64".to_string(),
693                components: None,
694                type_parameters: None,
695            },
696            TypeDeclaration {
697                type_id: 6,
698                type_field: "u8".to_string(),
699                components: None,
700                type_parameters: None,
701            },
702        ];
703
704        let type_application = TypeApplication {
705            name: "arg".to_string(),
706            type_id: 4,
707            type_arguments: Some(vec![TypeApplication {
708                name: "".to_string(),
709                type_id: 6,
710                type_arguments: None,
711            }]),
712        };
713
714        let type_lookup = declarations
715            .into_iter()
716            .map(|decl| (decl.type_id, decl))
717            .collect::<HashMap<_, _>>();
718
719        // when
720        let result = ParamType::try_from_type_application(&type_application, &type_lookup)?;
721
722        // then
723        assert_eq!(result, ParamType::Vector(Box::new(ParamType::U8)));
724
725        Ok(())
726    }
727
728    #[test]
729    fn handles_structs() -> Result<()> {
730        // given
731        let declarations = [
732            TypeDeclaration {
733                type_id: 1,
734                type_field: "generic T".to_string(),
735                components: None,
736                type_parameters: None,
737            },
738            TypeDeclaration {
739                type_id: 2,
740                type_field: "struct SomeStruct".to_string(),
741                components: Some(vec![TypeApplication {
742                    name: "field".to_string(),
743                    type_id: 1,
744                    type_arguments: None,
745                }]),
746                type_parameters: Some(vec![1]),
747            },
748            TypeDeclaration {
749                type_id: 3,
750                type_field: "u8".to_string(),
751                components: None,
752                type_parameters: None,
753            },
754        ];
755
756        let type_application = TypeApplication {
757            name: "arg".to_string(),
758            type_id: 2,
759            type_arguments: Some(vec![TypeApplication {
760                name: "".to_string(),
761                type_id: 3,
762                type_arguments: None,
763            }]),
764        };
765
766        let type_lookup = declarations
767            .into_iter()
768            .map(|decl| (decl.type_id, decl))
769            .collect::<HashMap<_, _>>();
770
771        // when
772        let result = ParamType::try_from_type_application(&type_application, &type_lookup)?;
773
774        // then
775        assert_eq!(
776            result,
777            ParamType::Struct {
778                fields: vec![ParamType::U8],
779                generics: vec![ParamType::U8]
780            }
781        );
782
783        Ok(())
784    }
785
786    #[test]
787    fn handles_enums() -> Result<()> {
788        // given
789        let declarations = [
790            TypeDeclaration {
791                type_id: 1,
792                type_field: "generic T".to_string(),
793                components: None,
794                type_parameters: None,
795            },
796            TypeDeclaration {
797                type_id: 2,
798                type_field: "enum SomeEnum".to_string(),
799                components: Some(vec![TypeApplication {
800                    name: "variant".to_string(),
801                    type_id: 1,
802                    type_arguments: None,
803                }]),
804                type_parameters: Some(vec![1]),
805            },
806            TypeDeclaration {
807                type_id: 3,
808                type_field: "u8".to_string(),
809                components: None,
810                type_parameters: None,
811            },
812        ];
813
814        let type_application = TypeApplication {
815            name: "arg".to_string(),
816            type_id: 2,
817            type_arguments: Some(vec![TypeApplication {
818                name: "".to_string(),
819                type_id: 3,
820                type_arguments: None,
821            }]),
822        };
823
824        let type_lookup = declarations
825            .into_iter()
826            .map(|decl| (decl.type_id, decl))
827            .collect::<HashMap<_, _>>();
828
829        // when
830        let result = ParamType::try_from_type_application(&type_application, &type_lookup)?;
831
832        // then
833        assert_eq!(
834            result,
835            ParamType::Enum {
836                variants: EnumVariants::new(vec![ParamType::U8])?,
837                generics: vec![ParamType::U8]
838            }
839        );
840
841        Ok(())
842    }
843
844    #[test]
845    fn handles_tuples() -> Result<()> {
846        // given
847        let declarations = [
848            TypeDeclaration {
849                type_id: 1,
850                type_field: "(_, _)".to_string(),
851                components: Some(vec![
852                    TypeApplication {
853                        name: "__tuple_element".to_string(),
854                        type_id: 3,
855                        type_arguments: None,
856                    },
857                    TypeApplication {
858                        name: "__tuple_element".to_string(),
859                        type_id: 2,
860                        type_arguments: None,
861                    },
862                ]),
863                type_parameters: None,
864            },
865            TypeDeclaration {
866                type_id: 2,
867                type_field: "str[15]".to_string(),
868                components: None,
869                type_parameters: None,
870            },
871            TypeDeclaration {
872                type_id: 3,
873                type_field: "u8".to_string(),
874                components: None,
875                type_parameters: None,
876            },
877        ];
878
879        let type_application = TypeApplication {
880            name: "arg".to_string(),
881            type_id: 1,
882            type_arguments: None,
883        };
884        let type_lookup = declarations
885            .into_iter()
886            .map(|decl| (decl.type_id, decl))
887            .collect::<HashMap<_, _>>();
888
889        // when
890        let result = ParamType::try_from_type_application(&type_application, &type_lookup)?;
891
892        // then
893        assert_eq!(
894            result,
895            ParamType::Tuple(vec![ParamType::U8, ParamType::String(15)])
896        );
897
898        Ok(())
899    }
900
901    #[test]
902    fn ultimate_example() -> Result<()> {
903        // given
904        let declarations = [
905            TypeDeclaration {
906                type_id: 1,
907                type_field: "(_, _)".to_string(),
908                components: Some(vec![
909                    TypeApplication {
910                        name: "__tuple_element".to_string(),
911                        type_id: 11,
912                        type_arguments: None,
913                    },
914                    TypeApplication {
915                        name: "__tuple_element".to_string(),
916                        type_id: 11,
917                        type_arguments: None,
918                    },
919                ]),
920                type_parameters: None,
921            },
922            TypeDeclaration {
923                type_id: 2,
924                type_field: "(_, _)".to_string(),
925                components: Some(vec![
926                    TypeApplication {
927                        name: "__tuple_element".to_string(),
928                        type_id: 4,
929                        type_arguments: None,
930                    },
931                    TypeApplication {
932                        name: "__tuple_element".to_string(),
933                        type_id: 24,
934                        type_arguments: None,
935                    },
936                ]),
937                type_parameters: None,
938            },
939            TypeDeclaration {
940                type_id: 3,
941                type_field: "(_, _)".to_string(),
942                components: Some(vec![
943                    TypeApplication {
944                        name: "__tuple_element".to_string(),
945                        type_id: 5,
946                        type_arguments: None,
947                    },
948                    TypeApplication {
949                        name: "__tuple_element".to_string(),
950                        type_id: 13,
951                        type_arguments: None,
952                    },
953                ]),
954                type_parameters: None,
955            },
956            TypeDeclaration {
957                type_id: 4,
958                type_field: "[_; 1]".to_string(),
959                components: Some(vec![TypeApplication {
960                    name: "__array_element".to_string(),
961                    type_id: 8,
962                    type_arguments: Some(vec![TypeApplication {
963                        name: "".to_string(),
964                        type_id: 22,
965                        type_arguments: Some(vec![TypeApplication {
966                            name: "".to_string(),
967                            type_id: 21,
968                            type_arguments: Some(vec![TypeApplication {
969                                name: "".to_string(),
970                                type_id: 18,
971                                type_arguments: Some(vec![TypeApplication {
972                                    name: "".to_string(),
973                                    type_id: 13,
974                                    type_arguments: None,
975                                }]),
976                            }]),
977                        }]),
978                    }]),
979                }]),
980                type_parameters: None,
981            },
982            TypeDeclaration {
983                type_id: 5,
984                type_field: "[_; 2]".to_string(),
985                components: Some(vec![TypeApplication {
986                    name: "__array_element".to_string(),
987                    type_id: 14,
988                    type_arguments: None,
989                }]),
990                type_parameters: None,
991            },
992            TypeDeclaration {
993                type_id: 6,
994                type_field: "[_; 2]".to_string(),
995                components: Some(vec![TypeApplication {
996                    name: "__array_element".to_string(),
997                    type_id: 10,
998                    type_arguments: None,
999                }]),
1000                type_parameters: None,
1001            },
1002            TypeDeclaration {
1003                type_id: 7,
1004                type_field: "b256".to_string(),
1005                components: None,
1006                type_parameters: None,
1007            },
1008            TypeDeclaration {
1009                type_id: 8,
1010                type_field: "enum EnumWGeneric".to_string(),
1011                components: Some(vec![
1012                    TypeApplication {
1013                        name: "a".to_string(),
1014                        type_id: 25,
1015                        type_arguments: None,
1016                    },
1017                    TypeApplication {
1018                        name: "b".to_string(),
1019                        type_id: 12,
1020                        type_arguments: None,
1021                    },
1022                ]),
1023                type_parameters: Some(vec![12]),
1024            },
1025            TypeDeclaration {
1026                type_id: 9,
1027                type_field: "generic K".to_string(),
1028                components: None,
1029                type_parameters: None,
1030            },
1031            TypeDeclaration {
1032                type_id: 10,
1033                type_field: "generic L".to_string(),
1034                components: None,
1035                type_parameters: None,
1036            },
1037            TypeDeclaration {
1038                type_id: 11,
1039                type_field: "generic M".to_string(),
1040                components: None,
1041                type_parameters: None,
1042            },
1043            TypeDeclaration {
1044                type_id: 12,
1045                type_field: "generic N".to_string(),
1046                components: None,
1047                type_parameters: None,
1048            },
1049            TypeDeclaration {
1050                type_id: 13,
1051                type_field: "generic T".to_string(),
1052                components: None,
1053                type_parameters: None,
1054            },
1055            TypeDeclaration {
1056                type_id: 14,
1057                type_field: "generic U".to_string(),
1058                components: None,
1059                type_parameters: None,
1060            },
1061            TypeDeclaration {
1062                type_id: 15,
1063                type_field: "raw untyped ptr".to_string(),
1064                components: None,
1065                type_parameters: None,
1066            },
1067            TypeDeclaration {
1068                type_id: 16,
1069                type_field: "str[2]".to_string(),
1070                components: None,
1071                type_parameters: None,
1072            },
1073            TypeDeclaration {
1074                type_id: 17,
1075                type_field: "struct MegaExample".to_string(),
1076                components: Some(vec![
1077                    TypeApplication {
1078                        name: "a".to_string(),
1079                        type_id: 3,
1080                        type_arguments: None,
1081                    },
1082                    TypeApplication {
1083                        name: "b".to_string(),
1084                        type_id: 23,
1085                        type_arguments: Some(vec![TypeApplication {
1086                            name: "".to_string(),
1087                            type_id: 2,
1088                            type_arguments: None,
1089                        }]),
1090                    },
1091                ]),
1092                type_parameters: Some(vec![13, 14]),
1093            },
1094            TypeDeclaration {
1095                type_id: 18,
1096                type_field: "struct PassTheGenericOn".to_string(),
1097                components: Some(vec![TypeApplication {
1098                    name: "one".to_string(),
1099                    type_id: 20,
1100                    type_arguments: Some(vec![TypeApplication {
1101                        name: "".to_string(),
1102                        type_id: 9,
1103                        type_arguments: None,
1104                    }]),
1105                }]),
1106                type_parameters: Some(vec![9]),
1107            },
1108            TypeDeclaration {
1109                type_id: 19,
1110                type_field: "struct std::vec::RawVec".to_string(),
1111                components: Some(vec![
1112                    TypeApplication {
1113                        name: "ptr".to_string(),
1114                        type_id: 15,
1115                        type_arguments: None,
1116                    },
1117                    TypeApplication {
1118                        name: "cap".to_string(),
1119                        type_id: 25,
1120                        type_arguments: None,
1121                    },
1122                ]),
1123                type_parameters: Some(vec![13]),
1124            },
1125            TypeDeclaration {
1126                type_id: 20,
1127                type_field: "struct SimpleGeneric".to_string(),
1128                components: Some(vec![TypeApplication {
1129                    name: "single_generic_param".to_string(),
1130                    type_id: 13,
1131                    type_arguments: None,
1132                }]),
1133                type_parameters: Some(vec![13]),
1134            },
1135            TypeDeclaration {
1136                type_id: 21,
1137                type_field: "struct StructWArrayGeneric".to_string(),
1138                components: Some(vec![TypeApplication {
1139                    name: "a".to_string(),
1140                    type_id: 6,
1141                    type_arguments: None,
1142                }]),
1143                type_parameters: Some(vec![10]),
1144            },
1145            TypeDeclaration {
1146                type_id: 22,
1147                type_field: "struct StructWTupleGeneric".to_string(),
1148                components: Some(vec![TypeApplication {
1149                    name: "a".to_string(),
1150                    type_id: 1,
1151                    type_arguments: None,
1152                }]),
1153                type_parameters: Some(vec![11]),
1154            },
1155            TypeDeclaration {
1156                type_id: 23,
1157                type_field: "struct std::vec::Vec".to_string(),
1158                components: Some(vec![
1159                    TypeApplication {
1160                        name: "buf".to_string(),
1161                        type_id: 19,
1162                        type_arguments: Some(vec![TypeApplication {
1163                            name: "".to_string(),
1164                            type_id: 13,
1165                            type_arguments: None,
1166                        }]),
1167                    },
1168                    TypeApplication {
1169                        name: "len".to_string(),
1170                        type_id: 25,
1171                        type_arguments: None,
1172                    },
1173                ]),
1174                type_parameters: Some(vec![13]),
1175            },
1176            TypeDeclaration {
1177                type_id: 24,
1178                type_field: "u32".to_string(),
1179                components: None,
1180                type_parameters: None,
1181            },
1182            TypeDeclaration {
1183                type_id: 25,
1184                type_field: "u64".to_string(),
1185                components: None,
1186                type_parameters: None,
1187            },
1188        ];
1189
1190        let type_lookup = declarations
1191            .into_iter()
1192            .map(|decl| (decl.type_id, decl))
1193            .collect::<HashMap<_, _>>();
1194
1195        let type_application = TypeApplication {
1196            name: "arg1".to_string(),
1197            type_id: 17,
1198            type_arguments: Some(vec![
1199                TypeApplication {
1200                    name: "".to_string(),
1201                    type_id: 16,
1202                    type_arguments: None,
1203                },
1204                TypeApplication {
1205                    name: "".to_string(),
1206                    type_id: 7,
1207                    type_arguments: None,
1208                },
1209            ]),
1210        };
1211
1212        // when
1213        let result = ParamType::try_from_type_application(&type_application, &type_lookup)?;
1214
1215        // then
1216        let expected_param_type = {
1217            let fields = vec![ParamType::Struct {
1218                fields: vec![ParamType::String(2)],
1219                generics: vec![ParamType::String(2)],
1220            }];
1221            let pass_the_generic_on = ParamType::Struct {
1222                fields,
1223                generics: vec![ParamType::String(2)],
1224            };
1225
1226            let fields = vec![ParamType::Array(Box::from(pass_the_generic_on.clone()), 2)];
1227            let struct_w_array_generic = ParamType::Struct {
1228                fields,
1229                generics: vec![pass_the_generic_on],
1230            };
1231
1232            let fields = vec![ParamType::Tuple(vec![
1233                struct_w_array_generic.clone(),
1234                struct_w_array_generic.clone(),
1235            ])];
1236            let struct_w_tuple_generic = ParamType::Struct {
1237                fields,
1238                generics: vec![struct_w_array_generic],
1239            };
1240
1241            let types = vec![ParamType::U64, struct_w_tuple_generic.clone()];
1242            let fields = vec![
1243                ParamType::Tuple(vec![
1244                    ParamType::Array(Box::from(ParamType::B256), 2),
1245                    ParamType::String(2),
1246                ]),
1247                ParamType::Vector(Box::from(ParamType::Tuple(vec![
1248                    ParamType::Array(
1249                        Box::from(ParamType::Enum {
1250                            variants: EnumVariants::new(types).unwrap(),
1251                            generics: vec![struct_w_tuple_generic],
1252                        }),
1253                        1,
1254                    ),
1255                    ParamType::U32,
1256                ]))),
1257            ];
1258            ParamType::Struct {
1259                fields,
1260                generics: vec![ParamType::String(2), ParamType::B256],
1261            }
1262        };
1263
1264        assert_eq!(result, expected_param_type);
1265
1266        Ok(())
1267    }
1268
1269    #[test]
1270    fn contains_nested_heap_types_false_on_simple_types() -> Result<()> {
1271        // Simple types cannot have nested heap types
1272        assert!(!ParamType::Unit.contains_nested_heap_types());
1273        assert!(!ParamType::U8.contains_nested_heap_types());
1274        assert!(!ParamType::U16.contains_nested_heap_types());
1275        assert!(!ParamType::U32.contains_nested_heap_types());
1276        assert!(!ParamType::U64.contains_nested_heap_types());
1277        assert!(!ParamType::Bool.contains_nested_heap_types());
1278        assert!(!ParamType::B256.contains_nested_heap_types());
1279        assert!(!ParamType::String(10).contains_nested_heap_types());
1280        assert!(!ParamType::RawSlice.contains_nested_heap_types());
1281        assert!(!ParamType::Bytes.contains_nested_heap_types());
1282        Ok(())
1283    }
1284
1285    #[test]
1286    fn test_complex_types_for_nested_heap_types_containing_vectors() -> Result<()> {
1287        let base_vector = ParamType::Vector(Box::from(ParamType::U8));
1288        let param_types_no_nested_vec = vec![ParamType::U64, ParamType::U32];
1289        let param_types_nested_vec = vec![ParamType::Unit, ParamType::Bool, base_vector.clone()];
1290
1291        let is_nested = |param_type: ParamType| assert!(param_type.contains_nested_heap_types());
1292        let not_nested = |param_type: ParamType| assert!(!param_type.contains_nested_heap_types());
1293
1294        not_nested(base_vector.clone());
1295        is_nested(ParamType::Vector(Box::from(base_vector.clone())));
1296
1297        not_nested(ParamType::Array(Box::from(ParamType::U8), 10));
1298        is_nested(ParamType::Array(Box::from(base_vector), 10));
1299
1300        not_nested(ParamType::Tuple(param_types_no_nested_vec.clone()));
1301        is_nested(ParamType::Tuple(param_types_nested_vec.clone()));
1302
1303        not_nested(ParamType::Struct {
1304            generics: param_types_no_nested_vec.clone(),
1305            fields: param_types_no_nested_vec.clone(),
1306        });
1307        is_nested(ParamType::Struct {
1308            generics: param_types_nested_vec.clone(),
1309            fields: param_types_no_nested_vec.clone(),
1310        });
1311        is_nested(ParamType::Struct {
1312            generics: param_types_no_nested_vec.clone(),
1313            fields: param_types_nested_vec.clone(),
1314        });
1315
1316        not_nested(ParamType::Enum {
1317            variants: EnumVariants::new(param_types_no_nested_vec.clone())?,
1318            generics: param_types_no_nested_vec.clone(),
1319        });
1320        is_nested(ParamType::Enum {
1321            variants: EnumVariants::new(param_types_nested_vec.clone())?,
1322            generics: param_types_no_nested_vec.clone(),
1323        });
1324        is_nested(ParamType::Enum {
1325            variants: EnumVariants::new(param_types_no_nested_vec)?,
1326            generics: param_types_nested_vec,
1327        });
1328        Ok(())
1329    }
1330
1331    #[test]
1332    fn test_complex_types_for_nested_heap_types_containing_bytes() -> Result<()> {
1333        let base_bytes = ParamType::Bytes;
1334        let param_types_no_nested_bytes = vec![ParamType::U64, ParamType::U32];
1335        let param_types_nested_bytes = vec![ParamType::Unit, ParamType::Bool, base_bytes.clone()];
1336
1337        let is_nested = |param_type: ParamType| assert!(param_type.contains_nested_heap_types());
1338        let not_nested = |param_type: ParamType| assert!(!param_type.contains_nested_heap_types());
1339
1340        not_nested(base_bytes.clone());
1341        is_nested(ParamType::Vector(Box::from(base_bytes.clone())));
1342
1343        not_nested(ParamType::Array(Box::from(ParamType::U8), 10));
1344        is_nested(ParamType::Array(Box::from(base_bytes), 10));
1345
1346        not_nested(ParamType::Tuple(param_types_no_nested_bytes.clone()));
1347        is_nested(ParamType::Tuple(param_types_nested_bytes.clone()));
1348
1349        let not_nested_struct = ParamType::Struct {
1350            generics: param_types_no_nested_bytes.clone(),
1351            fields: param_types_no_nested_bytes.clone(),
1352        };
1353        not_nested(not_nested_struct);
1354
1355        let nested_struct = ParamType::Struct {
1356            generics: param_types_nested_bytes.clone(),
1357            fields: param_types_no_nested_bytes.clone(),
1358        };
1359        is_nested(nested_struct);
1360
1361        let nested_struct = ParamType::Struct {
1362            generics: param_types_no_nested_bytes.clone(),
1363            fields: param_types_nested_bytes.clone(),
1364        };
1365        is_nested(nested_struct);
1366
1367        let not_nested_enum = ParamType::Enum {
1368            variants: EnumVariants::new(param_types_no_nested_bytes.clone())?,
1369            generics: param_types_no_nested_bytes.clone(),
1370        };
1371        not_nested(not_nested_enum);
1372
1373        let nested_enum = ParamType::Enum {
1374            variants: EnumVariants::new(param_types_nested_bytes.clone())?,
1375            generics: param_types_no_nested_bytes.clone(),
1376        };
1377        is_nested(nested_enum);
1378
1379        let nested_enum = ParamType::Enum {
1380            variants: EnumVariants::new(param_types_no_nested_bytes)?,
1381            generics: param_types_nested_bytes,
1382        };
1383        is_nested(nested_enum);
1384
1385        Ok(())
1386    }
1387
1388    #[test]
1389    fn try_vector_is_type_path_backward_compatible() {
1390        // TODO: To be removed once https://github.com/FuelLabs/fuels-rs/issues/881 is unblocked.
1391        let the_type = given_generic_type_with_path("Vec");
1392
1393        let param_type = try_vector(&the_type).unwrap().unwrap();
1394
1395        assert_eq!(param_type, ParamType::Vector(Box::new(ParamType::U8)));
1396    }
1397
1398    #[test]
1399    fn try_vector_correctly_resolves_param_type() {
1400        let the_type = given_generic_type_with_path("std::vec::Vec");
1401
1402        let param_type = try_vector(&the_type).unwrap().unwrap();
1403
1404        assert_eq!(param_type, ParamType::Vector(Box::new(ParamType::U8)));
1405    }
1406
1407    #[test]
1408    fn try_bytes_is_type_path_backward_compatible() {
1409        // TODO: To be removed once https://github.com/FuelLabs/fuels-rs/issues/881 is unblocked.
1410        let the_type = given_type_with_path("Bytes");
1411
1412        let param_type = try_bytes(&the_type).unwrap().unwrap();
1413
1414        assert_eq!(param_type, ParamType::Bytes);
1415    }
1416
1417    #[test]
1418    fn try_bytes_correctly_resolves_param_type() {
1419        let the_type = given_type_with_path("std::bytes::Bytes");
1420
1421        let param_type = try_bytes(&the_type).unwrap().unwrap();
1422
1423        assert_eq!(param_type, ParamType::Bytes);
1424    }
1425
1426    #[test]
1427    fn try_raw_slice_correctly_resolves_param_type() {
1428        let the_type = Type {
1429            type_field: "raw untyped slice".to_string(),
1430            generic_params: vec![],
1431            components: vec![],
1432        };
1433
1434        let param_type = try_raw_slice(&the_type).unwrap().unwrap();
1435
1436        assert_eq!(param_type, ParamType::RawSlice);
1437    }
1438
1439    fn given_type_with_path(path: &str) -> Type {
1440        Type {
1441            type_field: format!("struct {path}"),
1442            generic_params: vec![],
1443            components: vec![],
1444        }
1445    }
1446
1447    fn given_generic_type_with_path(path: &str) -> Type {
1448        Type {
1449            type_field: format!("struct {path}"),
1450            generic_params: vec![Type {
1451                type_field: "u8".to_string(),
1452                generic_params: vec![],
1453                components: vec![],
1454            }],
1455            components: vec![],
1456        }
1457    }
1458}