use std;
use std::rc::Rc;
use parity_wasm::elements;
use num::ToPrimitive;
pub trait TryFrom<T>
where
Self: Sized,
{
type Error;
fn try_from(value: T) -> Result<Self, Self::Error>;
}
#[derive(Debug, Clone, PartialEq)]
pub struct FuncType {
pub params: Vec<elements::ValueType>,
pub return_type: Option<elements::ValueType>,
}
impl<'a> From<&'a elements::Type> for FuncType {
fn from(t: &'a elements::Type) -> Self {
match *t {
elements::Type::Function(ref ft) => Self {
params: ft.params().to_owned(),
return_type: ft.return_type(),
},
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct TypeIdx(pub usize);
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct FuncIdx(pub usize);
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct GlobalIdx(pub usize);
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub enum Value {
I32(i32),
I64(i64),
F32(f32),
F64(f64),
}
impl Value {
pub fn default_from_type(t: elements::ValueType) -> Self {
match t {
elements::ValueType::I32 => Value::I32(0),
elements::ValueType::I64 => Value::I64(0),
elements::ValueType::F32 => Value::F32(0.0),
elements::ValueType::F64 => Value::F64(0.0),
}
}
pub fn get_type(self) -> elements::ValueType {
match self {
Value::I32(_) => elements::ValueType::I32,
Value::I64(_) => elements::ValueType::I64,
Value::F32(_) => elements::ValueType::F32,
Value::F64(_) => elements::ValueType::F64,
}
}
}
impl From<Value> for i32 {
fn from(vl: Value) -> i32 {
match vl {
Value::I32(i) => i,
_ => panic!("Unwrap value failed"),
}
}
}
impl From<Value> for i64 {
fn from(vl: Value) -> i64 {
match vl {
Value::I64(i) => i,
_ => panic!("Unwrap value failed"),
}
}
}
impl From<Value> for u32 {
fn from(vl: Value) -> u32 {
match vl {
Value::I32(i) => i as u32,
_ => panic!("Unwrap value failed"),
}
}
}
impl From<Value> for u64 {
fn from(vl: Value) -> u64 {
match vl {
Value::I64(i) => i as u64,
_ => panic!("Unwrap value failed"),
}
}
}
impl From<Value> for f32 {
fn from(vl: Value) -> f32 {
match vl {
Value::F32(i) => i,
_ => panic!("Unwrap value failed"),
}
}
}
impl From<Value> for f64 {
fn from(vl: Value) -> f64 {
match vl {
Value::F64(i) => i,
_ => panic!("Unwrap value failed"),
}
}
}
impl From<Value> for bool {
fn from(vl: Value) -> bool {
match vl {
Value::I32(i) => i != 0,
_ => panic!("Unwrap value failed"),
}
}
}
impl From<i32> for Value {
fn from(num: i32) -> Self {
Value::I32(num)
}
}
impl From<i64> for Value {
fn from(num: i64) -> Self {
Value::I64(num)
}
}
impl From<u32> for Value {
fn from(num: u32) -> Self {
Value::I32(num as i32)
}
}
impl From<u64> for Value {
fn from(num: u64) -> Self {
Value::I64(num as i64)
}
}
impl From<f32> for Value {
fn from(num: f32) -> Self {
Value::F32(num)
}
}
impl From<f64> for Value {
fn from(num: f64) -> Self {
Value::F64(num)
}
}
impl From<bool> for Value {
fn from(b: bool) -> Self {
if b {
Value::I32(1)
} else {
Value::I32(0)
}
}
}
pub trait Wrap<T> {
fn wrap(self) -> T;
}
macro_rules! impl_wrap_into {
($from: ident, $into: ident) => {
impl Wrap<$into> for $from {
fn wrap(self) -> $into {
self as $into
}
}
}
}
impl_wrap_into!(i32, i8);
impl_wrap_into!(i32, i16);
impl_wrap_into!(i64, i8);
impl_wrap_into!(i64, i16);
impl_wrap_into!(i64, i32);
impl_wrap_into!(i64, f32);
impl_wrap_into!(u64, f32);
pub trait Extend<T> {
fn extend(self) -> T;
}
macro_rules! impl_extend_into {
($from: ident, $into: ident) => {
impl Extend<$into> for $from {
fn extend(self) -> $into {
self as $into
}
}
}
}
impl_extend_into!(i8, i32);
impl_extend_into!(u8, i32);
impl_extend_into!(i16, i32);
impl_extend_into!(u16, i32);
impl_extend_into!(i8, i64);
impl_extend_into!(u8, i64);
impl_extend_into!(i16, i64);
impl_extend_into!(u16, i64);
impl_extend_into!(i32, i64);
impl_extend_into!(u32, i64);
impl_extend_into!(u32, u64);
impl_extend_into!(i32, f32);
impl_extend_into!(i32, f64);
impl_extend_into!(u32, f32);
impl_extend_into!(u32, f64);
impl_extend_into!(i64, f64);
impl_extend_into!(u64, f64);
impl_extend_into!(f32, f64);
#[derive(Clone)]
pub enum FuncBody {
Opcodes(Vec<elements::Opcode>),
HostFunction(Rc<Fn(&mut Vec<Value>)>),
}
use std::fmt;
impl fmt::Debug for FuncBody {
fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
match *self {
FuncBody::Opcodes(ref o) => write!(f, "Opcodes({:?})", o),
FuncBody::HostFunction(_) => write!(f, "HostFunction(&mut Vec<Value>)"),
}
}
}
#[derive(Debug, Clone)]
pub struct Func {
pub typeidx: TypeIdx,
pub locals: Vec<elements::ValueType>,
pub body: FuncBody,
}
#[derive(Debug, Clone)]
pub struct Table {
pub data: Vec<FuncIdx>,
pub max: Option<u32>,
}
impl Table {
pub fn new() -> Self {
Self {
data: vec![],
max: None,
}
}
pub fn fill(&mut self, size: u32) {
self.data.resize(size as usize, FuncIdx(std::usize::MAX));
self.max = Some(size);
}
pub fn initialize(&mut self, inits: &[(ConstExpr, Vec<FuncIdx>)]) -> Result<(), ()> {
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct Memory {
pub data: Vec<u8>,
pub max: Option<u32>,
}
impl Memory {
const PAGE_SIZE: usize = 65_536;
pub fn new(size: Option<u32>) -> Self {
let mut mem = Self {
data: vec![],
max: None,
};
if let Some(size) = size {
let size_i = size.to_i32().expect(
"Should never happen; 32-bit wasm should always have memory sizes << i32::MAX",
);
mem.resize(size_i);
}
mem
}
pub fn len(&self) -> u32 {
(self.data.len() / Self::PAGE_SIZE)
.to_u32()
.expect("Page count of memory > u32::MAX; should never happen!")
}
pub fn resize(&mut self, delta: i32) {
use std::usize;
let delta_bytes = i32::checked_mul(Self::PAGE_SIZE as i32, delta)
.expect("Asked for more memory than can fit in an i32?");
assert!(self.data.len() < std::i32::MAX as usize);
let new_size = self.data.len() as i32 + delta_bytes;
self.data.resize(new_size as usize, 0);
}
pub fn initialize(&mut self, offset: u32, val: &[u8]) -> Result<(), ()> {
let offset_start = offset as usize;
let offset_end = offset_start + val.len();
assert!(offset_end <= self.data.len());
self.data.as_mut_slice()[offset_start..offset_end].copy_from_slice(val);
Ok(())
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ConstOpcode {
I32Const(i32),
I64Const(i64),
F32Const(f32),
F64Const(f64),
GetGlobal(u32),
}
impl TryFrom<elements::Opcode> for ConstOpcode {
type Error = elements::Opcode;
fn try_from(opcode: elements::Opcode) -> Result<ConstOpcode, elements::Opcode> {
match opcode {
elements::Opcode::I32Const(i) => Ok(ConstOpcode::I32Const(i as i32)),
elements::Opcode::I64Const(i) => Ok(ConstOpcode::I64Const(i as i64)),
elements::Opcode::F32Const(f) => Ok(ConstOpcode::F32Const(f32::from_bits(f))),
elements::Opcode::F64Const(f) => Ok(ConstOpcode::F64Const(f64::from_bits(f))),
elements::Opcode::GetGlobal(i) => Ok(ConstOpcode::GetGlobal(i)),
op => Err(op),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ConstExpr(pub Vec<ConstOpcode>);
impl<'a> TryFrom<&'a [elements::Opcode]> for ConstExpr {
type Error = elements::Opcode;
fn try_from(opcodes: &[elements::Opcode]) -> Result<ConstExpr, elements::Opcode> {
let ops = opcodes
.iter()
.filter(|op| **op != elements::Opcode::End)
.cloned()
.map(ConstOpcode::try_from)
.collect::<Result<Vec<_>, _>>()?;
Ok(ConstExpr(ops))
}
}
#[derive(Debug, Clone)]
pub struct Global {
pub mutable: bool,
pub variable_type: elements::ValueType,
pub value: Value,
}
impl Global {
pub fn initialize(&mut self, init_value: Value) {
self.value = init_value;
}
}
#[derive(Debug, Clone)]
pub struct Import<T> {
pub module_name: String,
pub field_name: String,
pub value: T,
}
#[derive(Debug, Clone)]
pub struct Export<T> {
pub name: String,
pub value: T,
}
#[derive(Debug, Fail)]
pub enum Error {
#[fail(display = "Module {} does not exist, desired by module {}!", module, dependent_module)]
ModuleNotFound {
module: String,
dependent_module: String,
},
#[fail(display = "Module {} does not export value {} of expected type {} imported by module {}", module, name, typ, dependent_module)]
NotExported {
module: String,
name: String,
typ: String,
dependent_module: String,
},
#[fail(display = "Module {} is invalid: {}", module, reason)]
Invalid {
module: String,
reason: String,
},
#[fail(display = "Module {} has the wrong version; expected {}, got {}", module, expected, got)]
VersionMismatch {
module: String,
expected: u32,
got: u32,
}
}