1use crate::{
10 helper::error_buf_to_string, helper::DEFAULT_ERROR_BUF_SIZE, runtime::Runtime,
11 wasi_context::WasiCtx, RuntimeError,
12};
13use core::marker::PhantomData;
14use std::{
15 ffi::{c_char, CString},
16 fs::File,
17 io::Read,
18 path::Path,
19 ptr,
20 string::String,
21 vec::Vec,
22};
23use wamr_sys::{
24 wasm_module_t, wasm_runtime_load, wasm_runtime_set_module_name,
25 wasm_runtime_set_wasi_addr_pool, wasm_runtime_set_wasi_args,
26 wasm_runtime_set_wasi_ns_lookup_pool, wasm_runtime_unload,
27};
28
29#[allow(dead_code)]
30#[derive(Debug)]
31pub struct Module<'runtime> {
32 name: String,
33 module: wasm_module_t,
34 content: Vec<u8>,
36 wasi_ctx: WasiCtx,
37 _phantom: PhantomData<&'runtime Runtime>,
38}
39
40impl<'runtime> Module<'runtime> {
41 pub fn from_file(runtime: &'runtime Runtime, wasm_file: &Path) -> Result<Self, RuntimeError> {
48 let name = wasm_file.file_name().unwrap().to_str().unwrap();
49 let mut wasm_file = File::open(wasm_file)?;
50
51 let mut binary: Vec<u8> = Vec::new();
52 wasm_file.read_to_end(&mut binary)?;
53
54 Self::from_vec(runtime, binary, name)
55 }
56
57 pub fn from_vec(
64 _runtime: &'runtime Runtime,
65 mut content: Vec<u8>,
66 name: &str,
67 ) -> Result<Self, RuntimeError> {
68 let mut error_buf: [c_char; DEFAULT_ERROR_BUF_SIZE] = [0; DEFAULT_ERROR_BUF_SIZE];
69 let module = unsafe {
70 wasm_runtime_load(
71 content.as_mut_ptr(),
72 content.len() as u32,
73 error_buf.as_mut_ptr(),
74 error_buf.len() as u32,
75 )
76 };
77
78 if module.is_null() {
79 match error_buf.len() {
80 0 => {
81 return Err(RuntimeError::CompilationError(String::from(
82 "load module failed",
83 )))
84 }
85 _ => {
86 return Err(RuntimeError::CompilationError(error_buf_to_string(
87 &error_buf,
88 )))
89 }
90 }
91 }
92
93 unsafe {
94 let name_c = CString::new(name.as_bytes()).unwrap();
95 if !wasm_runtime_set_module_name(
96 module,
97 name_c.as_ptr() as *mut c_char,
98 error_buf.as_mut_ptr(),
99 error_buf.len() as u32,
100 ) {
101 return Err(RuntimeError::CompilationError(error_buf_to_string(
102 &error_buf,
103 )));
104 }
105 }
106
107 Ok(Module {
108 name: String::from(name),
109 module,
110 content,
111 wasi_ctx: WasiCtx::default(),
112 _phantom: PhantomData,
113 })
114 }
115
116 pub fn set_wasi_context(&mut self, wasi_ctx: WasiCtx) {
120 self.wasi_ctx = wasi_ctx;
121
122 let real_paths = if self.wasi_ctx.get_preopen_real_paths().is_empty() {
123 ptr::null_mut()
124 } else {
125 self.wasi_ctx.get_preopen_real_paths().as_ptr() as *mut *const c_char
126 };
127
128 let mapped_paths = if self.wasi_ctx.get_preopen_mapped_paths().is_empty() {
129 ptr::null_mut()
130 } else {
131 self.wasi_ctx.get_preopen_mapped_paths().as_ptr() as *mut *const c_char
132 };
133
134 let env = if self.wasi_ctx.get_env_vars().is_empty() {
135 ptr::null_mut()
136 } else {
137 self.wasi_ctx.get_env_vars_ptrs().as_ptr() as *mut *const c_char
138 };
139
140 let args = if self.wasi_ctx.get_arguments().is_empty() {
141 ptr::null_mut()
142 } else {
143 self.wasi_ctx.get_arguments_ptrs().as_ptr() as *mut *mut c_char
144 };
145
146 unsafe {
147 wasm_runtime_set_wasi_args(
148 self.get_inner_module(),
149 real_paths,
150 self.wasi_ctx.get_preopen_real_paths().len() as u32,
151 mapped_paths,
152 self.wasi_ctx.get_preopen_mapped_paths().len() as u32,
153 env,
154 self.wasi_ctx.get_env_vars().len() as u32,
155 args,
156 self.wasi_ctx.get_arguments().len() as i32,
157 );
158
159 let ns_lookup_pool = if self.wasi_ctx.get_allowed_dns().is_empty() {
160 ptr::null_mut()
161 } else {
162 self.wasi_ctx.get_allowed_dns().as_ptr() as *mut *const c_char
163 };
164
165 wasm_runtime_set_wasi_ns_lookup_pool(
166 self.get_inner_module(),
167 ns_lookup_pool,
168 self.wasi_ctx.get_allowed_dns().len() as u32,
169 );
170
171 let addr_pool = if self.wasi_ctx.get_allowed_address().is_empty() {
172 ptr::null_mut()
173 } else {
174 self.wasi_ctx.get_allowed_address().as_ptr() as *mut *const c_char
175 };
176 wasm_runtime_set_wasi_addr_pool(
177 self.get_inner_module(),
178 addr_pool,
179 self.wasi_ctx.get_allowed_address().len() as u32,
180 );
181 }
182 }
183
184 pub fn get_inner_module(&self) -> wasm_module_t {
185 self.module
186 }
187
188 pub fn get_name(&self) -> &str {
189 &self.name
190 }
191}
192
193impl Drop for Module<'_> {
194 fn drop(&mut self) {
195 unsafe {
196 wasm_runtime_unload(self.module);
197 }
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204 use crate::{helper::cstr_to_string, runtime::Runtime, wasi_context::WasiCtxBuilder};
205 use std::path::PathBuf;
206 use wamr_sys::wasm_runtime_get_module_name;
207
208 #[test]
209 fn test_module_not_exist() {
210 let runtime = Runtime::new();
211 assert!(runtime.is_ok());
212
213 let runtime = runtime.unwrap();
214
215 let module = Module::from_file(&runtime, Path::new("not_exist"));
216 assert!(module.is_err());
217 }
218
219 #[test]
220 fn test_module_from_buf() {
221 let runtime = Runtime::new().unwrap();
222
223 let binary = vec![
231 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01, 0x60, 0x02, 0x7f,
232 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x07, 0x01, 0x03, 0x61, 0x64, 0x64,
233 0x00, 0x00, 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b,
234 ];
235 let binary = binary.into_iter().map(|c| c as u8).collect::<Vec<u8>>();
236
237 let module = Module::from_vec(&runtime, binary, "");
238 assert!(module.is_ok());
239 }
240
241 #[test]
242 fn test_module_from_file() {
243 let runtime = Runtime::new().unwrap();
244
245 let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
246 d.push("resources/test");
247 d.push("gcd_wasm32_wasi.wasm");
248 let module = Module::from_file(&runtime, d.as_path());
249 assert!(module.is_ok());
250 }
251
252 #[test]
253 fn test_module_with_wasi_args() {
254 let runtime = Runtime::new().unwrap();
255
256 let binary = vec![
264 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01, 0x60, 0x02, 0x7f,
265 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x07, 0x01, 0x03, 0x61, 0x64, 0x64,
266 0x00, 0x00, 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b,
267 ];
268 let binary = binary.into_iter().map(|c| c as u8).collect::<Vec<u8>>();
269
270 let module = Module::from_vec(&runtime, binary, "add");
271 assert!(module.is_ok());
272 let mut module = module.unwrap();
273
274 let wasi_ctx = WasiCtxBuilder::new()
275 .set_pre_open_path(vec!["."], vec![])
276 .set_env_vars(vec![])
277 .set_allowed_address(vec![])
278 .set_allowed_dns(vec![])
279 .build();
280
281 module.set_wasi_context(wasi_ctx);
282 }
283
284 #[test]
285 fn test_module_name() -> Result<(), RuntimeError> {
286 let runtime = Runtime::new()?;
287
288 let binary = vec![
296 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01, 0x60, 0x02, 0x7f,
297 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x07, 0x01, 0x03, 0x61, 0x64, 0x64,
298 0x00, 0x00, 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b,
299 ];
300 let binary = binary.into_iter().map(|c| c as u8).collect::<Vec<u8>>();
301
302 let module = Module::from_vec(&runtime, binary, "add")?;
303
304 assert_eq!(module.get_name(), "add");
305
306 let name =
307 cstr_to_string(unsafe { wasm_runtime_get_module_name(module.get_inner_module()) });
308 assert_eq!(&name, module.get_name());
309
310 Ok(())
311 }
312}