sway_core/abi_generation/
abi_str.rsuse sway_types::integer_bits::IntegerBits;
use crate::{language::CallPath, Engines, TypeArgument, TypeId, TypeInfo};
#[derive(Clone)]
pub struct AbiStrContext {
pub program_name: String,
pub abi_with_callpaths: bool,
pub abi_with_fully_specified_types: bool,
pub abi_root_type_without_generic_type_parameters: bool,
}
impl TypeId {
pub fn get_abi_type_str(
&self,
ctx: &AbiStrContext,
engines: &Engines,
resolved_type_id: TypeId,
) -> String {
let type_engine = engines.te();
let self_abi_str = type_engine.get(*self).abi_str(ctx, engines, true);
if self.is_generic_parameter(engines, resolved_type_id) {
format!("generic {}", self_abi_str)
} else {
match (
&*type_engine.get(*self),
&*type_engine.get(resolved_type_id),
) {
(TypeInfo::Custom { .. }, TypeInfo::Struct { .. })
| (TypeInfo::Custom { .. }, TypeInfo::Enum { .. }) => type_engine
.get(resolved_type_id)
.abi_str(ctx, engines, true),
(_, TypeInfo::Alias { ty, .. }) => {
ty.type_id.get_abi_type_str(ctx, engines, ty.type_id)
}
(TypeInfo::Tuple(fields), TypeInfo::Tuple(resolved_fields)) => {
assert_eq!(fields.len(), resolved_fields.len());
let field_strs = resolved_fields
.iter()
.map(|f| {
if ctx.abi_with_fully_specified_types {
type_engine.get(f.type_id).abi_str(ctx, engines, false)
} else {
"_".to_string()
}
})
.collect::<Vec<String>>();
format!("({})", field_strs.join(", "))
}
(TypeInfo::Array(_, count), TypeInfo::Array(type_arg, resolved_count)) => {
assert_eq!(count.val(), resolved_count.val());
let inner_type = if ctx.abi_with_fully_specified_types {
type_engine
.get(type_arg.type_id)
.abi_str(ctx, engines, false)
} else {
"_".to_string()
};
format!("[{}; {}]", inner_type, count.val())
}
(TypeInfo::Slice(type_arg), TypeInfo::Slice(_)) => {
let inner_type = if ctx.abi_with_fully_specified_types {
type_engine
.get(type_arg.type_id)
.abi_str(ctx, engines, false)
} else {
"_".to_string()
};
format!("[{}]", inner_type)
}
(TypeInfo::Custom { .. }, _) => {
format!("generic {}", self_abi_str)
}
_ => type_engine
.get(resolved_type_id)
.abi_str(ctx, engines, true),
}
}
}
}
impl TypeInfo {
pub fn abi_str(&self, ctx: &AbiStrContext, engines: &Engines, is_root: bool) -> String {
use TypeInfo::*;
let decl_engine = engines.de();
let type_engine = engines.te();
match self {
Unknown => "unknown".into(),
Never => "never".into(),
UnknownGeneric { name, .. } => name.to_string(),
Placeholder(_) => "_".to_string(),
TypeParam(n) => format!("typeparam({n})"),
StringSlice => "str".into(),
StringArray(x) => format!("str[{}]", x.val()),
UnsignedInteger(x) => match x {
IntegerBits::Eight => "u8",
IntegerBits::Sixteen => "u16",
IntegerBits::ThirtyTwo => "u32",
IntegerBits::SixtyFour => "u64",
IntegerBits::V256 => "u256",
}
.into(),
Boolean => "bool".into(),
Custom {
qualified_call_path: call_path,
..
} => call_path.call_path.suffix.to_string(),
Tuple(fields) => {
let field_strs = fields
.iter()
.map(|field| field.abi_str(ctx, engines, false))
.collect::<Vec<String>>();
format!("({})", field_strs.join(", "))
}
B256 => "b256".into(),
Numeric => "u64".into(), Contract => "contract".into(),
ErrorRecovery(_) => "unknown due to error".into(),
UntypedEnum(decl_id) => {
let decl = engines.pe().get_enum(decl_id);
format!("untyped enum {}", decl.name)
}
UntypedStruct(decl_id) => {
let decl = engines.pe().get_struct(decl_id);
format!("untyped struct {}", decl.name)
}
Enum(decl_ref) => {
let decl = decl_engine.get_enum(decl_ref);
let type_params = if (ctx.abi_root_type_without_generic_type_parameters && is_root)
|| decl.type_parameters.is_empty()
{
"".into()
} else {
format!(
"<{}>",
decl.type_parameters
.iter()
.map(|p| type_engine.get(p.type_id).abi_str(ctx, engines, false))
.collect::<Vec<_>>()
.join(",")
)
};
format!(
"enum {}{}",
call_path_display(ctx, &decl.call_path),
type_params
)
}
Struct(decl_ref) => {
let decl = decl_engine.get_struct(decl_ref);
let type_params = if (ctx.abi_root_type_without_generic_type_parameters && is_root)
|| decl.type_parameters.is_empty()
{
"".into()
} else {
format!(
"<{}>",
decl.type_parameters
.iter()
.map(|p| type_engine.get(p.type_id).abi_str(ctx, engines, false))
.collect::<Vec<_>>()
.join(",")
)
};
format!(
"struct {}{}",
call_path_display(ctx, &decl.call_path),
type_params
)
}
ContractCaller { abi_name, .. } => {
format!("contract caller {abi_name}")
}
Array(elem_ty, length) => {
format!(
"[{}; {}]",
elem_ty.abi_str(ctx, engines, false),
length.val()
)
}
RawUntypedPtr => "raw untyped ptr".into(),
RawUntypedSlice => "raw untyped slice".into(),
Ptr(ty) => {
format!("__ptr {}", ty.abi_str(ctx, engines, false))
}
Slice(ty) => {
format!("__slice {}", ty.abi_str(ctx, engines, false))
}
Alias { ty, .. } => ty.abi_str(ctx, engines, false),
TraitType {
name,
trait_type_id: _,
} => format!("trait type {}", name),
Ref {
to_mutable_value,
referenced_type,
} => {
format!(
"__ref {}{}", if *to_mutable_value { "mut " } else { "" },
referenced_type.abi_str(ctx, engines, false)
)
}
}
}
}
fn call_path_display(ctx: &AbiStrContext, call_path: &CallPath) -> String {
if !ctx.abi_with_callpaths {
return call_path.suffix.as_str().to_string();
}
let mut buf = String::new();
for (index, prefix) in call_path.prefixes.iter().enumerate() {
if index == 0 && prefix.as_str() == ctx.program_name {
continue;
}
buf.push_str(prefix.as_str());
buf.push_str("::");
}
buf.push_str(&call_path.suffix.to_string());
buf
}
impl TypeArgument {
pub(self) fn abi_str(&self, ctx: &AbiStrContext, engines: &Engines, is_root: bool) -> String {
engines
.te()
.get(self.type_id)
.abi_str(ctx, engines, is_root)
}
}