1use crate::{Exports, Extern, LinkError, Module};
5use std::collections::HashMap;
6use std::fmt;
7use wasmer_types::ImportError;
8
9#[derive(Clone, Default)]
37pub struct Imports {
38 pub(crate) map: HashMap<(String, String), Extern>,
39}
40
41impl Imports {
42 pub fn new() -> Self {
44 Default::default()
45 }
46
47 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 pub fn exists(&self, module: &str, name: &str) -> bool {
72 self.map
73 .contains_key(&(module.to_string(), name.to_string()))
74 }
75
76 pub fn contains_namespace(&self, name: &str) -> bool {
78 self.map.keys().any(|(k, _)| (k == name))
79 }
80
81 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 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 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 #[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 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#[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 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 }
476}