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 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 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 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 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 ParamType::Bytes => Some(std::mem::size_of::<u8>()),
128 _ => None,
129 }
130 }
131
132 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 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 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 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 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 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 Some(params) if !params.is_empty() => {
276 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 parent_generic_params
290 .iter()
291 .map(|(_, ty)| ty)
292 .cloned()
293 .collect()
294 };
295
296 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 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 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 let result = ParamType::try_from_type_application(&type_application, &type_lookup)?;
629
630 assert_eq!(result, ParamType::Array(Box::new(ParamType::U8), 10));
632
633 Ok(())
634 }
635
636 #[test]
637 fn handles_vectors() -> Result<()> {
638 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 let result = ParamType::try_from_type_application(&type_application, &type_lookup)?;
721
722 assert_eq!(result, ParamType::Vector(Box::new(ParamType::U8)));
724
725 Ok(())
726 }
727
728 #[test]
729 fn handles_structs() -> Result<()> {
730 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 let result = ParamType::try_from_type_application(&type_application, &type_lookup)?;
773
774 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 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 let result = ParamType::try_from_type_application(&type_application, &type_lookup)?;
831
832 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 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 let result = ParamType::try_from_type_application(&type_application, &type_lookup)?;
891
892 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 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 let result = ParamType::try_from_type_application(&type_application, &type_lookup)?;
1214
1215 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 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 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 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}