diff options
| author | Henry Gressmann <mail@henrygressmann.de> | 2023-12-10 14:22:48 +0100 |
|---|---|---|
| committer | Henry Gressmann <mail@henrygressmann.de> | 2023-12-10 14:22:48 +0100 |
| commit | 5315ea932697da4bf6fa814576e1823233063a95 (patch) | |
| tree | 56239489c19ee3d6ae731fe08559521f86605354 /crates | |
| parent | 52bebfac2e6a2dc934273e38230d3986e68a3fe3 (diff) | |
docs: improve rustdoc
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/cli/src/args.rs | 2 | ||||
| -rw-r--r-- | crates/cli/src/bin.rs | 2 | ||||
| -rw-r--r-- | crates/tinywasm/src/lib.rs | 56 | ||||
| -rw-r--r-- | crates/tinywasm/src/runtime/mod.rs | 3 | ||||
| -rw-r--r-- | crates/tinywasm/src/store.rs | 2 | ||||
| -rw-r--r-- | crates/types/src/lib.rs | 66 | ||||
| -rw-r--r-- | crates/wasm-testsuite/lib.rs | 49 |
7 files changed, 120 insertions, 60 deletions
diff --git a/crates/cli/src/args.rs b/crates/cli/src/args.rs index 4023be6..379ecf8 100644 --- a/crates/cli/src/args.rs +++ b/crates/cli/src/args.rs @@ -1,5 +1,5 @@ use std::str::FromStr; -use tinywasm::WasmValue; +use tinywasm::types::WasmValue; #[derive(Debug)] pub struct WasmArg(WasmValue); diff --git a/crates/cli/src/bin.rs b/crates/cli/src/bin.rs index 07513fb..2712751 100644 --- a/crates/cli/src/bin.rs +++ b/crates/cli/src/bin.rs @@ -4,7 +4,7 @@ use argh::FromArgs; use args::WasmArg; use color_eyre::eyre::Result; use log::{debug, info}; -use tinywasm::{self, Module, WasmValue}; +use tinywasm::{self, types::WasmValue, Module}; use crate::args::to_wasm_args; mod args; diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs index aa01ef9..8abf280 100644 --- a/crates/tinywasm/src/lib.rs +++ b/crates/tinywasm/src/lib.rs @@ -10,7 +10,56 @@ #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms, unreachable_pub)] #![cfg_attr(feature = "nightly", feature(error_in_core))] -//! ## A tiny WebAssembly Runtime written in Rust +//! A tiny WebAssembly Runtime written in Rust +//! +//! TinyWasm provides a minimal WebAssembly runtime for executing WebAssembly modules. +//! It currently supports a subset of the WebAssembly MVP specification and is intended +//! to be useful for embedded systems and other environments where a full-featured +//! runtime is not required. +//! +//! ## Getting Started +//! +//! The easiest way to get started is to use the [`Module::parse_bytes`] function to load a +//! WebAssembly module from bytes. This will parse the module and validate it, returning +//! a [`Module`] that can be used to instantiate the module. +//! +//! ```rust +//! use tinywasm::{Store, Module}; +//! +//! // Load a module from bytes +//! let wasm = include_bytes!("../../../examples/wasm/add.wasm"); +//! let module = Module::parse_bytes(wasm)?; +//! +//! // Create a new store +//! // Stores are used to allocate objects like functions and globals +//! let mut store = Store::default(); +//! +//! // Instantiate the module +//! // This will allocate the module and its globals into the store +//! // and execute the module's start function. +//! // Every ModuleInstance has its own ID space for functions, globals, etc. +//! let instance = module.instantiate(&mut store)?; +//! +//! // Get a typed handle to the exported "add" function +//! // Alternatively, you can use `instance.get_func` to get an untyped handle +//! // that takes and returns WasmValue types +//! let func = instance.get_typed_func::<(i32, i32), (i32,)>(&mut store, "add")?; +//! let res = func.call(&mut store, (1, 2))?; +//! +//! assert_eq!(res, (3,)); +//! # Ok::<(), tinywasm::Error>(()) +//! ``` +//! +//! ## Features +//! - `std` (default): Enables the use of `std` and `std::io` for parsing from files and streams. +//! - `logging` (default): Enables logging via the `log` crate. +//! - `parser` (default): Enables the `tinywasm_parser` crate for parsing WebAssembly modules. +//! +//! ## No-std support +//! TinyWasm supports `no_std` environments by disabling the `std` feature. This removes +//! support for parsing from files and streams, but otherwise the API is the same. +//! Additionally, you must use a nightly compiler as TinyWasm uses the `error_in_core` feature +//! and have a `GlobalAlloc` implementation for allocating memory. // compiler error when using no_std without nightly #[cfg(all(not(feature = "std"), not(nightly)))] @@ -57,7 +106,10 @@ pub mod parser { pub use tinywasm_parser::*; } -pub use tinywasm_types::*; +/// Re-export of [`tinywasm_types`]. +pub mod types { + pub use tinywasm_types::*; +} #[cfg(test)] mod tests { diff --git a/crates/tinywasm/src/runtime/mod.rs b/crates/tinywasm/src/runtime/mod.rs index 07cff38..610810f 100644 --- a/crates/tinywasm/src/runtime/mod.rs +++ b/crates/tinywasm/src/runtime/mod.rs @@ -5,6 +5,7 @@ mod value; pub use stack::*; pub(crate) use value::RawWasmValue; +#[allow(rustdoc::private_intra_doc_links)] /// A WebAssembly Runtime. /// /// Generic over `CheckTypes` to enable type checking at runtime. @@ -13,6 +14,6 @@ pub(crate) use value::RawWasmValue; /// /// See <https://webassembly.github.io/spec/core/exec/runtime.html> /// -/// Execution is implemented in the [`crate::runtime::executer`] module +/// Execution is implemented in the [`crate::runtime::executor`] module #[derive(Debug, Default)] pub struct DefaultRuntime {} diff --git a/crates/tinywasm/src/store.rs b/crates/tinywasm/src/store.rs index 3214540..1a9d968 100644 --- a/crates/tinywasm/src/store.rs +++ b/crates/tinywasm/src/store.rs @@ -98,7 +98,7 @@ impl FunctionInstance { #[derive(Debug, Default)] /// Global state that can be manipulated by WebAssembly programs -pub struct StoreData { +pub(crate) struct StoreData { pub(crate) funcs: Vec<Rc<FunctionInstance>>, // pub tables: Vec<TableAddr>, // pub mems: Vec<MemAddr>, diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index b79c72a..4e09e00 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -1,3 +1,16 @@ +#![no_std] +#![forbid(unsafe_code)] +#![doc(test( + no_crate_inject, + attr( + deny(warnings, rust_2018_idioms), + allow(dead_code, unused_assignments, unused_variables) + ) +))] +#![warn(missing_debug_implementations, rust_2018_idioms, unreachable_pub)] + +//! Types used by [`tinywasm`](https://docs.rs/tinywasm) and [`tinywasm_parser`](https://docs.rs/tinywasm_parser). + extern crate alloc; // log for logging (optional). @@ -15,15 +28,29 @@ extern crate alloc; mod instructions; use core::fmt::Debug; +use alloc::boxed::Box; pub use instructions::*; +/// A TinyWasm WebAssembly Module +/// +/// This is the internal representation of a WebAssembly module in TinyWasm. +/// TinyWasmModules are validated before being created, so they are guaranteed to be valid (as long as they were created by TinyWasm). +/// This means you should not trust a TinyWasmModule created by a third party to be valid. #[derive(Debug)] pub struct TinyWasmModule { + /// The version of the WebAssembly module. pub version: Option<u16>, + + /// The start function of the WebAssembly module. pub start_func: Option<FuncAddr>, + /// The functions of the WebAssembly module. pub funcs: Box<[Function]>, + + /// The types of the WebAssembly module. pub types: Box<[FuncType]>, + + /// The exports of the WebAssembly module. pub exports: Box<[Export]>, // pub tables: Option<TableType>, // pub memories: Option<MemoryType>, @@ -39,15 +66,20 @@ pub struct TinyWasmModule { #[derive(Clone, PartialEq, Copy)] pub enum WasmValue { // Num types + /// A 32-bit integer. I32(i32), + /// A 64-bit integer. I64(i64), + /// A 32-bit float. F32(f32), + /// A 64-bit float. F64(f64), // Vec types // V128(i128), } impl WasmValue { + /// Get the default value for a given type. pub fn default_for(ty: ValType) -> Self { match ty { ValType::I32 => Self::I32(0), @@ -135,19 +167,8 @@ impl TryFrom<WasmValue> for f64 { } } -// impl TryFrom<WasmValue> for i128 { -// type Error = (); - -// fn try_from(value: WasmValue) -> Result<Self, Self::Error> { -// match value { -// WasmValue::V128(i) => Ok(i), -// _ => Err(()), -// } -// } -// } - impl Debug for WasmValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result { match self { WasmValue::I32(i) => write!(f, "i32({})", i), WasmValue::I64(i) => write!(f, "i64({})", i), @@ -159,6 +180,7 @@ impl Debug for WasmValue { } impl WasmValue { + /// Get the type of a [`WasmValue`] pub fn val_type(&self) -> ValType { match self { Self::I32(_) => ValType::I32, @@ -173,12 +195,19 @@ impl WasmValue { /// Type of a WebAssembly value. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ValType { + /// A 32-bit integer. I32, + /// A 64-bit integer. I64, + /// A 32-bit float. F32, + /// A 64-bit float. F64, + /// A 128-bit vector. V128, + /// A reference to a function. FuncRef, + /// A reference to an external value. ExternRef, } @@ -187,9 +216,13 @@ pub enum ValType { /// See <https://webassembly.github.io/spec/core/syntax/types.html#external-types> #[derive(Debug, Clone, PartialEq)] pub enum ExternalKind { + /// A WebAssembly Function. Func, + /// A WebAssembly Table. Table, + /// A WebAssembly Memory. Memory, + /// A WebAssembly Global. Global, } @@ -212,15 +245,6 @@ pub type LocalAddr = Addr; pub type LabelAddr = Addr; pub type ModuleInstanceAddr = Addr; -/// A WebAssembly Export Instance. -/// -/// See <https://webassembly.github.io/spec/core/exec/runtime.html#export-instances> -#[derive(Debug)] -pub struct ExportInst { - pub name: String, - pub value: ExternVal, -} - /// A WebAssembly External Value. /// /// See <https://webassembly.github.io/spec/core/exec/runtime.html#external-values> diff --git a/crates/wasm-testsuite/lib.rs b/crates/wasm-testsuite/lib.rs index 102389a..5590f35 100644 --- a/crates/wasm-testsuite/lib.rs +++ b/crates/wasm-testsuite/lib.rs @@ -2,7 +2,7 @@ //! //! The testsuite is included as a git submodule and embedded into the binary. //! -//! Generated from https://github.com/WebAssembly/testsuite +//! Generated from <https://github.com/WebAssembly/testsuite> #![forbid(unsafe_code)] #![doc(test( @@ -22,18 +22,21 @@ use std::borrow::Cow; #[include = "*.wast"] struct Asset; -/// List of all proposals. -/// This list is generated from the `proposals` folder in https://github.com/WebAssembly/testsuite +/// List of all proposals. Used to filter tests. +/// +/// Includes all proposals from <https://github.com/WebAssembly/testsuite/tree/master/proposals> #[rustfmt::skip] pub const PROPOSALS: &[&str] = &["annotations", "exception-handling", "memory64", "function-references", "multi-memory", "relaxed-simd", "tail-call", "threads", "extended-const", "gc"]; /// Get all test file names and their contents. -/// -/// Proposals can be filtered by passing a list of proposal names. -/// Valid proposal names are listed in [`PROPOSALS`]. -/// Returns an iterator over tuples of the form `(test_name, test_data)`. -/// test_name is the name of the test file and the proposal name (if any), e.g. `annotations/br.wast`. -pub fn get_tests(include_proposals: &[String]) -> impl Iterator<Item = (String, Cow<'static, [u8]>)> { +pub fn get_tests_wast(include_proposals: &[String]) -> impl Iterator<Item = (String, Cow<'static, [u8]>)> { + get_tests(&include_proposals) + .filter_map(|name| Some((name.clone(), get_test_wast(&name)?))) + .map(|(name, data)| (name, Cow::Owned(data.to_vec()))) +} + +/// Get all test file names. +pub fn get_tests(include_proposals: &[String]) -> impl Iterator<Item = String> { let include_proposals = include_proposals.to_vec(); Asset::iter().filter_map(move |x| { @@ -45,27 +48,19 @@ pub fn get_tests(include_proposals: &[String]) -> impl Iterator<Item = (String, if proposal.map_or(false, |p| include_proposals.contains(&p.to_string())) { let full_path = format!("{}/{}", proposal.unwrap_or_default(), test_name); - let data = Asset::get(&x).unwrap().data; - Some((full_path, data)) + Some(full_path) } else { None } } - Some(test_name) => { - let data = Asset::get(&x).unwrap().data; - Some((test_name.to_owned(), data)) - } + Some(test_name) => Some(test_name.to_owned()), None => None, } }) } /// Get the WAST file as a byte slice. -/// -/// # Examples -/// proposals: {proposal}/{test_name}.wast -/// tests: {test_name}.wast -pub fn get_wast(name: &str) -> Option<Cow<'_, [u8]>> { +pub fn get_test_wast(name: &str) -> Option<Cow<'static, [u8]>> { if !name.ends_with(".wast") { panic!("Expected .wast file. Got: {}", name); } @@ -94,19 +89,7 @@ mod tests { let proposal = proposal.split('/').nth(1).unwrap(); unique_proposals.insert(proposal.to_owned()); - // assert!(PROPOSALS.contains(&proposal)); + assert!(PROPOSALS.contains(&proposal)); } - println!("{:?}", unique_proposals); - } - - #[test] - fn test_get_tests() { - let tests = get_tests(&["annotations".to_owned()]); - let tests: Vec<_> = tests.collect(); - println!("{:?}", tests.iter().map(|(name, _)| name).collect::<Vec<_>>()); - - // for (name, data) in tests { - // println!("{}: {}", name, data.len()); - // } } } |
