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:
Sergey Pepyakin 2018-03-13 23:23:12 +01:00 committed by Nikolay Volf
parent 9fa933ccd6
commit 6253dd6fdf
4 changed files with 137 additions and 135 deletions

View File

@ -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")
} }

View File

@ -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};

View File

@ -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();

View File

@ -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) => {