1use crate::{Exports, Extern, Module, error::LinkError};
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() { None } else { Some(ret) }
134 }
135
136 #[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 pub fn iter(&self) -> ImportsIterator<'_> {
161 ImportsIterator::new(self)
162 }
163}
164
165pub 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#[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 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 }
474}