use std::fmt;
use wasmtime_environ::{EntityType, Global, Memory, ModuleTypes, Table, WasmFuncType, WasmType};
pub(crate) mod matching;
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
pub enum Mutability {
Const,
Var,
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum ValType {
I32,
I64,
F32,
F64,
V128,
FuncRef,
ExternRef,
}
impl fmt::Display for ValType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ValType::I32 => write!(f, "i32"),
ValType::I64 => write!(f, "i64"),
ValType::F32 => write!(f, "f32"),
ValType::F64 => write!(f, "f64"),
ValType::V128 => write!(f, "v128"),
ValType::ExternRef => write!(f, "externref"),
ValType::FuncRef => write!(f, "funcref"),
}
}
}
impl ValType {
pub fn is_num(&self) -> bool {
match self {
ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => true,
_ => false,
}
}
pub fn is_ref(&self) -> bool {
match self {
ValType::ExternRef | ValType::FuncRef => true,
_ => false,
}
}
pub(crate) fn to_wasm_type(&self) -> WasmType {
match self {
Self::I32 => WasmType::I32,
Self::I64 => WasmType::I64,
Self::F32 => WasmType::F32,
Self::F64 => WasmType::F64,
Self::V128 => WasmType::V128,
Self::FuncRef => WasmType::FuncRef,
Self::ExternRef => WasmType::ExternRef,
}
}
pub(crate) fn from_wasm_type(ty: &WasmType) -> Self {
match ty {
WasmType::I32 => Self::I32,
WasmType::I64 => Self::I64,
WasmType::F32 => Self::F32,
WasmType::F64 => Self::F64,
WasmType::V128 => Self::V128,
WasmType::FuncRef => Self::FuncRef,
WasmType::ExternRef => Self::ExternRef,
}
}
}
#[derive(Debug, Clone)]
pub enum ExternType {
Func(FuncType),
Global(GlobalType),
Table(TableType),
Memory(MemoryType),
}
macro_rules! accessors {
($(($variant:ident($ty:ty) $get:ident $unwrap:ident))*) => ($(
/// Attempt to return the underlying type of this external type,
/// returning `None` if it is a different type.
pub fn $get(&self) -> Option<&$ty> {
if let ExternType::$variant(e) = self {
Some(e)
} else {
None
}
}
pub fn $unwrap(&self) -> &$ty {
self.$get().expect(concat!("expected ", stringify!($ty)))
}
)*)
}
impl ExternType {
accessors! {
(Func(FuncType) func unwrap_func)
(Global(GlobalType) global unwrap_global)
(Table(TableType) table unwrap_table)
(Memory(MemoryType) memory unwrap_memory)
}
pub(crate) fn from_wasmtime(types: &ModuleTypes, ty: &EntityType) -> ExternType {
match ty {
EntityType::Function(idx) => FuncType::from_wasm_func_type(types[*idx].clone()).into(),
EntityType::Global(ty) => GlobalType::from_wasmtime_global(ty).into(),
EntityType::Memory(ty) => MemoryType::from_wasmtime_memory(ty).into(),
EntityType::Table(ty) => TableType::from_wasmtime_table(ty).into(),
EntityType::Tag(_) => unimplemented!("wasm tag support"),
}
}
}
impl From<FuncType> for ExternType {
fn from(ty: FuncType) -> ExternType {
ExternType::Func(ty)
}
}
impl From<GlobalType> for ExternType {
fn from(ty: GlobalType) -> ExternType {
ExternType::Global(ty)
}
}
impl From<MemoryType> for ExternType {
fn from(ty: MemoryType) -> ExternType {
ExternType::Memory(ty)
}
}
impl From<TableType> for ExternType {
fn from(ty: TableType) -> ExternType {
ExternType::Table(ty)
}
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct FuncType {
sig: WasmFuncType,
}
impl FuncType {
pub fn new(
params: impl IntoIterator<Item = ValType>,
results: impl IntoIterator<Item = ValType>,
) -> FuncType {
FuncType {
sig: WasmFuncType::new(
params.into_iter().map(|t| t.to_wasm_type()).collect(),
results.into_iter().map(|t| t.to_wasm_type()).collect(),
),
}
}
#[inline]
pub fn params(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
self.sig.params().iter().map(ValType::from_wasm_type)
}
#[inline]
pub fn results(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
self.sig.returns().iter().map(ValType::from_wasm_type)
}
pub(crate) fn as_wasm_func_type(&self) -> &WasmFuncType {
&self.sig
}
pub(crate) fn from_wasm_func_type(sig: WasmFuncType) -> FuncType {
Self { sig }
}
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct GlobalType {
content: ValType,
mutability: Mutability,
}
impl GlobalType {
pub fn new(content: ValType, mutability: Mutability) -> GlobalType {
GlobalType {
content,
mutability,
}
}
pub fn content(&self) -> &ValType {
&self.content
}
pub fn mutability(&self) -> Mutability {
self.mutability
}
pub(crate) fn from_wasmtime_global(global: &Global) -> GlobalType {
let ty = ValType::from_wasm_type(&global.wasm_ty);
let mutability = if global.mutability {
Mutability::Var
} else {
Mutability::Const
};
GlobalType::new(ty, mutability)
}
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct TableType {
ty: Table,
}
impl TableType {
pub fn new(element: ValType, min: u32, max: Option<u32>) -> TableType {
TableType {
ty: Table {
wasm_ty: element.to_wasm_type(),
minimum: min,
maximum: max,
},
}
}
pub fn element(&self) -> ValType {
ValType::from_wasm_type(&self.ty.wasm_ty)
}
pub fn minimum(&self) -> u32 {
self.ty.minimum
}
pub fn maximum(&self) -> Option<u32> {
self.ty.maximum
}
pub(crate) fn from_wasmtime_table(table: &Table) -> TableType {
TableType { ty: table.clone() }
}
pub(crate) fn wasmtime_table(&self) -> &Table {
&self.ty
}
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct MemoryType {
ty: Memory,
}
impl MemoryType {
pub fn new(minimum: u32, maximum: Option<u32>) -> MemoryType {
MemoryType {
ty: Memory {
memory64: false,
shared: false,
minimum: minimum.into(),
maximum: maximum.map(|i| i.into()),
},
}
}
pub fn new64(minimum: u64, maximum: Option<u64>) -> MemoryType {
MemoryType {
ty: Memory {
memory64: true,
shared: false,
minimum,
maximum,
},
}
}
pub fn shared(minimum: u32, maximum: u32) -> MemoryType {
MemoryType {
ty: Memory {
memory64: false,
shared: true,
minimum: minimum.into(),
maximum: Some(maximum.into()),
},
}
}
pub fn is_64(&self) -> bool {
self.ty.memory64
}
pub fn is_shared(&self) -> bool {
self.ty.shared
}
pub fn minimum(&self) -> u64 {
self.ty.minimum
}
pub fn maximum(&self) -> Option<u64> {
self.ty.maximum
}
pub(crate) fn from_wasmtime_memory(memory: &Memory) -> MemoryType {
MemoryType { ty: memory.clone() }
}
pub(crate) fn wasmtime_memory(&self) -> &Memory {
&self.ty
}
}
#[derive(Clone)]
pub struct ImportType<'module> {
module: &'module str,
name: &'module str,
ty: EntityType,
types: &'module ModuleTypes,
}
impl<'module> ImportType<'module> {
pub(crate) fn new(
module: &'module str,
name: &'module str,
ty: EntityType,
types: &'module ModuleTypes,
) -> ImportType<'module> {
ImportType {
module,
name,
ty,
types,
}
}
pub fn module(&self) -> &'module str {
self.module
}
pub fn name(&self) -> &'module str {
self.name
}
pub fn ty(&self) -> ExternType {
ExternType::from_wasmtime(self.types, &self.ty)
}
}
impl<'module> fmt::Debug for ImportType<'module> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ImportType")
.field("module", &self.module())
.field("name", &self.name())
.field("ty", &self.ty())
.finish()
}
}
#[derive(Clone)]
pub struct ExportType<'module> {
name: &'module str,
ty: EntityType,
types: &'module ModuleTypes,
}
impl<'module> ExportType<'module> {
pub(crate) fn new(
name: &'module str,
ty: EntityType,
types: &'module ModuleTypes,
) -> ExportType<'module> {
ExportType { name, ty, types }
}
pub fn name(&self) -> &'module str {
self.name
}
pub fn ty(&self) -> ExternType {
ExternType::from_wasmtime(self.types, &self.ty)
}
}
impl<'module> fmt::Debug for ExportType<'module> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ExportType")
.field("name", &self.name().to_owned())
.field("ty", &self.ty())
.finish()
}
}