use crate::types::CoreTypeId;
use crate::{
BinaryReaderError, FuncType, GlobalType, HeapType, MemoryType, RefType, TableType, ValType,
WasmFeatures,
};
use std::ops::Range;
pub trait WasmFuncType: Clone {
fn len_inputs(&self) -> usize;
fn len_outputs(&self) -> usize;
fn input_at(&self, at: u32) -> Option<ValType>;
fn output_at(&self, at: u32) -> Option<ValType>;
fn inputs(&self) -> WasmFuncTypeInputs<'_, Self>
where
Self: Sized,
{
let range = 0..self.len_inputs() as u32;
WasmFuncTypeInputs {
func_type: self,
range,
}
}
fn outputs(&self) -> WasmFuncTypeOutputs<'_, Self>
where
Self: Sized,
{
let range = 0..self.len_outputs() as u32;
WasmFuncTypeOutputs {
func_type: self,
range,
}
}
}
impl<T> WasmFuncType for &'_ T
where
T: ?Sized + WasmFuncType,
{
fn len_inputs(&self) -> usize {
T::len_inputs(self)
}
fn len_outputs(&self) -> usize {
T::len_outputs(self)
}
fn input_at(&self, at: u32) -> Option<ValType> {
T::input_at(self, at)
}
fn output_at(&self, at: u32) -> Option<ValType> {
T::output_at(self, at)
}
}
#[derive(Clone)]
pub struct WasmFuncTypeInputs<'a, T> {
func_type: &'a T,
range: Range<u32>,
}
impl<T> Iterator for WasmFuncTypeInputs<'_, T>
where
T: WasmFuncType,
{
type Item = crate::ValType;
fn next(&mut self) -> Option<Self::Item> {
self.range
.next()
.map(|i| self.func_type.input_at(i).unwrap())
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
}
impl<T> DoubleEndedIterator for WasmFuncTypeInputs<'_, T>
where
T: WasmFuncType,
{
fn next_back(&mut self) -> Option<Self::Item> {
self.range
.next_back()
.map(|i| self.func_type.input_at(i).unwrap())
}
}
impl<T> ExactSizeIterator for WasmFuncTypeInputs<'_, T>
where
T: WasmFuncType,
{
fn len(&self) -> usize {
self.range.len()
}
}
#[derive(Clone)]
pub struct WasmFuncTypeOutputs<'a, T> {
func_type: &'a T,
range: Range<u32>,
}
impl<T> Iterator for WasmFuncTypeOutputs<'_, T>
where
T: WasmFuncType,
{
type Item = crate::ValType;
fn next(&mut self) -> Option<Self::Item> {
self.range
.next()
.map(|i| self.func_type.output_at(i).unwrap())
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
}
impl<T> DoubleEndedIterator for WasmFuncTypeOutputs<'_, T>
where
T: WasmFuncType,
{
fn next_back(&mut self) -> Option<Self::Item> {
self.range
.next_back()
.map(|i| self.func_type.output_at(i).unwrap())
}
}
impl<T> ExactSizeIterator for WasmFuncTypeOutputs<'_, T>
where
T: WasmFuncType,
{
fn len(&self) -> usize {
self.range.len()
}
}
pub trait WasmModuleResources {
type FuncType: WasmFuncType;
fn table_at(&self, at: u32) -> Option<TableType>;
fn memory_at(&self, at: u32) -> Option<MemoryType>;
fn tag_at(&self, at: u32) -> Option<&Self::FuncType>;
fn global_at(&self, at: u32) -> Option<GlobalType>;
fn func_type_at(&self, type_idx: u32) -> Option<&Self::FuncType>;
fn type_id_of_function(&self, func_idx: u32) -> Option<CoreTypeId>;
fn type_of_function(&self, func_idx: u32) -> Option<&Self::FuncType>;
fn element_type_at(&self, at: u32) -> Option<RefType>;
fn is_subtype(&self, a: ValType, b: ValType) -> bool;
fn check_value_type(
&self,
t: &mut ValType,
features: &WasmFeatures,
offset: usize,
) -> Result<(), BinaryReaderError> {
features
.check_value_type(*t)
.map_err(|s| BinaryReaderError::new(s, offset))?;
match t {
ValType::Ref(r) => {
let nullable = r.is_nullable();
let mut hty = r.heap_type();
self.check_heap_type(&mut hty, offset)?;
*r = RefType::new(nullable, hty).unwrap();
Ok(())
}
ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => Ok(()),
}
}
fn check_heap_type(
&self,
heap_type: &mut HeapType,
offset: usize,
) -> Result<(), BinaryReaderError>;
fn element_count(&self) -> u32;
fn data_count(&self) -> Option<u32>;
fn is_function_referenced(&self, idx: u32) -> bool;
}
impl<T> WasmModuleResources for &'_ T
where
T: ?Sized + WasmModuleResources,
{
type FuncType = T::FuncType;
fn table_at(&self, at: u32) -> Option<TableType> {
T::table_at(self, at)
}
fn memory_at(&self, at: u32) -> Option<MemoryType> {
T::memory_at(self, at)
}
fn tag_at(&self, at: u32) -> Option<&Self::FuncType> {
T::tag_at(self, at)
}
fn global_at(&self, at: u32) -> Option<GlobalType> {
T::global_at(self, at)
}
fn func_type_at(&self, at: u32) -> Option<&Self::FuncType> {
T::func_type_at(self, at)
}
fn type_id_of_function(&self, func_idx: u32) -> Option<CoreTypeId> {
T::type_id_of_function(self, func_idx)
}
fn type_of_function(&self, func_idx: u32) -> Option<&Self::FuncType> {
T::type_of_function(self, func_idx)
}
fn check_heap_type(&self, t: &mut HeapType, offset: usize) -> Result<(), BinaryReaderError> {
T::check_heap_type(self, t, offset)
}
fn element_type_at(&self, at: u32) -> Option<RefType> {
T::element_type_at(self, at)
}
fn is_subtype(&self, a: ValType, b: ValType) -> bool {
T::is_subtype(self, a, b)
}
fn element_count(&self) -> u32 {
T::element_count(self)
}
fn data_count(&self) -> Option<u32> {
T::data_count(self)
}
fn is_function_referenced(&self, idx: u32) -> bool {
T::is_function_referenced(self, idx)
}
}
impl<T> WasmModuleResources for std::sync::Arc<T>
where
T: WasmModuleResources,
{
type FuncType = T::FuncType;
fn table_at(&self, at: u32) -> Option<TableType> {
T::table_at(self, at)
}
fn memory_at(&self, at: u32) -> Option<MemoryType> {
T::memory_at(self, at)
}
fn tag_at(&self, at: u32) -> Option<&Self::FuncType> {
T::tag_at(self, at)
}
fn global_at(&self, at: u32) -> Option<GlobalType> {
T::global_at(self, at)
}
fn func_type_at(&self, type_idx: u32) -> Option<&Self::FuncType> {
T::func_type_at(self, type_idx)
}
fn type_id_of_function(&self, func_idx: u32) -> Option<CoreTypeId> {
T::type_id_of_function(self, func_idx)
}
fn type_of_function(&self, func_idx: u32) -> Option<&Self::FuncType> {
T::type_of_function(self, func_idx)
}
fn check_heap_type(&self, t: &mut HeapType, offset: usize) -> Result<(), BinaryReaderError> {
T::check_heap_type(self, t, offset)
}
fn element_type_at(&self, at: u32) -> Option<RefType> {
T::element_type_at(self, at)
}
fn is_subtype(&self, a: ValType, b: ValType) -> bool {
T::is_subtype(self, a, b)
}
fn element_count(&self) -> u32 {
T::element_count(self)
}
fn data_count(&self) -> Option<u32> {
T::data_count(self)
}
fn is_function_referenced(&self, idx: u32) -> bool {
T::is_function_referenced(self, idx)
}
}
impl WasmFuncType for FuncType {
fn len_inputs(&self) -> usize {
self.params().len()
}
fn len_outputs(&self) -> usize {
self.results().len()
}
fn input_at(&self, at: u32) -> Option<ValType> {
self.params().get(at as usize).copied()
}
fn output_at(&self, at: u32) -> Option<ValType> {
self.results().get(at as usize).copied()
}
}