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}