// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see .
//! Types and traits for interfacing between the host and the wasm runtime.
use std::{borrow::Cow, marker::PhantomData, mem, iter::Iterator, result};
mod wasmi_impl;
/// Result type used by traits in this crate.
pub type Result = result::Result;
/// Value types supported by Substrate on the boundary between host/Wasm.
#[derive(Copy, Clone, PartialEq, Debug, Eq)]
pub enum ValueType {
/// An `i32` value type.
I32,
/// An `i64` value type.
I64,
/// An `f32` value type.
F32,
/// An `f64` value type.
F64,
}
/// Values supported by Substrate on the boundary between host/Wasm.
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum Value {
/// An `i32` value.
I32(i32),
/// An `i64` value.
I64(i64),
/// An nan-preserving `f32` value.
F32(u32),
/// An nan-preserving `f64` value.
F64(u64),
}
impl Value {
/// Returns the type of this value.
pub fn value_type(&self) -> ValueType {
match self {
Value::I32(_) => ValueType::I32,
Value::I64(_) => ValueType::I64,
Value::F32(_) => ValueType::F32,
Value::F64(_) => ValueType::F64,
}
}
}
/// Provides `Sealed` trait to prevent implementing trait `PointerType` outside of this crate.
mod private {
pub trait Sealed {}
impl Sealed for u8 {}
impl Sealed for u16 {}
impl Sealed for u32 {}
impl Sealed for u64 {}
}
/// Something that can be wrapped in a wasm `Pointer`.
///
/// This trait is sealed.
pub trait PointerType: Sized {
/// The size of the type in wasm.
const SIZE: u32 = mem::size_of::() as u32;
}
impl PointerType for u8 {}
impl PointerType for u16 {}
impl PointerType for u32 {}
impl PointerType for u64 {}
/// Type to represent a pointer in wasm at the host.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Pointer {
ptr: u32,
_marker: PhantomData,
}
impl Pointer {
/// Create a new instance of `Self`.
pub fn new(ptr: u32) -> Self {
Self {
ptr,
_marker: Default::default(),
}
}
/// Calculate the offset from this pointer.
///
/// `offset` is in units of `T`. So, `3` means `3 * mem::size_of::()` as offset to the pointer.
///
/// Returns an `Option` to respect that the pointer could probably overflow.
pub fn offset(self, offset: u32) -> Option {
offset.checked_mul(T::SIZE).and_then(|o| self.ptr.checked_add(o)).map(|ptr| {
Self {
ptr,
_marker: Default::default(),
}
})
}
/// Create a null pointer.
pub fn null() -> Self {
Self::new(0)
}
/// Cast this pointer of type `T` to a pointer of type `R`.
pub fn cast(self) -> Pointer {
Pointer::new(self.ptr)
}
}
impl From> for u32 {
fn from(ptr: Pointer) -> Self {
ptr.ptr
}
}
impl From> for usize {
fn from(ptr: Pointer) -> Self {
ptr.ptr as _
}
}
impl IntoValue for Pointer {
const VALUE_TYPE: ValueType = ValueType::I32;
fn into_value(self) -> Value { Value::I32(self.ptr as _) }
}
impl TryFromValue for Pointer {
fn try_from_value(val: Value) -> Option {
match val {
Value::I32(val) => Some(Self::new(val as _)),
_ => None,
}
}
}
/// The word size used in wasm. Normally known as `usize` in Rust.
pub type WordSize = u32;
/// The Signature of a function
#[derive(Eq, PartialEq, Debug, Clone)]
pub struct Signature {
/// The arguments of a function.
pub args: Cow<'static, [ValueType]>,
/// The optional return value of a function.
pub return_value: Option,
}
impl Signature {
/// Create a new instance of `Signature`.
pub fn new>>(args: T, return_value: Option) -> Self {
Self {
args: args.into(),
return_value,
}
}
/// Create a new instance of `Signature` with the given `args` and without any return value.
pub fn new_with_args>>(args: T) -> Self {
Self {
args: args.into(),
return_value: None,
}
}
}
/// Something that provides a function implementation on the host for a wasm function.
pub trait Function {
/// Returns the name of this function.
fn name(&self) -> &str;
/// Returns the signature of this function.
fn signature(&self) -> Signature;
/// Execute this function with the given arguments.
fn execute(
&self,
context: &mut dyn FunctionContext,
args: &mut dyn Iterator,
) -> Result