Coverage Report

Created: 2024-10-16 07:58

/src/wasmer/lib/api/src/exports.rs
Line
Count
Source (jump to first uncovered line)
1
use crate::store::AsStoreRef;
2
use crate::{Extern, Function, Global, Memory, Table, TypedFunction, WasmTypeList};
3
use indexmap::IndexMap;
4
use std::fmt;
5
use std::iter::{ExactSizeIterator, FromIterator};
6
use thiserror::Error;
7
8
/// The `ExportError` can happen when trying to get a specific
9
/// export [`Extern`] from the [`Instance`] exports.
10
///
11
/// [`Instance`]: crate::Instance
12
///
13
/// # Examples
14
///
15
/// ## Incompatible export type
16
///
17
/// ```should_panic
18
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value, ExportError};
19
/// # let mut store = Store::default();
20
/// # let wasm_bytes = wat2wasm(r#"
21
/// # (module
22
/// #   (global $one (export "glob") f32 (f32.const 1)))
23
/// # "#.as_bytes()).unwrap();
24
/// # let module = Module::new(&store, wasm_bytes).unwrap();
25
/// # let import_object = imports! {};
26
/// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
27
/// #
28
/// // This results with an error: `ExportError::IncompatibleType`.
29
/// let export = instance.exports.get_function("glob").unwrap();
30
/// ```
31
///
32
/// ## Missing export
33
///
34
/// ```should_panic
35
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value, ExportError};
36
/// # let mut store = Store::default();
37
/// # let wasm_bytes = wat2wasm("(module)".as_bytes()).unwrap();
38
/// # let module = Module::new(&store, wasm_bytes).unwrap();
39
/// # let import_object = imports! {};
40
/// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
41
/// #
42
/// // This results with an error: `ExportError::Missing`.
43
/// let export = instance.exports.get_function("unknown").unwrap();
44
/// ```
45
0
#[derive(Error, Debug, Clone)]
Unexecuted instantiation: <wasmer::exports::ExportError as core::fmt::Display>::fmt
Unexecuted instantiation: <wasmer::exports::ExportError as core::fmt::Display>::fmt
46
pub enum ExportError {
47
    /// An error than occurs when the exported type and the expected type
48
    /// are incompatible.
49
    #[error("Incompatible Export Type")]
50
    IncompatibleType,
51
    /// This error arises when an export is missing
52
    #[error("Missing export {0}")]
53
    Missing(String),
54
}
55
56
/// Exports is a special kind of map that allows easily unwrapping
57
/// the types of instances.
58
///
59
/// TODO: add examples of using exports
60
#[derive(Clone, Default, PartialEq, Eq)]
61
#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
62
pub struct Exports {
63
    map: IndexMap<String, Extern>,
64
}
65
66
impl Exports {
67
    /// Creates a new `Exports`.
68
0
    pub fn new() -> Self {
69
0
        Default::default()
70
0
    }
Unexecuted instantiation: <wasmer::exports::Exports>::new
Unexecuted instantiation: <wasmer::exports::Exports>::new
71
72
    /// Creates a new `Exports` with capacity `n`.
73
0
    pub fn with_capacity(n: usize) -> Self {
74
0
        Self {
75
0
            map: IndexMap::with_capacity(n),
76
0
        }
77
0
    }
Unexecuted instantiation: <wasmer::exports::Exports>::with_capacity
Unexecuted instantiation: <wasmer::exports::Exports>::with_capacity
78
79
    /// Return the number of exports in the `Exports` map.
80
0
    pub fn len(&self) -> usize {
81
0
        self.map.len()
82
0
    }
Unexecuted instantiation: <wasmer::exports::Exports>::len
Unexecuted instantiation: <wasmer::exports::Exports>::len
83
84
    /// Return whether or not there are no exports
85
0
    pub fn is_empty(&self) -> bool {
86
0
        self.len() == 0
87
0
    }
Unexecuted instantiation: <wasmer::exports::Exports>::is_empty
Unexecuted instantiation: <wasmer::exports::Exports>::is_empty
88
89
    /// Insert a new export into this `Exports` map.
90
0
    pub fn insert<S, E>(&mut self, name: S, value: E)
91
0
    where
92
0
        S: Into<String>,
93
0
        E: Into<Extern>,
94
0
    {
95
0
        self.map.insert(name.into(), value.into());
96
0
    }
Unexecuted instantiation: <wasmer::exports::Exports>::insert::<_, _>
Unexecuted instantiation: <wasmer::exports::Exports>::insert::<_, _>
97
98
    /// Get an export given a `name`.
99
    ///
100
    /// The `get` method is specifically made for usage inside of
101
    /// Rust APIs, as we can detect what's the desired type easily.
102
    ///
103
    /// If you want to get an export dynamically with type checking
104
    /// please use the following functions: `get_func`, `get_memory`,
105
    /// `get_table` or `get_global` instead.
106
    ///
107
    /// If you want to get an export dynamically handling manually
108
    /// type checking manually, please use `get_extern`.
109
0
    pub fn get<'a, T: Exportable<'a>>(&'a self, name: &str) -> Result<&'a T, ExportError> {
110
0
        match self.map.get(name) {
111
0
            None => Err(ExportError::Missing(name.to_string())),
112
0
            Some(extern_) => T::get_self_from_extern(extern_),
113
        }
114
0
    }
Unexecuted instantiation: <wasmer::exports::Exports>::get::<wasmer::externals::table::Table>
Unexecuted instantiation: <wasmer::exports::Exports>::get::<wasmer::externals::global::Global>
Unexecuted instantiation: <wasmer::exports::Exports>::get::<wasmer::externals::memory::Memory>
Unexecuted instantiation: <wasmer::exports::Exports>::get::<wasmer::externals::function::Function>
Unexecuted instantiation: <wasmer::exports::Exports>::get::<wasmer::externals::table::Table>
Unexecuted instantiation: <wasmer::exports::Exports>::get::<wasmer::externals::global::Global>
Unexecuted instantiation: <wasmer::exports::Exports>::get::<wasmer::externals::memory::Memory>
Unexecuted instantiation: <wasmer::exports::Exports>::get::<wasmer::externals::function::Function>
115
116
    /// Get an export as a `Global`.
117
0
    pub fn get_global(&self, name: &str) -> Result<&Global, ExportError> {
118
0
        self.get(name)
119
0
    }
Unexecuted instantiation: <wasmer::exports::Exports>::get_global
Unexecuted instantiation: <wasmer::exports::Exports>::get_global
120
121
    /// Get an export as a `Memory`.
122
0
    pub fn get_memory(&self, name: &str) -> Result<&Memory, ExportError> {
123
0
        self.get(name)
124
0
    }
Unexecuted instantiation: <wasmer::exports::Exports>::get_memory
Unexecuted instantiation: <wasmer::exports::Exports>::get_memory
125
126
    /// Get an export as a `Table`.
127
0
    pub fn get_table(&self, name: &str) -> Result<&Table, ExportError> {
128
0
        self.get(name)
129
0
    }
Unexecuted instantiation: <wasmer::exports::Exports>::get_table
Unexecuted instantiation: <wasmer::exports::Exports>::get_table
130
131
    /// Get an export as a `Func`.
132
0
    pub fn get_function(&self, name: &str) -> Result<&Function, ExportError> {
133
0
        self.get(name)
134
0
    }
Unexecuted instantiation: <wasmer::exports::Exports>::get_function
Unexecuted instantiation: <wasmer::exports::Exports>::get_function
135
136
    /// Get an export as a `TypedFunction`.
137
0
    pub fn get_typed_function<Args, Rets>(
138
0
        &self,
139
0
        store: &impl AsStoreRef,
140
0
        name: &str,
141
0
    ) -> Result<TypedFunction<Args, Rets>, ExportError>
142
0
    where
143
0
        Args: WasmTypeList,
144
0
        Rets: WasmTypeList,
145
0
    {
146
0
        self.get_function(name)?
147
0
            .typed(store)
148
0
            .map_err(|_| ExportError::IncompatibleType)
Unexecuted instantiation: <wasmer::exports::Exports>::get_typed_function::<_, _, _>::{closure#0}
Unexecuted instantiation: <wasmer::exports::Exports>::get_typed_function::<_, _, _>::{closure#0}
149
0
    }
Unexecuted instantiation: <wasmer::exports::Exports>::get_typed_function::<_, _, _>
Unexecuted instantiation: <wasmer::exports::Exports>::get_typed_function::<_, _, _>
150
151
    /// Hack to get this working with nativefunc too
152
0
    pub fn get_with_generics<'a, T, Args, Rets>(&'a self, name: &str) -> Result<T, ExportError>
153
0
    where
154
0
        Args: WasmTypeList,
155
0
        Rets: WasmTypeList,
156
0
        T: ExportableWithGenerics<'a, Args, Rets>,
157
0
    {
158
0
        match self.map.get(name) {
159
0
            None => Err(ExportError::Missing(name.to_string())),
160
0
            Some(extern_) => T::get_self_from_extern_with_generics(extern_),
161
        }
162
0
    }
Unexecuted instantiation: <wasmer::exports::Exports>::get_with_generics::<_, _, _>
Unexecuted instantiation: <wasmer::exports::Exports>::get_with_generics::<_, _, _>
163
164
    /// Get an export as an `Extern`.
165
0
    pub fn get_extern(&self, name: &str) -> Option<&Extern> {
166
0
        self.map.get(name)
167
0
    }
Unexecuted instantiation: <wasmer::exports::Exports>::get_extern
Unexecuted instantiation: <wasmer::exports::Exports>::get_extern
168
169
    /// Returns true if the `Exports` contains the given export name.
170
0
    pub fn contains<S>(&self, name: S) -> bool
171
0
    where
172
0
        S: Into<String>,
173
0
    {
174
0
        self.map.contains_key(&name.into())
175
0
    }
Unexecuted instantiation: <wasmer::exports::Exports>::contains::<_>
Unexecuted instantiation: <wasmer::exports::Exports>::contains::<_>
176
177
    /// Get an iterator over the exports.
178
0
    pub fn iter(&self) -> ExportsIterator<impl Iterator<Item = (&String, &Extern)>> {
179
0
        ExportsIterator {
180
0
            iter: self.map.iter(),
181
0
        }
182
0
    }
Unexecuted instantiation: <wasmer::exports::Exports>::iter
Unexecuted instantiation: <wasmer::exports::Exports>::iter
183
}
184
185
impl fmt::Debug for Exports {
186
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
187
0
        f.debug_set().entries(self.iter()).finish()
188
0
    }
Unexecuted instantiation: <wasmer::exports::Exports as core::fmt::Debug>::fmt
Unexecuted instantiation: <wasmer::exports::Exports as core::fmt::Debug>::fmt
189
}
190
191
/// An iterator over exports.
192
pub struct ExportsIterator<'a, I>
193
where
194
    I: Iterator<Item = (&'a String, &'a Extern)> + Sized,
195
{
196
    iter: I,
197
}
198
199
impl<'a, I> Iterator for ExportsIterator<'a, I>
200
where
201
    I: Iterator<Item = (&'a String, &'a Extern)> + Sized,
202
{
203
    type Item = (&'a String, &'a Extern);
204
205
0
    fn next(&mut self) -> Option<Self::Item> {
206
0
        self.iter.next()
207
0
    }
Unexecuted instantiation: <wasmer::exports::ExportsIterator<indexmap::map::Iter<alloc::string::String, wasmer::externals::Extern>> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <wasmer::exports::ExportsIterator<indexmap::map::Iter<alloc::string::String, wasmer::externals::Extern>> as core::iter::traits::iterator::Iterator>::next
208
}
209
210
impl<'a, I> ExactSizeIterator for ExportsIterator<'a, I>
211
where
212
    I: Iterator<Item = (&'a String, &'a Extern)> + ExactSizeIterator + Sized,
213
{
214
0
    fn len(&self) -> usize {
215
0
        self.iter.len()
216
0
    }
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_> as core::iter::traits::exact_size::ExactSizeIterator>::len
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_> as core::iter::traits::exact_size::ExactSizeIterator>::len
217
}
218
219
impl<'a, I> ExportsIterator<'a, I>
220
where
221
    I: Iterator<Item = (&'a String, &'a Extern)> + Sized,
222
{
223
    /// Get only the functions.
224
0
    pub fn functions(self) -> impl Iterator<Item = (&'a String, &'a Function)> + Sized {
225
0
        self.iter.filter_map(|(name, export)| match export {
226
0
            Extern::Function(function) => Some((name, function)),
227
0
            _ => None,
228
0
        })
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_>>::functions::{closure#0}
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_>>::functions::{closure#0}
229
0
    }
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_>>::functions
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_>>::functions
230
231
    /// Get only the memories.
232
0
    pub fn memories(self) -> impl Iterator<Item = (&'a String, &'a Memory)> + Sized {
233
0
        self.iter.filter_map(|(name, export)| match export {
234
0
            Extern::Memory(memory) => Some((name, memory)),
235
0
            _ => None,
236
0
        })
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_>>::memories::{closure#0}
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_>>::memories::{closure#0}
237
0
    }
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_>>::memories
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_>>::memories
238
239
    /// Get only the globals.
240
0
    pub fn globals(self) -> impl Iterator<Item = (&'a String, &'a Global)> + Sized {
241
0
        self.iter.filter_map(|(name, export)| match export {
242
0
            Extern::Global(global) => Some((name, global)),
243
0
            _ => None,
244
0
        })
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_>>::globals::{closure#0}
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_>>::globals::{closure#0}
245
0
    }
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_>>::globals
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_>>::globals
246
247
    /// Get only the tables.
248
0
    pub fn tables(self) -> impl Iterator<Item = (&'a String, &'a Table)> + Sized {
249
0
        self.iter.filter_map(|(name, export)| match export {
250
0
            Extern::Table(table) => Some((name, table)),
251
0
            _ => None,
252
0
        })
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_>>::tables::{closure#0}
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_>>::tables::{closure#0}
253
0
    }
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_>>::tables
Unexecuted instantiation: <wasmer::exports::ExportsIterator<_>>::tables
254
}
255
256
impl FromIterator<(String, Extern)> for Exports {
257
11.1k
    fn from_iter<I: IntoIterator<Item = (String, Extern)>>(iter: I) -> Self {
258
11.1k
        Self {
259
11.1k
            map: IndexMap::from_iter(iter),
260
11.1k
        }
261
11.1k
    }
<wasmer::exports::Exports as core::iter::traits::collect::FromIterator<(alloc::string::String, wasmer::externals::Extern)>>::from_iter::<core::iter::adapters::map::Map<wasmer_types::module::ExportsIterator<core::iter::adapters::map::Map<indexmap::map::Iter<alloc::string::String, wasmer_types::indexes::ExportIndex>, <wasmer_types::module::ModuleInfo>::exports::{closure#0}>>, <wasmer::sys::instance::Instance>::get_exports<wasmer::store::Store>::{closure#0}>>
Line
Count
Source
257
108
    fn from_iter<I: IntoIterator<Item = (String, Extern)>>(iter: I) -> Self {
258
108
        Self {
259
108
            map: IndexMap::from_iter(iter),
260
108
        }
261
108
    }
Unexecuted instantiation: <wasmer::exports::Exports as core::iter::traits::collect::FromIterator<(alloc::string::String, wasmer::externals::Extern)>>::from_iter::<core::iter::adapters::map::Map<core::iter::adapters::filter::Filter<std::collections::hash::map::Iter<(alloc::string::String, alloc::string::String), wasmer::externals::Extern>, <wasmer::imports::Imports>::get_namespace_exports::{closure#0}>, <wasmer::imports::Imports>::get_namespace_exports::{closure#1}>>
<wasmer::exports::Exports as core::iter::traits::collect::FromIterator<(alloc::string::String, wasmer::externals::Extern)>>::from_iter::<core::iter::adapters::map::Map<wasmer_types::module::ExportsIterator<core::iter::adapters::map::Map<indexmap::map::Iter<alloc::string::String, wasmer_types::indexes::ExportIndex>, <wasmer_types::module::ModuleInfo>::exports::{closure#0}>>, <wasmer::sys::instance::Instance>::get_exports<wasmer::store::Store>::{closure#0}>>
Line
Count
Source
257
11.0k
    fn from_iter<I: IntoIterator<Item = (String, Extern)>>(iter: I) -> Self {
258
11.0k
        Self {
259
11.0k
            map: IndexMap::from_iter(iter),
260
11.0k
        }
261
11.0k
    }
Unexecuted instantiation: <wasmer::exports::Exports as core::iter::traits::collect::FromIterator<(alloc::string::String, wasmer::externals::Extern)>>::from_iter::<core::iter::adapters::map::Map<core::iter::adapters::filter::Filter<std::collections::hash::map::Iter<(alloc::string::String, alloc::string::String), wasmer::externals::Extern>, <wasmer::imports::Imports>::get_namespace_exports::{closure#0}>, <wasmer::imports::Imports>::get_namespace_exports::{closure#1}>>
Unexecuted instantiation: <wasmer::exports::Exports as core::iter::traits::collect::FromIterator<(alloc::string::String, wasmer::externals::Extern)>>::from_iter::<core::iter::adapters::map::Map<wasmer_types::module::ExportsIterator<core::iter::adapters::map::Map<indexmap::map::Iter<alloc::string::String, wasmer_types::indexes::ExportIndex>, <wasmer_types::module::ModuleInfo>::exports::{closure#0}>>, <wasmer::sys::instance::Instance>::get_exports<wasmer::store::Store>::{closure#0}>>
Unexecuted instantiation: <wasmer::exports::Exports as core::iter::traits::collect::FromIterator<(alloc::string::String, wasmer::externals::Extern)>>::from_iter::<core::iter::adapters::map::Map<wasmer_types::module::ExportsIterator<core::iter::adapters::map::Map<indexmap::map::Iter<alloc::string::String, wasmer_types::indexes::ExportIndex>, <wasmer_types::module::ModuleInfo>::exports::{closure#0}>>, <wasmer::sys::instance::Instance>::get_exports<wasmer::store::Store>::{closure#0}>>
262
}
263
264
impl IntoIterator for Exports {
265
    type IntoIter = indexmap::map::IntoIter<String, Extern>;
266
    type Item = (String, Extern);
267
268
0
    fn into_iter(self) -> Self::IntoIter {
269
0
        self.map.into_iter()
270
0
    }
Unexecuted instantiation: <wasmer::exports::Exports as core::iter::traits::collect::IntoIterator>::into_iter
Unexecuted instantiation: <wasmer::exports::Exports as core::iter::traits::collect::IntoIterator>::into_iter
271
}
272
273
impl<'a> IntoIterator for &'a Exports {
274
    type IntoIter = indexmap::map::Iter<'a, String, Extern>;
275
    type Item = (&'a String, &'a Extern);
276
277
0
    fn into_iter(self) -> Self::IntoIter {
278
0
        self.map.iter()
279
0
    }
Unexecuted instantiation: <&wasmer::exports::Exports as core::iter::traits::collect::IntoIterator>::into_iter
Unexecuted instantiation: <&wasmer::exports::Exports as core::iter::traits::collect::IntoIterator>::into_iter
280
}
281
282
/// This trait is used to mark types as gettable from an [`Instance`].
283
///
284
/// [`Instance`]: crate::Instance
285
pub trait Exportable<'a>: Sized {
286
    /// Implementation of how to get the export corresponding to the implementing type
287
    /// from an [`Instance`] by name.
288
    ///
289
    /// [`Instance`]: crate::Instance
290
    fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError>;
291
}
292
293
/// A trait for accessing exports (like [`Exportable`]) but it takes generic
294
/// `Args` and `Rets` parameters so that `TypedFunction` can be accessed directly
295
/// as well.
296
pub trait ExportableWithGenerics<'a, Args: WasmTypeList, Rets: WasmTypeList>: Sized {
297
    /// Get an export with the given generics.
298
    fn get_self_from_extern_with_generics(_extern: &'a Extern) -> Result<Self, ExportError>;
299
}
300
301
/// We implement it for all concrete [`Exportable`] types (that are `Clone`)
302
/// with empty `Args` and `Rets`.
303
impl<'a, T: Exportable<'a> + Clone + 'static> ExportableWithGenerics<'a, (), ()> for T {
304
0
    fn get_self_from_extern_with_generics(_extern: &'a Extern) -> Result<Self, ExportError> {
305
0
        T::get_self_from_extern(_extern).map(|i| i.clone())
Unexecuted instantiation: <_ as wasmer::exports::ExportableWithGenerics<(), ()>>::get_self_from_extern_with_generics::{closure#0}
Unexecuted instantiation: <_ as wasmer::exports::ExportableWithGenerics<(), ()>>::get_self_from_extern_with_generics::{closure#0}
306
0
    }
Unexecuted instantiation: <_ as wasmer::exports::ExportableWithGenerics<(), ()>>::get_self_from_extern_with_generics
Unexecuted instantiation: <_ as wasmer::exports::ExportableWithGenerics<(), ()>>::get_self_from_extern_with_generics
307
}