Skip to content

Commit

Permalink
docs: improve rustdoc
Browse files Browse the repository at this point in the history
Signed-off-by: Henry Gressmann <[email protected]>
  • Loading branch information
explodingcamera committed Dec 10, 2023
1 parent 52bebfa commit 5315ea9
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 61 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
- **`std`**\
Enables the use of `std` and `std::io` for parsing from files and streams. This is enabled by default.
- **`logging`**\
Enables logging of the parsing process using the `log` crate. This is enabled by default.
Enables logging using the `log` crate. This is enabled by default.
- **`parser`**\
Enables the `tinywasm-parser` crate. This is enabled by default.

Expand Down
2 changes: 1 addition & 1 deletion crates/cli/src/args.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::str::FromStr;
use tinywasm::WasmValue;
use tinywasm::types::WasmValue;

#[derive(Debug)]
pub struct WasmArg(WasmValue);
Expand Down
2 changes: 1 addition & 1 deletion crates/cli/src/bin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
56 changes: 54 additions & 2 deletions crates/tinywasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)))]
Expand Down Expand Up @@ -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 {
Expand Down
3 changes: 2 additions & 1 deletion crates/tinywasm/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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 {}
2 changes: 1 addition & 1 deletion crates/tinywasm/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down
66 changes: 45 additions & 21 deletions crates/types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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).
Expand All @@ -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>,
Expand All @@ -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),
Expand Down Expand Up @@ -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),
Expand All @@ -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,
Expand All @@ -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,
}

Expand All @@ -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,
}

Expand All @@ -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>
Expand Down
49 changes: 16 additions & 33 deletions crates/wasm-testsuite/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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| {
Expand All @@ -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);
}
Expand Down Expand Up @@ -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());
// }
}
}

0 comments on commit 5315ea9

Please sign in to comment.