#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StructFieldMetadata {
pub name: String,
pub ty: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StructTypeMetadata {
pub name: String,
pub fields: Vec<StructFieldMetadata>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumTypeMetadata {
pub name: String,
pub variants: usize,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NeoType {
Integer { signed: bool, bits: u16 },
Boolean,
String,
Address,
ByteArray { fixed_len: Option<u16> },
Array(Box<NeoType>, Option<usize>),
Mapping { key: Box<NeoType>, value: Box<NeoType> },
Struct { name: String, fields: Vec<StructFieldType> },
Any,
}
impl NeoType {
pub fn uint256() -> Self {
Self::Integer { signed: false, bits: 256 }
}
pub fn int256() -> Self {
Self::Integer { signed: true, bits: 256 }
}
pub fn bytes_fixed(len: u16) -> Self {
Self::ByteArray { fixed_len: Some(len) }
}
pub fn bytes_dynamic() -> Self {
Self::ByteArray { fixed_len: None }
}
pub fn is_value_type(&self) -> bool {
matches!(self, Self::Integer { .. } | Self::Boolean | Self::Address)
}
pub fn is_reference_type(&self) -> bool {
matches!(self, Self::Array(..) | Self::Mapping { .. } | Self::Struct { .. })
}
pub fn storage_size(&self) -> Option<usize> {
match self {
Self::Integer { bits, .. } => Some((*bits as usize).div_ceil(8)),
Self::Boolean => Some(1),
Self::Address => Some(20),
Self::ByteArray { fixed_len: Some(len) } => Some(*len as usize),
_ => None,
}
}
pub fn type_name(&self) -> String {
match self {
Self::Integer { signed: true, bits } => format!("int{bits}"),
Self::Integer { signed: false, bits } => format!("uint{bits}"),
Self::Boolean => "bool".to_string(),
Self::String => "string".to_string(),
Self::Address => "address".to_string(),
Self::ByteArray { fixed_len: Some(n) } => format!("bytes{n}"),
Self::ByteArray { fixed_len: None } => "bytes".to_string(),
Self::Array(inner, Some(n)) => format!("{}[{}]", inner.type_name(), n),
Self::Array(inner, None) => format!("{}[]", inner.type_name()),
Self::Mapping { key, value } => {
format!("mapping({} => {})", key.type_name(), value.type_name())
}
Self::Struct { name, .. } => name.clone(),
Self::Any => "any".to_string(),
}
}
pub fn canonical_abi_type(&self) -> String {
match self {
Self::Integer { signed: true, bits } => format!("int{bits}"),
Self::Integer { signed: false, bits } => format!("uint{bits}"),
Self::Boolean => "bool".to_string(),
Self::String => "string".to_string(),
Self::Address => "address".to_string(),
Self::ByteArray { fixed_len: Some(n) } => format!("bytes{n}"),
Self::ByteArray { fixed_len: None } => "bytes".to_string(),
Self::Array(inner, Some(n)) => format!("{}[{}]", inner.canonical_abi_type(), n),
Self::Array(inner, None) => format!("{}[]", inner.canonical_abi_type()),
Self::Struct { fields, .. } => {
let parts: Vec<String> =
fields.iter().map(|f| f.ty.canonical_abi_type()).collect();
format!("({})", parts.join(","))
}
Self::Mapping { key, value } => format!(
"mapping({} => {})",
key.canonical_abi_type(),
value.canonical_abi_type()
),
Self::Any => "bytes".to_string(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StructFieldType {
pub name: String,
pub ty: Box<NeoType>,
}
#[derive(Debug, Error)]
pub enum TypeParseError {
#[error("unsupported Solidity type '{0}'")]
Unsupported(String),
#[error("fixed-point types are not supported on NeoVM: '{0}'")]
FixedPoint(String),
}