1use crate::{config::Config, ExternalInstanceType, WasmEdgeResult};
4use std::{borrow::Cow, marker::PhantomData, path::Path, sync::Arc};
5use wasmedge_sys as sys;
6
7#[derive(Debug, Clone)]
11pub struct Module {
12 pub(crate) inner: Arc<sys::Module>,
13}
14impl Module {
15 pub fn from_file(config: Option<&Config>, file: impl AsRef<Path>) -> WasmEdgeResult<Self> {
27 let inner_config = config.map(|cfg| cfg.inner.as_ref());
28
29 let inner_module = sys::Loader::create(inner_config)?.from_file(file.as_ref())?;
31
32 sys::Validator::create(inner_config)?.validate(&inner_module)?;
34
35 Ok(Self {
36 inner: inner_module,
37 })
38 }
39
40 pub fn from_bytes(config: Option<&Config>, bytes: impl AsRef<[u8]>) -> WasmEdgeResult<Self> {
52 let inner_config = config.map(|cfg| cfg.inner.as_ref());
53
54 let inner_module = sys::Loader::create(inner_config)?.from_bytes(bytes.as_ref())?;
56
57 sys::Validator::create(inner_config)?.validate(&inner_module)?;
59
60 Ok(Self {
61 inner: inner_module,
62 })
63 }
64
65 pub fn count_of_imports(&self) -> u32 {
67 self.inner.count_of_imports()
68 }
69
70 pub fn imports(&self) -> Vec<ImportType<'_>> {
72 let mut imports = Vec::new();
73 for inner_import in self.inner.imports() {
74 let import = ImportType {
75 inner: inner_import,
76 _marker: PhantomData,
77 };
78 imports.push(import);
79 }
80 imports
81 }
82
83 pub fn count_of_exports(&self) -> u32 {
85 self.inner.count_of_exports()
86 }
87
88 pub fn exports(&self) -> Vec<ExportType<'_>> {
90 let mut exports = Vec::new();
91 for inner_export in self.inner.export() {
92 let export = ExportType {
93 inner: inner_export,
94 _marker: PhantomData,
95 };
96 exports.push(export);
97 }
98 exports
99 }
100
101 pub fn get_export(&self, name: impl AsRef<str>) -> Option<ExternalInstanceType> {
107 let exports = self
108 .exports()
109 .into_iter()
110 .filter(|x| x.name() == name.as_ref())
111 .collect::<Vec<_>>();
112 match exports.is_empty() {
113 true => None,
114 false => exports[0].ty().ok(),
115 }
116 }
117}
118
119#[derive(Debug)]
121pub struct ImportType<'module> {
122 inner: sys::ImportType<'module>,
123 _marker: PhantomData<&'module Module>,
124}
125impl ImportType<'_> {
126 pub fn name(&self) -> Cow<'_, str> {
128 self.inner.name()
129 }
130
131 pub fn module_name(&self) -> Cow<'_, str> {
133 self.inner.module_name()
134 }
135
136 pub fn ty(&self) -> WasmEdgeResult<ExternalInstanceType> {
138 let ty = self.inner.ty()?;
139 Ok(ty)
140 }
141}
142
143#[derive(Debug)]
145pub struct ExportType<'module> {
146 inner: sys::ExportType<'module>,
147 _marker: PhantomData<&'module Module>,
148}
149impl ExportType<'_> {
150 pub fn name(&self) -> Cow<'_, str> {
152 self.inner.name()
153 }
154
155 pub fn ty(&self) -> WasmEdgeResult<ExternalInstanceType> {
157 let ty = self.inner.ty()?;
158 Ok(ty)
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165 use crate::{
166 error::{CoreError, CoreLoadError, WasmEdgeError},
167 wat2wasm,
168 };
169
170 #[test]
171 #[allow(clippy::assertions_on_result_states)]
172 fn test_module_from_wasm() {
173 let file = std::env::current_dir()
175 .unwrap()
176 .join("examples/wasmedge-sys/data/fibonacci.wat");
177
178 let result = Module::from_file(None, file);
179 assert!(result.is_ok());
180
181 let result = Module::from_file(None, "not_exist_file.wasm");
183 assert!(result.is_err());
184 assert_eq!(
185 result.unwrap_err(),
186 Box::new(WasmEdgeError::Core(CoreError::Load(
187 CoreLoadError::IllegalPath
188 )))
189 );
190 }
191
192 #[test]
193 #[allow(clippy::assertions_on_result_states)]
194 fn test_module_from_wat() {
195 let file = std::env::current_dir()
197 .unwrap()
198 .join("examples/wasmedge-sys/data/fibonacci.wat");
199
200 let result = Module::from_file(None, file);
201 assert!(result.is_ok());
202 }
203
204 #[test]
205 #[allow(clippy::assertions_on_result_states)]
206 fn test_module_from_bytes() {
207 let wasm_bytes = wat2wasm(
209 br#"
210 (module
211 (export "fib" (func $fib))
212 (func $fib (param $n i32) (result i32)
213 (if
214 (i32.lt_s
215 (local.get $n)
216 (i32.const 2)
217 )
218 (then
219 (return (i32.const 1))
220 )
221 )
222 (return
223 (i32.add
224 (call $fib
225 (i32.sub
226 (local.get $n)
227 (i32.const 2)
228 )
229 )
230 (call $fib
231 (i32.sub
232 (local.get $n)
233 (i32.const 1)
234 )
235 )
236 )
237 )
238 )
239 )
240"#,
241 )
242 .unwrap();
243
244 let result = Module::from_bytes(None, wasm_bytes);
245 assert!(result.is_ok());
246
247 let result = Module::from_bytes(None, []);
249 assert_eq!(
250 result.unwrap_err(),
251 Box::new(WasmEdgeError::Core(CoreError::Load(
252 CoreLoadError::UnexpectedEnd
253 ))),
254 );
255 }
256
257 #[test]
258 #[allow(clippy::assertions_on_result_states)]
259 fn test_module_clone() {
260 let wasm_bytes = wat2wasm(
262 br#"
263 (module
264 (export "fib" (func $fib))
265 (func $fib (param $n i32) (result i32)
266 (if
267 (i32.lt_s
268 (local.get $n)
269 (i32.const 2)
270 )
271 (then
272 (return (i32.const 1))
273 )
274 )
275 (return
276 (i32.add
277 (call $fib
278 (i32.sub
279 (local.get $n)
280 (i32.const 2)
281 )
282 )
283 (call $fib
284 (i32.sub
285 (local.get $n)
286 (i32.const 1)
287 )
288 )
289 )
290 )
291 )
292 )
293"#,
294 )
295 .unwrap();
296
297 let result = Module::from_bytes(None, wasm_bytes);
298 assert!(result.is_ok());
299 let module = result.unwrap();
300 assert_eq!(module.exports().len(), 1);
301
302 let module_clone = module.clone();
304 assert_eq!(module.exports().len(), module_clone.exports().len());
305 }
306}