1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use crate::{Val, ValType, core::CoreFuncType, errors::FuncError};
/// Types that are dynamically typed, such as [`ValType`].
pub trait DynamicallyTyped {
/// Returns the [`ValType`] of `self`.
fn ty(&self) -> ValType;
}
impl DynamicallyTyped for ValType {
fn ty(&self) -> ValType {
*self
}
}
impl DynamicallyTyped for Val {
fn ty(&self) -> ValType {
self.ty()
}
}
/// A Wasm function descriptor.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FuncType {
core: CoreFuncType,
}
impl FuncType {
/// Creates a new [`FuncType`].
///
/// # Errors
///
/// If an out of bounds number of parameters or results are given.
pub fn new<P, R>(params: P, results: R) -> Self
where
P: IntoIterator,
R: IntoIterator,
<P as IntoIterator>::IntoIter: Iterator<Item = ValType> + ExactSizeIterator,
<R as IntoIterator>::IntoIter: Iterator<Item = ValType> + ExactSizeIterator,
{
let core = match CoreFuncType::new(params, results) {
Ok(func_type) => func_type,
Err(error) => panic!("failed to create function type: {error}"),
};
Self { core }
}
/// Returns the parameter types of the function type.
pub fn params(&self) -> &[ValType] {
self.core.params()
}
/// Returns the result types of the function type.
pub fn results(&self) -> &[ValType] {
self.core.results()
}
/// Returns the number of parameter types of the function type.
pub(crate) fn len_params(&self) -> u16 {
self.core.len_params()
}
/// Returns the number of result types of the function type.
pub(crate) fn len_results(&self) -> u16 {
self.core.len_results()
}
/// Returns `Ok` if the number and types of items in `params` matches as expected by the [`FuncType`].
///
/// # Errors
///
/// - If the number of items in `params` does not match the number of parameters of the function type.
/// - If any type of an item in `params` does not match the expected type of the function type.
pub(crate) fn match_params<T>(&self, params: &[T]) -> Result<(), FuncError>
where
T: DynamicallyTyped,
{
if self.params().len() != params.len() {
return Err(FuncError::MismatchingParameterLen);
}
if self
.params()
.iter()
.copied()
.ne(params.iter().map(<T as DynamicallyTyped>::ty))
{
return Err(FuncError::MismatchingParameterType);
}
Ok(())
}
/// Returns `Ok` if the number and types of items in `results` matches as expected by the [`FuncType`].
///
/// # Note
///
/// Only checks types if `check_type` is set to `true`.
///
/// # Errors
///
/// - If the number of items in `results` does not match the number of results of the function type.
/// - If any type of an item in `results` does not match the expected type of the function type.
pub(crate) fn match_results<T>(&self, results: &[T]) -> Result<(), FuncError>
where
T: DynamicallyTyped,
{
if self.results().len() != results.len() {
return Err(FuncError::MismatchingResultLen);
}
if self
.results()
.iter()
.copied()
.ne(results.iter().map(<T as DynamicallyTyped>::ty))
{
return Err(FuncError::MismatchingResultType);
}
Ok(())
}
/// Initializes the values in `outputs` to match the types expected by the [`FuncType`].
///
/// # Note
///
/// This is required by an implementation detail of how function result passing is current
/// implemented in the Wasmi execution engine and might change in the future.
///
/// # Errors
///
/// If the number of items in `outputs` does not match the number of results of the [`FuncType`].
pub(crate) fn prepare_outputs(&self, outputs: &mut [Val]) -> Result<(), FuncError> {
if self.results().len() != outputs.len() {
return Err(FuncError::MismatchingResultLen);
}
for (output, result_ty) in outputs.iter_mut().zip(self.results()) {
*output = Val::default_for_ty(*result_ty);
}
Ok(())
}
}