1use crate::{
4 ast_module::{InnerModule, Module},
5 ffi, utils,
6 utils::check,
7 Config, WasmEdgeResult,
8};
9use std::{path::Path, sync::Arc};
10use wasmedge_types::error::WasmEdgeError;
11
12#[derive(Debug)]
14pub struct Loader {
15 pub(crate) inner: InnerLoader,
16}
17impl Loader {
18 pub fn create(config: Option<&Config>) -> WasmEdgeResult<Self> {
28 let ctx = match config {
29 Some(config) => unsafe { ffi::WasmEdge_LoaderCreate(config.inner.0) },
30 None => unsafe { ffi::WasmEdge_LoaderCreate(std::ptr::null_mut()) },
31 };
32
33 match ctx.is_null() {
34 true => Err(Box::new(WasmEdgeError::LoaderCreate)),
35 false => Ok(Self {
36 inner: InnerLoader(ctx),
37 }),
38 }
39 }
40
41 pub fn from_file(&self, file: impl AsRef<Path>) -> WasmEdgeResult<Arc<Module>> {
58 match file.as_ref().extension() {
59 Some(extension) => match extension.to_str() {
60 Some("wasm") => self.load_from_wasm_or_aot_file(&file),
61 #[cfg(target_os = "macos")]
62 Some("dylib") => self.load_from_wasm_or_aot_file(&file),
63 #[cfg(target_os = "linux")]
64 Some("so") => self.load_from_wasm_or_aot_file(&file),
65 #[cfg(target_os = "windows")]
66 Some("dll") => self.load_from_wasm_or_aot_file(&file),
67 Some("wat") => {
68 let bytes = wat::parse_file(file.as_ref())
69 .map_err(|_| WasmEdgeError::Operation("Failed to parse wat file".into()))?;
70 self.from_bytes(bytes)
71 }
72 _ => Err(Box::new(WasmEdgeError::Operation(
73 "The source file's extension should be one of `wasm`, `wat`, `dylib` on macOS, `so` on Linux or `dll` on Windows.".into(),
74 ))),
75 },
76 None => self.load_from_wasm_or_aot_file(&file),
77 }
78 }
79
80 fn load_from_wasm_or_aot_file(&self, file: impl AsRef<Path>) -> WasmEdgeResult<Arc<Module>> {
81 let c_path = utils::path_to_cstring(file.as_ref())?;
82 let mut mod_ctx = std::ptr::null_mut();
83 unsafe {
84 check(ffi::WasmEdge_LoaderParseFromFile(
85 self.inner.0,
86 &mut mod_ctx,
87 c_path.as_ptr(),
88 ))?;
89 }
90
91 match mod_ctx.is_null() {
92 true => Err(Box::new(WasmEdgeError::ModuleCreate)),
93 false => Ok(Module {
94 inner: InnerModule(mod_ctx),
95 }
96 .into()),
97 }
98 }
99
100 pub fn from_bytes(&self, bytes: impl AsRef<[u8]>) -> WasmEdgeResult<Arc<Module>> {
123 let bytes = bytes.as_ref();
124 let mut mod_ctx: *mut ffi::WasmEdge_ASTModuleContext = std::ptr::null_mut();
125
126 unsafe {
127 check(ffi::WasmEdge_LoaderParseFromBuffer(
128 self.inner.0,
129 &mut mod_ctx,
130 bytes.as_ptr(),
131 bytes.len() as u32,
132 ))?;
133 }
134
135 match mod_ctx.is_null() {
136 true => Err(Box::new(WasmEdgeError::ModuleCreate)),
137 false => Ok(Module {
138 inner: InnerModule(mod_ctx),
139 }
140 .into()),
141 }
142 }
143}
144impl Drop for Loader {
145 fn drop(&mut self) {
146 unsafe { ffi::WasmEdge_LoaderDelete(self.inner.0) }
147 }
148}
149
150#[derive(Debug)]
151pub(crate) struct InnerLoader(pub(crate) *mut ffi::WasmEdge_LoaderContext);
152unsafe impl Send for InnerLoader {}
153unsafe impl Sync for InnerLoader {}
154
155#[cfg(test)]
156mod tests {
157 use super::Loader;
158 use crate::Config;
159 use std::{
160 sync::{Arc, Mutex},
161 thread,
162 };
163 use wasmedge_types::error::{CoreError, CoreLoadError, WasmEdgeError};
164
165 #[test]
166 #[allow(clippy::assertions_on_result_states)]
167 fn test_loader() {
168 let result = Loader::create(None);
170 assert!(result.is_ok());
171
172 let result = Config::create();
174 assert!(result.is_ok());
175 let mut config = result.unwrap();
176 config.reference_types(true);
177 let result = Loader::create(Some(&config));
178 assert!(result.is_ok());
179 let loader = result.unwrap();
180
181 {
183 let path = std::env::current_dir()
185 .unwrap()
186 .ancestors()
187 .nth(2)
188 .unwrap()
189 .join("examples/wasmedge-sys/data/fibonacci.wat");
190 let result = loader.from_file(path);
191 assert!(result.is_ok());
192 let module = result.unwrap();
193 assert!(!module.inner.0.is_null());
194
195 let path = std::env::current_dir()
196 .unwrap()
197 .ancestors()
198 .nth(2)
199 .unwrap()
200 .join("examples/wasmedge-sys/data/fibonacci.wat");
201 let result = loader.from_file(path);
202 assert!(result.is_ok());
203
204 let result = loader.from_file("not_exist_file.wasm");
205 assert!(result.is_err());
206 assert_eq!(
207 result.unwrap_err(),
208 Box::new(WasmEdgeError::Core(CoreError::Load(
209 CoreLoadError::IllegalPath
210 )))
211 );
212 }
213
214 {
216 let buffer = b"\0asm\x01\0\0\0";
217 let result = loader.from_bytes(buffer);
218 assert!(result.is_ok());
219 let module = result.unwrap();
220 assert!(!module.inner.0.is_null());
221
222 let result = loader.from_bytes(b"(module)");
224 assert!(result.is_err());
225 assert_eq!(
226 result.unwrap_err(),
227 Box::new(WasmEdgeError::Core(CoreError::Load(
228 CoreLoadError::MalformedMagic
229 )))
230 );
231
232 let result = loader.from_bytes([]);
234 assert!(result.is_err());
235 assert_eq!(
236 result.unwrap_err(),
237 Box::new(WasmEdgeError::Core(CoreError::Load(
238 CoreLoadError::UnexpectedEnd
239 )))
240 );
241 }
242 }
243
244 #[test]
245 #[allow(clippy::assertions_on_result_states)]
246 fn test_loader_send() {
247 let result = Loader::create(None);
249 assert!(result.is_ok());
250
251 let result = Config::create();
253 assert!(result.is_ok());
254 let mut config = result.unwrap();
255 config.reference_types(true);
256 let result = Loader::create(Some(&config));
257 assert!(result.is_ok());
258 let loader = result.unwrap();
259
260 let handle = thread::spawn(move || {
261 assert!(!loader.inner.0.is_null());
262 println!("{:?}", loader.inner);
263 });
264
265 handle.join().unwrap();
266 }
267
268 #[test]
269 #[allow(clippy::assertions_on_result_states)]
270 fn test_loader_sync() {
271 let result = Loader::create(None);
273 assert!(result.is_ok());
274
275 let result = Config::create();
277 assert!(result.is_ok());
278 let mut config = result.unwrap();
279 config.reference_types(true);
280 let result = Loader::create(Some(&config));
281 assert!(result.is_ok());
282 let loader = Arc::new(Mutex::new(result.unwrap()));
283
284 let loader_cloned = Arc::clone(&loader);
285 let handle = thread::spawn(move || {
286 let result = loader_cloned.lock();
287 assert!(result.is_ok());
288 let loader = result.unwrap();
289
290 assert!(!loader.inner.0.is_null());
291 });
292
293 handle.join().unwrap();
294 }
295}