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