Skip to main content

wasmtime_c_api/types/
func.rs

1use crate::{CExternType, wasm_externtype_t, wasm_valtype_t, wasm_valtype_vec_t};
2use std::cell::OnceCell;
3use std::{
4    mem,
5    sync::{Arc, Mutex},
6};
7use wasmtime::{Engine, FuncType, ValType};
8
9#[repr(transparent)]
10#[derive(Clone)]
11pub struct wasm_functype_t {
12    ext: wasm_externtype_t,
13}
14
15wasmtime_c_api_macros::declare_ty!(wasm_functype_t);
16
17#[derive(Clone)]
18enum LazyFuncType {
19    Lazy {
20        params: Vec<ValType>,
21        results: Vec<ValType>,
22    },
23    FuncType(FuncType),
24}
25
26impl LazyFuncType {
27    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
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
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
55enum LazyFuncTypeIter<'a, T> {
56    Lazy(std::slice::Iter<'a, ValType>),
57    FuncType(T),
58}
59
60impl<'a, T> Iterator for LazyFuncTypeIter<'a, T>
61where
62    T: Iterator<Item = ValType>,
63{
64    type Item = ValType;
65
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
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
81impl<'a, T> ExactSizeIterator for LazyFuncTypeIter<'a, T> where T: ExactSizeIterator<Item = ValType> {}
82
83#[derive(Clone)]
84pub(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
90impl wasm_functype_t {
91    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
97    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
105    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
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
118    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
126impl CFuncType {
127    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
135    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
143    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)]
150pub 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)]
168pub 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)]
180pub 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)]
192pub extern "C" fn wasm_functype_as_externtype(ty: &wasm_functype_t) -> &wasm_externtype_t {
193    &ty.ext
194}
195
196#[unsafe(no_mangle)]
197pub extern "C" fn wasm_functype_as_externtype_const(ty: &wasm_functype_t) -> &wasm_externtype_t {
198    &ty.ext
199}