Args refactor (#71)
* Refactor TryInto → FromRuntimeValue. Replace `TryInto<T, E>` with `FromRuntimeValue`. The main difference is that `FromRuntimeValue` is implemented for the concrete type of the value we create, rather than on `RuntimeValue`. This makes more sense to me and seems more clear. The `try_into` method is now implemented on `RuntimeValue` itself. And finally, `FromRuntimeValue` has been made public. * Impl AsRef<[RuntimeValue]> for RuntimeArgs This impl can be used as an escape hatch if the user wants to use the inner slice. * Little doc fixes for RuntimeArgs.
This commit is contained in:
parent
9fa933ccd6
commit
6253dd6fdf
21
src/host.rs
21
src/host.rs
|
@ -1,8 +1,11 @@
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use value::{RuntimeValue, TryInto};
|
use value::{RuntimeValue, FromRuntimeValue};
|
||||||
use {TrapKind, Trap};
|
use {TrapKind, Trap};
|
||||||
|
|
||||||
/// Safe wrapper for list of arguments.
|
/// Wrapper around slice of [`RuntimeValue`] for using it
|
||||||
|
/// as an argument list conveniently.
|
||||||
|
///
|
||||||
|
/// [`RuntimeValue`]: enum.RuntimeValue.html
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RuntimeArgs<'a>(&'a [RuntimeValue]);
|
pub struct RuntimeArgs<'a>(&'a [RuntimeValue]);
|
||||||
|
|
||||||
|
@ -12,14 +15,20 @@ impl<'a> From<&'a [RuntimeValue]> for RuntimeArgs<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> AsRef<[RuntimeValue]> for RuntimeArgs<'a> {
|
||||||
|
fn as_ref(&self) -> &[RuntimeValue] {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> RuntimeArgs<'a> {
|
impl<'a> RuntimeArgs<'a> {
|
||||||
/// Extract argument by index `idx`.
|
/// Extract argument by index `idx`.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns `Err` if cast is invalid or not enough arguments.
|
/// Returns `Err` if cast is invalid or not enough arguments.
|
||||||
pub fn nth_checked<T>(&self, idx: usize) -> Result<T, Trap> where RuntimeValue: TryInto<T, ::value::Error> {
|
pub fn nth_checked<T>(&self, idx: usize) -> Result<T, Trap> where T: FromRuntimeValue {
|
||||||
Ok(self.nth_value_checked(idx)?.try_into().map_err(|_| TrapKind::UnexpectedSignature)?)
|
Ok(self.nth_value_checked(idx)?.try_into().ok_or_else(|| TrapKind::UnexpectedSignature)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract argument as a [`RuntimeValue`] by index `idx`.
|
/// Extract argument as a [`RuntimeValue`] by index `idx`.
|
||||||
|
@ -27,6 +36,8 @@ impl<'a> RuntimeArgs<'a> {
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns `Err` if this list has not enough arguments.
|
/// Returns `Err` if this list has not enough arguments.
|
||||||
|
///
|
||||||
|
/// [`RuntimeValue`]: enum.RuntimeValue.html
|
||||||
pub fn nth_value_checked(&self, idx: usize) -> Result<RuntimeValue, Trap> {
|
pub fn nth_value_checked(&self, idx: usize) -> Result<RuntimeValue, Trap> {
|
||||||
if self.0.len() <= idx {
|
if self.0.len() <= idx {
|
||||||
return Err(TrapKind::UnexpectedSignature.into());
|
return Err(TrapKind::UnexpectedSignature.into());
|
||||||
|
@ -39,7 +50,7 @@ impl<'a> RuntimeArgs<'a> {
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if cast is invalid or not enough arguments.
|
/// Panics if cast is invalid or not enough arguments.
|
||||||
pub fn nth<T>(&self, idx: usize) -> T where RuntimeValue: TryInto<T, ::value::Error> {
|
pub fn nth<T>(&self, idx: usize) -> T where T: FromRuntimeValue {
|
||||||
let value = self.nth_value_checked(idx).expect("Invalid argument index");
|
let value = self.nth_value_checked(idx).expect("Invalid argument index");
|
||||||
value.try_into().expect("Unexpected argument type")
|
value.try_into().expect("Unexpected argument type")
|
||||||
}
|
}
|
||||||
|
|
|
@ -364,7 +364,7 @@ mod tests;
|
||||||
|
|
||||||
pub use self::memory::{MemoryInstance, MemoryRef, LINEAR_MEMORY_PAGE_SIZE};
|
pub use self::memory::{MemoryInstance, MemoryRef, LINEAR_MEMORY_PAGE_SIZE};
|
||||||
pub use self::table::{TableInstance, TableRef};
|
pub use self::table::{TableInstance, TableRef};
|
||||||
pub use self::value::RuntimeValue;
|
pub use self::value::{RuntimeValue, FromRuntimeValue};
|
||||||
pub use self::host::{Externals, NopExternals, HostError, RuntimeArgs};
|
pub use self::host::{Externals, NopExternals, HostError, RuntimeArgs};
|
||||||
pub use self::imports::{ModuleImportResolver, ImportResolver, ImportsBuilder};
|
pub use self::imports::{ModuleImportResolver, ImportResolver, ImportsBuilder};
|
||||||
pub use self::module::{ModuleInstance, ModuleRef, ExternVal, NotStartedModuleRef};
|
pub use self::module::{ModuleInstance, ModuleRef, ExternVal, NotStartedModuleRef};
|
||||||
|
|
127
src/runner.rs
127
src/runner.rs
|
@ -1,7 +1,7 @@
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops;
|
use std::ops;
|
||||||
use std::{u32, usize};
|
use std::{u32, usize};
|
||||||
use std::fmt::{self, Display};
|
use std::fmt;
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use parity_wasm::elements::{Opcode, BlockType, Local};
|
use parity_wasm::elements::{Opcode, BlockType, Local};
|
||||||
|
@ -9,7 +9,7 @@ use {Error, Trap, TrapKind, Signature};
|
||||||
use module::ModuleRef;
|
use module::ModuleRef;
|
||||||
use func::{FuncRef, FuncInstance, FuncInstanceInternal};
|
use func::{FuncRef, FuncInstance, FuncInstanceInternal};
|
||||||
use value::{
|
use value::{
|
||||||
RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto,
|
RuntimeValue, FromRuntimeValue, WrapInto, TryTruncateInto, ExtendInto,
|
||||||
ArithmeticOps, Integer, Float, LittleEndianConvert, TransmuteInto,
|
ArithmeticOps, Integer, Float, LittleEndianConvert, TransmuteInto,
|
||||||
};
|
};
|
||||||
use host::Externals;
|
use host::Externals;
|
||||||
|
@ -589,7 +589,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_store<T>(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, TrapKind>
|
fn run_store<T>(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: TryInto<T, ::value::Error>, T: LittleEndianConvert {
|
where T: FromRuntimeValue, T: LittleEndianConvert {
|
||||||
let stack_value = context
|
let stack_value = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_as::<T>()
|
.pop_as::<T>()
|
||||||
|
@ -618,7 +618,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
offset: u32,
|
offset: u32,
|
||||||
) -> Result<InstructionOutcome, TrapKind>
|
) -> Result<InstructionOutcome, TrapKind>
|
||||||
where
|
where
|
||||||
RuntimeValue: TryInto<T, ::value::Error>,
|
T: FromRuntimeValue,
|
||||||
T: WrapInto<U>,
|
T: WrapInto<U>,
|
||||||
U: LittleEndianConvert,
|
U: LittleEndianConvert,
|
||||||
{
|
{
|
||||||
|
@ -682,7 +682,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
|
|
||||||
fn run_relop<T, F>(&mut self, context: &mut FunctionContext, f: F) -> Result<InstructionOutcome, TrapKind>
|
fn run_relop<T, F>(&mut self, context: &mut FunctionContext, f: F) -> Result<InstructionOutcome, TrapKind>
|
||||||
where
|
where
|
||||||
RuntimeValue: TryInto<T, ::value::Error>,
|
T: FromRuntimeValue,
|
||||||
F: FnOnce(T, T) -> bool,
|
F: FnOnce(T, T) -> bool,
|
||||||
{
|
{
|
||||||
let (left, right) = context
|
let (left, right) = context
|
||||||
|
@ -699,7 +699,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_eqz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_eqz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: TryInto<T, ::value::Error>, T: PartialEq<T> + Default {
|
where T: FromRuntimeValue, T: PartialEq<T> + Default {
|
||||||
let v = context
|
let v = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_as::<T>();
|
.pop_as::<T>();
|
||||||
|
@ -709,40 +709,41 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_eq<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_eq<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: TryInto<T, ::value::Error>, T: PartialEq<T>
|
where T: FromRuntimeValue + PartialEq<T>
|
||||||
{
|
{
|
||||||
self.run_relop(context, |left, right| left == right)
|
self.run_relop(context, |left: T, right: T| left == right)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_ne<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_ne<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: TryInto<T, ::value::Error>, T: PartialEq<T> {
|
where T: FromRuntimeValue + PartialEq<T> {
|
||||||
self.run_relop(context, |left, right| left != right)
|
self.run_relop(context, |left: T, right: T| left != right)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_lt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_lt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: TryInto<T, ::value::Error>, T: PartialOrd<T> + Display {
|
where T: FromRuntimeValue + PartialOrd<T> {
|
||||||
self.run_relop(context, |left, right| left < right)
|
self.run_relop(context, |left: T, right: T| left < right)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_gt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_gt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: TryInto<T, ::value::Error>, T: PartialOrd<T> {
|
where T: FromRuntimeValue + PartialOrd<T> {
|
||||||
self.run_relop(context, |left, right| left > right)
|
self.run_relop(context, |left: T, right: T| left > right)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_lte<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_lte<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: TryInto<T, ::value::Error>, T: PartialOrd<T> {
|
where T: FromRuntimeValue + PartialOrd<T> {
|
||||||
self.run_relop(context, |left, right| left <= right)
|
self.run_relop(context, |left: T, right: T| left <= right)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_gte<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_gte<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: TryInto<T, ::value::Error>, T: PartialOrd<T> {
|
where T: FromRuntimeValue + PartialOrd<T> {
|
||||||
self.run_relop(context, |left, right| left >= right)
|
self.run_relop(context, |left: T, right: T| left >= right)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_unop<T, U, F>(&mut self, context: &mut FunctionContext, f: F) -> Result<InstructionOutcome, TrapKind>
|
fn run_unop<T, U, F>(&mut self, context: &mut FunctionContext, f: F) -> Result<InstructionOutcome, TrapKind>
|
||||||
where
|
where
|
||||||
F: FnOnce(T) -> U,
|
F: FnOnce(T) -> U,
|
||||||
RuntimeValue: From<U> + TryInto<T, ::value::Error>
|
T: FromRuntimeValue,
|
||||||
|
RuntimeValue: From<U>
|
||||||
{
|
{
|
||||||
let v = context
|
let v = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
|
@ -753,22 +754,22 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_clz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_clz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Integer<T> {
|
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue {
|
||||||
self.run_unop(context, |v| v.leading_zeros())
|
self.run_unop(context, |v: T| v.leading_zeros())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_ctz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_ctz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Integer<T> {
|
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue {
|
||||||
self.run_unop(context, |v| v.trailing_zeros())
|
self.run_unop(context, |v: T| v.trailing_zeros())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_popcnt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_popcnt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Integer<T> {
|
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue {
|
||||||
self.run_unop(context, |v| v.count_ones())
|
self.run_unop(context, |v: T| v.count_ones())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_add<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_add<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: ArithmeticOps<T> {
|
where RuntimeValue: From<T>, T: ArithmeticOps<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_pair_as::<T>()
|
.pop_pair_as::<T>()
|
||||||
|
@ -779,7 +780,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_sub<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_sub<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: ArithmeticOps<T> {
|
where RuntimeValue: From<T>, T: ArithmeticOps<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_pair_as::<T>()
|
.pop_pair_as::<T>()
|
||||||
|
@ -790,7 +791,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_mul<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_mul<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: ArithmeticOps<T> {
|
where RuntimeValue: From<T>, T: ArithmeticOps<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_pair_as::<T>()
|
.pop_pair_as::<T>()
|
||||||
|
@ -801,7 +802,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_div<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_div<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: TransmuteInto<U> + Display, U: ArithmeticOps<U> + TransmuteInto<T> {
|
where RuntimeValue: From<T>, T: TransmuteInto<U> + FromRuntimeValue, U: ArithmeticOps<U> + TransmuteInto<T> {
|
||||||
let (left, right) = context
|
let (left, right) = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_pair_as::<T>()
|
.pop_pair_as::<T>()
|
||||||
|
@ -814,7 +815,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_rem<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_rem<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: TransmuteInto<U>, U: Integer<U> + TransmuteInto<T> {
|
where RuntimeValue: From<T>, T: TransmuteInto<U> + FromRuntimeValue, U: Integer<U> + TransmuteInto<T> {
|
||||||
let (left, right) = context
|
let (left, right) = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_pair_as::<T>()
|
.pop_pair_as::<T>()
|
||||||
|
@ -827,7 +828,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_and<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_and<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<<T as ops::BitAnd>::Output> + TryInto<T, ::value::Error>, T: ops::BitAnd<T> {
|
where RuntimeValue: From<<T as ops::BitAnd>::Output>, T: ops::BitAnd<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_pair_as::<T>()
|
.pop_pair_as::<T>()
|
||||||
|
@ -838,7 +839,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_or<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_or<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<<T as ops::BitOr>::Output> + TryInto<T, ::value::Error>, T: ops::BitOr<T> {
|
where RuntimeValue: From<<T as ops::BitOr>::Output>, T: ops::BitOr<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_pair_as::<T>()
|
.pop_pair_as::<T>()
|
||||||
|
@ -849,7 +850,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_xor<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_xor<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<<T as ops::BitXor>::Output> + TryInto<T, ::value::Error>, T: ops::BitXor<T> {
|
where RuntimeValue: From<<T as ops::BitXor>::Output>, T: ops::BitXor<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_pair_as::<T>()
|
.pop_pair_as::<T>()
|
||||||
|
@ -860,7 +861,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_shl<T>(&mut self, context: &mut FunctionContext, mask: T) -> Result<InstructionOutcome, TrapKind>
|
fn run_shl<T>(&mut self, context: &mut FunctionContext, mask: T) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<<T as ops::Shl<T>>::Output> + TryInto<T, ::value::Error>, T: ops::Shl<T> + ops::BitAnd<T, Output=T> {
|
where RuntimeValue: From<<T as ops::Shl<T>>::Output>, T: ops::Shl<T> + ops::BitAnd<T, Output=T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_pair_as::<T>()
|
.pop_pair_as::<T>()
|
||||||
|
@ -871,7 +872,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_shr<T, U>(&mut self, context: &mut FunctionContext, mask: U) -> Result<InstructionOutcome, TrapKind>
|
fn run_shr<T, U>(&mut self, context: &mut FunctionContext, mask: U) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: TransmuteInto<U>, U: ops::Shr<U> + ops::BitAnd<U, Output=U>, <U as ops::Shr<U>>::Output: TransmuteInto<T> {
|
where RuntimeValue: From<T>, T: TransmuteInto<U> + FromRuntimeValue, U: ops::Shr<U> + ops::BitAnd<U, Output=U>, <U as ops::Shr<U>>::Output: TransmuteInto<T> {
|
||||||
let (left, right) = context
|
let (left, right) = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_pair_as::<T>()
|
.pop_pair_as::<T>()
|
||||||
|
@ -884,7 +885,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_rotl<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_rotl<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Integer<T> {
|
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_pair_as::<T>()
|
.pop_pair_as::<T>()
|
||||||
|
@ -895,7 +896,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_rotr<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_rotr<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Integer<T>
|
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue
|
||||||
{
|
{
|
||||||
let (left, right) = context
|
let (left, right) = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
|
@ -907,51 +908,51 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_abs<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_abs<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T>
|
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
|
||||||
{
|
{
|
||||||
self.run_unop(context, |v| v.abs())
|
self.run_unop(context, |v: T| v.abs())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_neg<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_neg<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where
|
where
|
||||||
RuntimeValue: From<<T as ops::Neg>::Output> + TryInto<T, ::value::Error>,
|
RuntimeValue: From<<T as ops::Neg>::Output>,
|
||||||
T: ops::Neg
|
T: ops::Neg + FromRuntimeValue
|
||||||
{
|
{
|
||||||
self.run_unop(context, |v| v.neg())
|
self.run_unop(context, |v: T| v.neg())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_ceil<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_ceil<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T>
|
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
|
||||||
{
|
{
|
||||||
self.run_unop(context, |v| v.ceil())
|
self.run_unop(context, |v: T| v.ceil())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_floor<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_floor<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T>
|
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
|
||||||
{
|
{
|
||||||
self.run_unop(context, |v| v.floor())
|
self.run_unop(context, |v: T| v.floor())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_trunc<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_trunc<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T>
|
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
|
||||||
{
|
{
|
||||||
self.run_unop(context, |v| v.trunc())
|
self.run_unop(context, |v: T| v.trunc())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_nearest<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_nearest<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T>
|
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
|
||||||
{
|
{
|
||||||
self.run_unop(context, |v| v.nearest())
|
self.run_unop(context, |v: T| v.nearest())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_sqrt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_sqrt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T>
|
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
|
||||||
{
|
{
|
||||||
self.run_unop(context, |v| v.sqrt())
|
self.run_unop(context, |v: T| v.sqrt())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_min<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_min<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T>
|
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
|
||||||
{
|
{
|
||||||
let (left, right) = context
|
let (left, right) = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
|
@ -963,7 +964,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_max<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_max<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T> {
|
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_pair_as::<T>()
|
.pop_pair_as::<T>()
|
||||||
|
@ -974,7 +975,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_copysign<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_copysign<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T> {
|
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue {
|
||||||
let (left, right) = context
|
let (left, right) = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_pair_as::<T>()
|
.pop_pair_as::<T>()
|
||||||
|
@ -985,12 +986,12 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_wrap<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_wrap<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<U> + TryInto<T, ::value::Error>, T: WrapInto<U> {
|
where RuntimeValue: From<U>, T: WrapInto<U> + FromRuntimeValue {
|
||||||
self.run_unop(context, |v| v.wrap_into())
|
self.run_unop(context, |v: T| v.wrap_into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_trunc_to_int<T, U, V>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_trunc_to_int<T, U, V>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<V> + TryInto<T, ::value::Error>, T: TryTruncateInto<U, TrapKind>, U: TransmuteInto<V>, {
|
where RuntimeValue: From<V>, T: TryTruncateInto<U, TrapKind> + FromRuntimeValue, U: TransmuteInto<V>, {
|
||||||
let v = context
|
let v = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_as::<T>();
|
.pop_as::<T>();
|
||||||
|
@ -1003,7 +1004,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
|
|
||||||
fn run_extend<T, U, V>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_extend<T, U, V>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where
|
where
|
||||||
RuntimeValue: From<V> + TryInto<T, ::value::Error>, T: ExtendInto<U>, U: TransmuteInto<V>
|
RuntimeValue: From<V>, T: ExtendInto<U> + FromRuntimeValue, U: TransmuteInto<V>
|
||||||
{
|
{
|
||||||
let v = context
|
let v = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
|
@ -1017,7 +1018,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
|
|
||||||
fn run_reinterpret<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
fn run_reinterpret<T, U>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
|
||||||
where
|
where
|
||||||
RuntimeValue: From<U>, RuntimeValue: TryInto<T, ::value::Error>, T: TransmuteInto<U>
|
RuntimeValue: From<U>, T: FromRuntimeValue, T: TransmuteInto<U>
|
||||||
{
|
{
|
||||||
let v = context
|
let v = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
|
@ -1255,17 +1256,17 @@ impl ValueStack {
|
||||||
|
|
||||||
fn pop_as<T>(&mut self) -> T
|
fn pop_as<T>(&mut self) -> T
|
||||||
where
|
where
|
||||||
RuntimeValue: TryInto<T, ::value::Error>,
|
T: FromRuntimeValue,
|
||||||
{
|
{
|
||||||
let value = self.stack_with_limit
|
let value = self.stack_with_limit
|
||||||
.pop()
|
.pop()
|
||||||
.expect("Due to validation stack shouldn't be empty");
|
.expect("Due to validation stack shouldn't be empty");
|
||||||
TryInto::try_into(value).expect("Due to validation stack top's type should match")
|
value.try_into().expect("Due to validation stack top's type should match")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop_pair_as<T>(&mut self) -> Result<(T, T), Error>
|
fn pop_pair_as<T>(&mut self) -> Result<(T, T), Error>
|
||||||
where
|
where
|
||||||
RuntimeValue: TryInto<T, ::value::Error>,
|
T: FromRuntimeValue,
|
||||||
{
|
{
|
||||||
let right = self.pop_as();
|
let right = self.pop_as();
|
||||||
let left = self.pop_as();
|
let left = self.pop_as();
|
||||||
|
|
122
src/value.rs
122
src/value.rs
|
@ -1,14 +1,10 @@
|
||||||
use std::{i32, i64, u32, u64, f32};
|
use std::{i32, i64, u32, u64, f32};
|
||||||
use std::io;
|
use std::io;
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use parity_wasm::elements::ValueType;
|
|
||||||
use TrapKind;
|
use TrapKind;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
UnexpectedType {
|
|
||||||
expected: ValueType,
|
|
||||||
},
|
|
||||||
InvalidLittleEndianBuffer,
|
InvalidLittleEndianBuffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,10 +27,23 @@ pub enum RuntimeValue {
|
||||||
F64(f64),
|
F64(f64),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to convert into trait.
|
/// Trait for creating value from a [`RuntimeValue`].
|
||||||
pub trait TryInto<T, E> {
|
///
|
||||||
/// Try to convert self into other value.
|
/// Typically each implementation can create a value from the specific type.
|
||||||
fn try_into(self) -> Result<T, E>;
|
/// For example, values of type `bool` or `u32` are both represented by [`I32`] and `f64` values are represented by
|
||||||
|
/// [`F64`].
|
||||||
|
///
|
||||||
|
/// [`I32`]: enum.RuntimeValue.html#variant.I32
|
||||||
|
/// [`F64`]: enum.RuntimeValue.html#variant.F64
|
||||||
|
/// [`RuntimeValue`]: enum.RuntimeValue.html
|
||||||
|
pub trait FromRuntimeValue where Self: Sized {
|
||||||
|
/// Create a value of type `Self` from a given [`RuntimeValue`].
|
||||||
|
///
|
||||||
|
/// Returns `None` if the [`RuntimeValue`] is of type different than
|
||||||
|
/// expected by the conversion in question.
|
||||||
|
///
|
||||||
|
/// [`RuntimeValue`]: enum.RuntimeValue.html
|
||||||
|
fn from_runtime_value(val: RuntimeValue) -> Option<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert one type to another by wrapping.
|
/// Convert one type to another by wrapping.
|
||||||
|
@ -151,6 +160,17 @@ impl RuntimeValue {
|
||||||
RuntimeValue::F64(_) => ::types::ValueType::F64,
|
RuntimeValue::F64(_) => ::types::ValueType::F64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `T` if this particular [`RuntimeValue`] contains
|
||||||
|
/// appropriate type.
|
||||||
|
///
|
||||||
|
/// See [`FromRuntimeValue`] for details.
|
||||||
|
///
|
||||||
|
/// [`FromRuntimeValue`]: trait.FromRuntimeValue.html
|
||||||
|
/// [`RuntimeValue`]: enum.RuntimeValue.html
|
||||||
|
pub fn try_into<T: FromRuntimeValue>(self) -> Option<T> {
|
||||||
|
FromRuntimeValue::from_runtime_value(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<i32> for RuntimeValue {
|
impl From<i32> for RuntimeValue {
|
||||||
|
@ -189,68 +209,38 @@ impl From<f64> for RuntimeValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryInto<bool, Error> for RuntimeValue {
|
macro_rules! impl_from_runtime_value {
|
||||||
fn try_into(self) -> Result<bool, Error> {
|
($expected_rt_ty: ident, $into: ty) => {
|
||||||
match self {
|
impl FromRuntimeValue for $into {
|
||||||
RuntimeValue::I32(val) => Ok(val != 0),
|
fn from_runtime_value(val: RuntimeValue) -> Option<Self> {
|
||||||
_ => Err(Error::UnexpectedType { expected: ValueType::I32 }),
|
match val {
|
||||||
|
RuntimeValue::$expected_rt_ty(val) => Some(val as $into),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This conversion assumes that boolean values are represented by
|
||||||
|
/// [`I32`] type.
|
||||||
|
///
|
||||||
|
/// [`I32`]: enum.RuntimeValue.html#variant.I32
|
||||||
|
impl FromRuntimeValue for bool {
|
||||||
|
fn from_runtime_value(val: RuntimeValue) -> Option<Self> {
|
||||||
|
match val {
|
||||||
|
RuntimeValue::I32(val) => Some(val != 0),
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryInto<i32, Error> for RuntimeValue {
|
impl_from_runtime_value!(I32, i32);
|
||||||
fn try_into(self) -> Result<i32, Error> {
|
impl_from_runtime_value!(I64, i64);
|
||||||
match self {
|
impl_from_runtime_value!(F32, f32);
|
||||||
RuntimeValue::I32(val) => Ok(val),
|
impl_from_runtime_value!(F64, f64);
|
||||||
_ => Err(Error::UnexpectedType { expected: ValueType::I32 }),
|
impl_from_runtime_value!(I32, u32);
|
||||||
}
|
impl_from_runtime_value!(I64, u64);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryInto<i64, Error> for RuntimeValue {
|
|
||||||
fn try_into(self) -> Result<i64, Error> {
|
|
||||||
match self {
|
|
||||||
RuntimeValue::I64(val) => Ok(val),
|
|
||||||
_ => Err(Error::UnexpectedType { expected: ValueType::I64 }),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryInto<f32, Error> for RuntimeValue {
|
|
||||||
fn try_into(self) -> Result<f32, Error> {
|
|
||||||
match self {
|
|
||||||
RuntimeValue::F32(val) => Ok(val),
|
|
||||||
_ => Err(Error::UnexpectedType { expected: ValueType::F32 }),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryInto<f64, Error> for RuntimeValue {
|
|
||||||
fn try_into(self) -> Result<f64, Error> {
|
|
||||||
match self {
|
|
||||||
RuntimeValue::F64(val) => Ok(val),
|
|
||||||
_ => Err(Error::UnexpectedType { expected: ValueType::F64 }),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryInto<u32, Error> for RuntimeValue {
|
|
||||||
fn try_into(self) -> Result<u32, Error> {
|
|
||||||
match self {
|
|
||||||
RuntimeValue::I32(val) => Ok(val as u32),
|
|
||||||
_ => Err(Error::UnexpectedType { expected: ValueType::I32 }),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryInto<u64, Error> for RuntimeValue {
|
|
||||||
fn try_into(self) -> Result<u64, Error> {
|
|
||||||
match self {
|
|
||||||
RuntimeValue::I64(val) => Ok(val as u64),
|
|
||||||
_ => Err(Error::UnexpectedType { expected: ValueType::I64 }),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_wrap_into {
|
macro_rules! impl_wrap_into {
|
||||||
($from: ident, $into: ident) => {
|
($from: ident, $into: ident) => {
|
||||||
|
|
Loading…
Reference in New Issue