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 {
24            abi: String::new(),
25            rust: String::new(),
26        },
27        contents: TypeContents::NotSpecified,
28        macro_attributes: Vec::new(),
29    };
30}
31
32impl TypeDescription {
33    /// Used in code generation.
34    pub fn new(
35        docs: &[&str],
36        names: TypeNames,
37        contents: TypeContents,
38        macro_attributes: &[&str],
39    ) -> Self {
40        TypeDescription {
41            docs: docs.iter().map(|s| s.to_string()).collect(),
42            names,
43            contents,
44            macro_attributes: macro_attributes.iter().map(|s| s.to_string()).collect(),
45        }
46    }
47}
48
49#[derive(Clone, Debug)]
50pub enum TypeContents {
51    NotSpecified,
52    Enum(Vec<EnumVariantDescription>),
53    Struct(Vec<StructFieldDescription>),
54    ExplicitEnum(Vec<ExplicitEnumVariantDescription>),
55}
56
57impl TypeContents {
58    pub fn is_specified(&self) -> bool {
59        !matches!(*self, TypeContents::NotSpecified)
60    }
61}
62
63#[derive(Clone, Debug, PartialEq, Eq)]
64pub struct EnumVariantDescription {
65    pub docs: Vec<String>,
66    pub name: String,
67    pub discriminant: usize,
68    pub fields: Vec<StructFieldDescription>,
69}
70
71impl EnumVariantDescription {
72    /// Used in code generation.
73    ///
74    /// TODO: builder pattern for more elegant code.
75    pub fn new(
76        docs: &[&str],
77        name: &str,
78        discriminant: usize,
79        fields: Vec<StructFieldDescription>,
80    ) -> Self {
81        EnumVariantDescription {
82            docs: docs.iter().map(|s| s.to_string()).collect(),
83            name: name.to_string(),
84            discriminant,
85            fields,
86        }
87    }
88
89    pub fn is_empty_variant(&self) -> bool {
90        self.fields.is_empty()
91    }
92
93    pub fn is_tuple_variant(&self) -> bool {
94        // all fields are numbers
95        for field in self.fields.iter() {
96            if field.name.parse::<u64>().is_err() {
97                return false;
98            }
99        }
100
101        true
102    }
103}
104
105#[derive(Clone, Debug, PartialEq, Eq)]
106pub struct StructFieldDescription {
107    pub docs: Vec<String>,
108    pub name: String,
109    pub field_type: TypeNames,
110}
111
112impl StructFieldDescription {
113    /// Used in code generation.
114    pub fn new(docs: &[&str], name: &str, field_type: TypeNames) -> Self {
115        Self {
116            docs: docs.iter().map(|s| s.to_string()).collect(),
117            name: name.to_string(),
118            field_type,
119        }
120    }
121}
122
123/// An explicit enum is an enum that gets serialized by name instead of discriminant.
124///
125/// This makes it easier for humans to read readable in the transaction output.
126///
127/// It cannot have data fields, only simple enums allowed.
128#[derive(Clone, Debug)]
129pub struct ExplicitEnumVariantDescription {
130    pub docs: Vec<String>,
131    pub name: String,
132}
133
134impl ExplicitEnumVariantDescription {
135    /// Used in code generation.
136    pub fn new(docs: &[&str], name: &str) -> Self {
137        Self {
138            docs: docs.iter().map(|s| s.to_string()).collect(),
139            name: name.to_string(),
140        }
141    }
142}