use crate::error::Result;
use crate::tombstone_arena::Tombstone;
use anyhow::bail;
use id_arena::Id;
use std::cmp::Ordering;
use std::fmt;
use std::hash;
pub type TypeId = Id<Type>;
#[derive(Debug, Clone)]
pub struct Type {
id: TypeId,
params: Box<[ValType]>,
results: Box<[ValType]>,
is_for_function_entry: bool,
pub name: Option<String>,
}
impl PartialEq for Type {
#[inline]
fn eq(&self, rhs: &Type) -> bool {
self.params == rhs.params
&& self.results == rhs.results
&& self.is_for_function_entry == rhs.is_for_function_entry
}
}
impl Eq for Type {}
impl PartialOrd for Type {
fn partial_cmp(&self, rhs: &Type) -> Option<Ordering> {
Some(self.cmp(rhs))
}
}
impl Ord for Type {
fn cmp(&self, rhs: &Type) -> Ordering {
self.params()
.cmp(rhs.params())
.then_with(|| self.results().cmp(rhs.results()))
}
}
impl hash::Hash for Type {
#[inline]
fn hash<H: hash::Hasher>(&self, h: &mut H) {
self.params.hash(h);
self.results.hash(h);
self.is_for_function_entry.hash(h);
}
}
impl Tombstone for Type {
fn on_delete(&mut self) {
self.params = Box::new([]);
self.results = Box::new([]);
}
}
impl Type {
#[inline]
pub(crate) fn new(id: TypeId, params: Box<[ValType]>, results: Box<[ValType]>) -> Type {
Type {
id,
params,
results,
is_for_function_entry: false,
name: None,
}
}
#[inline]
pub(crate) fn for_function_entry(id: TypeId, results: Box<[ValType]>) -> Type {
let params = vec![].into();
Type {
id,
params,
results,
is_for_function_entry: true,
name: None,
}
}
#[inline]
pub fn id(&self) -> TypeId {
self.id
}
#[inline]
pub fn params(&self) -> &[ValType] {
&*self.params
}
#[inline]
pub fn results(&self) -> &[ValType] {
&*self.results
}
pub(crate) fn is_for_function_entry(&self) -> bool {
self.is_for_function_entry
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum ValType {
I32,
I64,
F32,
F64,
V128,
Externref,
Funcref,
}
impl ValType {
pub(crate) fn from_wasmparser_type(ty: wasmparser::Type) -> Result<Box<[ValType]>> {
let v = match ty {
wasmparser::Type::EmptyBlockType => Vec::new(),
_ => vec![ValType::parse(&ty)?],
};
Ok(v.into_boxed_slice())
}
pub(crate) fn to_wasmencoder_type(&self) -> wasm_encoder::ValType {
match self {
ValType::I32 => wasm_encoder::ValType::I32,
ValType::I64 => wasm_encoder::ValType::I64,
ValType::F32 => wasm_encoder::ValType::F32,
ValType::F64 => wasm_encoder::ValType::F64,
ValType::V128 => wasm_encoder::ValType::V128,
ValType::Externref => wasm_encoder::ValType::Ref(wasm_encoder::RefType::EXTERNREF),
ValType::Funcref => wasm_encoder::ValType::Ref(wasm_encoder::RefType::FUNCREF),
}
}
pub(crate) fn parse(input: &wasmparser::Type) -> Result<ValType> {
match input {
wasmparser::Type::I32 => Ok(ValType::I32),
wasmparser::Type::I64 => Ok(ValType::I64),
wasmparser::Type::F32 => Ok(ValType::F32),
wasmparser::Type::F64 => Ok(ValType::F64),
wasmparser::Type::V128 => Ok(ValType::V128),
wasmparser::Type::ExternRef => Ok(ValType::Externref),
wasmparser::Type::FuncRef => Ok(ValType::Funcref),
_ => bail!("not a value type"),
}
}
}
impl fmt::Display for ValType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
ValType::I32 => "i32",
ValType::I64 => "i64",
ValType::F32 => "f32",
ValType::F64 => "f64",
ValType::V128 => "v128",
ValType::Externref => "externref",
ValType::Funcref => "funcref",
}
)
}
}