Skip to content

Commit 7946350

Browse files
chore: refactor executor and improve documentation
Signed-off-by: Henry Gressmann <[email protected]>
1 parent 00ac903 commit 7946350

File tree

14 files changed

+140
-105
lines changed

14 files changed

+140
-105
lines changed

.github/workflows/test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
submodules: true
3939

4040
- name: Install nightly Rust toolchain
41-
run: rustup update stable nightly
41+
run: rustup update nightly
4242

4343
- name: Build (nightly, no default features)
4444
run: cargo +nightly build --workspace --exclude wasm-testsuite --no-default-features

crates/parser/src/error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use alloc::string::{String, ToString};
44
use wasmparser::Encoding;
55

66
#[derive(Debug)]
7+
/// Errors that can occur when parsing a WebAssembly module
78
pub enum ParseError {
89
InvalidType,
910
UnsupportedSection(String),

crates/tinywasm/src/error.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,31 @@ use core::fmt::Display;
33
use tinywasm_types::FuncType;
44

55
#[cfg(feature = "parser")]
6-
use tinywasm_parser::ParseError;
6+
pub use tinywasm_parser::ParseError;
77

8-
/// A tinywasm error
8+
/// Errors that can occur for TinyWasm operations
99
#[derive(Debug)]
1010
pub enum Error {
11-
#[cfg(feature = "parser")]
12-
/// A parsing error occurred
13-
ParseError(ParseError),
14-
1511
#[cfg(feature = "std")]
1612
/// An I/O error occurred
1713
Io(crate::std::io::Error),
1814

19-
/// A WebAssembly feature is not supported
20-
UnsupportedFeature(String),
21-
22-
/// An unknown error occurred
23-
Other(String),
15+
#[cfg(feature = "parser")]
16+
/// A parsing error occurred
17+
ParseError(ParseError),
2418

2519
/// A WebAssembly trap occurred
2620
Trap(Trap),
2721

2822
/// A linking error occurred
2923
Linker(LinkingError),
3024

25+
/// A WebAssembly feature is not supported
26+
UnsupportedFeature(String),
27+
28+
/// An unknown error occurred
29+
Other(String),
30+
3131
/// A function did not return a value
3232
FuncDidNotReturn,
3333

@@ -48,7 +48,7 @@ pub enum Error {
4848
}
4949

5050
#[derive(Debug)]
51-
/// A linking error
51+
/// Errors that can occur when linking a WebAssembly module
5252
pub enum LinkingError {
5353
/// An unknown import was encountered
5454
UnknownImport {
@@ -210,5 +210,5 @@ impl From<tinywasm_parser::ParseError> for Error {
210210
}
211211
}
212212

213-
/// A specialized [`Result`] type for tinywasm operations
213+
/// A wrapper around [`core::result::Result`] for tinywasm operations
214214
pub type Result<T, E = Error> = crate::std::result::Result<T, E>;

crates/tinywasm/src/func.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ impl FuncHandle {
8989

9090
#[derive(Debug)]
9191
/// A typed function handle
92-
pub struct TypedFuncHandle<P, R> {
92+
pub struct FuncHandleTyped<P, R> {
9393
/// The underlying function handle
9494
pub func: FuncHandle,
9595
pub(crate) marker: core::marker::PhantomData<(P, R)>,
@@ -105,7 +105,7 @@ pub trait FromWasmValueTuple {
105105
Self: Sized;
106106
}
107107

108-
impl<P: IntoWasmValueTuple, R: FromWasmValueTuple> TypedFuncHandle<P, R> {
108+
impl<P: IntoWasmValueTuple, R: FromWasmValueTuple> FuncHandleTyped<P, R> {
109109
/// Call a typed function
110110
pub fn call(&self, store: &mut Store, params: P) -> Result<R> {
111111
// Convert params into Vec<WasmValue>

crates/tinywasm/src/imports.rs

Lines changed: 65 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -90,56 +90,45 @@ impl Debug for HostFunction {
9090
/// An external value
9191
pub enum Extern {
9292
/// A global value
93-
Global(ExternGlobal),
93+
Global {
94+
/// The type of the global value.
95+
ty: GlobalType,
96+
/// The actual value of the global, encapsulated in `WasmValue`.
97+
val: WasmValue,
98+
},
9499

95100
/// A table
96-
Table(ExternTable),
101+
Table {
102+
/// Defines the type of the table, including its element type and limits.
103+
ty: TableType,
104+
/// The initial value of the table.
105+
init: WasmValue,
106+
},
97107

98108
/// A memory
99-
Memory(ExternMemory),
109+
Memory {
110+
/// Defines the type of the memory, including its limits and the type of its pages.
111+
ty: MemoryType,
112+
},
100113

101114
/// A function
102115
Function(Function),
103116
}
104117

105-
/// A function
106-
#[derive(Debug, Clone)]
107-
pub struct ExternFunc(pub(crate) HostFunction);
108-
109-
/// A global value
110-
#[derive(Debug, Clone)]
111-
pub struct ExternGlobal {
112-
pub(crate) ty: GlobalType,
113-
pub(crate) val: WasmValue,
114-
}
115-
116-
/// A table
117-
#[derive(Debug, Clone)]
118-
pub struct ExternTable {
119-
pub(crate) ty: TableType,
120-
pub(crate) val: WasmValue,
121-
}
122-
123-
/// A memory
124-
#[derive(Debug, Clone)]
125-
pub struct ExternMemory {
126-
pub(crate) ty: MemoryType,
127-
}
128-
129118
impl Extern {
130119
/// Create a new global import
131120
pub fn global(val: WasmValue, mutable: bool) -> Self {
132-
Self::Global(ExternGlobal { ty: GlobalType { ty: val.val_type(), mutable }, val })
121+
Self::Global { ty: GlobalType { ty: val.val_type(), mutable }, val }
133122
}
134123

135124
/// Create a new table import
136-
pub fn table(ty: TableType, val: WasmValue) -> Self {
137-
Self::Table(ExternTable { ty, val })
125+
pub fn table(ty: TableType, init: WasmValue) -> Self {
126+
Self::Table { ty, init }
138127
}
139128

140129
/// Create a new memory import
141130
pub fn memory(ty: MemoryType) -> Self {
142-
Self::Memory(ExternMemory { ty })
131+
Self::Memory { ty }
143132
}
144133

145134
/// Create a new function import
@@ -174,10 +163,10 @@ impl Extern {
174163

175164
pub(crate) fn kind(&self) -> ExternalKind {
176165
match self {
177-
Self::Global(_) => ExternalKind::Global,
178-
Self::Table(_) => ExternalKind::Table,
179-
Self::Memory(_) => ExternalKind::Memory,
180-
Self::Function(_) => ExternalKind::Func,
166+
Self::Global { .. } => ExternalKind::Global,
167+
Self::Table { .. } => ExternalKind::Table,
168+
Self::Memory { .. } => ExternalKind::Memory,
169+
Self::Function { .. } => ExternalKind::Func,
181170
}
182171
}
183172
}
@@ -197,6 +186,38 @@ impl From<&Import> for ExternName {
197186

198187
#[derive(Debug, Default)]
199188
/// Imports for a module instance
189+
///
190+
/// This is used to link a module instance to its imports
191+
///
192+
/// ## Example
193+
/// ```rust
194+
/// # fn main() -> tinywasm::Result<()> {
195+
/// use tinywasm::{Imports, Extern};
196+
/// use tinywasm::types::{ValType, TableType, MemoryType, WasmValue};
197+
/// let mut imports = Imports::new();
198+
///
199+
/// // function args can be either a single
200+
/// // value that implements `TryFrom<WasmValue>` or a tuple of them
201+
/// let print_i32 = Extern::typed_func(|_ctx: tinywasm::FuncContext<'_>, arg: i32| {
202+
/// log::debug!("print_i32: {}", arg);
203+
/// Ok(())
204+
/// });
205+
///
206+
/// let table_type = TableType::new(ValType::RefFunc, 10, Some(20));
207+
/// let table_init = WasmValue::default_for(ValType::RefFunc);
208+
///
209+
/// imports
210+
/// .define("my_module", "print_i32", print_i32)?
211+
/// .define("my_module", "table", Extern::table(table_type, table_init))?
212+
/// .define("my_module", "memory", Extern::memory(MemoryType::new_32(1, Some(2))))?
213+
/// .define("my_module", "global_i32", Extern::global(WasmValue::I32(666), false))?
214+
/// .link_module("my_other_module", 0)?;
215+
/// # Ok(())
216+
/// # }
217+
/// ```
218+
///
219+
/// Note that module instance addresses for [`Imports::link_module`] can be obtained from [`crate::ModuleInstance::id`].
220+
/// Now, the imports object can be passed to [`crate::ModuleInstance::instantiate`].
200221
pub struct Imports {
201222
values: BTreeMap<ExternName, Extern>,
202223
modules: BTreeMap<String, ModuleInstanceAddr>,
@@ -334,17 +355,17 @@ impl Imports {
334355
match val {
335356
// A link to something that needs to be added to the store
336357
ResolvedExtern::Extern(ex) => match (ex, &import.kind) {
337-
(Extern::Global(extern_global), ImportKind::Global(ty)) => {
338-
Self::compare_types(import, &extern_global.ty, ty)?;
339-
imports.globals.push(store.add_global(extern_global.ty, extern_global.val.into(), idx)?);
358+
(Extern::Global { ty, val }, ImportKind::Global(import_ty)) => {
359+
Self::compare_types(import, &ty, import_ty)?;
360+
imports.globals.push(store.add_global(ty, val.into(), idx)?);
340361
}
341-
(Extern::Table(extern_table), ImportKind::Table(ty)) => {
342-
Self::compare_table_types(import, &extern_table.ty, ty)?;
343-
imports.tables.push(store.add_table(extern_table.ty, idx)?);
362+
(Extern::Table { ty, .. }, ImportKind::Table(import_ty)) => {
363+
Self::compare_table_types(import, &ty, import_ty)?;
364+
imports.tables.push(store.add_table(ty, idx)?);
344365
}
345-
(Extern::Memory(extern_memory), ImportKind::Memory(ty)) => {
346-
Self::compare_memory_types(import, &extern_memory.ty, ty, None)?;
347-
imports.memories.push(store.add_mem(extern_memory.ty, idx)?);
366+
(Extern::Memory { ty }, ImportKind::Memory(import_ty)) => {
367+
Self::compare_memory_types(import, &ty, import_ty, None)?;
368+
imports.memories.push(store.add_mem(ty, idx)?);
348369
}
349370
(Extern::Function(extern_func), ImportKind::Function(ty)) => {
350371
let import_func_type = module

crates/tinywasm/src/instance.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ use tinywasm_types::{
66

77
use crate::{
88
func::{FromWasmValueTuple, IntoWasmValueTuple},
9-
Error, FuncHandle, Imports, Module, Result, Store, TypedFuncHandle,
9+
Error, FuncHandle, FuncHandleTyped, Imports, Module, Result, Store,
1010
};
1111

12-
/// A WebAssembly Module Instance
12+
/// An instanciated WebAssembly module
1313
///
1414
/// Backed by an Arc, so cloning is cheap
1515
///
@@ -178,13 +178,13 @@ impl ModuleInstance {
178178
}
179179

180180
/// Get a typed exported function by name
181-
pub fn typed_func<P, R>(&self, store: &Store, name: &str) -> Result<TypedFuncHandle<P, R>>
181+
pub fn typed_func<P, R>(&self, store: &Store, name: &str) -> Result<FuncHandleTyped<P, R>>
182182
where
183183
P: IntoWasmValueTuple,
184184
R: FromWasmValueTuple,
185185
{
186186
let func = self.exported_func_by_name(store, name)?;
187-
Ok(TypedFuncHandle { func, marker: core::marker::PhantomData })
187+
Ok(FuncHandleTyped { func, marker: core::marker::PhantomData })
188188
}
189189

190190
/// Get the start function of the module

crates/tinywasm/src/lib.rs

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,23 @@
1414
//! to be useful for embedded systems and other environments where a full-featured
1515
//! runtime is not required.
1616
//!
17-
//! ## Getting Started
17+
//! ## Features
18+
//! - `std` (default): Enables the use of `std` and `std::io` for parsing from files and streams.
19+
//! - `logging` (default): Enables logging via the `log` crate.
20+
//! - `parser` (default): Enables the `tinywasm_parser` crate for parsing WebAssembly modules.
21+
//!
22+
//! ## No-std support
23+
//! TinyWasm supports `no_std` environments by disabling the `std` feature and registering
24+
//! a custom allocator. This removes support for parsing from files and streams,
25+
//! but otherwise the API is the same.
26+
//! Additionally, to have proper error types, you currently need a `nightly` compiler to have the error trait in core.
1827
//!
28+
//! ## Getting Started
1929
//! The easiest way to get started is to use the [`Module::parse_bytes`] function to load a
2030
//! WebAssembly module from bytes. This will parse the module and validate it, returning
2131
//! a [`Module`] that can be used to instantiate the module.
2232
//!
33+
//!
2334
//! ```rust
2435
//! use tinywasm::{Store, Module};
2536
//!
@@ -39,25 +50,21 @@
3950
//!
4051
//! // Get a typed handle to the exported "add" function
4152
//! // Alternatively, you can use `instance.get_func` to get an untyped handle
42-
//! // that takes and returns WasmValue types
43-
//! let func = instance.typed_func::<(i32, i32), (i32,)>(&mut store, "add")?;
53+
//! // that takes and returns [`WasmValue`]s
54+
//! let func = instance.typed_func::<(i32, i32), i32>(&mut store, "add")?;
4455
//! let res = func.call(&mut store, (1, 2))?;
4556
//!
46-
//! assert_eq!(res, (3,));
57+
//! assert_eq!(res, 3);
4758
//! # Ok::<(), tinywasm::Error>(())
4859
//! ```
4960
//!
50-
//! ## Features
51-
//! - `std` (default): Enables the use of `std` and `std::io` for parsing from files and streams.
52-
//! - `logging` (default): Enables logging via the `log` crate.
53-
//! - `parser` (default): Enables the `tinywasm_parser` crate for parsing WebAssembly modules.
61+
//! ## Custom Imports
5462
//!
55-
//! ## No-std support
56-
//! TinyWasm supports `no_std` environments by disabling the `std` feature and registering
57-
//! a custom allocator. This removes support for parsing from files and streams,
58-
//! but otherwise the API is the same.
63+
//! To provide custom imports to a module, you can use the [`Imports`] struct.
64+
//! This struct allows you to register custom functions, globals, memories, tables,
65+
//! and other modules to be linked into the module when it is instantiated.
5966
//!
60-
//! Additionally, if you want proper error types, you must use a `nightly` compiler to have the error trait in core.
67+
//! See the [`Imports`] documentation for more information.
6168
6269
mod std;
6370
extern crate alloc;
@@ -87,13 +94,14 @@ mod instance;
8794
pub use instance::ModuleInstance;
8895

8996
mod func;
90-
pub use func::{FuncHandle, TypedFuncHandle};
97+
pub use func::{FuncHandle, FuncHandleTyped};
9198

9299
mod imports;
93100
pub use imports::*;
94101

95-
mod runtime;
96-
pub use runtime::*;
102+
/// Runtime for executing WebAssembly modules.
103+
pub mod runtime;
104+
pub use runtime::InterpreterRuntime;
97105

98106
#[cfg(feature = "parser")]
99107
/// Re-export of [`tinywasm_parser`]. Requires `parser` feature.

0 commit comments

Comments
 (0)