diff --git a/src/host.rs b/src/host.rs index a15fd9d..65393e8 100644 --- a/src/host.rs +++ b/src/host.rs @@ -1,8 +1,11 @@ use std::any::TypeId; -use value::{RuntimeValue, TryInto}; +use value::{RuntimeValue, FromRuntimeValue}; 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)] 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> { /// Extract argument by index `idx`. /// /// # Errors /// /// Returns `Err` if cast is invalid or not enough arguments. - pub fn nth_checked(&self, idx: usize) -> Result where RuntimeValue: TryInto { - Ok(self.nth_value_checked(idx)?.try_into().map_err(|_| TrapKind::UnexpectedSignature)?) + pub fn nth_checked(&self, idx: usize) -> Result where T: FromRuntimeValue { + Ok(self.nth_value_checked(idx)?.try_into().ok_or_else(|| TrapKind::UnexpectedSignature)?) } /// Extract argument as a [`RuntimeValue`] by index `idx`. @@ -27,6 +36,8 @@ impl<'a> RuntimeArgs<'a> { /// # Errors /// /// Returns `Err` if this list has not enough arguments. + /// + /// [`RuntimeValue`]: enum.RuntimeValue.html pub fn nth_value_checked(&self, idx: usize) -> Result { if self.0.len() <= idx { return Err(TrapKind::UnexpectedSignature.into()); @@ -39,7 +50,7 @@ impl<'a> RuntimeArgs<'a> { /// # Panics /// /// Panics if cast is invalid or not enough arguments. - pub fn nth(&self, idx: usize) -> T where RuntimeValue: TryInto { + pub fn nth(&self, idx: usize) -> T where T: FromRuntimeValue { let value = self.nth_value_checked(idx).expect("Invalid argument index"); value.try_into().expect("Unexpected argument type") } diff --git a/src/lib.rs b/src/lib.rs index 0229243..697cec4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -364,7 +364,7 @@ mod tests; pub use self::memory::{MemoryInstance, MemoryRef, LINEAR_MEMORY_PAGE_SIZE}; 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::imports::{ModuleImportResolver, ImportResolver, ImportsBuilder}; pub use self::module::{ModuleInstance, ModuleRef, ExternVal, NotStartedModuleRef}; diff --git a/src/runner.rs b/src/runner.rs index 3e069a5..15ec910 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -1,7 +1,7 @@ use std::mem; use std::ops; use std::{u32, usize}; -use std::fmt::{self, Display}; +use std::fmt; use std::iter::repeat; use std::collections::{HashMap, VecDeque}; use parity_wasm::elements::{Opcode, BlockType, Local}; @@ -9,7 +9,7 @@ use {Error, Trap, TrapKind, Signature}; use module::ModuleRef; use func::{FuncRef, FuncInstance, FuncInstanceInternal}; use value::{ - RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto, + RuntimeValue, FromRuntimeValue, WrapInto, TryTruncateInto, ExtendInto, ArithmeticOps, Integer, Float, LittleEndianConvert, TransmuteInto, }; use host::Externals; @@ -589,7 +589,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_store(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result - where RuntimeValue: TryInto, T: LittleEndianConvert { + where T: FromRuntimeValue, T: LittleEndianConvert { let stack_value = context .value_stack_mut() .pop_as::() @@ -618,7 +618,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { offset: u32, ) -> Result where - RuntimeValue: TryInto, + T: FromRuntimeValue, T: WrapInto, U: LittleEndianConvert, { @@ -682,7 +682,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { fn run_relop(&mut self, context: &mut FunctionContext, f: F) -> Result where - RuntimeValue: TryInto, + T: FromRuntimeValue, F: FnOnce(T, T) -> bool, { let (left, right) = context @@ -699,7 +699,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_eqz(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: TryInto, T: PartialEq + Default { + where T: FromRuntimeValue, T: PartialEq + Default { let v = context .value_stack_mut() .pop_as::(); @@ -709,40 +709,41 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_eq(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: TryInto, T: PartialEq + where T: FromRuntimeValue + PartialEq { - self.run_relop(context, |left, right| left == right) + self.run_relop(context, |left: T, right: T| left == right) } fn run_ne(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: TryInto, T: PartialEq { - self.run_relop(context, |left, right| left != right) + where T: FromRuntimeValue + PartialEq { + self.run_relop(context, |left: T, right: T| left != right) } fn run_lt(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: TryInto, T: PartialOrd + Display { - self.run_relop(context, |left, right| left < right) + where T: FromRuntimeValue + PartialOrd { + self.run_relop(context, |left: T, right: T| left < right) } fn run_gt(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: TryInto, T: PartialOrd { - self.run_relop(context, |left, right| left > right) + where T: FromRuntimeValue + PartialOrd { + self.run_relop(context, |left: T, right: T| left > right) } fn run_lte(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: TryInto, T: PartialOrd { - self.run_relop(context, |left, right| left <= right) + where T: FromRuntimeValue + PartialOrd { + self.run_relop(context, |left: T, right: T| left <= right) } fn run_gte(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: TryInto, T: PartialOrd { - self.run_relop(context, |left, right| left >= right) + where T: FromRuntimeValue + PartialOrd { + self.run_relop(context, |left: T, right: T| left >= right) } fn run_unop(&mut self, context: &mut FunctionContext, f: F) -> Result where F: FnOnce(T) -> U, - RuntimeValue: From + TryInto + T: FromRuntimeValue, + RuntimeValue: From { let v = context .value_stack_mut() @@ -753,22 +754,22 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_clz(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: Integer { - self.run_unop(context, |v| v.leading_zeros()) + where RuntimeValue: From, T: Integer + FromRuntimeValue { + self.run_unop(context, |v: T| v.leading_zeros()) } fn run_ctz(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: Integer { - self.run_unop(context, |v| v.trailing_zeros()) + where RuntimeValue: From, T: Integer + FromRuntimeValue { + self.run_unop(context, |v: T| v.trailing_zeros()) } fn run_popcnt(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: Integer { - self.run_unop(context, |v| v.count_ones()) + where RuntimeValue: From, T: Integer + FromRuntimeValue { + self.run_unop(context, |v: T| v.count_ones()) } fn run_add(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: ArithmeticOps { + where RuntimeValue: From, T: ArithmeticOps + FromRuntimeValue { let (left, right) = context .value_stack_mut() .pop_pair_as::() @@ -779,7 +780,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_sub(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: ArithmeticOps { + where RuntimeValue: From, T: ArithmeticOps + FromRuntimeValue { let (left, right) = context .value_stack_mut() .pop_pair_as::() @@ -790,7 +791,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_mul(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: ArithmeticOps { + where RuntimeValue: From, T: ArithmeticOps + FromRuntimeValue { let (left, right) = context .value_stack_mut() .pop_pair_as::() @@ -801,7 +802,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_div(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: TransmuteInto + Display, U: ArithmeticOps + TransmuteInto { + where RuntimeValue: From, T: TransmuteInto + FromRuntimeValue, U: ArithmeticOps + TransmuteInto { let (left, right) = context .value_stack_mut() .pop_pair_as::() @@ -814,7 +815,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_rem(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: TransmuteInto, U: Integer + TransmuteInto { + where RuntimeValue: From, T: TransmuteInto + FromRuntimeValue, U: Integer + TransmuteInto { let (left, right) = context .value_stack_mut() .pop_pair_as::() @@ -827,7 +828,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_and(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From<::Output> + TryInto, T: ops::BitAnd { + where RuntimeValue: From<::Output>, T: ops::BitAnd + FromRuntimeValue { let (left, right) = context .value_stack_mut() .pop_pair_as::() @@ -838,7 +839,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_or(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From<::Output> + TryInto, T: ops::BitOr { + where RuntimeValue: From<::Output>, T: ops::BitOr + FromRuntimeValue { let (left, right) = context .value_stack_mut() .pop_pair_as::() @@ -849,7 +850,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_xor(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From<::Output> + TryInto, T: ops::BitXor { + where RuntimeValue: From<::Output>, T: ops::BitXor + FromRuntimeValue { let (left, right) = context .value_stack_mut() .pop_pair_as::() @@ -860,7 +861,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_shl(&mut self, context: &mut FunctionContext, mask: T) -> Result - where RuntimeValue: From<>::Output> + TryInto, T: ops::Shl + ops::BitAnd { + where RuntimeValue: From<>::Output>, T: ops::Shl + ops::BitAnd + FromRuntimeValue { let (left, right) = context .value_stack_mut() .pop_pair_as::() @@ -871,7 +872,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_shr(&mut self, context: &mut FunctionContext, mask: U) -> Result - where RuntimeValue: From + TryInto, T: TransmuteInto, U: ops::Shr + ops::BitAnd, >::Output: TransmuteInto { + where RuntimeValue: From, T: TransmuteInto + FromRuntimeValue, U: ops::Shr + ops::BitAnd, >::Output: TransmuteInto { let (left, right) = context .value_stack_mut() .pop_pair_as::() @@ -884,7 +885,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_rotl(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: Integer { + where RuntimeValue: From, T: Integer + FromRuntimeValue { let (left, right) = context .value_stack_mut() .pop_pair_as::() @@ -895,7 +896,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_rotr(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: Integer + where RuntimeValue: From, T: Integer + FromRuntimeValue { let (left, right) = context .value_stack_mut() @@ -907,51 +908,51 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_abs(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: Float + where RuntimeValue: From, T: Float + FromRuntimeValue { - self.run_unop(context, |v| v.abs()) + self.run_unop(context, |v: T| v.abs()) } fn run_neg(&mut self, context: &mut FunctionContext) -> Result where - RuntimeValue: From<::Output> + TryInto, - T: ops::Neg + RuntimeValue: From<::Output>, + T: ops::Neg + FromRuntimeValue { - self.run_unop(context, |v| v.neg()) + self.run_unop(context, |v: T| v.neg()) } fn run_ceil(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: Float + where RuntimeValue: From, T: Float + FromRuntimeValue { - self.run_unop(context, |v| v.ceil()) + self.run_unop(context, |v: T| v.ceil()) } fn run_floor(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: Float + where RuntimeValue: From, T: Float + FromRuntimeValue { - self.run_unop(context, |v| v.floor()) + self.run_unop(context, |v: T| v.floor()) } fn run_trunc(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: Float + where RuntimeValue: From, T: Float + FromRuntimeValue { - self.run_unop(context, |v| v.trunc()) + self.run_unop(context, |v: T| v.trunc()) } fn run_nearest(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: Float + where RuntimeValue: From, T: Float + FromRuntimeValue { - self.run_unop(context, |v| v.nearest()) + self.run_unop(context, |v: T| v.nearest()) } fn run_sqrt(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: Float + where RuntimeValue: From, T: Float + FromRuntimeValue { - self.run_unop(context, |v| v.sqrt()) + self.run_unop(context, |v: T| v.sqrt()) } fn run_min(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: Float + where RuntimeValue: From, T: Float + FromRuntimeValue { let (left, right) = context .value_stack_mut() @@ -963,7 +964,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_max(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: Float { + where RuntimeValue: From, T: Float + FromRuntimeValue { let (left, right) = context .value_stack_mut() .pop_pair_as::() @@ -974,7 +975,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_copysign(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: Float { + where RuntimeValue: From, T: Float + FromRuntimeValue { let (left, right) = context .value_stack_mut() .pop_pair_as::() @@ -985,12 +986,12 @@ impl<'a, E: Externals> Interpreter<'a, E> { } fn run_wrap(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: WrapInto { - self.run_unop(context, |v| v.wrap_into()) + where RuntimeValue: From, T: WrapInto + FromRuntimeValue { + self.run_unop(context, |v: T| v.wrap_into()) } fn run_trunc_to_int(&mut self, context: &mut FunctionContext) -> Result - where RuntimeValue: From + TryInto, T: TryTruncateInto, U: TransmuteInto, { + where RuntimeValue: From, T: TryTruncateInto + FromRuntimeValue, U: TransmuteInto, { let v = context .value_stack_mut() .pop_as::(); @@ -1003,7 +1004,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { fn run_extend(&mut self, context: &mut FunctionContext) -> Result where - RuntimeValue: From + TryInto, T: ExtendInto, U: TransmuteInto + RuntimeValue: From, T: ExtendInto + FromRuntimeValue, U: TransmuteInto { let v = context .value_stack_mut() @@ -1017,7 +1018,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { fn run_reinterpret(&mut self, context: &mut FunctionContext) -> Result where - RuntimeValue: From, RuntimeValue: TryInto, T: TransmuteInto + RuntimeValue: From, T: FromRuntimeValue, T: TransmuteInto { let v = context .value_stack_mut() @@ -1255,17 +1256,17 @@ impl ValueStack { fn pop_as(&mut self) -> T where - RuntimeValue: TryInto, + T: FromRuntimeValue, { let value = self.stack_with_limit .pop() .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(&mut self) -> Result<(T, T), Error> where - RuntimeValue: TryInto, + T: FromRuntimeValue, { let right = self.pop_as(); let left = self.pop_as(); diff --git a/src/value.rs b/src/value.rs index e5b8760..892e4df 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,14 +1,10 @@ use std::{i32, i64, u32, u64, f32}; use std::io; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use parity_wasm::elements::ValueType; use TrapKind; #[derive(Debug)] pub enum Error { - UnexpectedType { - expected: ValueType, - }, InvalidLittleEndianBuffer, } @@ -31,10 +27,23 @@ pub enum RuntimeValue { F64(f64), } -/// Try to convert into trait. -pub trait TryInto { - /// Try to convert self into other value. - fn try_into(self) -> Result; +/// Trait for creating value from a [`RuntimeValue`]. +/// +/// Typically each implementation can create a value from the specific type. +/// 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; } /// Convert one type to another by wrapping. @@ -151,6 +160,17 @@ impl RuntimeValue { 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(self) -> Option { + FromRuntimeValue::from_runtime_value(self) + } } impl From for RuntimeValue { @@ -189,68 +209,38 @@ impl From for RuntimeValue { } } -impl TryInto for RuntimeValue { - fn try_into(self) -> Result { - match self { - RuntimeValue::I32(val) => Ok(val != 0), - _ => Err(Error::UnexpectedType { expected: ValueType::I32 }), +macro_rules! impl_from_runtime_value { + ($expected_rt_ty: ident, $into: ty) => { + impl FromRuntimeValue for $into { + fn from_runtime_value(val: RuntimeValue) -> Option { + 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 { + match val { + RuntimeValue::I32(val) => Some(val != 0), + _ => None, } } } -impl TryInto for RuntimeValue { - fn try_into(self) -> Result { - match self { - RuntimeValue::I32(val) => Ok(val), - _ => Err(Error::UnexpectedType { expected: ValueType::I32 }), - } - } -} - -impl TryInto for RuntimeValue { - fn try_into(self) -> Result { - match self { - RuntimeValue::I64(val) => Ok(val), - _ => Err(Error::UnexpectedType { expected: ValueType::I64 }), - } - } -} - -impl TryInto for RuntimeValue { - fn try_into(self) -> Result { - match self { - RuntimeValue::F32(val) => Ok(val), - _ => Err(Error::UnexpectedType { expected: ValueType::F32 }), - } - } -} - -impl TryInto for RuntimeValue { - fn try_into(self) -> Result { - match self { - RuntimeValue::F64(val) => Ok(val), - _ => Err(Error::UnexpectedType { expected: ValueType::F64 }), - } - } -} - -impl TryInto for RuntimeValue { - fn try_into(self) -> Result { - match self { - RuntimeValue::I32(val) => Ok(val as u32), - _ => Err(Error::UnexpectedType { expected: ValueType::I32 }), - } - } -} - -impl TryInto for RuntimeValue { - fn try_into(self) -> Result { - match self { - RuntimeValue::I64(val) => Ok(val as u64), - _ => Err(Error::UnexpectedType { expected: ValueType::I64 }), - } - } -} +impl_from_runtime_value!(I32, i32); +impl_from_runtime_value!(I64, i64); +impl_from_runtime_value!(F32, f32); +impl_from_runtime_value!(F64, f64); +impl_from_runtime_value!(I32, u32); +impl_from_runtime_value!(I64, u64); macro_rules! impl_wrap_into { ($from: ident, $into: ident) => {