/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 | | } |