Add explanation of `RuntimeValueInternal`, move it so I don't need to do `pub(crate)`

This commit is contained in:
Jef 2018-10-29 11:37:55 +01:00
parent 68e447ce28
commit 24d69b5bd6
2 changed files with 355 additions and 257 deletions

View File

@ -1,24 +1,22 @@
#[allow(unused_imports)]
use alloc::prelude::*;
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
use core::fmt;
use core::ops;
use core::{u32, usize};
use core::fmt;
use core::iter::repeat;
use parity_wasm::elements::Local;
use {Trap, TrapKind, Signature};
use module::ModuleRef;
use memory::MemoryRef;
use func::{FuncRef, FuncInstance, FuncInstanceInternal};
use value::{
ArithmeticOps, ExtendInto, Float, FromRuntimeValueInternal, Integer, LittleEndianConvert,
RuntimeValue, RuntimeValueInternal, TransmuteInto, TryTruncateInto, WrapInto,
};
use func::{FuncInstance, FuncInstanceInternal, FuncRef};
use host::Externals;
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
use types::ValueType;
use memory_units::Pages;
use nan_preserving_float::{F32, F64};
use isa;
use memory::MemoryRef;
use memory_units::Pages;
use module::ModuleRef;
use nan_preserving_float::{F32, F64};
use parity_wasm::elements::Local;
use value::{
ArithmeticOps, ExtendInto, Float, Integer, LittleEndianConvert, RuntimeValue, TransmuteInto,
TryTruncateInto, WrapInto,
};
use {Signature, Trap, TrapKind, ValueType};
/// Maximum number of entries in value stack.
pub const DEFAULT_VALUE_STACK_LIMIT: usize = (1024 * 1024) / ::core::mem::size_of::<RuntimeValue>();
@ -26,6 +24,104 @@ pub const DEFAULT_VALUE_STACK_LIMIT: usize = (1024 * 1024) / ::core::mem::size_o
// TODO: Make these parameters changeble.
pub const DEFAULT_CALL_STACK_LIMIT: usize = 64 * 1024;
/// This is a wrapper around u64 to allow us to treat runtime values as a tag-free `u64`
/// (where if the runtime value is <64 bits the upper bits are 0). This is safe, since
/// all of the possible runtime values are valid to create from 64 defined bits, so if
/// types don't line up we get a logic error (which will ideally be caught by the wasm
/// spec tests) and not undefined behaviour.
///
/// At the boundary between the interpreter and the outside world we convert to the public
/// `RuntimeValue` type, which can then be matched on. We can create a `RuntimeValue` from
/// a `RuntimeValueInternal` only when the type is statically known, which it always is
/// at these boundaries.
#[derive(Copy, Clone, Debug, PartialEq, Default)]
#[repr(transparent)]
struct RuntimeValueInternal(pub u64);
impl RuntimeValueInternal {
pub fn with_type(self, ty: ValueType) -> RuntimeValue {
match ty {
ValueType::I32 => RuntimeValue::I32(<_>::from_runtime_value_internal(self)),
ValueType::I64 => RuntimeValue::I64(<_>::from_runtime_value_internal(self)),
ValueType::F32 => RuntimeValue::F32(<_>::from_runtime_value_internal(self)),
ValueType::F64 => RuntimeValue::F64(<_>::from_runtime_value_internal(self)),
}
}
}
trait FromRuntimeValueInternal
where
Self: Sized,
{
fn from_runtime_value_internal(val: RuntimeValueInternal) -> Self;
}
macro_rules! impl_from_runtime_value_internal {
($($t:ty),*) => {
$(
impl FromRuntimeValueInternal for $t {
fn from_runtime_value_internal(
RuntimeValueInternal(val): RuntimeValueInternal,
) -> Self {
val as _
}
}
impl From<$t> for RuntimeValueInternal {
fn from(other: $t) -> Self {
RuntimeValueInternal(other as _)
}
}
)*
};
}
macro_rules! impl_from_runtime_value_internal_float {
($($t:ty),*) => {
$(
impl FromRuntimeValueInternal for $t {
fn from_runtime_value_internal(
RuntimeValueInternal(val): RuntimeValueInternal,
) -> Self {
<$t>::from_bits(val as _)
}
}
impl From<$t> for RuntimeValueInternal {
fn from(other: $t) -> Self {
RuntimeValueInternal(other.to_bits() as _)
}
}
)*
};
}
impl_from_runtime_value_internal!(i8, u8, i16, u16, i32, u32, i64, u64);
impl_from_runtime_value_internal_float!(f32, f64, F32, F64);
impl From<bool> for RuntimeValueInternal {
fn from(other: bool) -> Self {
(if other { 1 } else { 0 }).into()
}
}
impl FromRuntimeValueInternal for bool {
fn from_runtime_value_internal(RuntimeValueInternal(val): RuntimeValueInternal) -> Self {
val != 0
}
}
impl From<RuntimeValue> for RuntimeValueInternal {
fn from(other: RuntimeValue) -> Self {
match other {
RuntimeValue::I32(val) => val.into(),
RuntimeValue::I64(val) => val.into(),
RuntimeValue::F32(val) => val.into(),
RuntimeValue::F64(val) => val.into(),
}
}
}
/// Interpreter action to execute after executing instruction.
pub enum InstructionOutcome {
/// Continue with next instruction.
@ -105,7 +201,10 @@ impl Interpreter {
&self.state
}
pub fn start_execution<'a, E: Externals + 'a>(&mut self, externals: &'a mut E) -> Result<Option<RuntimeValue>, Trap> {
pub fn start_execution<'a, E: Externals + 'a>(
&mut self,
externals: &'a mut E,
) -> Result<Option<RuntimeValue>, Trap> {
// Ensure that the VM has not been executed. This is checked in `FuncInvocation::start_execution`.
assert!(self.state == InterpreterState::Initialized);
@ -122,7 +221,11 @@ impl Interpreter {
Ok(opt_return_value)
}
pub fn resume_execution<'a, E: Externals + 'a>(&mut self, return_val: Option<RuntimeValue>, externals: &'a mut E) -> Result<Option<RuntimeValue>, Trap> {
pub fn resume_execution<'a, E: Externals + 'a>(
&mut self,
return_val: Option<RuntimeValue>,
externals: &'a mut E,
) -> Result<Option<RuntimeValue>, Trap> {
use core::mem::swap;
// Ensure that the VM is resumable. This is checked in `FuncInvocation::resume_execution`.
@ -149,11 +252,14 @@ impl Interpreter {
Ok(opt_return_value)
}
fn run_interpreter_loop<'a, E: Externals + 'a>(&mut self, externals: &'a mut E) -> Result<(), Trap> {
fn run_interpreter_loop<'a, E: Externals + 'a>(
&mut self,
externals: &'a mut E,
) -> Result<(), Trap> {
loop {
let mut function_context = self.call_stack
.pop()
.expect("on loop entry - not empty; on loop continue - checking for emptiness; qed");
let mut function_context = self.call_stack.pop().expect(
"on loop entry - not empty; on loop continue - checking for emptiness; qed",
);
let function_ref = function_context.function.clone();
let function_body = function_ref
.body()
@ -166,11 +272,9 @@ impl Interpreter {
function_context.initialize(&function_body.locals, &mut self.value_stack)?;
}
let function_return =
self.do_run_function(
&mut function_context,
&function_body.code,
).map_err(Trap::new)?;
let function_return = self
.do_run_function(&mut function_context, &function_body.code)
.map_err(Trap::new)?;
match function_return {
RunResult::Return => {
@ -179,7 +283,7 @@ impl Interpreter {
// are done executing.
return Ok(());
}
},
}
RunResult::NestedCall(nested_func) => {
if self.call_stack.len() + 1 >= DEFAULT_CALL_STACK_LIMIT {
return Err(TrapKind::StackOverflow.into());
@ -190,21 +294,24 @@ impl Interpreter {
let nested_context = FunctionContext::new(nested_func.clone());
self.call_stack.push(function_context);
self.call_stack.push(nested_context);
},
}
FuncInstanceInternal::Host { ref signature, .. } => {
let args = prepare_function_args(signature, &mut self.value_stack);
// We push the function context first. If the VM is not resumable, it does no harm. If it is, we then save the context here.
self.call_stack.push(function_context);
let return_val = match FuncInstance::invoke(&nested_func, &args, externals) {
Ok(val) => val,
Err(trap) => {
if trap.kind().is_host() {
self.state = InterpreterState::Resumable(nested_func.signature().return_type());
let return_val =
match FuncInstance::invoke(&nested_func, &args, externals) {
Ok(val) => val,
Err(trap) => {
if trap.kind().is_host() {
self.state = InterpreterState::Resumable(
nested_func.signature().return_type(),
);
}
return Err(trap);
}
return Err(trap);
},
};
};
// Check if `return_val` matches the signature.
let value_ty = return_val.as_ref().map(|val| val.value_type());
@ -220,32 +327,34 @@ impl Interpreter {
}
}
}
},
}
}
}
}
fn do_run_function(&mut self, function_context: &mut FunctionContext, instructions: &isa::Instructions)
-> Result<RunResult, TrapKind>
{
fn do_run_function(
&mut self,
function_context: &mut FunctionContext,
instructions: &isa::Instructions,
) -> Result<RunResult, TrapKind> {
let mut iter = instructions.iterate_from(function_context.position);
loop {
let instruction = iter.next().expect("instruction");
match self.run_instruction(function_context, instruction)? {
InstructionOutcome::RunNextInstruction => {},
InstructionOutcome::RunNextInstruction => {}
InstructionOutcome::Branch(target) => {
iter = instructions.iterate_from(target.dst_pc);
self.value_stack.drop_keep(target.drop_keep);
},
}
InstructionOutcome::ExecuteCall(func_ref) => {
function_context.position = iter.position();
return Ok(RunResult::NestedCall(func_ref));
},
}
InstructionOutcome::Return(drop_keep) => {
self.value_stack.drop_keep(drop_keep);
break;
},
}
}
}
@ -253,7 +362,11 @@ impl Interpreter {
}
#[inline(always)]
fn run_instruction(&mut self, context: &mut FunctionContext, instruction: &isa::Instruction) -> Result<InstructionOutcome, TrapKind> {
fn run_instruction(
&mut self,
context: &mut FunctionContext,
instruction: &isa::Instruction,
) -> Result<InstructionOutcome, TrapKind> {
match instruction {
&isa::Instruction::Unreachable => self.run_unreachable(context),
@ -279,26 +392,52 @@ impl Interpreter {
&isa::Instruction::I64Load(offset) => self.run_load::<i64>(context, offset),
&isa::Instruction::F32Load(offset) => self.run_load::<F32>(context, offset),
&isa::Instruction::F64Load(offset) => self.run_load::<F64>(context, offset),
&isa::Instruction::I32Load8S(offset) => self.run_load_extend::<i8, i32>(context, offset),
&isa::Instruction::I32Load8U(offset) => self.run_load_extend::<u8, i32>(context, offset),
&isa::Instruction::I32Load16S(offset) => self.run_load_extend::<i16, i32>(context, offset),
&isa::Instruction::I32Load16U(offset) => self.run_load_extend::<u16, i32>(context, offset),
&isa::Instruction::I64Load8S(offset) => self.run_load_extend::<i8, i64>(context, offset),
&isa::Instruction::I64Load8U(offset) => self.run_load_extend::<u8, i64>(context, offset),
&isa::Instruction::I64Load16S(offset) => self.run_load_extend::<i16, i64>(context, offset),
&isa::Instruction::I64Load16U(offset) => self.run_load_extend::<u16, i64>(context, offset),
&isa::Instruction::I64Load32S(offset) => self.run_load_extend::<i32, i64>(context, offset),
&isa::Instruction::I64Load32U(offset) => self.run_load_extend::<u32, i64>(context, offset),
&isa::Instruction::I32Load8S(offset) => {
self.run_load_extend::<i8, i32>(context, offset)
}
&isa::Instruction::I32Load8U(offset) => {
self.run_load_extend::<u8, i32>(context, offset)
}
&isa::Instruction::I32Load16S(offset) => {
self.run_load_extend::<i16, i32>(context, offset)
}
&isa::Instruction::I32Load16U(offset) => {
self.run_load_extend::<u16, i32>(context, offset)
}
&isa::Instruction::I64Load8S(offset) => {
self.run_load_extend::<i8, i64>(context, offset)
}
&isa::Instruction::I64Load8U(offset) => {
self.run_load_extend::<u8, i64>(context, offset)
}
&isa::Instruction::I64Load16S(offset) => {
self.run_load_extend::<i16, i64>(context, offset)
}
&isa::Instruction::I64Load16U(offset) => {
self.run_load_extend::<u16, i64>(context, offset)
}
&isa::Instruction::I64Load32S(offset) => {
self.run_load_extend::<i32, i64>(context, offset)
}
&isa::Instruction::I64Load32U(offset) => {
self.run_load_extend::<u32, i64>(context, offset)
}
&isa::Instruction::I32Store(offset) => self.run_store::<i32>(context, offset),
&isa::Instruction::I64Store(offset) => self.run_store::<i64>(context, offset),
&isa::Instruction::F32Store(offset) => self.run_store::<F32>(context, offset),
&isa::Instruction::F64Store(offset) => self.run_store::<F64>(context, offset),
&isa::Instruction::I32Store8(offset) => self.run_store_wrap::<i32, i8>(context, offset),
&isa::Instruction::I32Store16(offset) => self.run_store_wrap::<i32, i16>(context, offset),
&isa::Instruction::I32Store16(offset) => {
self.run_store_wrap::<i32, i16>(context, offset)
}
&isa::Instruction::I64Store8(offset) => self.run_store_wrap::<i64, i8>(context, offset),
&isa::Instruction::I64Store16(offset) => self.run_store_wrap::<i64, i16>(context, offset),
&isa::Instruction::I64Store32(offset) => self.run_store_wrap::<i64, i32>(context, offset),
&isa::Instruction::I64Store16(offset) => {
self.run_store_wrap::<i64, i16>(context, offset)
}
&isa::Instruction::I64Store32(offset) => {
self.run_store_wrap::<i64, i32>(context, offset)
}
&isa::Instruction::CurrentMemory => self.run_current_memory(context),
&isa::Instruction::GrowMemory => self.run_grow_memory(context),
@ -443,11 +582,18 @@ impl Interpreter {
}
}
fn run_unreachable(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
fn run_unreachable(
&mut self,
_context: &mut FunctionContext,
) -> Result<InstructionOutcome, TrapKind> {
Err(TrapKind::Unreachable)
}
fn run_br(&mut self, _context: &mut FunctionContext, target: isa::Target) -> Result<InstructionOutcome, TrapKind> {
fn run_br(
&mut self,
_context: &mut FunctionContext,
target: isa::Target,
) -> Result<InstructionOutcome, TrapKind> {
Ok(InstructionOutcome::Branch(target))
}
@ -465,7 +611,6 @@ impl Interpreter {
if condition {
Ok(InstructionOutcome::RunNextInstruction)
} else {
Ok(InstructionOutcome::Branch(target))
}
}
@ -510,7 +655,8 @@ impl Interpreter {
.module()
.table_by_index(DEFAULT_TABLE_INDEX)
.expect("Due to validation table should exists");
let func_ref = table.get(table_func_idx)
let func_ref = table
.get(table_func_idx)
.map_err(|_| TrapKind::TableAccessOutOfBounds)?
.ok_or_else(|| TrapKind::ElemUninitialized)?;
@ -535,9 +681,7 @@ impl Interpreter {
}
fn run_select(&mut self) -> Result<InstructionOutcome, TrapKind> {
let (left, mid, right) = self
.value_stack
.pop_triple();
let (left, mid, right) = self.value_stack.pop_triple();
let condition = <_>::from_runtime_value_internal(right);
let val = if condition { left } else { mid };
@ -552,18 +696,13 @@ impl Interpreter {
}
fn run_set_local(&mut self, index: u32) -> Result<InstructionOutcome, TrapKind> {
let val = self
.value_stack
.pop();
let val = self.value_stack.pop();
*self.value_stack.pick_mut(index as usize) = val;
Ok(InstructionOutcome::RunNextInstruction)
}
fn run_tee_local(&mut self, index: u32) -> Result<InstructionOutcome, TrapKind> {
let val = self
.value_stack
.top()
.clone();
let val = self.value_stack.top().clone();
*self.value_stack.pick_mut(index as usize) = val;
Ok(InstructionOutcome::RunNextInstruction)
}
@ -587,9 +726,7 @@ impl Interpreter {
context: &mut FunctionContext,
index: u32,
) -> Result<InstructionOutcome, TrapKind> {
let val = self
.value_stack
.pop();
let val = self.value_stack.pop();
let global = context
.module()
.global_by_index(index)
@ -614,7 +751,8 @@ impl Interpreter {
let m = context
.memory()
.expect("Due to validation memory should exists");
let n: T = m.get_value(address)
let n: T = m
.get_value(address)
.map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
self.value_stack.push(n.into())?;
Ok(InstructionOutcome::RunNextInstruction)
@ -635,11 +773,11 @@ impl Interpreter {
let m = context
.memory()
.expect("Due to validation memory should exists");
let v: T = m.get_value(address)
let v: T = m
.get_value(address)
.map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
let stack_value: U = v.extend_into();
self
.value_stack
self.value_stack
.push(stack_value.into())
.map_err(Into::into)
.map(|_| InstructionOutcome::RunNextInstruction)
@ -678,14 +816,8 @@ impl Interpreter {
{
let stack_value: T = <_>::from_runtime_value_internal(self.value_stack.pop());
let stack_value = stack_value.wrap_into();
let raw_address = self
.value_stack
.pop_as::<u32>();
let address =
effective_address(
offset,
raw_address,
)?;
let raw_address = self.value_stack.pop_as::<u32>();
let address = effective_address(offset, raw_address)?;
let m = context
.memory()
.expect("Due to validation memory should exists");
@ -694,7 +826,10 @@ impl Interpreter {
Ok(InstructionOutcome::RunNextInstruction)
}
fn run_current_memory(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
fn run_current_memory(
&mut self,
context: &mut FunctionContext,
) -> Result<InstructionOutcome, TrapKind> {
let m = context
.memory()
.expect("Due to validation memory should exists");
@ -703,10 +838,11 @@ impl Interpreter {
Ok(InstructionOutcome::RunNextInstruction)
}
fn run_grow_memory(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
let pages: u32 = self
.value_stack
.pop_as();
fn run_grow_memory(
&mut self,
context: &mut FunctionContext,
) -> Result<InstructionOutcome, TrapKind> {
let pages: u32 = self.value_stack.pop_as();
let m = context
.memory()
.expect("Due to validation memory should exists");
@ -719,8 +855,7 @@ impl Interpreter {
}
fn run_const(&mut self, val: RuntimeValue) -> Result<InstructionOutcome, TrapKind> {
self
.value_stack
self.value_stack
.push(val.into())
.map_err(Into::into)
.map(|_| InstructionOutcome::RunNextInstruction)
@ -731,9 +866,7 @@ impl Interpreter {
T: FromRuntimeValueInternal,
F: FnOnce(T, T) -> bool,
{
let (left, right) = self
.value_stack
.pop_pair_as::<T>();
let (left, right) = self.value_stack.pop_pair_as::<T>();
let v = if f(left, right) {
RuntimeValueInternal(1)
} else {
@ -802,9 +935,7 @@ impl Interpreter {
T: FromRuntimeValueInternal,
RuntimeValueInternal: From<U>,
{
let v = self
.value_stack
.pop_as::<T>();
let v = self.value_stack.pop_as::<T>();
let v = f(v);
self.value_stack.push(v.into())?;
Ok(InstructionOutcome::RunNextInstruction)
@ -970,9 +1101,7 @@ impl Interpreter {
RuntimeValueInternal: From<T>,
T: Integer<T> + FromRuntimeValueInternal,
{
let (left, right) = self
.value_stack
.pop_pair_as::<T>();
let (left, right) = self.value_stack.pop_pair_as::<T>();
let v = left.rotr(right);
self.value_stack.push(v.into())?;
Ok(InstructionOutcome::RunNextInstruction)
@ -1039,9 +1168,7 @@ impl Interpreter {
RuntimeValueInternal: From<T>,
T: Float<T> + FromRuntimeValueInternal,
{
let (left, right) = self
.value_stack
.pop_pair_as::<T>();
let (left, right) = self.value_stack.pop_pair_as::<T>();
let v = left.min(right);
self.value_stack.push(v.into())?;
Ok(InstructionOutcome::RunNextInstruction)
@ -1152,18 +1279,20 @@ impl FunctionContext {
self.is_initialized
}
pub fn initialize(&mut self, locals: &[Local], value_stack: &mut ValueStack) -> Result<(), TrapKind> {
pub fn initialize(
&mut self,
locals: &[Local],
value_stack: &mut ValueStack,
) -> Result<(), TrapKind> {
debug_assert!(!self.is_initialized);
let num_locals = locals
.iter()
.map(|l| l.count() as usize)
.sum();
let num_locals = locals.iter().map(|l| l.count() as usize).sum();
let locals = vec![Default::default(); num_locals];
// TODO: Replace with extend.
for local in locals {
value_stack.push(local)
value_stack
.push(local)
.map_err(|_| TrapKind::StackOverflow)?;
}
@ -1209,15 +1338,17 @@ fn prepare_function_args(
pub fn check_function_args(signature: &Signature, args: &[RuntimeValue]) -> Result<(), Trap> {
if signature.params().len() != args.len() {
return Err(
TrapKind::UnexpectedSignature.into()
);
return Err(TrapKind::UnexpectedSignature.into());
}
if signature.params().iter().zip(args).any(|(expected_type, param_value)| {
let actual_type = param_value.value_type();
&actual_type != expected_type
}) {
if signature
.params()
.iter()
.zip(args)
.any(|(expected_type, param_value)| {
let actual_type = param_value.value_type();
&actual_type != expected_type
}) {
return Err(TrapKind::UnexpectedSignature.into());
}

View File

@ -1,6 +1,7 @@
use byteorder::{ByteOrder, LittleEndian};
use nan_preserving_float::{F32, F64};
use core::{f32, i32, i64, u32, u64};
use nan_preserving_float::{F32, F64};
use types::ValueType;
use TrapKind;
#[derive(Debug)]
@ -27,93 +28,6 @@ pub enum RuntimeValue {
F64(F64),
}
#[derive(Copy, Clone, Debug, PartialEq, Default)]
pub(crate) struct RuntimeValueInternal(pub u64);
impl RuntimeValueInternal {
pub fn with_type(self, ty: ValueType) -> RuntimeValue {
match ty {
ValueType::I32 => RuntimeValue::I32(<_>::from_runtime_value_internal(self)),
ValueType::I64 => RuntimeValue::I64(<_>::from_runtime_value_internal(self)),
ValueType::F32 => RuntimeValue::F32(<_>::from_runtime_value_internal(self)),
ValueType::F64 => RuntimeValue::F64(<_>::from_runtime_value_internal(self)),
}
}
}
pub(crate) trait FromRuntimeValueInternal
where
Self: Sized,
{
fn from_runtime_value_internal(val: RuntimeValueInternal) -> Self;
}
macro_rules! impl_from_runtime_value_internal {
($($t:ty),*) => {
$(
impl FromRuntimeValueInternal for $t {
fn from_runtime_value_internal(
RuntimeValueInternal(val): RuntimeValueInternal,
) -> Self {
val as _
}
}
impl From<$t> for RuntimeValueInternal {
fn from(other: $t) -> Self {
RuntimeValueInternal(other as _)
}
}
)*
};
}
macro_rules! impl_from_runtime_value_internal_float {
($($t:ty),*) => {
$(
impl FromRuntimeValueInternal for $t {
fn from_runtime_value_internal(
RuntimeValueInternal(val): RuntimeValueInternal,
) -> Self {
<$t>::from_bits(val as _)
}
}
impl From<$t> for RuntimeValueInternal {
fn from(other: $t) -> Self {
RuntimeValueInternal(other.to_bits() as _)
}
}
)*
};
}
impl_from_runtime_value_internal!(i8, u8, i16, u16, i32, u32, i64, u64);
impl_from_runtime_value_internal_float!(f32, f64, F32, F64);
impl From<bool> for RuntimeValueInternal {
fn from(other: bool) -> Self {
(if other { 1 } else { 0 }).into()
}
}
impl FromRuntimeValueInternal for bool {
fn from_runtime_value_internal(RuntimeValueInternal(val): RuntimeValueInternal) -> Self {
val != 0
}
}
impl From<RuntimeValue> for RuntimeValueInternal {
fn from(other: RuntimeValue) -> Self {
match other {
RuntimeValue::I32(val) => val.into(),
RuntimeValue::I64(val) => val.into(),
RuntimeValue::F32(val) => val.into(),
RuntimeValue::F64(val) => val.into(),
}
}
}
/// Trait for creating value from a [`RuntimeValue`].
///
/// Typically each implementation can create a value from the specific type.
@ -123,7 +37,10 @@ impl From<RuntimeValue> for RuntimeValueInternal {
/// [`I32`]: enum.RuntimeValue.html#variant.I32
/// [`F64`]: enum.RuntimeValue.html#variant.F64
/// [`RuntimeValue`]: enum.RuntimeValue.html
pub trait FromRuntimeValue where Self: Sized {
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
@ -158,9 +75,12 @@ pub trait TransmuteInto<T> {
}
/// Convert from and to little endian.
pub trait LittleEndianConvert where Self: Sized {
pub trait LittleEndianConvert
where
Self: Sized,
{
/// Convert to little endian buffer.
fn into_little_endian(self, buffer: &mut[u8]);
fn into_little_endian(self, buffer: &mut [u8]);
/// Convert from little endian buffer.
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error>;
}
@ -548,7 +468,7 @@ macro_rules! impl_transmute_into_self {
self
}
}
}
};
}
impl_transmute_into_self!(i32);
@ -565,7 +485,7 @@ macro_rules! impl_transmute_into_as {
self as $into
}
}
}
};
}
impl_transmute_into_as!(i8, u8);
@ -616,139 +536,160 @@ impl_transmute_into_npf!(F32, f32, i32, u32);
impl_transmute_into_npf!(F64, f64, i64, u64);
impl TransmuteInto<i32> for f32 {
fn transmute_into(self) -> i32 { self.to_bits() as i32 }
fn transmute_into(self) -> i32 {
self.to_bits() as i32
}
}
impl TransmuteInto<i64> for f64 {
fn transmute_into(self) -> i64 { self.to_bits() as i64 }
fn transmute_into(self) -> i64 {
self.to_bits() as i64
}
}
impl TransmuteInto<f32> for i32 {
fn transmute_into(self) -> f32 { f32::from_bits(self as u32) }
fn transmute_into(self) -> f32 {
f32::from_bits(self as u32)
}
}
impl TransmuteInto<f64> for i64 {
fn transmute_into(self) -> f64 { f64::from_bits(self as u64) }
fn transmute_into(self) -> f64 {
f64::from_bits(self as u64)
}
}
impl TransmuteInto<i32> for u32 {
fn transmute_into(self) -> i32 { self as _ }
fn transmute_into(self) -> i32 {
self as _
}
}
impl TransmuteInto<i64> for u64 {
fn transmute_into(self) -> i64 { self as _ }
fn transmute_into(self) -> i64 {
self as _
}
}
impl LittleEndianConvert for i8 {
fn into_little_endian(self, buffer: &mut[u8]) {
fn into_little_endian(self, buffer: &mut [u8]) {
buffer[0] = self as u8;
}
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
buffer.get(0)
buffer
.get(0)
.map(|v| *v as i8)
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
}
}
impl LittleEndianConvert for u8 {
fn into_little_endian(self, buffer: &mut[u8]) {
fn into_little_endian(self, buffer: &mut [u8]) {
buffer[0] = self;
}
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
buffer.get(0)
buffer
.get(0)
.cloned()
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
}
}
impl LittleEndianConvert for i16 {
fn into_little_endian(self, buffer: &mut[u8]) {
fn into_little_endian(self, buffer: &mut [u8]) {
LittleEndian::write_i16(buffer, self);
}
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
buffer.get(0..2)
buffer
.get(0..2)
.map(LittleEndian::read_i16)
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
}
}
impl LittleEndianConvert for u16 {
fn into_little_endian(self, buffer: &mut[u8]) {
fn into_little_endian(self, buffer: &mut [u8]) {
LittleEndian::write_u16(buffer, self);
}
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
buffer.get(0..2)
buffer
.get(0..2)
.map(LittleEndian::read_u16)
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
}
}
impl LittleEndianConvert for i32 {
fn into_little_endian(self, buffer: &mut[u8]) {
fn into_little_endian(self, buffer: &mut [u8]) {
LittleEndian::write_i32(buffer, self);
}
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
buffer.get(0..4)
buffer
.get(0..4)
.map(LittleEndian::read_i32)
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
}
}
impl LittleEndianConvert for u32 {
fn into_little_endian(self, buffer: &mut[u8]) {
fn into_little_endian(self, buffer: &mut [u8]) {
LittleEndian::write_u32(buffer, self);
}
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
buffer.get(0..4)
buffer
.get(0..4)
.map(LittleEndian::read_u32)
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
}
}
impl LittleEndianConvert for i64 {
fn into_little_endian(self, buffer: &mut[u8]) {
fn into_little_endian(self, buffer: &mut [u8]) {
LittleEndian::write_i64(buffer, self);
}
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
buffer.get(0..8)
buffer
.get(0..8)
.map(LittleEndian::read_i64)
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
}
}
impl LittleEndianConvert for f32 {
fn into_little_endian(self, buffer: &mut[u8]) {
fn into_little_endian(self, buffer: &mut [u8]) {
LittleEndian::write_f32(buffer, self);
}
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
buffer.get(0..4)
buffer
.get(0..4)
.map(LittleEndian::read_f32)
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
}
}
impl LittleEndianConvert for f64 {
fn into_little_endian(self, buffer: &mut[u8]) {
fn into_little_endian(self, buffer: &mut [u8]) {
LittleEndian::write_f64(buffer, self);
}
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
buffer.get(0..8)
buffer
.get(0..8)
.map(LittleEndian::read_f64)
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
}
}
impl LittleEndianConvert for F32 {
fn into_little_endian(self, buffer: &mut[u8]) {
fn into_little_endian(self, buffer: &mut [u8]) {
(self.to_bits() as i32).into_little_endian(buffer)
}
@ -758,7 +699,7 @@ impl LittleEndianConvert for F32 {
}
impl LittleEndianConvert for F64 {
fn into_little_endian(self, buffer: &mut[u8]) {
fn into_little_endian(self, buffer: &mut [u8]) {
(self.to_bits() as i64).into_little_endian(buffer)
}
@ -770,14 +711,19 @@ impl LittleEndianConvert for F64 {
macro_rules! impl_integer_arithmetic_ops {
($type: ident) => {
impl ArithmeticOps<$type> for $type {
fn add(self, other: $type) -> $type { self.wrapping_add(other) }
fn sub(self, other: $type) -> $type { self.wrapping_sub(other) }
fn mul(self, other: $type) -> $type { self.wrapping_mul(other) }
fn add(self, other: $type) -> $type {
self.wrapping_add(other)
}
fn sub(self, other: $type) -> $type {
self.wrapping_sub(other)
}
fn mul(self, other: $type) -> $type {
self.wrapping_mul(other)
}
fn div(self, other: $type) -> Result<$type, TrapKind> {
if other == 0 {
Err(TrapKind::DivisionByZero)
}
else {
} else {
let (result, overflow) = self.overflowing_div(other);
if overflow {
Err(TrapKind::InvalidConversionToInt)
@ -787,7 +733,7 @@ macro_rules! impl_integer_arithmetic_ops {
}
}
}
}
};
}
impl_integer_arithmetic_ops!(i32);
@ -798,12 +744,20 @@ impl_integer_arithmetic_ops!(u64);
macro_rules! impl_float_arithmetic_ops {
($type: ident) => {
impl ArithmeticOps<$type> for $type {
fn add(self, other: $type) -> $type { self + other }
fn sub(self, other: $type) -> $type { self - other }
fn mul(self, other: $type) -> $type { self * other }
fn div(self, other: $type) -> Result<$type, TrapKind> { Ok(self / other) }
fn add(self, other: $type) -> $type {
self + other
}
fn sub(self, other: $type) -> $type {
self - other
}
fn mul(self, other: $type) -> $type {
self * other
}
fn div(self, other: $type) -> Result<$type, TrapKind> {
Ok(self / other)
}
}
}
};
}
impl_float_arithmetic_ops!(f32);
@ -814,17 +768,30 @@ impl_float_arithmetic_ops!(F64);
macro_rules! impl_integer {
($type: ident) => {
impl Integer<$type> for $type {
fn leading_zeros(self) -> $type { self.leading_zeros() as $type }
fn trailing_zeros(self) -> $type { self.trailing_zeros() as $type }
fn count_ones(self) -> $type { self.count_ones() as $type }
fn rotl(self, other: $type) -> $type { self.rotate_left(other as u32) }
fn rotr(self, other: $type) -> $type { self.rotate_right(other as u32) }
fn leading_zeros(self) -> $type {
self.leading_zeros() as $type
}
fn trailing_zeros(self) -> $type {
self.trailing_zeros() as $type
}
fn count_ones(self) -> $type {
self.count_ones() as $type
}
fn rotl(self, other: $type) -> $type {
self.rotate_left(other as u32)
}
fn rotr(self, other: $type) -> $type {
self.rotate_right(other as u32)
}
fn rem(self, other: $type) -> Result<$type, TrapKind> {
if other == 0 { Err(TrapKind::DivisionByZero) }
else { Ok(self.wrapping_rem(other)) }
if other == 0 {
Err(TrapKind::DivisionByZero)
} else {
Ok(self.wrapping_rem(other))
}
}
}
}
};
}
impl_integer!(i32);