1use crate::{core::ValType, func::FuncError, Val};
2use core::fmt;
3use std::{sync::Arc, vec::Vec};
4
5#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
11pub struct FuncType {
12 inner: FuncTypeInner,
14}
15
16#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
18pub enum FuncTypeInner {
19 Inline {
21 len_params: u8,
23 len_results: u8,
25 params_results: [ValType; Self::INLINE_SIZE],
27 },
28 Big {
30 len_params: u32,
32 params_results: Arc<[ValType]>,
34 },
35}
36
37impl FuncTypeInner {
38 #[cfg(target_pointer_width = "32")]
44 const INLINE_SIZE: usize = 14;
45
46 #[cfg(target_pointer_width = "64")]
52 const INLINE_SIZE: usize = 21;
53
54 pub fn new<P, R>(params: P, results: R) -> Self
60 where
61 P: IntoIterator,
62 R: IntoIterator,
63 <P as IntoIterator>::IntoIter: Iterator<Item = ValType> + ExactSizeIterator,
64 <R as IntoIterator>::IntoIter: Iterator<Item = ValType> + ExactSizeIterator,
65 {
66 let mut params = params.into_iter();
67 let mut results = results.into_iter();
68 let len_params = params.len();
69 let len_results = results.len();
70 if let Some(small) = Self::try_new_small(&mut params, &mut results) {
71 return small;
72 }
73 let mut params_results = params.collect::<Vec<_>>();
74 let len_params = u32::try_from(params_results.len()).unwrap_or_else(|_| {
75 panic!("out of bounds parameters (={len_params}) and results (={len_results}) for FuncType")
76 });
77 params_results.extend(results);
78 Self::Big {
79 params_results: params_results.into(),
80 len_params,
81 }
82 }
83
84 pub fn try_new_small<P, R>(params: &mut P, results: &mut R) -> Option<Self>
91 where
92 P: Iterator<Item = ValType> + ExactSizeIterator,
93 R: Iterator<Item = ValType> + ExactSizeIterator,
94 {
95 let params = params.into_iter();
96 let results = results.into_iter();
97 let len_params = u8::try_from(params.len()).ok()?;
98 let len_results = u8::try_from(results.len()).ok()?;
99 let len = len_params.checked_add(len_results)?;
100 if usize::from(len) > Self::INLINE_SIZE {
101 return None;
102 }
103 let mut params_results = [ValType::I32; Self::INLINE_SIZE];
104 params_results
105 .iter_mut()
106 .zip(params.chain(results))
107 .for_each(|(cell, param_or_result)| {
108 *cell = param_or_result;
109 });
110 Some(Self::Inline {
111 len_params,
112 len_results,
113 params_results,
114 })
115 }
116
117 pub fn params(&self) -> &[ValType] {
119 match self {
120 FuncTypeInner::Inline {
121 len_params,
122 params_results,
123 ..
124 } => ¶ms_results[..usize::from(*len_params)],
125 FuncTypeInner::Big {
126 len_params,
127 params_results,
128 } => ¶ms_results[..(*len_params as usize)],
129 }
130 }
131
132 pub fn results(&self) -> &[ValType] {
134 match self {
135 FuncTypeInner::Inline {
136 len_params,
137 len_results,
138 params_results,
139 ..
140 } => {
141 let start_results = usize::from(*len_params);
142 let end_results = start_results + usize::from(*len_results);
143 ¶ms_results[start_results..end_results]
144 }
145 FuncTypeInner::Big {
146 len_params,
147 params_results,
148 } => ¶ms_results[(*len_params as usize)..],
149 }
150 }
151
152 pub fn len_results(&self) -> usize {
154 match self {
155 FuncTypeInner::Inline { len_results, .. } => usize::from(*len_results),
156 FuncTypeInner::Big {
157 len_params,
158 params_results,
159 } => {
160 let len_buffer = params_results.len();
161 let len_params = *len_params as usize;
162 len_buffer - len_params
163 }
164 }
165 }
166
167 pub(crate) fn params_results(&self) -> (&[ValType], &[ValType]) {
169 match self {
170 FuncTypeInner::Inline {
171 len_params,
172 len_results,
173 params_results,
174 } => {
175 let len_params = usize::from(*len_params);
176 let len_results = usize::from(*len_results);
177 params_results[..len_params + len_results].split_at(len_params)
178 }
179 FuncTypeInner::Big {
180 len_params,
181 params_results,
182 } => params_results.split_at(*len_params as usize),
183 }
184 }
185}
186
187#[test]
188fn size_of_func_type() {
189 #[cfg(target_pointer_width = "32")]
190 assert!(core::mem::size_of::<FuncTypeInner>() <= 16);
191 #[cfg(target_pointer_width = "64")]
192 assert!(core::mem::size_of::<FuncTypeInner>() <= 24);
193}
194
195impl fmt::Debug for FuncType {
196 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
197 f.debug_struct("FuncType")
198 .field("params", &self.params())
199 .field("results", &self.results())
200 .finish()
201 }
202}
203
204impl FuncType {
205 pub fn new<P, R>(params: P, results: R) -> Self
207 where
208 P: IntoIterator,
209 R: IntoIterator,
210 <P as IntoIterator>::IntoIter: Iterator<Item = ValType> + ExactSizeIterator,
211 <R as IntoIterator>::IntoIter: Iterator<Item = ValType> + ExactSizeIterator,
212 {
213 Self {
214 inner: FuncTypeInner::new(params, results),
215 }
216 }
217
218 pub fn params(&self) -> &[ValType] {
220 self.inner.params()
221 }
222
223 pub fn results(&self) -> &[ValType] {
225 self.inner.results()
226 }
227
228 pub fn len_results(&self) -> usize {
230 self.inner.len_results()
231 }
232
233 pub(crate) fn params_results(&self) -> (&[ValType], &[ValType]) {
235 self.inner.params_results()
236 }
237
238 pub(crate) fn match_params<T>(&self, params: &[T]) -> Result<(), FuncError>
245 where
246 T: Ty,
247 {
248 if self.params().len() != params.len() {
249 return Err(FuncError::MismatchingParameterLen);
250 }
251 if self
252 .params()
253 .iter()
254 .copied()
255 .ne(params.iter().map(<T as Ty>::ty))
256 {
257 return Err(FuncError::MismatchingParameterType);
258 }
259 Ok(())
260 }
261
262 pub(crate) fn match_results<T>(&self, results: &[T], check_type: bool) -> Result<(), FuncError>
273 where
274 T: Ty,
275 {
276 if self.results().len() != results.len() {
277 return Err(FuncError::MismatchingResultLen);
278 }
279 if check_type
280 && self
281 .results()
282 .iter()
283 .copied()
284 .ne(results.iter().map(<T as Ty>::ty))
285 {
286 return Err(FuncError::MismatchingResultType);
287 }
288 Ok(())
289 }
290
291 pub(crate) fn prepare_outputs(&self, outputs: &mut [Val]) {
302 assert_eq!(
303 self.results().len(),
304 outputs.len(),
305 "must have the same number of items in outputs as results of the function type"
306 );
307 let init_values = self.results().iter().copied().map(Val::default);
308 outputs
309 .iter_mut()
310 .zip(init_values)
311 .for_each(|(output, init)| *output = init);
312 }
313}
314
315pub(crate) trait Ty {
322 fn ty(&self) -> ValType;
323}
324
325impl Ty for ValType {
326 fn ty(&self) -> ValType {
327 *self
328 }
329}
330
331impl Ty for Val {
332 fn ty(&self) -> ValType {
333 self.ty()
334 }
335}
336
337#[cfg(test)]
338mod tests {
339 use super::*;
340
341 #[test]
342 fn new_empty_works() {
343 let ft = FuncType::new([], []);
344 assert!(ft.params().is_empty());
345 assert!(ft.results().is_empty());
346 assert_eq!(ft.params(), ft.params_results().0);
347 assert_eq!(ft.results(), ft.params_results().1);
348 }
349
350 #[test]
351 fn new_works() {
352 let types = [
353 &[ValType::I32][..],
354 &[ValType::I64][..],
355 &[ValType::F32][..],
356 &[ValType::F64][..],
357 &[ValType::I32, ValType::I32][..],
358 &[ValType::I32, ValType::I32, ValType::I32][..],
359 &[ValType::I32, ValType::I32, ValType::I32, ValType::I32][..],
360 &[
361 ValType::I32,
362 ValType::I32,
363 ValType::I32,
364 ValType::I32,
365 ValType::I32,
366 ValType::I32,
367 ValType::I32,
368 ValType::I32,
369 ][..],
370 &[ValType::I32, ValType::I64, ValType::F32, ValType::F64][..],
371 ];
372 for params in types {
373 for results in types {
374 let ft = FuncType::new(params.iter().copied(), results.iter().copied());
375 assert_eq!(ft.params(), params);
376 assert_eq!(ft.results(), results);
377 assert_eq!(ft.params(), ft.params_results().0);
378 assert_eq!(ft.results(), ft.params_results().1);
379 }
380 }
381 }
382}