doc(interface-types) Improve the documentation of the interpreter module.

This commit is contained in:
Ivan Enderlin 2020-02-12 17:37:06 +01:00
parent 278a743e60
commit 8ba931e33f
2 changed files with 100 additions and 0 deletions

View File

@ -10,6 +10,8 @@ use stack::Stack;
use std::{convert::TryFrom, marker::PhantomData};
use wasm::values::InterfaceValue;
/// Represents the `Runtime`, which is used by an adapter to execute
/// its instructions.
pub(crate) struct Runtime<'invocation, 'instance, Instance, Export, LocalImport, Memory, MemoryView>
where
Export: wasm::structures::Export + 'instance,
@ -18,16 +20,104 @@ where
MemoryView: wasm::structures::MemoryView,
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView> + 'instance,
{
/// The invocation inputs are all the arguments received by an
/// adapter.
invocation_inputs: &'invocation [InterfaceValue],
/// Each runtime (so adapter) has its own stack instance.
stack: Stack<InterfaceValue>,
/// The WebAssembly module instance. It is used by adapter's
/// instructions.
wasm_instance: &'instance mut Instance,
/// Phantom data.
_phantom: PhantomData<(Export, LocalImport, Memory, MemoryView)>,
}
/// Type alias for an executable instruction. It's an implementation
/// details, but an instruction is a boxed closure instance.
pub(crate) type ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView> = Box<
dyn Fn(&mut Runtime<Instance, Export, LocalImport, Memory, MemoryView>) -> Result<(), String>,
>;
/// An interpreter is the central piece of this crate. It is a set of
/// executable instructions. Each instruction takes the runtime as
/// argument. The runtime holds the invocation inputs, the stack, and
/// the WebAssembly instance.
///
/// When the interpreter executes the instructions, each of them can
/// query the WebAssembly instance, operates on the stack, or reads
/// the invocation inputs. At the end of the execution, the stack
/// supposedly contains a result. Since an interpreter is used by a
/// WIT adapter to execute its instructions, the result on the stack
/// is the result of the adapter.
///
/// # Example
///
/// ```rust,ignore
/// use std::{cell::Cell, collections::HashMap, convert::TryInto};
/// use wasmer_interface_types::interpreter::{
/// instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView},
/// // ^^^^^^^^^^^^ This is private and for testing purposes only.
/// // It is basically a fake WebAssembly runtime.
/// stack::Stackable,
/// wasm::values::{InterfaceType, InterfaceValue},
/// Instruction, Interpreter,
/// };
///
/// # fn main() {
/// // 1. Creates an interpreter from a set of instructions. They will
/// // be transformed into executable instructions.
/// let interpreter: Interpreter<Instance, Export, LocalImport, Memory, MemoryView> = (&vec![
/// Instruction::ArgumentGet { index: 1 },
/// Instruction::ArgumentGet { index: 0 },
/// Instruction::CallExport { export_name: "sum" },
/// ])
/// .try_into()
/// .unwrap();
///
/// // 2. Defines the arguments of the adapter.
/// let invocation_inputs = vec![InterfaceValue::I32(3), InterfaceValue::I32(4)];
///
/// // 3. Creates a WebAssembly instance.
/// let mut instance = Instance {
/// // 3.1. Defines one exported function: `fn sum(a: i32, b: i32) -> i32 { a + b }`.
/// exports: {
/// let mut hashmap = HashMap::new();
/// hashmap.insert(
/// "sum".into(),
/// Export {
/// // Defines the argument types of the function.
/// inputs: vec![InterfaceType::I32, InterfaceType::I32],
///
/// // Defines the result types.
/// outputs: vec![InterfaceType::I32],
///
/// // Defines the function implementation.
/// function: |arguments: &[InterfaceValue]| {
/// let a: i32 = (&arguments[0]).try_into().unwrap();
/// let b: i32 = (&arguments[1]).try_into().unwrap();
///
/// Ok(vec![InterfaceValue::I32(a + b)])
/// },
/// },
/// );
/// },
/// ..Default::default()
/// };
///
/// // 4. Executes the instructions.
/// let run = interpreter.run(&invocation_inputs, &mut instance);
///
/// assert!(run.is_ok());
///
/// let stack = run.unwrap();
///
/// // 5. Read the stack to get the result.
/// assert_eq!(stack.as_slice(), &[InterfaceValue::I32(7)]);
/// # }
/// ```
pub struct Interpreter<Instance, Export, LocalImport, Memory, MemoryView>
where
Export: wasm::structures::Export,
@ -57,6 +147,11 @@ where
self.executable_instructions.iter()
}
/// Runs the interpreter, such as:
/// 1. Create a fresh stack,
/// 2. Create a fresh stack,
/// 3. Execute the instructions one after the other, and
/// returns the stack.
pub fn run(
&self,
invocation_inputs: &[InterfaceValue],
@ -80,6 +175,7 @@ where
}
}
/// Transforms a `Vec<Instruction>` into an `Interpreter`.
impl<'binary_input, Instance, Export, LocalImport, Memory, MemoryView>
TryFrom<&Vec<Instruction<'binary_input>>>
for Interpreter<Instance, Export, LocalImport, Memory, MemoryView>

View File

@ -1,2 +1,6 @@
//! An hypothetic WebAssembly runtime, represented as a set of enums,
//! types, and traits —basically this is the part a runtime should
//! take a look to use the `wasmer-interface-types` crate—.
pub mod structures;
pub mod values;