1use crate::{
2 CExternType, handle_result, wasm_byte_vec_t, wasm_engine_t, wasm_exporttype_t,
3 wasm_exporttype_vec_t, wasm_importtype_t, wasm_importtype_vec_t, wasm_store_t,
4 wasmtime_error_t,
5};
6use anyhow::Context;
7use std::ffi::CStr;
8use std::os::raw::c_char;
9use wasmtime::{Engine, Module};
10
11#[derive(Clone)]
12pub struct wasm_module_t {
13 pub(crate) module: Module,
14}
15
16wasmtime_c_api_macros::declare_ref!(wasm_module_t);
17
18impl wasm_module_t {
19 pub(crate) fn new(module: Module) -> wasm_module_t {
20 wasm_module_t { module }
21 }
22}
23
24#[repr(C)]
25#[derive(Clone)]
26pub struct wasm_shared_module_t {
27 module: Module,
28}
29
30wasmtime_c_api_macros::declare_own!(wasm_shared_module_t);
31
32#[unsafe(no_mangle)]
33#[cfg(any(feature = "cranelift", feature = "winch"))]
34pub unsafe extern "C" fn wasm_module_new(
35 store: &mut wasm_store_t,
36 binary: &wasm_byte_vec_t,
37) -> Option<Box<wasm_module_t>> {
38 match Module::from_binary(store.store.context().engine(), binary.as_slice()) {
39 Ok(module) => Some(Box::new(wasm_module_t::new(module))),
40 Err(_) => None,
41 }
42}
43
44#[unsafe(no_mangle)]
45#[cfg(any(feature = "cranelift", feature = "winch"))]
46pub unsafe extern "C" fn wasm_module_validate(
47 store: &mut wasm_store_t,
48 binary: &wasm_byte_vec_t,
49) -> bool {
50 Module::validate(store.store.context().engine(), binary.as_slice()).is_ok()
51}
52
53fn fill_exports(module: &Module, out: &mut wasm_exporttype_vec_t) {
54 let exports = module
55 .exports()
56 .map(|e| {
57 Some(Box::new(wasm_exporttype_t::new(
58 e.name().to_owned(),
59 CExternType::new(e.ty()),
60 )))
61 })
62 .collect::<Vec<_>>();
63 out.set_buffer(exports);
64}
65
66fn fill_imports(module: &Module, out: &mut wasm_importtype_vec_t) {
67 let imports = module
68 .imports()
69 .map(|i| {
70 Some(Box::new(wasm_importtype_t::new(
71 i.module().to_owned(),
72 i.name().to_owned(),
73 CExternType::new(i.ty()),
74 )))
75 })
76 .collect::<Vec<_>>();
77 out.set_buffer(imports);
78}
79
80#[unsafe(no_mangle)]
81pub extern "C" fn wasm_module_exports(module: &wasm_module_t, out: &mut wasm_exporttype_vec_t) {
82 fill_exports(&module.module, out);
83}
84
85#[unsafe(no_mangle)]
86pub extern "C" fn wasm_module_imports(module: &wasm_module_t, out: &mut wasm_importtype_vec_t) {
87 fill_imports(&module.module, out);
88}
89
90#[unsafe(no_mangle)]
91pub extern "C" fn wasm_module_share(module: &wasm_module_t) -> Box<wasm_shared_module_t> {
92 Box::new(wasm_shared_module_t {
93 module: module.module.clone(),
94 })
95}
96
97#[unsafe(no_mangle)]
98pub unsafe extern "C" fn wasm_module_obtain(
99 store: &mut wasm_store_t,
100 shared_module: &wasm_shared_module_t,
101) -> Option<Box<wasm_module_t>> {
102 let module = shared_module.module.clone();
103 if Engine::same(store.store.context().engine(), module.engine()) {
104 Some(Box::new(wasm_module_t::new(module)))
105 } else {
106 None
107 }
108}
109
110#[unsafe(no_mangle)]
111#[cfg(any(feature = "cranelift", feature = "winch"))]
112pub extern "C" fn wasm_module_serialize(module: &wasm_module_t, ret: &mut wasm_byte_vec_t) {
113 if let Ok(buf) = module.module.serialize() {
114 ret.set_buffer(buf);
115 }
116}
117
118#[unsafe(no_mangle)]
119pub unsafe extern "C" fn wasm_module_deserialize(
120 store: &mut wasm_store_t,
121 binary: &wasm_byte_vec_t,
122) -> Option<Box<wasm_module_t>> {
123 match Module::deserialize(store.store.context().engine(), binary.as_slice()) {
124 Ok(module) => Some(Box::new(wasm_module_t::new(module))),
125 Err(_) => None,
126 }
127}
128
129#[derive(Clone)]
130pub struct wasmtime_module_t {
131 pub(crate) module: Module,
132}
133
134wasmtime_c_api_macros::declare_own!(wasmtime_module_t);
135
136#[unsafe(no_mangle)]
137#[cfg(any(feature = "cranelift", feature = "winch"))]
138pub unsafe extern "C" fn wasmtime_module_new(
139 engine: &wasm_engine_t,
140 wasm: *const u8,
141 len: usize,
142 out: &mut *mut wasmtime_module_t,
143) -> Option<Box<wasmtime_error_t>> {
144 handle_result(
145 Module::from_binary(&engine.engine, crate::slice_from_raw_parts(wasm, len)),
146 |module| {
147 *out = Box::into_raw(Box::new(wasmtime_module_t { module }));
148 },
149 )
150}
151
152#[unsafe(no_mangle)]
153pub extern "C" fn wasmtime_module_clone(module: &wasmtime_module_t) -> Box<wasmtime_module_t> {
154 Box::new(module.clone())
155}
156
157#[unsafe(no_mangle)]
158pub extern "C" fn wasmtime_module_exports(
159 module: &wasmtime_module_t,
160 out: &mut wasm_exporttype_vec_t,
161) {
162 fill_exports(&module.module, out);
163}
164
165#[unsafe(no_mangle)]
166pub extern "C" fn wasmtime_module_imports(
167 module: &wasmtime_module_t,
168 out: &mut wasm_importtype_vec_t,
169) {
170 fill_imports(&module.module, out);
171}
172
173#[unsafe(no_mangle)]
174#[cfg(any(feature = "cranelift", feature = "winch"))]
175pub unsafe extern "C" fn wasmtime_module_validate(
176 engine: &wasm_engine_t,
177 wasm: *const u8,
178 len: usize,
179) -> Option<Box<wasmtime_error_t>> {
180 let binary = crate::slice_from_raw_parts(wasm, len);
181 handle_result(Module::validate(&engine.engine, binary), |()| {})
182}
183
184#[unsafe(no_mangle)]
185#[cfg(any(feature = "cranelift", feature = "winch"))]
186pub extern "C" fn wasmtime_module_serialize(
187 module: &wasmtime_module_t,
188 ret: &mut wasm_byte_vec_t,
189) -> Option<Box<wasmtime_error_t>> {
190 handle_result(module.module.serialize(), |buf| ret.set_buffer(buf))
191}
192
193#[unsafe(no_mangle)]
194pub extern "C" fn wasmtime_module_image_range(
195 module: &wasmtime_module_t,
196 start: &mut *const u8,
197 end: &mut *const u8,
198) {
199 let range = module.module.image_range();
200 *start = range.start;
201 *end = range.end;
202}
203
204#[unsafe(no_mangle)]
205pub unsafe extern "C" fn wasmtime_module_deserialize(
206 engine: &wasm_engine_t,
207 bytes: *const u8,
208 len: usize,
209 out: &mut *mut wasmtime_module_t,
210) -> Option<Box<wasmtime_error_t>> {
211 let bytes = crate::slice_from_raw_parts(bytes, len);
212 handle_result(Module::deserialize(&engine.engine, bytes), |module| {
213 *out = Box::into_raw(Box::new(wasmtime_module_t { module }));
214 })
215}
216
217#[unsafe(no_mangle)]
218pub unsafe extern "C" fn wasmtime_module_deserialize_file(
219 engine: &wasm_engine_t,
220 path: *const c_char,
221 out: &mut *mut wasmtime_module_t,
222) -> Option<Box<wasmtime_error_t>> {
223 let path = CStr::from_ptr(path);
224 let result = path
225 .to_str()
226 .context("input path is not valid utf-8")
227 .and_then(|path| Module::deserialize_file(&engine.engine, path));
228 handle_result(result, |module| {
229 *out = Box::into_raw(Box::new(wasmtime_module_t { module }));
230 })
231}