sway_core/abi_generation/
abi_str.rs1use sway_types::{integer_bits::IntegerBits, Named};
2
3use crate::{language::CallPath, Engines, GenericArgument, TypeId, TypeInfo};
4
5#[derive(Clone)]
6pub struct AbiStrContext {
7 pub program_name: String,
8 pub abi_with_callpaths: bool,
9 pub abi_with_fully_specified_types: bool,
10 pub abi_root_type_without_generic_type_parameters: bool,
11}
12
13impl TypeId {
14 pub fn get_abi_type_str(
16 &self,
17 ctx: &AbiStrContext,
18 engines: &Engines,
19 resolved_type_id: TypeId,
20 ) -> String {
21 let type_engine = engines.te();
22 let self_abi_str = type_engine.get(*self).abi_str(ctx, engines, true);
23 if self.is_generic_parameter(engines, resolved_type_id) {
24 format!("generic {}", self_abi_str)
25 } else {
26 match (
27 &*type_engine.get(*self),
28 &*type_engine.get(resolved_type_id),
29 ) {
30 (TypeInfo::Custom { .. }, TypeInfo::Struct { .. })
31 | (TypeInfo::Custom { .. }, TypeInfo::Enum { .. }) => type_engine
32 .get(resolved_type_id)
33 .abi_str(ctx, engines, true),
34 (_, TypeInfo::Alias { ty, .. }) => {
35 ty.type_id().get_abi_type_str(ctx, engines, ty.type_id())
36 }
37 (TypeInfo::Tuple(fields), TypeInfo::Tuple(resolved_fields)) => {
38 assert_eq!(fields.len(), resolved_fields.len());
39 let field_strs = resolved_fields
40 .iter()
41 .map(|f| {
42 if ctx.abi_with_fully_specified_types {
43 type_engine.get(f.type_id()).abi_str(ctx, engines, false)
44 } else {
45 "_".to_string()
46 }
47 })
48 .collect::<Vec<String>>();
49 format!("({})", field_strs.join(", "))
50 }
51 (TypeInfo::Array(_, length), TypeInfo::Array(type_arg, resolved_length)) => {
52 assert_eq!(
53 length.as_literal_val().unwrap(),
54 resolved_length.as_literal_val().unwrap()
55 );
56 let inner_type = if ctx.abi_with_fully_specified_types {
57 type_engine
58 .get(type_arg.type_id())
59 .abi_str(ctx, engines, false)
60 } else {
61 "_".to_string()
62 };
63 format!("[{}; {:?}]", inner_type, engines.help_out(length))
64 }
65 (TypeInfo::Slice(type_arg), TypeInfo::Slice(_)) => {
66 let inner_type = if ctx.abi_with_fully_specified_types {
67 type_engine
68 .get(type_arg.type_id())
69 .abi_str(ctx, engines, false)
70 } else {
71 "_".to_string()
72 };
73 format!("[{}]", inner_type)
74 }
75 (TypeInfo::Custom { .. }, _) => {
76 format!("generic {}", self_abi_str)
77 }
78 _ => type_engine
79 .get(resolved_type_id)
80 .abi_str(ctx, engines, true),
81 }
82 }
83 }
84}
85
86impl TypeInfo {
87 pub fn abi_str(&self, ctx: &AbiStrContext, engines: &Engines, is_root: bool) -> String {
88 use TypeInfo::*;
89 let decl_engine = engines.de();
90 match self {
91 Unknown => "unknown".into(),
92 Never => "never".into(),
93 UnknownGeneric { name, .. } => name.to_string(),
94 Placeholder(_) => "_".to_string(),
95 TypeParam(param) => format!("typeparam({})", param.name()),
96 StringSlice => "str".into(),
97 StringArray(length) => format!("str[{}]", length.val()),
98 UnsignedInteger(x) => match x {
99 IntegerBits::Eight => "u8",
100 IntegerBits::Sixteen => "u16",
101 IntegerBits::ThirtyTwo => "u32",
102 IntegerBits::SixtyFour => "u64",
103 IntegerBits::V256 => "u256",
104 }
105 .into(),
106 Boolean => "bool".into(),
107 Custom {
108 qualified_call_path: call_path,
109 ..
110 } => call_path.call_path.suffix.to_string(),
111 Tuple(fields) => {
112 let field_strs = fields
113 .iter()
114 .map(|field| field.abi_str(ctx, engines, false))
115 .collect::<Vec<String>>();
116 format!("({})", field_strs.join(", "))
117 }
118 B256 => "b256".into(),
119 Numeric => "u64".into(), Contract => "contract".into(),
121 ErrorRecovery(_) => "unknown due to error".into(),
122 UntypedEnum(decl_id) => {
123 let decl = engines.pe().get_enum(decl_id);
124 format!("untyped enum {}", decl.name)
125 }
126 UntypedStruct(decl_id) => {
127 let decl = engines.pe().get_struct(decl_id);
128 format!("untyped struct {}", decl.name)
129 }
130 Enum(decl_ref) => {
131 let decl = decl_engine.get_enum(decl_ref);
132 let type_params = if (ctx.abi_root_type_without_generic_type_parameters && is_root)
133 || decl.type_parameters.is_empty()
134 {
135 "".into()
136 } else {
137 format!(
138 "<{}>",
139 decl.type_parameters
140 .iter()
141 .map(|p| p.abi_str(engines, ctx, false))
142 .collect::<Vec<_>>()
143 .join(",")
144 )
145 };
146 format!(
147 "enum {}{}",
148 call_path_display(ctx, &decl.call_path),
149 type_params
150 )
151 }
152 Struct(decl_ref) => {
153 let decl = decl_engine.get_struct(decl_ref);
154 let type_params = if (ctx.abi_root_type_without_generic_type_parameters && is_root)
155 || decl.type_parameters.is_empty()
156 {
157 "".into()
158 } else {
159 format!(
160 "<{}>",
161 decl.type_parameters
162 .iter()
163 .map(|p| p.abi_str(engines, ctx, false))
164 .collect::<Vec<_>>()
165 .join(",")
166 )
167 };
168 format!(
169 "struct {}{}",
170 call_path_display(ctx, &decl.call_path),
171 type_params
172 )
173 }
174 ContractCaller { abi_name, .. } => {
175 format!("contract caller {abi_name}")
176 }
177 Array(elem_ty, length) => {
178 format!(
179 "[{}; {:?}]",
180 elem_ty.abi_str(ctx, engines, false),
181 engines.help_out(length)
182 )
183 }
184 RawUntypedPtr => "raw untyped ptr".into(),
185 RawUntypedSlice => "raw untyped slice".into(),
186 Ptr(ty) => {
187 format!("__ptr {}", ty.abi_str(ctx, engines, false))
188 }
189 Slice(ty) => {
190 format!("__slice {}", ty.abi_str(ctx, engines, false))
191 }
192 Alias { ty, .. } => ty.abi_str(ctx, engines, false),
193 TraitType {
194 name,
195 trait_type_id: _,
196 } => format!("trait type {}", name),
197 Ref {
198 to_mutable_value,
199 referenced_type,
200 } => {
201 format!(
202 "__ref {}{}", if *to_mutable_value { "mut " } else { "" },
204 referenced_type.abi_str(ctx, engines, false)
205 )
206 }
207 }
208 }
209}
210
211fn call_path_display(ctx: &AbiStrContext, call_path: &CallPath) -> String {
214 if !ctx.abi_with_callpaths {
215 return call_path.suffix.as_str().to_string();
216 }
217 let mut buf = String::new();
218 for (index, prefix) in call_path.prefixes.iter().enumerate() {
219 if index == 0 && prefix.as_str() == ctx.program_name {
220 continue;
221 }
222 buf.push_str(prefix.as_str());
223 buf.push_str("::");
224 }
225 buf.push_str(&call_path.suffix.to_string());
226
227 buf
228}
229
230impl GenericArgument {
231 pub(self) fn abi_str(&self, ctx: &AbiStrContext, engines: &Engines, is_root: bool) -> String {
232 engines
233 .te()
234 .get(self.type_id())
235 .abi_str(ctx, engines, is_root)
236 }
237}