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 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<T>(&self, idx: usize) -> Result<T, Trap> where RuntimeValue: TryInto<T, ::value::Error> {
Ok(self.nth_value_checked(idx)?.try_into().map_err(|_| TrapKind::UnexpectedSignature)?)
pub fn nth_checked<T>(&self, idx: usize) -> Result<T, Trap> 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<RuntimeValue, Trap> {
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<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");
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::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};

View File

@ -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<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
.value_stack_mut()
.pop_as::<T>()
@ -618,7 +618,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
offset: u32,
) -> Result<InstructionOutcome, TrapKind>
where
RuntimeValue: TryInto<T, ::value::Error>,
T: FromRuntimeValue,
T: WrapInto<U>,
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>
where
RuntimeValue: TryInto<T, ::value::Error>,
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<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
.value_stack_mut()
.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>
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>
where RuntimeValue: TryInto<T, ::value::Error>, T: PartialEq<T> {
self.run_relop(context, |left, right| left != right)
where T: FromRuntimeValue + PartialEq<T> {
self.run_relop(context, |left: T, right: T| left != right)
}
fn run_lt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: TryInto<T, ::value::Error>, T: PartialOrd<T> + Display {
self.run_relop(context, |left, right| left < right)
where T: FromRuntimeValue + PartialOrd<T> {
self.run_relop(context, |left: T, right: T| left < right)
}
fn run_gt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: TryInto<T, ::value::Error>, T: PartialOrd<T> {
self.run_relop(context, |left, right| left > right)
where T: FromRuntimeValue + PartialOrd<T> {
self.run_relop(context, |left: T, right: T| left > right)
}
fn run_lte<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: TryInto<T, ::value::Error>, T: PartialOrd<T> {
self.run_relop(context, |left, right| left <= right)
where T: FromRuntimeValue + PartialOrd<T> {
self.run_relop(context, |left: T, right: T| left <= right)
}
fn run_gte<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: TryInto<T, ::value::Error>, T: PartialOrd<T> {
self.run_relop(context, |left, right| left >= right)
where T: FromRuntimeValue + PartialOrd<T> {
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>
where
F: FnOnce(T) -> U,
RuntimeValue: From<U> + TryInto<T, ::value::Error>
T: FromRuntimeValue,
RuntimeValue: From<U>
{
let v = context
.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>
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Integer<T> {
self.run_unop(context, |v| v.leading_zeros())
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue {
self.run_unop(context, |v: T| v.leading_zeros())
}
fn run_ctz<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Integer<T> {
self.run_unop(context, |v| v.trailing_zeros())
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue {
self.run_unop(context, |v: T| v.trailing_zeros())
}
fn run_popcnt<T>(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind>
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Integer<T> {
self.run_unop(context, |v| v.count_ones())
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue {
self.run_unop(context, |v: T| v.count_ones())
}
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
.value_stack_mut()
.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>
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: ArithmeticOps<T> {
where RuntimeValue: From<T>, T: ArithmeticOps<T> + FromRuntimeValue {
let (left, right) = context
.value_stack_mut()
.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>
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: ArithmeticOps<T> {
where RuntimeValue: From<T>, T: ArithmeticOps<T> + FromRuntimeValue {
let (left, right) = context
.value_stack_mut()
.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>
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
.value_stack_mut()
.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>
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
.value_stack_mut()
.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>
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
.value_stack_mut()
.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>
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
.value_stack_mut()
.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>
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
.value_stack_mut()
.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>
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
.value_stack_mut()
.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>
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
.value_stack_mut()
.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>
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Integer<T> {
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue {
let (left, right) = context
.value_stack_mut()
.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>
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Integer<T>
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue
{
let (left, right) = context
.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>
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>
where
RuntimeValue: From<<T as ops::Neg>::Output> + TryInto<T, ::value::Error>,
T: ops::Neg
RuntimeValue: From<<T as ops::Neg>::Output>,
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>
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>
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>
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>
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>
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>
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T>
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
{
let (left, right) = context
.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>
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T> {
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue {
let (left, right) = context
.value_stack_mut()
.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>
where RuntimeValue: From<T> + TryInto<T, ::value::Error>, T: Float<T> {
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue {
let (left, right) = context
.value_stack_mut()
.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>
where RuntimeValue: From<U> + TryInto<T, ::value::Error>, T: WrapInto<U> {
self.run_unop(context, |v| v.wrap_into())
where RuntimeValue: From<U>, T: WrapInto<U> + FromRuntimeValue {
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>
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
.value_stack_mut()
.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>
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
.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>
where
RuntimeValue: From<U>, RuntimeValue: TryInto<T, ::value::Error>, T: TransmuteInto<U>
RuntimeValue: From<U>, T: FromRuntimeValue, T: TransmuteInto<U>
{
let v = context
.value_stack_mut()
@ -1255,17 +1256,17 @@ impl ValueStack {
fn pop_as<T>(&mut self) -> T
where
RuntimeValue: TryInto<T, ::value::Error>,
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<T>(&mut self) -> Result<(T, T), Error>
where
RuntimeValue: TryInto<T, ::value::Error>,
T: FromRuntimeValue,
{
let right = self.pop_as();
let left = self.pop_as();

View File

@ -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<T, E> {
/// Try to convert self into other value.
fn try_into(self) -> Result<T, E>;
/// 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<Self>;
}
/// 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<T: FromRuntimeValue>(self) -> Option<T> {
FromRuntimeValue::from_runtime_value(self)
}
}
impl From<i32> for RuntimeValue {
@ -189,68 +209,38 @@ impl From<f64> for RuntimeValue {
}
}
impl TryInto<bool, Error> for RuntimeValue {
fn try_into(self) -> Result<bool, Error> {
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<Self> {
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 {
fn try_into(self) -> Result<i32, Error> {
match self {
RuntimeValue::I32(val) => Ok(val),
_ => Err(Error::UnexpectedType { expected: ValueType::I32 }),
}
}
}
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 }),
}
}
}
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) => {