summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenry Gressmann <mail@henrygressmann.de>2025-01-14 17:41:29 +0100
committerHenry Gressmann <mail@henrygressmann.de>2025-01-14 17:41:29 +0100
commit40e570cf8bdd948c1e7e9dd85e5ac24d9a062d2a (patch)
tree64e9338f1c656fd9d81f51cd4f425359b2dbc6d1
parent1a64f4092af9304694e98f441b79f0a93ee1c194 (diff)
chore: update deps, spelling
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
-rw-r--r--Cargo.lock52
-rw-r--r--Cargo.toml4
-rw-r--r--README.md17
-rw-r--r--crates/parser/Cargo.toml2
-rw-r--r--crates/tinywasm/tests/test-wasm-3.rs2
-rw-r--r--crates/tinywasm/tests/testsuite/run.rs4
-rw-r--r--crates/tinywasm/tests/testsuite/util.rs12
-rw-r--r--examples/archive.rs6
-rw-r--r--examples/funcref_callbacks.rs101
-rw-r--r--examples/linking.rs9
-rw-r--r--examples/wasm-rust.rs3
11 files changed, 129 insertions, 83 deletions
diff --git a/Cargo.lock b/Cargo.lock
index c31c41f..d7b7d99 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -704,7 +704,7 @@ dependencies = [
"tinywasm-parser",
"tinywasm-types",
"wasm-testsuite",
- "wast",
+ "wast 223.0.0",
"wat",
]
@@ -717,7 +717,7 @@ dependencies = [
"log",
"pretty_env_logger",
"tinywasm",
- "wast",
+ "wast 223.0.0",
]
[[package]]
@@ -726,7 +726,7 @@ version = "0.9.0-alpha.0"
dependencies = [
"log",
"tinywasm-types",
- "wasmparser",
+ "wasmparser 0.223.0",
]
[[package]]
@@ -782,7 +782,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3432682105d7e994565ef928ccf5856cf6af4ba3dddebedb737f61caed70f956"
dependencies = [
"leb128",
- "wasmparser",
+ "wasmparser 0.222.0",
+]
+
+[[package]]
+name = "wasm-encoder"
+version = "0.223.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e636076193fa68103e937ac951b5f2f587624097017d764b8984d9c0f149464"
+dependencies = [
+ "leb128",
+ "wasmparser 0.223.0",
]
[[package]]
@@ -792,7 +802,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d01e1e4857b055d8ad6d542d95074106b5b2afd411d3e26ae6da37a560053c97"
dependencies = [
"include_dir",
- "wast",
+ "wast 222.0.0",
]
[[package]]
@@ -807,6 +817,17 @@ dependencies = [
]
[[package]]
+name = "wasmparser"
+version = "0.223.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5a99faceb1a5a84dd6084ec4bfa4b2ab153b5793b43fd8f58b89232634afc35"
+dependencies = [
+ "bitflags",
+ "indexmap",
+ "semver",
+]
+
+[[package]]
name = "wast"
version = "222.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -816,16 +837,29 @@ dependencies = [
"leb128",
"memchr",
"unicode-width",
- "wasm-encoder",
+ "wasm-encoder 0.222.0",
+]
+
+[[package]]
+name = "wast"
+version = "223.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d59b2ba8a2ff9f06194b7be9524f92e45e70149f4dacc0d0c7ad92b59ac875e4"
+dependencies = [
+ "bumpalo",
+ "leb128",
+ "memchr",
+ "unicode-width",
+ "wasm-encoder 0.223.0",
]
[[package]]
name = "wat"
-version = "1.222.0"
+version = "1.223.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fde61b4b52f9a84ae31b5e8902a2cd3162ea45d8bf564c729c3288fe52f4334"
+checksum = "662786915c427e4918ff01eabb3c4756d4d947cd8f635761526b4cc9da2eaaad"
dependencies = [
- "wast",
+ "wast 223.0.0",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 0c2f571..119dc45 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,8 +4,8 @@ default-members=[".", "crates/tinywasm", "crates/types", "crates/parser"]
resolver="2"
[workspace.dependencies]
-wast="222"
-wat="1.222"
+wast="223"
+wat="1.223"
eyre="0.6"
log="0.4"
pretty_env_logger="0.5"
diff --git a/README.md b/README.md
index a963ea7..8db5a84 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@
- **Tiny**: TinyWasm is designed to be as small as possible without significantly compromising performance or functionality (< 4000 LLOC).
- **Portable**: TinyWasm runs on any platform that Rust can target, including `no_std`, with minimal external dependencies.
-- **Safe**: No unsafe code is used in the runtime (`rkyv` which uses unsafe code can be used for serialization, but is optional).
+- **Safe**: No unsafe code is used in the runtime (`rkyv`, which uses unsafe code, can be used for serialization but is optional).
## Status
@@ -24,7 +24,7 @@ TinyWasm passes all WebAssembly MVP tests from the [WebAssembly core testsuite](
**Legend**\
🌑 -- not available\
-🚧 -- in development / partialy supported\
+🚧 -- in development/partially supported\
🟢 -- fully supported
| Proposal | Status | TinyWasm Version |
@@ -61,24 +61,21 @@ $ tinywasm-cli --help
- **`archive`**\
Enables pre-parsing of archives. This is enabled by default.
-With all these features disabled, TinyWasm only depends on `core`, `alloc` ,and `libm` and can be used in `no_std` environments.
-Since `libm` is not as performant as the compiler's math intrinsics, it is recommended to use the `std` feature if possible (at least [for now](https://github.com/rust-lang/rfcs/issues/2505)), especially on wasm32 targets.
+With all these features disabled, TinyWasm only depends on `core`, `alloc`, and `libm` and can be used in `no_std` environments. Since `libm` is not as performant as the compiler's math intrinsics, it is recommended to use the `std` feature if possible (at least [for now](https://github.com/rust-lang/rfcs/issues/2505)), especially on `wasm32` targets.
## Inspiration
Big thanks to the authors of the following projects, which have inspired and influenced TinyWasm:
-- [wasmi](https://github.com/wasmi-labs/wasmi) - an efficient and lightweight WebAssembly interpreter that also runs on `no_std` environments
-- [wasm3](https://github.com/wasm3/wasm3) - a high performance WebAssembly interpreter written in C
-- [wazero](https://wazero.io/) - a zero-dependency WebAssembly interpreter written in go
+- [wasmi](https://github.com/wasmi-labs/wasmi) - an efficient and lightweight WebAssembly interpreter that also runs in `no_std` environments
+- [wasm3](https://github.com/wasm3/wasm3) - a high-performance WebAssembly interpreter written in C
+- [wazero](https://wazero.io/) - a zero-dependency WebAssembly interpreter written in Go
- [wain](https://github.com/rhysd/wain) - a zero-dependency WebAssembly interpreter written in Rust
-I encourage you to check these projects out if you're looking for more mature and feature-complete WebAssembly Runtimes.
+I encourage you to check these projects out if you're looking for more mature and feature-complete WebAssembly runtimes.
## License
Licensed under either of [Apache License, Version 2.0](./LICENSE-APACHE) or [MIT license](./LICENSE-MIT) at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in TinyWasm by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
-
-**Note:** The GitHub repository contains a Submodule (`crates/tinywasm-parser/data`) which is licensed only under the [Apache License, Version 2.0](https://github.com/WebAssembly/spec/blob/main/test/LICENSE). This data is generated from the [WebAssembly Specification](https://github.com/WebAssembly/spec/tree/main/test) and is only used for testing purposes and not included in the final binary.
diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml
index 61224fd..f8eabb4 100644
--- a/crates/parser/Cargo.toml
+++ b/crates/parser/Cargo.toml
@@ -9,7 +9,7 @@ repository.workspace=true
rust-version.workspace=true
[dependencies]
-wasmparser={version="0.222", default-features=false, features=["validate", "features", "simd"]}
+wasmparser={version="0.223", default-features=false, features=["validate", "features", "simd"]}
log={workspace=true, optional=true}
tinywasm-types={version="0.9.0-alpha.0", path="../types", default-features=false}
diff --git a/crates/tinywasm/tests/test-wasm-3.rs b/crates/tinywasm/tests/test-wasm-3.rs
index 0bd2cb0..a0e2543 100644
--- a/crates/tinywasm/tests/test-wasm-3.rs
+++ b/crates/tinywasm/tests/test-wasm-3.rs
@@ -4,7 +4,7 @@ use testsuite::TestSuite;
use wasm_testsuite::data::{spec, SpecVersion};
fn main() -> Result<()> {
- if std::env::args().find(|x| x == "--enable").is_none() {
+ if !std::env::args().any(|x| &x == "--enable") {
println!("Skipping wasm-3 tests, use --enable to run");
return Ok(());
}
diff --git a/crates/tinywasm/tests/testsuite/run.rs b/crates/tinywasm/tests/testsuite/run.rs
index 7534142..0804266 100644
--- a/crates/tinywasm/tests/testsuite/run.rs
+++ b/crates/tinywasm/tests/testsuite/run.rs
@@ -8,8 +8,8 @@ use log::{debug, error, info};
use tinywasm::{Extern, Imports, ModuleInstance};
use tinywasm_types::{ExternVal, MemoryType, ModuleInstanceAddr, TableType, ValType, WasmValue};
use wasm_testsuite::data::TestFile;
-use wasm_testsuite::wast::{lexer::Lexer, parser::ParseBuffer, Wast};
use wasm_testsuite::wast;
+use wasm_testsuite::wast::{lexer::Lexer, parser::ParseBuffer, Wast};
#[derive(Default)]
struct ModuleRegistry {
@@ -171,7 +171,7 @@ impl TestSuite {
Ok(())
}
- pub fn run_file<'a>(&mut self, file: TestFile<'a>) -> Result<()> {
+ pub fn run_file(&mut self, file: TestFile<'_>) -> Result<()> {
let test_group = self.test_group(file.name(), file.parent());
let wast_raw = file.raw();
let wast = file.wast()?;
diff --git a/crates/tinywasm/tests/testsuite/util.rs b/crates/tinywasm/tests/testsuite/util.rs
index b555153..f8f862b 100644
--- a/crates/tinywasm/tests/testsuite/util.rs
+++ b/crates/tinywasm/tests/testsuite/util.rs
@@ -120,15 +120,15 @@ fn wastarg2tinywasmvalue(arg: wast::WastArg) -> Result<tinywasm_types::WasmValue
fn wast_i128_to_i128(i: wast::core::V128Pattern) -> u128 {
match i {
wast::core::V128Pattern::F32x4(f) => {
- f.iter().fold(0, |acc, &f| acc << 32 | nanpattern2tinywasmvalue(f).unwrap().as_f32().unwrap() as u128)
+ f.iter().fold(0, |acc, &f| (acc << 32) | nanpattern2tinywasmvalue(f).unwrap().as_f32().unwrap() as u128)
}
wast::core::V128Pattern::F64x2(f) => {
- f.iter().fold(0, |acc, &f| acc << 64 | nanpattern2tinywasmvalue(f).unwrap().as_f64().unwrap() as u128)
+ f.iter().fold(0, |acc, &f| (acc << 64) | nanpattern2tinywasmvalue(f).unwrap().as_f64().unwrap() as u128)
}
- wast::core::V128Pattern::I16x8(f) => f.iter().fold(0, |acc, &f| acc << 16 | f as u128),
- wast::core::V128Pattern::I32x4(f) => f.iter().fold(0, |acc, &f| acc << 32 | f as u128),
- wast::core::V128Pattern::I64x2(f) => f.iter().fold(0, |acc, &f| acc << 64 | f as u128),
- wast::core::V128Pattern::I8x16(f) => f.iter().fold(0, |acc, &f| acc << 8 | f as u128),
+ wast::core::V128Pattern::I16x8(f) => f.iter().fold(0, |acc, &f| (acc << 16) | f as u128),
+ wast::core::V128Pattern::I32x4(f) => f.iter().fold(0, |acc, &f| (acc << 32) | f as u128),
+ wast::core::V128Pattern::I64x2(f) => f.iter().fold(0, |acc, &f| (acc << 64) | f as u128),
+ wast::core::V128Pattern::I8x16(f) => f.iter().fold(0, |acc, &f| (acc << 8) | f as u128),
}
}
diff --git a/examples/archive.rs b/examples/archive.rs
index ea82c51..f1a19b6 100644
--- a/examples/archive.rs
+++ b/examples/archive.rs
@@ -11,12 +11,12 @@ const WASM: &str = r#"
"#;
fn main() -> Result<()> {
- let wasm = wat::parse_str(WASM).expect("failed to parse wat");
+ let wasm = wat::parse_str(WASM).expect("Failed to parse WAT");
let module = Parser::default().parse_module_bytes(wasm)?;
let twasm = module.serialize_twasm();
- // now, you could e.g. write twasm to a file called `add.twasm`
- // and load it later in a different program
+ // Now, you could e.g. write `twasm` to a file called `add.twasm`
+ // and load it later in a different program.
let module: Module = TinyWasmModule::from_twasm(&twasm)?.into();
let mut store = Store::default();
diff --git a/examples/funcref_callbacks.rs b/examples/funcref_callbacks.rs
index 08332cb..df50e75 100644
--- a/examples/funcref_callbacks.rs
+++ b/examples/funcref_callbacks.rs
@@ -1,6 +1,5 @@
use eyre::Result;
use tinywasm::{types::FuncRef, Extern, FuncContext, Imports, Module, Store};
-use wat;
fn main() -> Result<()> {
by_func_ref_passed()?;
@@ -8,30 +7,30 @@ fn main() -> Result<()> {
Ok(())
}
-/// example of passing wasm functions (as funcref) to imported host function
-/// and imported host function calling them
+/// Example of passing Wasm functions (as `funcref`) to an imported host function
+/// and the imported host function calling them.
fn by_func_ref_passed() -> Result<()> {
- // a module with:
- // imported function "host.call_this" that accepts a callback
- // exported wasm function "tell_host_to_call" that calls "host.call_this" with wasm functions $add and $sub
- // wasm functions $add and $sub and imported function $mul used as callbacks
- // (just to show that imported functions can be referenced too)
- // exported wasm function "call_binop_by_ref" is a proxy used by host to call func-references of type (i32, i32)->i32
+ // A module with:
+ // - Imported function "host.call_this" that accepts a callback.
+ // - Exported Wasm function "tell_host_to_call" that calls "host.call_this" with Wasm functions $add and $sub.
+ // - Wasm functions $add and $sub and an imported function $mul used as callbacks
+ // (just to show that imported functions can be referenced too).
+ // - Exported Wasm function "call_binop_by_ref", a proxy used by the host to call func-references of type (i32, i32) -> i32.
const WASM: &str = r#"
(module
(import "host" "call_this" (func $host_callback_caller (param funcref)))
(import "host" "mul" (func $host_mul (param $x i32) (param $y i32) (result i32)))
(func $tell_host_to_call (export "tell_host_to_call")
- (call $host_callback_caller (ref.func $add))
- (call $host_callback_caller (ref.func $sub))
- (call $host_callback_caller (ref.func $host_mul))
+ (call $host_callback_caller (ref.func $add))
+ (call $host_callback_caller (ref.func $sub))
+ (call $host_callback_caller (ref.func $host_mul))
)
(type $binop (func (param i32 i32) (result i32)))
(table 3 funcref)
- (elem (i32.const 0) $add $sub $host_mul) ;; function can only be taken reference of if it's added to a table
+ (elem (i32.const 0) $add $sub $host_mul) ;; Function can only be referenced if added to a table.
(func $add (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
@@ -45,59 +44,63 @@ fn by_func_ref_passed() -> Result<()> {
(table $callback_register 1 funcref)
(func (export "call_binop_by_ref") (param funcref i32 i32) (result i32)
- (table.set $callback_register (i32.const 0) (local.get 0))
+ (table.set $callback_register (i32.const 0) (local.get 0))
(call_indirect $callback_register (type $binop) (local.get 1)(local.get 2)(i32.const 0))
)
)
"#;
- let wasm = wat::parse_str(WASM).expect("failed to parse wat");
+ let wasm = wat::parse_str(WASM).expect("Failed to parse WAT");
let module = Module::parse_bytes(&wasm)?;
let mut store = Store::default();
let mut imports = Imports::new();
- // import host function that takes callbacks and calls them
+
+ // Import host function that takes callbacks and calls them.
imports.define(
"host",
"call_this",
Extern::typed_func(|mut ctx: FuncContext<'_>, fn_ref: FuncRef| -> tinywasm::Result<()> {
let proxy_caller =
ctx.module().exported_func::<(FuncRef, i32, i32), i32>(ctx.store(), "call_binop_by_ref")?;
- // call callback we got as argument using call_binop_by_ref
+ // Call the callback we got as an argument using "call_binop_by_ref".
let res = proxy_caller.call(ctx.store_mut(), (fn_ref, 5, 3))?;
println!("(funcref {fn_ref:?})(5,3) results in {res}");
Ok(())
}),
)?;
- // import host.mul function (one of the functions whose references are taken)
+
+ // Import host.mul function (one of the functions whose references are taken).
imports.define(
"host",
"mul",
Extern::typed_func(|_, args: (i32, i32)| -> tinywasm::Result<i32> { Ok(args.0 * args.1) }),
)?;
+
let instance = module.instantiate(&mut store, Some(imports))?;
- let caller = instance.exported_func::<(), ()>(&mut store, "tell_host_to_call")?;
- // call the tell_host_to_call
+ let caller = instance.exported_func::<(), ()>(&store, "tell_host_to_call")?;
+
+ // Call "tell_host_to_call".
caller.call(&mut store, ())?;
- // interesting detail is that neither $add $sub $mul were exported,
- // but with a little help from proxy "call_binop_by_ref" references to them host was able to call them
+ // An interesting detail is that neither $add, $sub, nor $mul were exported,
+ // but with a little help from the proxy "call_binop_by_ref", references to them are callable by the host.
Ok(())
}
-/// example of returning wasm function as callback to host function
-/// and host function calling it
+/// Example of returning a Wasm function as a callback to a host function
+/// and the host function calling it.
fn by_func_ref_returned() -> Result<()> {
- // a module with:
- // an exported function "what_should_host_call" that returns 3 funcrefs
- // wasm functions $add and $sub and imported function $mul used as callbacks
- // (just to show that imported functions can be referenced too)
- // exported wasm function "call_binop_by_ref" is a proxy used by host to call func-references of type (i32, i32)->i32
+ // A module with:
+ // - An exported function "what_should_host_call" that returns 3 `funcref`s.
+ // - Wasm functions $add and $sub and an imported function $mul used as callbacks
+ // (just to show that imported functions can be referenced too).
+ // - Another exported Wasm function "call_binop_by_ref", a proxy used by the host to call func-references of type (i32, i32) -> i32
const WASM: &str = r#"
(module
(import "host" "mul" (func $host_mul (param $x i32) (param $y i32) (result i32)))
(type $binop (func (param i32 i32) (result i32)))
(table 3 funcref)
- (elem (i32.const 0) $add $sub $host_mul)
+ (elem (i32.const 0) $add $sub $host_mul)
(func $add (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
@@ -109,24 +112,25 @@ fn by_func_ref_returned() -> Result<()> {
i32.sub
)
(func $ref_to_funcs (export "what_should_host_call") (result funcref funcref funcref)
- (ref.func $add)
- (ref.func $sub)
+ (ref.func $add)
+ (ref.func $sub)
(ref.func $host_mul)
)
(table $callback_register 1 funcref)
(func $call (export "call_binop_by_ref") (param funcref i32 i32) (result i32)
- (table.set $callback_register (i32.const 0) (local.get 0))
+ (table.set $callback_register (i32.const 0) (local.get 0))
(call_indirect $callback_register (type $binop) (local.get 1)(local.get 2)(i32.const 0))
)
)
"#;
- let wasm = wat::parse_str(WASM).expect("failed to parse wat");
+ let wasm = wat::parse_str(WASM).expect("Failed to parse WAT");
let module = Module::parse_bytes(&wasm)?;
let mut store = Store::default();
let mut imports = Imports::new();
- // import host.mul function (one of the possible operations)
+
+ // Import host.mul function (one of the possible operations).
imports.define(
"host",
"mul",
@@ -134,19 +138,20 @@ fn by_func_ref_returned() -> Result<()> {
)?;
let instance = module.instantiate(&mut store, Some(imports))?;
- {
- // ask module what should we call
- let funcrefs = {
- let address_getter =
- instance.exported_func::<(), (FuncRef, FuncRef, FuncRef)>(&mut store, "what_should_host_call")?;
- address_getter.call(&mut store, ())?
- };
- let proxy_caller = instance.exported_func::<(FuncRef, i32, i32), i32>(&mut store, "call_binop_by_ref")?;
- for (idx, func_ref) in [funcrefs.0, funcrefs.1, funcrefs.2].iter().enumerate() {
- // call those funcrefs via "call_binop_by_ref"
- let res = proxy_caller.call(&mut store, (*func_ref, 5, 3))?;
- println!("at idx: {idx} funcref {func_ref:?}(5,3) results in {res}");
- }
+
+ // Ask the module what to call.
+ let funcrefs = {
+ let address_getter =
+ instance.exported_func::<(), (FuncRef, FuncRef, FuncRef)>(&store, "what_should_host_call")?;
+ address_getter.call(&mut store, ())?
+ };
+
+ let proxy_caller = instance.exported_func::<(FuncRef, i32, i32), i32>(&store, "call_binop_by_ref")?;
+
+ for (idx, func_ref) in [funcrefs.0, funcrefs.1, funcrefs.2].iter().enumerate() {
+ // Call those `funcref`s via "call_binop_by_ref".
+ let res = proxy_caller.call(&mut store, (*func_ref, 5, 3))?;
+ println!("At idx: {idx}, funcref {func_ref:?}(5,3) results in {res}");
}
Ok(())
}
diff --git a/examples/linking.rs b/examples/linking.rs
index d215898..f94773a 100644
--- a/examples/linking.rs
+++ b/examples/linking.rs
@@ -1,6 +1,7 @@
use eyre::Result;
use tinywasm::{Module, Store};
+// WebAssembly module defining and exporting an `add` function.
const WASM_ADD: &str = r#"
(module
(func $add (param $lhs i32) (param $rhs i32) (result i32)
@@ -10,6 +11,7 @@ const WASM_ADD: &str = r#"
(export "add" (func $add)))
"#;
+// WebAssembly module importing an `add` function and using it.
const WASM_IMPORT: &str = r#"
(module
(import "adder" "add" (func $add (param i32 i32) (result i32)))
@@ -29,13 +31,20 @@ fn main() -> Result<()> {
let import_module = Module::parse_bytes(&wasm_import)?;
let mut store = Store::default();
+
+ // Instantiate the `add` module.
let add_instance = add_module.instantiate(&mut store, None)?;
+ // Link the `adder` namespace to the `add` module's instance.
let mut imports = tinywasm::Imports::new();
imports.link_module("adder", add_instance.id())?;
+
+ // Instantiate the `import` module with the linked imports.
let import_instance = import_module.instantiate(&mut store, Some(imports))?;
+ // Call the `main` function, which uses the imported `add` function.
let main = import_instance.exported_func::<(), i32>(&store, "main")?;
assert_eq!(main.call(&mut store, ())?, 3);
+
Ok(())
}
diff --git a/examples/wasm-rust.rs b/examples/wasm-rust.rs
index 89203c1..429bdcb 100644
--- a/examples/wasm-rust.rs
+++ b/examples/wasm-rust.rs
@@ -14,7 +14,8 @@ use tinywasm::{Extern, FuncContext, Imports, MemoryStringExt, Module, Store};
/// ./examples/rust/build.sh
/// ```
///
-/// This requires the `wasm32-unknown-unknown` target, `binaryen` and `wabt` to be installed.
+/// This requires the `wasm32-unknown-unknown` target, `binaryen`, and `wabt` to be installed:
+///
/// `rustup target add wasm32-unknown-unknown`.
/// <https://github.com/WebAssembly/wabt>
/// <https://github.com/WebAssembly/binaryen>