Skip to main content

multiversx_sc/abi/
type_description.rs

1use alloc::{
2    string::{String, ToString},
3    vec::Vec,
4};
5
6use super::TypeNames;
7
8#[derive(Clone, Debug)]
9pub struct TypeDescription {
10    pub docs: Vec<String>,
11    pub names: TypeNames,
12    pub contents: TypeContents,
13    pub macro_attributes: Vec<String>,
14}
15
16impl TypeDescription {
17    /// Used as temporary value.
18    /// To avoid an infinite loop for recursive types,
19    /// we must reserve the type key (type name) before computing its fields.
20    /// We use this as value while the fields are being computed.
21    pub const PLACEHOLDER: TypeDescription = TypeDescription {
22        docs: Vec::new(),
23        names: TypeNames::new(),
24        contents: TypeContents::NotSpecified,
25        macro_attributes: Vec::new(),
26    };
27}
28
29impl TypeDescription {
30    /// Used in code generation.
31    pub fn new(
32        docs: &[&str],
33        names: TypeNames,
34        contents: TypeContents,
35        macro_attributes: &[&str],
36    ) -> Self {
37        TypeDescription {
38            docs: docs.iter().map(|s| s.to_string()).collect(),
39            names,
40            contents,
41            macro_attributes: macro_attributes.iter().map(|s| s.to_string()).collect(),
42        }
43    }
44}
45
46#[derive(Clone, Debug)]
47pub enum TypeContents {
48    NotSpecified,
49    Enum(Vec<EnumVariantDescription>),
50    Struct(Vec<StructFieldDescription>),
51    ExplicitEnum(Vec<ExplicitEnumVariantDescription>),
52}
53
54impl TypeContents {
55    pub fn is_specified(&self) -> bool {
56        !matches!(*self, TypeContents::NotSpecified)
57    }
58}
59
60#[derive(Clone, Debug, PartialEq, Eq)]
61pub struct EnumVariantDescription {
62    pub docs: Vec<String>,
63    pub name: String,
64    pub discriminant: usize,
65    pub fields: Vec<StructFieldDescription>,
66}
67
68impl EnumVariantDescription {
69    /// Used in code generation.
70    ///
71    /// TODO: builder pattern for more elegant code.
72    pub fn new(
73        docs: &[&str],
74        name: &str,
75        discriminant: usize,
76        fields: Vec<StructFieldDescription>,
77    ) -> Self {
78        EnumVariantDescription {
79            docs: docs.iter().map(|s| s.to_string()).collect(),
80            name: name.to_string(),
81            discriminant,
82            fields,
83        }
84    }
85
86    pub fn is_empty_variant(&self) -> bool {
87        self.fields.is_empty()
88    }
89
90    pub fn is_tuple_variant(&self) -> bool {
91        // all fields are numbers
92        for field in self.fields.iter() {
93            if field.name.parse::<u64>().is_err() {
94                return false;
95            }
96        }
97
98        true
99    }
100}
101
102#[derive(Clone, Debug, PartialEq, Eq)]
103pub struct StructFieldDescription {
104    pub docs: Vec<String>,
105    pub name: String,
106    pub field_type: TypeNames,
107}
108
109impl StructFieldDescription {
110    /// Used in code generation.
111    pub fn new(docs: &[&str], name: &str, field_type: TypeNames) -> Self {
112        Self {
113            docs: docs.iter().map(|s| s.to_string()).collect(),
114            name: name.to_string(),
115            field_type,
116        }
117    }
118}
119
120/// An explicit enum is an enum that gets serialized by name instead of discriminant.
121///
122/// This makes it easier for humans to read readable in the transaction output.
123///
124/// It cannot have data fields, only simple enums allowed.
125#[derive(Clone, Debug)]
126pub struct ExplicitEnumVariantDescription {
127    pub docs: Vec<String>,
128    pub name: String,
129}
130
131impl ExplicitEnumVariantDescription {
132    /// Used in code generation.
133    pub fn new(docs: &[&str], name: &str) -> Self {
134        Self {
135            docs: docs.iter().map(|s| s.to_string()).collect(),
136            name: name.to_string(),
137        }
138    }
139}