wasmtime_c_api/types/
func.rs

1use crate::{wasm_externtype_t, wasm_valtype_t, wasm_valtype_vec_t, CExternType};
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 try_from(e: &wasm_externtype_t) -> Option<&wasm_functype_t> {
106        match &e.which {
107            CExternType::Func(_) => Some(unsafe { &*(e as *const _ as *const _) }),
108            _ => None,
109        }
110    }
111
112    pub(crate) fn ty(&self) -> &CFuncType {
113        match &self.ext.which {
114            CExternType::Func(f) => &f,
115            _ => unsafe { std::hint::unreachable_unchecked() },
116        }
117    }
118}
119
120impl CFuncType {
121    pub(crate) fn new(ty: FuncType) -> CFuncType {
122        CFuncType {
123            ty: Arc::new(Mutex::new(LazyFuncType::FuncType(ty))),
124            params_cache: OnceCell::new(),
125            returns_cache: OnceCell::new(),
126        }
127    }
128
129    pub(crate) fn lazy(params: Vec<ValType>, results: Vec<ValType>) -> CFuncType {
130        CFuncType {
131            ty: Arc::new(Mutex::new(LazyFuncType::Lazy { params, results })),
132            params_cache: OnceCell::new(),
133            returns_cache: OnceCell::new(),
134        }
135    }
136
137    pub(crate) fn ty(&self, engine: &Engine) -> FuncType {
138        let mut ty = self.ty.lock().unwrap();
139        ty.force(engine)
140    }
141}
142
143#[unsafe(no_mangle)]
144pub extern "C" fn wasm_functype_new(
145    params: &mut wasm_valtype_vec_t,
146    results: &mut wasm_valtype_vec_t,
147) -> Box<wasm_functype_t> {
148    let params = params
149        .take()
150        .into_iter()
151        .map(|vt| vt.unwrap().ty.clone())
152        .collect();
153    let results = results
154        .take()
155        .into_iter()
156        .map(|vt| vt.unwrap().ty.clone())
157        .collect();
158    Box::new(wasm_functype_t::lazy(params, results))
159}
160
161#[unsafe(no_mangle)]
162pub extern "C" fn wasm_functype_params(ft: &wasm_functype_t) -> &wasm_valtype_vec_t {
163    let ft = ft.ty();
164    ft.params_cache.get_or_init(|| {
165        let ty = ft.ty.lock().unwrap();
166        ty.params()
167            .map(|p| Some(Box::new(wasm_valtype_t { ty: p.clone() })))
168            .collect::<Vec<_>>()
169            .into()
170    })
171}
172
173#[unsafe(no_mangle)]
174pub extern "C" fn wasm_functype_results(ft: &wasm_functype_t) -> &wasm_valtype_vec_t {
175    let ft = ft.ty();
176    ft.returns_cache.get_or_init(|| {
177        let ty = ft.ty.lock().unwrap();
178        ty.results()
179            .map(|p| Some(Box::new(wasm_valtype_t { ty: p.clone() })))
180            .collect::<Vec<_>>()
181            .into()
182    })
183}
184
185#[unsafe(no_mangle)]
186pub extern "C" fn wasm_functype_as_externtype(ty: &wasm_functype_t) -> &wasm_externtype_t {
187    &ty.ext
188}
189
190#[unsafe(no_mangle)]
191pub extern "C" fn wasm_functype_as_externtype_const(ty: &wasm_functype_t) -> &wasm_externtype_t {
192    &ty.ext
193}