wasmer_c_api/wasm_c_api/unstable/
wasi.rs

1//! Unstable non-standard Wasmer-specific API that contains more WASI
2//! API.
3
4use super::super::{
5    externals::wasm_extern_t, module::wasm_module_t, types::wasm_name_t, wasi::wasi_env_t,
6};
7
8/// Unstable non-standard type wrapping `wasm_extern_t` with the
9/// addition of two `wasm_name_t` respectively for the module name and
10/// the name of the extern (very likely to be an import). This
11/// non-standard type is used by the unstable non-standard
12/// `wasi_get_unordered_imports` function.
13///
14/// The `module`, `name` and `extern` fields are all owned by this type.
15#[allow(non_camel_case_types)]
16#[derive(Clone)]
17pub struct wasmer_named_extern_t {
18    module: wasm_name_t,
19    name: wasm_name_t,
20    r#extern: Box<wasm_extern_t>,
21}
22
23wasm_declare_boxed_vec!(named_extern, wasmer);
24
25/// So. Let's explain a dirty hack. `cbindgen` reads the code and
26/// collects symbols. What symbols do we need? None of the one
27/// declared in `wasm.h`, but for non-standard API, we need to collect
28/// all of them. The problem is that `wasmer_named_extern_t` is the only
29/// non-standard type where extra symbols are generated by a macro
30/// (`wasm_declare_boxed_vec!`). If we want those macro-generated
31/// symbols to be collected by `cbindgen`, we need to _expand_ the
32/// crate (i.e. running something like `rustc -- -Zunstable-options
33/// --pretty=expanded`). Expanding code is unstable and available only
34/// on nightly compiler. We _don't want_ to use a nightly compiler
35/// only for that. So how can we help `cbindgen` to _see_ those
36/// symbols?
37///
38/// First solution: We write the C code directly in a file, which is
39/// then included in the generated header file with the `cbindgen`
40/// API. Problem, it's super easy to get it outdated, and it makes the
41/// build process more complex.
42///
43/// Second solution: We write those symbols in a custom module, that
44/// is just here for `cbindgen`, never used by our Rust code
45/// (otherwise it's duplicated code), with no particular
46/// implementation.
47///
48/// And that's why we have the following `cbindgen_hack`
49/// module.
50///
51/// But this module must not be compiled by `rustc`. How to force
52/// `rustc` to ignore a module? With conditional compilation. Because
53/// `cbindgen` does not support conditional compilation, it will
54/// always _ignore_ the `#[cfg]` attribute, and will always read the
55/// content of the module.
56///
57/// Sorry.
58#[doc(hidden)]
59#[cfg(__cbindgen_hack__ = "yes")]
60mod __cbindgen_hack__ {
61    use super::*;
62
63    #[repr(C)]
64    pub struct wasmer_named_extern_vec_t {
65        pub size: usize,
66        pub data: *mut *mut wasmer_named_extern_t,
67    }
68
69    #[unsafe(no_mangle)]
70    pub unsafe extern "C" fn wasmer_named_extern_vec_new(
71        out: *mut wasmer_named_extern_vec_t,
72        length: usize,
73        init: *const *mut wasmer_named_extern_t,
74    ) {
75        unimplemented!()
76    }
77
78    #[unsafe(no_mangle)]
79    pub unsafe extern "C" fn wasmer_named_extern_vec_new_uninitialized(
80        out: *mut wasmer_named_extern_vec_t,
81        length: usize,
82    ) {
83        unimplemented!()
84    }
85
86    #[unsafe(no_mangle)]
87    pub unsafe extern "C" fn wasmer_named_extern_vec_copy(
88        out_ptr: &mut wasmer_named_extern_vec_t,
89        in_ptr: &wasmer_named_extern_vec_t,
90    ) {
91        unimplemented!()
92    }
93
94    #[unsafe(no_mangle)]
95    pub unsafe extern "C" fn wasmer_named_extern_vec_delete(
96        ptr: Option<&mut wasmer_named_extern_vec_t>,
97    ) {
98        unimplemented!()
99    }
100
101    #[unsafe(no_mangle)]
102    pub unsafe extern "C" fn wasmer_named_extern_vec_new_empty(
103        out: *mut wasmer_named_extern_vec_t,
104    ) {
105        unimplemented!()
106    }
107}
108
109/// Non-standard function to get the module name of a
110/// `wasmer_named_extern_t`.
111///
112/// The returned value isn't owned by the caller.
113#[unsafe(no_mangle)]
114pub extern "C" fn wasmer_named_extern_module(
115    named_extern: Option<&wasmer_named_extern_t>,
116) -> Option<&wasm_name_t> {
117    Some(&named_extern?.module)
118}
119
120/// Non-standard function to get the name of a `wasmer_named_extern_t`.
121///
122/// The returned value isn't owned by the caller.
123#[unsafe(no_mangle)]
124pub extern "C" fn wasmer_named_extern_name(
125    named_extern: Option<&wasmer_named_extern_t>,
126) -> Option<&wasm_name_t> {
127    Some(&named_extern?.name)
128}
129
130/// Non-standard function to get the wrapped extern of a
131/// `wasmer_named_extern_t`.
132///
133/// The returned value isn't owned by the caller.
134#[unsafe(no_mangle)]
135pub extern "C" fn wasmer_named_extern_unwrap(
136    named_extern: Option<&wasmer_named_extern_t>,
137) -> Option<&wasm_extern_t> {
138    Some(named_extern?.r#extern.as_ref())
139}
140
141/// Non-standard function to get the imports needed for the WASI
142/// implementation with no particular order. Each import has its
143/// associated module name and name, so that it can be re-order later
144/// based on the `wasm_module_t` requirements.
145#[unsafe(no_mangle)]
146pub unsafe extern "C" fn wasi_get_unordered_imports(
147    wasi_env: Option<&mut wasi_env_t>,
148    module: Option<&wasm_module_t>,
149    imports: &mut wasmer_named_extern_vec_t,
150) -> bool {
151    unsafe { wasi_get_unordered_imports_inner(wasi_env, module, imports) }.is_some()
152}
153
154unsafe fn wasi_get_unordered_imports_inner(
155    wasi_env: Option<&mut wasi_env_t>,
156    module: Option<&wasm_module_t>,
157    imports: &mut wasmer_named_extern_vec_t,
158) -> Option<()> {
159    let wasi_env = wasi_env?;
160    let store = &mut wasi_env.store;
161    let module = module?;
162
163    let import_object = {
164        let mut store_mut = unsafe { store.store_mut() };
165        c_try!(wasi_env.inner.import_object(&mut store_mut, &module.inner))
166    };
167
168    imports.set_buffer(
169        import_object
170            .into_iter()
171            .map(move |((module, name), extern_)| {
172                let module = module.into();
173                let name = name.into();
174
175                Some(Box::new(wasmer_named_extern_t {
176                    module,
177                    name,
178                    r#extern: Box::new(wasm_extern_t::new(store.clone(), extern_)),
179                }))
180            })
181            .collect::<Vec<_>>(),
182    );
183
184    Some(())
185}