linera_wasmer/
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, LinkError, Module};
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() {
134            None
135        } else {
136            Some(ret)
137        }
138    }
139
140    /// Resolve and return a vector of imports in the order they are defined in the `module`'s source code.
141    ///
142    /// This means the returned `Vec<Extern>` might be a subset of the imports contained in `self`.
143    #[allow(clippy::result_large_err)]
144    pub fn imports_for_module(&self, module: &Module) -> Result<Vec<Extern>, LinkError> {
145        let mut ret = vec![];
146        for import in module.imports() {
147            if let Some(imp) = self
148                .map
149                .get(&(import.module().to_string(), import.name().to_string()))
150            {
151                ret.push(imp.clone());
152            } else {
153                return Err(LinkError::Import(
154                    import.module().to_string(),
155                    import.name().to_string(),
156                    ImportError::UnknownImport(import.ty().clone()),
157                ));
158            }
159        }
160        Ok(ret)
161    }
162
163    /// Iterates through all the imports in this structure
164    pub fn iter(&self) -> ImportsIterator<'_> {
165        ImportsIterator::new(self)
166    }
167}
168
169pub struct ImportsIterator<'a> {
170    iter: std::collections::hash_map::Iter<'a, (String, String), Extern>,
171}
172
173impl<'a> ImportsIterator<'a> {
174    fn new(imports: &'a Imports) -> Self {
175        let iter = imports.map.iter();
176        Self { iter }
177    }
178}
179
180impl<'a> Iterator for ImportsIterator<'a> {
181    type Item = (&'a str, &'a str, &'a Extern);
182
183    fn next(&mut self) -> Option<Self::Item> {
184        self.iter
185            .next()
186            .map(|(k, v)| (k.0.as_str(), k.1.as_str(), v))
187    }
188}
189
190impl IntoIterator for &Imports {
191    type IntoIter = std::collections::hash_map::IntoIter<(String, String), Extern>;
192    type Item = ((String, String), Extern);
193
194    fn into_iter(self) -> Self::IntoIter {
195        self.map.clone().into_iter()
196    }
197}
198
199impl Extend<((String, String), Extern)> for Imports {
200    fn extend<T: IntoIterator<Item = ((String, String), Extern)>>(&mut self, iter: T) {
201        for ((ns, name), ext) in iter.into_iter() {
202            self.define(&ns, &name, ext);
203        }
204    }
205}
206
207impl fmt::Debug for Imports {
208    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
209        enum SecretMap {
210            Empty,
211            Some(usize),
212        }
213
214        impl SecretMap {
215            fn new(len: usize) -> Self {
216                if len == 0 {
217                    Self::Empty
218                } else {
219                    Self::Some(len)
220                }
221            }
222        }
223
224        impl fmt::Debug for SecretMap {
225            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
226                match self {
227                    Self::Empty => write!(f, "(empty)"),
228                    Self::Some(len) => write!(f, "(... {} item(s) ...)", len),
229                }
230            }
231        }
232
233        f.debug_struct("Imports")
234            .field("map", &SecretMap::new(self.map.len()))
235            .finish()
236    }
237}
238
239// The import! macro for Imports
240
241/// Generate an [`Imports`] easily with the `imports!` macro.
242///
243/// [`Imports`]: struct.Imports.html
244///
245/// # Usage
246///
247/// ```
248/// # use wasmer::{StoreMut, Function, FunctionEnvMut, Store};
249/// # let mut store = Store::default();
250/// use wasmer::imports;
251///
252/// let import_object = imports! {
253///     "env" => {
254///         "foo" => Function::new_typed(&mut store, foo)
255///     },
256/// };
257///
258/// fn foo(n: i32) -> i32 {
259///     n
260/// }
261/// ```
262#[macro_export]
263macro_rules! imports {
264    ( $( $ns_name:expr => $ns:tt ),* $(,)? ) => {
265        {
266            #[allow(unused_mut)]
267            let mut import_object = $crate::Imports::new();
268
269            $({
270                let namespace = $crate::import_namespace!($ns);
271
272                import_object.register_namespace($ns_name, namespace);
273            })*
274
275            import_object
276        }
277    };
278}
279
280#[macro_export]
281#[doc(hidden)]
282macro_rules! namespace {
283    ($( $import_name:expr => $import_item:expr ),* $(,)? ) => {
284        $crate::import_namespace!( { $( $import_name => $import_item, )* } )
285    };
286}
287
288#[macro_export]
289#[doc(hidden)]
290macro_rules! import_namespace {
291    ( { $( $import_name:expr => $import_item:expr ),* $(,)? } ) => {{
292        let mut namespace = $crate::Exports::new();
293
294        $(
295            namespace.insert($import_name, $import_item);
296        )*
297
298        namespace
299    }};
300
301    ( $namespace:ident ) => {
302        $namespace
303    };
304}
305
306#[cfg(test)]
307mod test {
308    use crate::store::Store;
309    use crate::value::Value;
310    use crate::Extern;
311    use crate::Global;
312    use wasmer_types::Type;
313
314    #[test]
315    fn namespace() {
316        let mut store = Store::default();
317        let g1 = Global::new(&mut store, Value::I32(0));
318        let namespace = namespace! {
319            "happy" => g1
320        };
321        let imports1 = imports! {
322            "dog" => namespace
323        };
324
325        let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
326
327        assert!(if let Extern::Global(happy_dog_global) = happy_dog_entry {
328            happy_dog_global.get(&mut store).ty() == Type::I32
329        } else {
330            false
331        });
332    }
333
334    #[test]
335    fn imports_macro_allows_trailing_comma_and_none() {
336        use crate::Function;
337
338        let mut store: Store = Default::default();
339
340        fn func(arg: i32) -> i32 {
341            arg + 1
342        }
343
344        let _ = imports! {
345            "env" => {
346                "func" => Function::new_typed(&mut store, func),
347            },
348        };
349        let _ = imports! {
350            "env" => {
351                "func" => Function::new_typed(&mut store, func),
352            }
353        };
354        let _ = imports! {
355            "env" => {
356                "func" => Function::new_typed(&mut store, func),
357            },
358            "abc" => {
359                "def" => Function::new_typed(&mut store, func),
360            }
361        };
362        let _ = imports! {
363            "env" => {
364                "func" => Function::new_typed(&mut store, func)
365            },
366        };
367        let _ = imports! {
368            "env" => {
369                "func" => Function::new_typed(&mut store, func)
370            }
371        };
372        let _ = imports! {
373            "env" => {
374                "func1" => Function::new_typed(&mut store, func),
375                "func2" => Function::new_typed(&mut store, func)
376            }
377        };
378        let _ = imports! {
379            "env" => {
380                "func1" => Function::new_typed(&mut store, func),
381                "func2" => Function::new_typed(&mut store, func),
382            }
383        };
384    }
385
386    #[test]
387    fn chaining_works() {
388        let mut store = Store::default();
389
390        let g = Global::new(&mut store, Value::I32(0));
391
392        let mut imports1 = imports! {
393            "dog" => {
394                "happy" => g.clone()
395            }
396        };
397
398        let imports2 = imports! {
399            "dog" => {
400                "small" => g.clone()
401            },
402            "cat" => {
403                "small" => g
404            }
405        };
406
407        imports1.extend(&imports2);
408
409        let small_cat_export = imports1.get_export("cat", "small");
410        assert!(small_cat_export.is_some());
411
412        let happy = imports1.get_export("dog", "happy");
413        let small = imports1.get_export("dog", "small");
414        assert!(happy.is_some());
415        assert!(small.is_some());
416    }
417
418    #[test]
419    fn extending_conflict_overwrites() {
420        let mut store = Store::default();
421        let g1 = Global::new(&mut store, Value::I32(0));
422        let g2 = Global::new(&mut store, Value::I64(0));
423
424        let mut imports1 = imports! {
425            "dog" => {
426                "happy" => g1,
427            },
428        };
429
430        let imports2 = imports! {
431            "dog" => {
432                "happy" => g2,
433            },
434        };
435
436        imports1.extend(&imports2);
437        let _happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
438        /*
439        assert!(
440            if let Exports::Global(happy_dog_global) = happy_dog_entry.to_vm_extern() {
441                happy_dog_global.from.ty().ty == Type::I64
442            } else {
443                false
444            }
445        );
446        */
447        // now test it in reverse
448        let mut store = Store::default();
449        let g1 = Global::new(&mut store, Value::I32(0));
450        let g2 = Global::new(&mut store, Value::I64(0));
451
452        let imports1 = imports! {
453            "dog" => {
454                "happy" => g1,
455            },
456        };
457
458        let mut imports2 = imports! {
459            "dog" => {
460                "happy" => g2,
461            },
462        };
463
464        imports2.extend(&imports1);
465        let _happy_dog_entry = imports2.get_export("dog", "happy").unwrap();
466        /*
467        assert!(
468            if let Exports::Global(happy_dog_global) = happy_dog_entry.to_vm_extern() {
469                happy_dog_global.from.ty().ty == Type::I32
470            } else {
471                false
472            }
473        );
474        */
475    }
476}