wasmer/entities/
imports.rs

1//! The import module contains the implementation data structures and helper functions used to
2//! manipulate and access a wasm module's imports including memories, tables, globals, and
3//! functions.
4use crate::{Exports, Extern, Module, error::LinkError};
5use std::collections::HashMap;
6use std::fmt;
7use wasmer_types::ImportError;
8
9/// All of the import data used when instantiating.
10///
11/// It's suggested that you use the [`imports!`] macro
12/// instead of creating an `Imports` by hand.
13///
14/// [`imports!`]: macro.imports.html
15///
16/// # Usage:
17/// ```no_run
18/// use wasmer::{Store, Exports, Module, Instance, imports, Imports, Function, FunctionEnvMut};
19/// # fn foo_test(mut store: &mut Store, module: Module) {
20///
21/// let host_fn = Function::new_typed(&mut store, foo);
22/// let import_object: Imports = imports! {
23///     "env" => {
24///         "foo" => host_fn,
25///     },
26/// };
27///
28/// let instance = Instance::new(&mut store, &module, &import_object).expect("Could not instantiate module.");
29///
30/// fn foo(n: i32) -> i32 {
31///     n
32/// }
33///
34/// # }
35/// ```
36#[derive(Clone, Default)]
37pub struct Imports {
38    pub(crate) map: HashMap<(String, String), Extern>,
39}
40
41impl Imports {
42    /// Create a new `Imports`.
43    pub fn new() -> Self {
44        Default::default()
45    }
46
47    /// Gets an export given a module and a name
48    ///
49    /// # Usage
50    /// ```no_run
51    /// # use wasmer::Imports;
52    /// let mut import_object = Imports::new();
53    /// import_object.get_export("module", "name");
54    /// ```
55    pub fn get_export(&self, module: &str, name: &str) -> Option<Extern> {
56        if self.exists(module, name) {
57            let ext = &self.map[&(module.to_string(), name.to_string())];
58            return Some(ext.clone());
59        }
60        None
61    }
62
63    /// Returns if an export exist for a given module and name.
64    ///
65    /// # Usage
66    /// ```no_run
67    /// # use wasmer::Imports;
68    /// let mut import_object = Imports::new();
69    /// import_object.exists("module", "name");
70    /// ```
71    pub fn exists(&self, module: &str, name: &str) -> bool {
72        self.map
73            .contains_key(&(module.to_string(), name.to_string()))
74    }
75
76    /// Returns true if the Imports contains namespace with the provided name.
77    pub fn contains_namespace(&self, name: &str) -> bool {
78        self.map.keys().any(|(k, _)| (k == name))
79    }
80
81    /// Register a list of externs into a namespace.
82    ///
83    /// # Usage:
84    /// ```no_run
85    /// # use wasmer::{Imports, Exports, Memory};
86    /// # fn foo_test(memory: Memory) {
87    /// let mut exports = Exports::new();
88    /// exports.insert("memory", memory);
89    ///
90    /// let mut import_object = Imports::new();
91    /// import_object.register_namespace("env", exports);
92    /// // ...
93    /// # }
94    /// ```
95    pub fn register_namespace(
96        &mut self,
97        ns: &str,
98        contents: impl IntoIterator<Item = (String, Extern)>,
99    ) {
100        for (name, extern_) in contents.into_iter() {
101            self.map.insert((ns.to_string(), name.clone()), extern_);
102        }
103    }
104
105    /// Add a single import with a namespace `ns` and name `name`.
106    ///
107    /// # Usage
108    /// ```no_run
109    /// # use wasmer::{FunctionEnv, Store};
110    /// # let mut store: Store = Default::default();
111    /// use wasmer::{StoreMut, Imports, Function, FunctionEnvMut};
112    /// fn foo(n: i32) -> i32 {
113    ///     n
114    /// }
115    /// let mut import_object = Imports::new();
116    /// import_object.define("env", "foo", Function::new_typed(&mut store, foo));
117    /// ```
118    pub fn define(&mut self, ns: &str, name: &str, val: impl Into<Extern>) {
119        self.map
120            .insert((ns.to_string(), name.to_string()), val.into());
121    }
122
123    /// Returns the contents of a namespace as an `Exports`.
124    ///
125    /// Returns `None` if the namespace doesn't exist.
126    pub fn get_namespace_exports(&self, name: &str) -> Option<Exports> {
127        let ret: Exports = self
128            .map
129            .iter()
130            .filter(|((ns, _), _)| ns == name)
131            .map(|((_, name), e)| (name.clone(), e.clone()))
132            .collect();
133        if ret.is_empty() { None } else { Some(ret) }
134    }
135
136    /// Resolve and return a vector of imports in the order they are defined in the `module`'s source code.
137    ///
138    /// This means the returned `Vec<Extern>` might be a subset of the imports contained in `self`.
139    #[allow(clippy::result_large_err)]
140    pub fn imports_for_module(&self, module: &Module) -> Result<Vec<Extern>, LinkError> {
141        let mut ret = vec![];
142        for import in module.imports() {
143            if let Some(imp) = self
144                .map
145                .get(&(import.module().to_string(), import.name().to_string()))
146            {
147                ret.push(imp.clone());
148            } else {
149                return Err(LinkError::Import(
150                    import.module().to_string(),
151                    import.name().to_string(),
152                    ImportError::UnknownImport(import.ty().clone()),
153                ));
154            }
155        }
156        Ok(ret)
157    }
158
159    /// Iterates through all the imports in this structure
160    pub fn iter(&self) -> ImportsIterator<'_> {
161        ImportsIterator::new(self)
162    }
163}
164
165/// An iterator over module imports.
166pub struct ImportsIterator<'a> {
167    iter: std::collections::hash_map::Iter<'a, (String, String), Extern>,
168}
169
170impl<'a> ImportsIterator<'a> {
171    pub(crate) fn new(imports: &'a Imports) -> Self {
172        let iter = imports.map.iter();
173        Self { iter }
174    }
175}
176
177impl<'a> Iterator for ImportsIterator<'a> {
178    type Item = (&'a str, &'a str, &'a Extern);
179
180    fn next(&mut self) -> Option<Self::Item> {
181        self.iter
182            .next()
183            .map(|(k, v)| (k.0.as_str(), k.1.as_str(), v))
184    }
185}
186
187impl IntoIterator for &Imports {
188    type IntoIter = std::collections::hash_map::IntoIter<(String, String), Extern>;
189    type Item = ((String, String), Extern);
190
191    fn into_iter(self) -> Self::IntoIter {
192        self.map.clone().into_iter()
193    }
194}
195
196impl Extend<((String, String), Extern)> for Imports {
197    fn extend<T: IntoIterator<Item = ((String, String), Extern)>>(&mut self, iter: T) {
198        for ((ns, name), ext) in iter.into_iter() {
199            self.define(&ns, &name, ext);
200        }
201    }
202}
203
204impl fmt::Debug for Imports {
205    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
206        enum SecretMap {
207            Empty,
208            Some(usize),
209        }
210
211        impl SecretMap {
212            fn new(len: usize) -> Self {
213                if len == 0 {
214                    Self::Empty
215                } else {
216                    Self::Some(len)
217                }
218            }
219        }
220
221        impl fmt::Debug for SecretMap {
222            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
223                match self {
224                    Self::Empty => write!(f, "(empty)"),
225                    Self::Some(len) => write!(f, "(... {len} item(s) ...)"),
226                }
227            }
228        }
229
230        f.debug_struct("Imports")
231            .field("map", &SecretMap::new(self.map.len()))
232            .finish()
233    }
234}
235
236// The import! macro for Imports
237
238/// Generate an [`Imports`] easily with the `imports!` macro.
239///
240/// [`Imports`]: struct.Imports.html
241///
242/// # Usage
243///
244/// ```
245/// # use wasmer::{StoreMut, Function, FunctionEnvMut, Store};
246/// # let mut store = Store::default();
247/// use wasmer::imports;
248///
249/// let import_object = imports! {
250///     "env" => {
251///         "foo" => Function::new_typed(&mut store, foo)
252///     },
253/// };
254///
255/// fn foo(n: i32) -> i32 {
256///     n
257/// }
258/// ```
259#[macro_export]
260macro_rules! imports {
261    ( $( $ns_name:expr => $ns:tt ),* $(,)? ) => {
262        {
263            #[allow(unused_mut)]
264            let mut import_object = $crate::Imports::new();
265
266            $({
267                let namespace = $crate::import_namespace!($ns);
268
269                import_object.register_namespace($ns_name, namespace);
270            })*
271
272            import_object
273        }
274    };
275}
276
277#[macro_export]
278#[doc(hidden)]
279macro_rules! namespace {
280    ($( $import_name:expr => $import_item:expr ),* $(,)? ) => {
281        $crate::import_namespace!( { $( $import_name => $import_item, )* } )
282    };
283}
284
285#[macro_export]
286#[doc(hidden)]
287macro_rules! import_namespace {
288    ( { $( $import_name:expr => $import_item:expr ),* $(,)? } ) => {{
289        let mut namespace = $crate::Exports::new();
290
291        $(
292            namespace.insert($import_name, $import_item);
293        )*
294
295        namespace
296    }};
297
298    ( $namespace:ident ) => {
299        $namespace
300    };
301}
302
303#[cfg(test)]
304mod test {
305    use crate::Extern;
306    use crate::Global;
307    use crate::store::Store;
308    use crate::value::Value;
309    use wasmer_types::Type;
310
311    #[test]
312    fn namespace() {
313        let mut store = Store::default();
314        let g1 = Global::new(&mut store, Value::I32(0));
315        let namespace = namespace! {
316            "happy" => g1
317        };
318        let imports1 = imports! {
319            "dog" => namespace
320        };
321
322        let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
323
324        assert!(if let Extern::Global(happy_dog_global) = happy_dog_entry {
325            happy_dog_global.get(&mut store).ty() == Type::I32
326        } else {
327            false
328        });
329    }
330
331    #[test]
332    fn imports_macro_allows_trailing_comma_and_none() {
333        use crate::Function;
334
335        let mut store: Store = Default::default();
336
337        fn func(arg: i32) -> i32 {
338            arg + 1
339        }
340
341        let _ = imports! {
342            "env" => {
343                "func" => Function::new_typed(&mut store, func),
344            },
345        };
346        let _ = imports! {
347            "env" => {
348                "func" => Function::new_typed(&mut store, func),
349            }
350        };
351        let _ = imports! {
352            "env" => {
353                "func" => Function::new_typed(&mut store, func),
354            },
355            "abc" => {
356                "def" => Function::new_typed(&mut store, func),
357            }
358        };
359        let _ = imports! {
360            "env" => {
361                "func" => Function::new_typed(&mut store, func)
362            },
363        };
364        let _ = imports! {
365            "env" => {
366                "func" => Function::new_typed(&mut store, func)
367            }
368        };
369        let _ = imports! {
370            "env" => {
371                "func1" => Function::new_typed(&mut store, func),
372                "func2" => Function::new_typed(&mut store, func)
373            }
374        };
375        let _ = imports! {
376            "env" => {
377                "func1" => Function::new_typed(&mut store, func),
378                "func2" => Function::new_typed(&mut store, func),
379            }
380        };
381    }
382
383    #[test]
384    fn chaining_works() {
385        let mut store = Store::default();
386
387        let g = Global::new(&mut store, Value::I32(0));
388
389        let mut imports1 = imports! {
390            "dog" => {
391                "happy" => g.clone()
392            }
393        };
394
395        let imports2 = imports! {
396            "dog" => {
397                "small" => g.clone()
398            },
399            "cat" => {
400                "small" => g
401            }
402        };
403
404        imports1.extend(&imports2);
405
406        let small_cat_export = imports1.get_export("cat", "small");
407        assert!(small_cat_export.is_some());
408
409        let happy = imports1.get_export("dog", "happy");
410        let small = imports1.get_export("dog", "small");
411        assert!(happy.is_some());
412        assert!(small.is_some());
413    }
414
415    #[test]
416    fn extending_conflict_overwrites() {
417        let mut store = Store::default();
418        let g1 = Global::new(&mut store, Value::I32(0));
419        let g2 = Global::new(&mut store, Value::I64(0));
420
421        let mut imports1 = imports! {
422            "dog" => {
423                "happy" => g1,
424            },
425        };
426
427        let imports2 = imports! {
428            "dog" => {
429                "happy" => g2,
430            },
431        };
432
433        imports1.extend(&imports2);
434        let _happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
435        /*
436        assert!(
437            if let Exports::Global(happy_dog_global) = happy_dog_entry.to_vm_extern() {
438                happy_dog_global.from.ty().ty == Type::I64
439            } else {
440                false
441            }
442        );
443        */
444        // now test it in reverse
445        let mut store = Store::default();
446        let g1 = Global::new(&mut store, Value::I32(0));
447        let g2 = Global::new(&mut store, Value::I64(0));
448
449        let imports1 = imports! {
450            "dog" => {
451                "happy" => g1,
452            },
453        };
454
455        let mut imports2 = imports! {
456            "dog" => {
457                "happy" => g2,
458            },
459        };
460
461        imports2.extend(&imports1);
462
463        let _happy_dog_entry = imports2.get_export("dog", "happy").unwrap();
464        /*
465        assert!(
466            if let Exports::Global(happy_dog_global) = happy_dog_entry.to_vm_extern() {
467                happy_dog_global.from.ty().ty == Type::I32
468            } else {
469                false
470            }
471        );
472        */
473    }
474}