1 use crate::{CExternType, wasm_externtype_t, wasm_valtype_t, wasm_valtype_vec_t};
2 use std::cell::OnceCell;
3 use std::{
4 mem,
5 sync::{Arc, Mutex},
6 };
7 use wasmtime::{Engine, FuncType, ValType};
8
9 #[repr(transparent)]
10 #[derive(Clone)]
11 pub struct wasm_functype_t {
12 ext: wasm_externtype_t,
13 }
14
15 wasmtime_c_api_macros::declare_ty!(wasm_functype_t);
16
17 #[derive(Clone)]
18 enum LazyFuncType {
19 Lazy {
20 params: Vec<ValType>,
21 results: Vec<ValType>,
22 },
23 FuncType(FuncType),
24 }
25
26 impl LazyFuncType {
force(&mut self, engine: &Engine) -> FuncType27 pub(crate) fn force(&mut self, engine: &Engine) -> FuncType {
28 match self {
29 LazyFuncType::FuncType(ty) => ty.clone(),
30 LazyFuncType::Lazy { params, results } => {
31 let params = mem::take(params);
32 let results = mem::take(results);
33 let ty = FuncType::new(engine, params, results);
34 *self = LazyFuncType::FuncType(ty.clone());
35 ty
36 }
37 }
38 }
39
params(&self) -> impl ExactSizeIterator<Item = ValType> + '_40 fn params(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
41 match self {
42 LazyFuncType::Lazy { params, .. } => LazyFuncTypeIter::Lazy(params.iter()),
43 LazyFuncType::FuncType(f) => LazyFuncTypeIter::FuncType(f.params()),
44 }
45 }
46
results(&self) -> impl ExactSizeIterator<Item = ValType> + '_47 fn results(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
48 match self {
49 LazyFuncType::Lazy { results, .. } => LazyFuncTypeIter::Lazy(results.iter()),
50 LazyFuncType::FuncType(f) => LazyFuncTypeIter::FuncType(f.results()),
51 }
52 }
53 }
54
55 enum LazyFuncTypeIter<'a, T> {
56 Lazy(std::slice::Iter<'a, ValType>),
57 FuncType(T),
58 }
59
60 impl<'a, T> Iterator for LazyFuncTypeIter<'a, T>
61 where
62 T: Iterator<Item = ValType>,
63 {
64 type Item = ValType;
65
next(&mut self) -> Option<Self::Item>66 fn next(&mut self) -> Option<Self::Item> {
67 match self {
68 LazyFuncTypeIter::FuncType(i) => i.next(),
69 LazyFuncTypeIter::Lazy(i) => i.next().cloned(),
70 }
71 }
72
size_hint(&self) -> (usize, Option<usize>)73 fn size_hint(&self) -> (usize, Option<usize>) {
74 match self {
75 LazyFuncTypeIter::FuncType(i) => i.size_hint(),
76 LazyFuncTypeIter::Lazy(i) => i.size_hint(),
77 }
78 }
79 }
80
81 impl<'a, T> ExactSizeIterator for LazyFuncTypeIter<'a, T> where T: ExactSizeIterator<Item = ValType> {}
82
83 #[derive(Clone)]
84 pub(crate) struct CFuncType {
85 ty: Arc<Mutex<LazyFuncType>>,
86 params_cache: OnceCell<wasm_valtype_vec_t>,
87 returns_cache: OnceCell<wasm_valtype_vec_t>,
88 }
89
90 impl wasm_functype_t {
new(ty: FuncType) -> wasm_functype_t91 pub(crate) fn new(ty: FuncType) -> wasm_functype_t {
92 wasm_functype_t {
93 ext: wasm_externtype_t::from_extern_type(ty.into()),
94 }
95 }
96
lazy(params: Vec<ValType>, results: Vec<ValType>) -> wasm_functype_t97 pub(crate) fn lazy(params: Vec<ValType>, results: Vec<ValType>) -> wasm_functype_t {
98 wasm_functype_t {
99 ext: wasm_externtype_t::from_cextern_type(CExternType::Func(CFuncType::lazy(
100 params, results,
101 ))),
102 }
103 }
104
from_cfunc(ty: CFuncType) -> wasm_functype_t105 pub(crate) fn from_cfunc(ty: CFuncType) -> wasm_functype_t {
106 wasm_functype_t {
107 ext: wasm_externtype_t::from_cextern_type(CExternType::Func(ty)),
108 }
109 }
110
try_from(e: &wasm_externtype_t) -> Option<&wasm_functype_t>111 pub(crate) fn try_from(e: &wasm_externtype_t) -> Option<&wasm_functype_t> {
112 match &e.which {
113 CExternType::Func(_) => Some(unsafe { &*(e as *const _ as *const _) }),
114 _ => None,
115 }
116 }
117
ty(&self) -> &CFuncType118 pub(crate) fn ty(&self) -> &CFuncType {
119 match &self.ext.which {
120 CExternType::Func(f) => &f,
121 _ => unsafe { std::hint::unreachable_unchecked() },
122 }
123 }
124 }
125
126 impl CFuncType {
new(ty: FuncType) -> CFuncType127 pub(crate) fn new(ty: FuncType) -> CFuncType {
128 CFuncType {
129 ty: Arc::new(Mutex::new(LazyFuncType::FuncType(ty))),
130 params_cache: OnceCell::new(),
131 returns_cache: OnceCell::new(),
132 }
133 }
134
lazy(params: Vec<ValType>, results: Vec<ValType>) -> CFuncType135 pub(crate) fn lazy(params: Vec<ValType>, results: Vec<ValType>) -> CFuncType {
136 CFuncType {
137 ty: Arc::new(Mutex::new(LazyFuncType::Lazy { params, results })),
138 params_cache: OnceCell::new(),
139 returns_cache: OnceCell::new(),
140 }
141 }
142
ty(&self, engine: &Engine) -> FuncType143 pub(crate) fn ty(&self, engine: &Engine) -> FuncType {
144 let mut ty = self.ty.lock().unwrap();
145 ty.force(engine)
146 }
147 }
148
149 #[unsafe(no_mangle)]
wasm_functype_new( params: &mut wasm_valtype_vec_t, results: &mut wasm_valtype_vec_t, ) -> Box<wasm_functype_t>150 pub extern "C" fn wasm_functype_new(
151 params: &mut wasm_valtype_vec_t,
152 results: &mut wasm_valtype_vec_t,
153 ) -> Box<wasm_functype_t> {
154 let params = params
155 .take()
156 .into_iter()
157 .map(|vt| vt.unwrap().ty.clone())
158 .collect();
159 let results = results
160 .take()
161 .into_iter()
162 .map(|vt| vt.unwrap().ty.clone())
163 .collect();
164 Box::new(wasm_functype_t::lazy(params, results))
165 }
166
167 #[unsafe(no_mangle)]
wasm_functype_params(ft: &wasm_functype_t) -> &wasm_valtype_vec_t168 pub extern "C" fn wasm_functype_params(ft: &wasm_functype_t) -> &wasm_valtype_vec_t {
169 let ft = ft.ty();
170 ft.params_cache.get_or_init(|| {
171 let ty = ft.ty.lock().unwrap();
172 ty.params()
173 .map(|p| Some(Box::new(wasm_valtype_t { ty: p.clone() })))
174 .collect::<Vec<_>>()
175 .into()
176 })
177 }
178
179 #[unsafe(no_mangle)]
wasm_functype_results(ft: &wasm_functype_t) -> &wasm_valtype_vec_t180 pub extern "C" fn wasm_functype_results(ft: &wasm_functype_t) -> &wasm_valtype_vec_t {
181 let ft = ft.ty();
182 ft.returns_cache.get_or_init(|| {
183 let ty = ft.ty.lock().unwrap();
184 ty.results()
185 .map(|p| Some(Box::new(wasm_valtype_t { ty: p.clone() })))
186 .collect::<Vec<_>>()
187 .into()
188 })
189 }
190
191 #[unsafe(no_mangle)]
wasm_functype_as_externtype(ty: &wasm_functype_t) -> &wasm_externtype_t192 pub extern "C" fn wasm_functype_as_externtype(ty: &wasm_functype_t) -> &wasm_externtype_t {
193 &ty.ext
194 }
195
196 #[unsafe(no_mangle)]
wasm_functype_as_externtype_const(ty: &wasm_functype_t) -> &wasm_externtype_t197 pub extern "C" fn wasm_functype_as_externtype_const(ty: &wasm_functype_t) -> &wasm_externtype_t {
198 &ty.ext
199 }
200