1use alloc::{
2 boxed::Box,
3 string::{String, ToString},
4};
5use core::fmt;
6
7use anyhow::Result;
8use fxhash::FxBuildHasher;
9use hashbrown::HashMap;
10
11use crate::{
12 ExportType, ExternType, FuncType, GlobalType, ImportType, MemoryType, TableType, ValueType,
13};
14
15#[derive(Clone)]
17pub enum Value<E: WasmEngine> {
18 I32(i32),
20 I64(i64),
22 F32(f32),
24 F64(f64),
26 FuncRef(Option<E::Func>),
28 ExternRef(Option<E::ExternRef>),
30}
31
32impl<E: WasmEngine> Value<E> {
33 #[must_use]
35 pub const fn ty(&self) -> ValueType {
36 match self {
37 Value::I32(_) => ValueType::I32,
38 Value::I64(_) => ValueType::I64,
39 Value::F32(_) => ValueType::F32,
40 Value::F64(_) => ValueType::F64,
41 Value::FuncRef(_) => ValueType::FuncRef,
42 Value::ExternRef(_) => ValueType::ExternRef,
43 }
44 }
45}
46
47impl<E: WasmEngine> fmt::Debug for Value<E>
48where
49 E::Func: fmt::Debug,
50 E::ExternRef: fmt::Debug,
51{
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 match self {
54 Value::I32(v) => f.debug_tuple("I32").field(v).finish(),
55 Value::I64(v) => f.debug_tuple("I64").field(v).finish(),
56 Value::F32(v) => f.debug_tuple("F32").field(v).finish(),
57 Value::F64(v) => f.debug_tuple("F64").field(v).finish(),
58 Value::FuncRef(v) => f.debug_tuple("FuncRef").field(v).finish(),
59 Value::ExternRef(v) => f.debug_tuple("ExternRef").field(v).finish(),
60 }
61 }
62}
63
64pub enum Extern<E: WasmEngine> {
69 Global(E::Global),
73 Table(E::Table),
75 Memory(E::Memory),
77 Func(E::Func),
79}
80
81impl<E: WasmEngine> Extern<E> {
82 pub fn into_global(self) -> Option<E::Global> {
86 if let Self::Global(global) = self {
87 return Some(global);
88 }
89 None
90 }
91
92 pub fn into_table(self) -> Option<E::Table> {
96 if let Self::Table(table) = self {
97 return Some(table);
98 }
99 None
100 }
101
102 pub fn into_memory(self) -> Option<E::Memory> {
106 if let Self::Memory(memory) = self {
107 return Some(memory);
108 }
109 None
110 }
111
112 pub fn into_func(self) -> Option<E::Func> {
116 if let Self::Func(func) = self {
117 return Some(func);
118 }
119 None
120 }
121
122 pub fn ty(&self, ctx: impl AsContext<E>) -> ExternType {
128 match self {
129 Extern::Global(global) => global.ty(ctx).into(),
130 Extern::Table(table) => table.ty(ctx).into(),
131 Extern::Memory(memory) => memory.ty(ctx).into(),
132 Extern::Func(func) => func.ty(ctx).into(),
133 }
134 }
135}
136
137impl<E: WasmEngine> Clone for Extern<E> {
138 fn clone(&self) -> Self {
139 match self {
140 Self::Global(arg0) => Self::Global(arg0.clone()),
141 Self::Table(arg0) => Self::Table(arg0.clone()),
142 Self::Memory(arg0) => Self::Memory(arg0.clone()),
143 Self::Func(arg0) => Self::Func(arg0.clone()),
144 }
145 }
146}
147
148impl<E: WasmEngine> fmt::Debug for Extern<E>
149where
150 E::Global: fmt::Debug,
151 E::Func: fmt::Debug,
152 E::Memory: fmt::Debug,
153 E::Table: fmt::Debug,
154{
155 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156 match self {
157 Self::Global(arg0) => f.debug_tuple("Global").field(arg0).finish(),
158 Self::Table(arg0) => f.debug_tuple("Table").field(arg0).finish(),
159 Self::Memory(arg0) => f.debug_tuple("Memory").field(arg0).finish(),
160 Self::Func(arg0) => f.debug_tuple("Func").field(arg0).finish(),
161 }
162 }
163}
164
165#[derive(Clone)]
170pub struct Export<E: WasmEngine> {
171 pub name: String,
173 pub value: Extern<E>,
175}
176
177impl<E: WasmEngine> fmt::Debug for Export<E>
178where
179 Extern<E>: fmt::Debug,
180{
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 f.debug_struct("Export")
183 .field("name", &self.name)
184 .field("value", &self.value)
185 .finish()
186 }
187}
188
189#[derive(Clone)]
191pub struct Imports<E: WasmEngine> {
192 pub(crate) map: HashMap<(String, String), Extern<E>, FxBuildHasher>,
194}
195
196impl<E: WasmEngine> Imports<E> {
197 pub fn new() -> Self {
199 Self {
200 map: HashMap::default(),
201 }
202 }
203
204 pub fn get_export(&self, module: &str, name: &str) -> Option<Extern<E>> {
206 if self.exists(module, name) {
207 let ext = &self.map[&(module.to_string(), name.to_string())];
208 return Some(ext.clone());
209 }
210 None
211 }
212
213 pub fn exists(&self, module: &str, name: &str) -> bool {
215 self.map
216 .contains_key(&(module.to_string(), name.to_string()))
217 }
218
219 pub fn contains_namespace(&self, name: &str) -> bool {
221 self.map.keys().any(|(k, _)| (k == name))
222 }
223
224 pub fn register_namespace(
226 &mut self,
227 ns: &str,
228 contents: impl IntoIterator<Item = (String, Extern<E>)>,
229 ) {
230 for (name, extern_) in contents.into_iter() {
231 self.map.insert((ns.to_string(), name.clone()), extern_);
232 }
233 }
234
235 pub fn define(&mut self, ns: &str, name: &str, val: impl Into<Extern<E>>) {
237 self.map
238 .insert((ns.to_string(), name.to_string()), val.into());
239 }
240
241 pub fn iter(&self) -> ImportsIterator<E> {
243 ImportsIterator::new(self)
244 }
245}
246
247pub struct ImportsIterator<'a, E: WasmEngine> {
249 iter: hashbrown::hash_map::Iter<'a, (String, String), Extern<E>>,
251}
252
253impl<'a, E: WasmEngine> ImportsIterator<'a, E> {
254 fn new(imports: &'a Imports<E>) -> Self {
256 let iter = imports.map.iter();
257 Self { iter }
258 }
259}
260
261impl<'a, E: WasmEngine> Iterator for ImportsIterator<'a, E> {
262 type Item = (&'a str, &'a str, &'a Extern<E>);
263
264 fn next(&mut self) -> Option<Self::Item> {
265 self.iter
266 .next()
267 .map(|(k, v)| (k.0.as_str(), k.1.as_str(), v))
268 }
269}
270
271impl<E: WasmEngine> IntoIterator for &Imports<E> {
272 type IntoIter = hashbrown::hash_map::IntoIter<(String, String), Extern<E>>;
273 type Item = ((String, String), Extern<E>);
274
275 fn into_iter(self) -> Self::IntoIter {
276 self.map.clone().into_iter()
277 }
278}
279
280impl<E: WasmEngine> Default for Imports<E> {
281 fn default() -> Self {
282 Self::new()
283 }
284}
285
286impl<E: WasmEngine> Extend<((String, String), Extern<E>)> for Imports<E> {
287 fn extend<T: IntoIterator<Item = ((String, String), Extern<E>)>>(&mut self, iter: T) {
288 for ((ns, name), ext) in iter.into_iter() {
289 self.define(&ns, &name, ext);
290 }
291 }
292}
293
294impl<E: WasmEngine> fmt::Debug for Imports<E> {
295 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
296 enum SecretMap {
298 Empty,
300 Some(usize),
302 }
303
304 impl SecretMap {
305 fn new(len: usize) -> Self {
307 if len == 0 {
308 Self::Empty
309 } else {
310 Self::Some(len)
311 }
312 }
313 }
314
315 impl fmt::Debug for SecretMap {
316 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
317 match self {
318 Self::Empty => write!(f, "(empty)"),
319 Self::Some(len) => write!(f, "(... {} item(s) ...)", len),
320 }
321 }
322 }
323
324 f.debug_struct("Imports")
325 .field("map", &SecretMap::new(self.map.len()))
326 .finish()
327 }
328}
329
330pub trait WasmEngine: 'static + Clone + Sized {
332 type ExternRef: WasmExternRef<Self>;
334 type Func: WasmFunc<Self>;
336 type Global: WasmGlobal<Self>;
338 type Instance: WasmInstance<Self>;
340 type Memory: WasmMemory<Self>;
342 type Module: WasmModule<Self>;
344 type Store<T>: WasmStore<T, Self>;
346 type StoreContext<'a, T: 'a>: WasmStoreContext<'a, T, Self>;
348 type StoreContextMut<'a, T: 'a>: WasmStoreContextMut<'a, T, Self>;
350 type Table: WasmTable<Self>;
352}
353
354pub trait WasmExternRef<E: WasmEngine>: Clone + Sized + Send + Sync {
356 fn new<T: 'static + Send + Sync>(ctx: impl AsContextMut<E>, object: T) -> Self;
358 fn downcast<'a, 's: 'a, T: 'static, S: 's>(
360 &'a self,
361 store: E::StoreContext<'s, S>,
362 ) -> Result<&'a T>;
363}
364
365pub trait WasmFunc<E: WasmEngine>: Clone + Sized + Send + Sync {
367 fn new<T>(
369 ctx: impl AsContextMut<E, UserState = T>,
370 ty: FuncType,
371 func: impl 'static
372 + Send
373 + Sync
374 + Fn(E::StoreContextMut<'_, T>, &[Value<E>], &mut [Value<E>]) -> Result<()>,
375 ) -> Self;
376 fn ty(&self, ctx: impl AsContext<E>) -> FuncType;
378 fn call<T>(
380 &self,
381 ctx: impl AsContextMut<E>,
382 args: &[Value<E>],
383 results: &mut [Value<E>],
384 ) -> Result<()>;
385}
386
387pub trait WasmGlobal<E: WasmEngine>: Clone + Sized + Send + Sync {
389 fn new(ctx: impl AsContextMut<E>, value: Value<E>, mutable: bool) -> Self;
391 fn ty(&self, ctx: impl AsContext<E>) -> GlobalType;
393 fn set(&self, ctx: impl AsContextMut<E>, new_value: Value<E>) -> Result<()>;
395 fn get(&self, ctx: impl AsContextMut<E>) -> Value<E>;
397}
398
399pub trait WasmMemory<E: WasmEngine>: Clone + Sized + Send + Sync {
401 fn new(ctx: impl AsContextMut<E>, ty: MemoryType) -> Result<Self>;
403 fn ty(&self, ctx: impl AsContext<E>) -> MemoryType;
405 fn grow(&self, ctx: impl AsContextMut<E>, additional: u32) -> Result<u32>;
407 fn current_pages(&self, ctx: impl AsContext<E>) -> u32;
409 fn read(&self, ctx: impl AsContext<E>, offset: usize, buffer: &mut [u8]) -> Result<()>;
412 fn write(&self, ctx: impl AsContextMut<E>, offset: usize, buffer: &[u8]) -> Result<()>;
415}
416
417pub trait WasmTable<E: WasmEngine>: Clone + Sized + Send + Sync {
419 fn new(ctx: impl AsContextMut<E>, ty: TableType, init: Value<E>) -> Result<Self>;
421 fn ty(&self, ctx: impl AsContext<E>) -> TableType;
423 fn size(&self, ctx: impl AsContext<E>) -> u32;
425 fn grow(&self, ctx: impl AsContextMut<E>, delta: u32, init: Value<E>) -> Result<u32>;
427 fn get(&self, ctx: impl AsContextMut<E>, index: u32) -> Option<Value<E>>;
429 fn set(&self, ctx: impl AsContextMut<E>, index: u32, value: Value<E>) -> Result<()>;
431}
432
433pub trait WasmInstance<E: WasmEngine>: Clone + Sized + Send + Sync {
435 fn new(store: impl AsContextMut<E>, module: &E::Module, imports: &Imports<E>) -> Result<Self>;
437 fn exports(&self, store: impl AsContext<E>) -> Box<dyn Iterator<Item = Export<E>>>;
439 fn get_export(&self, store: impl AsContext<E>, name: &str) -> Option<Extern<E>>;
441}
442
443pub trait WasmModule<E: WasmEngine>: Clone + Sized + Send + Sync {
445 fn new(engine: &E, bytes: &[u8]) -> Result<Self>;
447 fn exports(&self) -> Box<dyn '_ + Iterator<Item = ExportType<'_>>>;
449 fn get_export(&self, name: &str) -> Option<ExternType>;
451 fn imports(&self) -> Box<dyn '_ + Iterator<Item = ImportType<'_>>>;
453}
454
455pub trait WasmStore<T, E: WasmEngine>:
457 AsContext<E, UserState = T> + AsContextMut<E, UserState = T>
458{
459 fn new(engine: &E, data: T) -> Self;
461 fn engine(&self) -> &E;
463 fn data(&self) -> &T;
465 fn data_mut(&mut self) -> &mut T;
467 fn into_data(self) -> T;
469}
470
471pub trait WasmStoreContext<'a, T, E: WasmEngine>: AsContext<E, UserState = T> {
473 fn engine(&self) -> &E;
475 fn data(&self) -> &T;
477}
478
479pub trait WasmStoreContextMut<'a, T, E: WasmEngine>:
481 WasmStoreContext<'a, T, E> + AsContextMut<E, UserState = T>
482{
483 fn data_mut(&mut self) -> &mut T;
485}
486
487pub trait AsContext<E: WasmEngine> {
489 type UserState;
491
492 fn as_context(&self) -> E::StoreContext<'_, Self::UserState>;
494}
495
496pub trait AsContextMut<E: WasmEngine>: AsContext<E> {
498 fn as_context_mut(&mut self) -> E::StoreContextMut<'_, Self::UserState>;
500}
501
502impl<E, C> AsContext<E> for C
503where
504 C: crate::AsContext<Engine = E>,
505 E: WasmEngine,
506{
507 type UserState = C::UserState;
508
509 fn as_context(&self) -> <E as WasmEngine>::StoreContext<'_, Self::UserState> {
510 <Self as crate::AsContext>::as_context(self).inner
511 }
512}
513
514impl<E, C> AsContextMut<E> for C
515where
516 C: crate::AsContextMut<Engine = E>,
517 E: WasmEngine,
518{
519 fn as_context_mut(&mut self) -> <E as WasmEngine>::StoreContextMut<'_, Self::UserState> {
520 <Self as crate::AsContextMut>::as_context_mut(self).inner
521 }
522}