Merge pull request #7 from fluencelabs/decouple_ivalues

Decouple IType and IValue
This commit is contained in:
vms
2020-12-29 12:55:01 +03:00
committed by GitHub
45 changed files with 1424 additions and 1362 deletions

42
Cargo.lock generated
View File

@ -18,11 +18,25 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "fluence-it-types"
version = "0.1.1"
dependencies = [
"it-to-bytes",
"nom",
"serde",
"wast",
]
[[package]]
name = "it-to-bytes"
version = "0.1.0"
[[package]]
name = "itoa"
version = "0.4.6"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "leb128"
@ -80,9 +94,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.7"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
dependencies = [
"proc-macro2",
]
@ -101,18 +115,18 @@ checksum = "50b8b2cd387f744f69469aaed197954ba4c0ecdb31e02edf99b023e0df11178a"
[[package]]
name = "serde"
version = "1.0.117"
version = "1.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.117"
version = "1.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e"
checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df"
dependencies = [
"proc-macro2",
"quote",
@ -121,9 +135,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.59"
version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95"
checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a"
dependencies = [
"itoa",
"ryu",
@ -138,9 +152,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "1.0.48"
version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac"
checksum = "a9802ddde94170d186eeee5005b798d9c159fa970403f1be19976d0cfb939b72"
dependencies = [
"proc-macro2",
"quote",
@ -161,8 +175,10 @@ checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
[[package]]
name = "wasmer-interface-types-fl"
version = "0.17.18"
version = "0.17.22"
dependencies = [
"fluence-it-types",
"it-to-bytes",
"log",
"nom",
"safe-transmute",

View File

@ -1,23 +1,14 @@
[package]
name = "wasmer-interface-types-fl"
version = "0.17.18"
description = "WebAssembly Interface Types library for Wasmer"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
repository = "https://github.com/wasmerio/wasmer"
edition = "2018"
[workspace]
members = [
"crates/to-bytes",
"crates/it-types",
"wasmer-it",
]
[dependencies]
nom = "5.1"
wast = "8.0"
# `serde` is useful only to simplify the users' life. It is not
# required by WIT itself, is is used to cross the boundary between the
# host and WIT more easily, but it is not used inside Wasm.
serde = { version = "1.0", features = ["derive", "rc"], optional = true }
serde_json = "1.0"
safe-transmute = "0.11.0"
log = "0.4.11"
[features]
default = ["serde"]
[profile.release]
opt-level = 3
debug = false
lto = true
debug-assertions = false
overflow-checks = false
panic = "abort"

View File

@ -0,0 +1,18 @@
[package]
name = "fluence-it-types"
version = "0.1.1"
description = "Definitions of IValue and IType"
authors = ["Fluence Labs"]
edition = "2018"
license = "Apache-2.0"
[dependencies]
it-to-bytes = { path = "../to-bytes/", version = "0.1.0" }
serde = { version = "1.0.118", features = ["derive", "rc"]}
nom = { version = "5.1", optional = true }
wast = { version = "8.0", optional = true }
[features]
impls = ["nom", "wast"]

View File

@ -0,0 +1,29 @@
use crate::IType;
use crate::IValue;
use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;
/// Structure to represent errors when casting from an `IType`
/// to a native value.
#[derive(Debug)]
pub struct WasmValueNativeCastError {
/// The initial type.
pub from: IValue,
/// The targeted type.
///
/// `IType` is used to represent the native type by
/// associativity.
pub to: IType,
}
impl Error for WasmValueNativeCastError {}
impl Display for WasmValueNativeCastError {
fn fmt(&self, formatter: &mut Formatter) -> Result {
write!(formatter, "{:?}", self)
}
}

View File

@ -0,0 +1,6 @@
mod errors;
mod types;
mod values;
pub use errors::WasmValueNativeCastError;
pub use values::NativeType;

View File

@ -0,0 +1,220 @@
use crate::ne_vec::NEVec;
use crate::IRecordFieldType;
use crate::IRecordType;
use crate::IType;
use it_to_bytes::ToBytes;
use wast::parser::Parse;
use wast::parser::Parser;
use wast::Error as ParseError;
use std::io;
use std::io::Write;
/// Encode an `IType` into bytes.
impl<W> ToBytes<W> for IType
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
match self {
IType::S8 => 0x00_u8.to_bytes(writer),
IType::S16 => 0x01_u8.to_bytes(writer),
IType::S32 => 0x02_u8.to_bytes(writer),
IType::S64 => 0x03_u8.to_bytes(writer),
IType::U8 => 0x04_u8.to_bytes(writer),
IType::U16 => 0x05_u8.to_bytes(writer),
IType::U32 => 0x06_u8.to_bytes(writer),
IType::U64 => 0x07_u8.to_bytes(writer),
IType::F32 => 0x08_u8.to_bytes(writer),
IType::F64 => 0x09_u8.to_bytes(writer),
IType::String => 0x0a_u8.to_bytes(writer),
IType::Array(ty) => {
0x36_u8.to_bytes(writer)?;
ty.to_bytes(writer)
}
IType::Anyref => 0x0b_u8.to_bytes(writer),
IType::I32 => 0x0c_u8.to_bytes(writer),
IType::I64 => 0x0d_u8.to_bytes(writer),
IType::Record(record_id) => {
0x0e_u8.to_bytes(writer)?;
record_id.to_bytes(writer)
}
}
}
}
/// Encode a `RecordType` into bytes.
impl<W> ToBytes<W> for IRecordFieldType
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
self.name.as_str().to_bytes(writer)?;
self.ty.to_bytes(writer)
}
}
/// Encode a `RecordType` into bytes.
impl<W> ToBytes<W> for IRecordType
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
self.name.as_str().to_bytes(writer)?;
self.fields.to_bytes(writer)
}
}
mod keyword {
pub use wast::{
custom_keyword,
kw::{anyref, export, f32, f64, func, i32, i64, import, param, result},
};
// New keywords.
custom_keyword!(record);
custom_keyword!(field);
// New types.
custom_keyword!(s8);
custom_keyword!(s16);
custom_keyword!(s32);
custom_keyword!(s64);
custom_keyword!(u8);
custom_keyword!(u16);
custom_keyword!(u32);
custom_keyword!(u64);
custom_keyword!(string);
custom_keyword!(array);
}
impl Parse<'_> for IType {
fn parse(parser: Parser<'_>) -> Result<IType, ParseError> {
let mut lookahead = parser.lookahead1();
if lookahead.peek::<keyword::s8>() {
parser.parse::<keyword::s8>()?;
Ok(IType::S8)
} else if lookahead.peek::<keyword::s16>() {
parser.parse::<keyword::s16>()?;
Ok(IType::S16)
} else if lookahead.peek::<keyword::s32>() {
parser.parse::<keyword::s32>()?;
Ok(IType::S32)
} else if lookahead.peek::<keyword::s64>() {
parser.parse::<keyword::s64>()?;
Ok(IType::S64)
} else if lookahead.peek::<keyword::u8>() {
parser.parse::<keyword::u8>()?;
Ok(IType::U8)
} else if lookahead.peek::<keyword::u16>() {
parser.parse::<keyword::u16>()?;
Ok(IType::U16)
} else if lookahead.peek::<keyword::u32>() {
parser.parse::<keyword::u32>()?;
Ok(IType::U32)
} else if lookahead.peek::<keyword::u64>() {
parser.parse::<keyword::u64>()?;
Ok(IType::U64)
} else if lookahead.peek::<keyword::f32>() {
parser.parse::<keyword::f32>()?;
Ok(IType::F32)
} else if lookahead.peek::<keyword::f64>() {
parser.parse::<keyword::f64>()?;
Ok(IType::F64)
} else if lookahead.peek::<keyword::string>() {
parser.parse::<keyword::string>()?;
Ok(IType::String)
} else if lookahead.peek::<keyword::array>() {
parser.parse::<keyword::array>()?;
let array_type = parser.parens(|p| p.parse())?;
Ok(IType::Array(Box::new(array_type)))
} else if lookahead.peek::<keyword::anyref>() {
parser.parse::<keyword::anyref>()?;
Ok(IType::Anyref)
} else if lookahead.peek::<keyword::i32>() {
parser.parse::<keyword::i32>()?;
Ok(IType::I32)
} else if lookahead.peek::<keyword::i64>() {
parser.parse::<keyword::i64>()?;
Ok(IType::I64)
} else if lookahead.peek::<keyword::record>() {
parser.parse::<keyword::record>()?;
Ok(IType::Record(parser.parse()?))
} else {
Err(lookahead.error())
}
}
}
impl Parse<'_> for IRecordType {
fn parse(parser: Parser<'_>) -> Result<Self, ParseError> {
parser.parse::<keyword::record>()?;
let record_name = parser
.step(|cursor| {
cursor
.id()
.ok_or_else(|| cursor.error("expecting argument identifier"))
})?
.to_string();
let mut fields = vec![];
parser.parens(|parser| {
while !parser.is_empty() {
parser.parse::<keyword::field>()?;
let name = parser
.step(|cursor| {
cursor
.id()
.ok_or_else(|| cursor.error("expecting argument identifier"))
})?
.to_string();
if !name.ends_with(':') {
parser.step(|cursor| {
if let Some((":", rest)) = cursor.reserved() {
return Ok(("", rest));
}
Err(cursor.error("expected : between an argument and a type"))
})?;
}
let ty = parser.parse()?;
let record_field_type = IRecordFieldType {
name: name.trim_end_matches(':').to_string(),
ty,
};
fields.push(record_field_type);
}
Ok(())
})?;
let record_type = IRecordType {
name: record_name,
fields: NEVec::new(fields).expect("Record must have at least one field, zero given."),
};
Ok(record_type)
}
}

View File

@ -0,0 +1,51 @@
use crate::IType;
use crate::IValue;
use crate::WasmValueNativeCastError;
use std::convert::TryFrom;
/// Represents a native type supported by WIT.
pub trait NativeType {
/// The associated interface type that maps to the native type.
const INTERFACE_TYPE: IType;
}
macro_rules! native {
($native_type:ty, $variant:ident) => {
impl NativeType for $native_type {
const INTERFACE_TYPE: IType = IType::$variant;
}
impl From<$native_type> for IValue {
fn from(n: $native_type) -> Self {
IValue::$variant(n)
}
}
impl TryFrom<&IValue> for $native_type {
type Error = WasmValueNativeCastError;
fn try_from(w: &IValue) -> Result<Self, Self::Error> {
match w {
IValue::$variant(n) => Ok(n.clone()),
_ => Err(WasmValueNativeCastError {
from: w.clone(),
to: <$native_type>::INTERFACE_TYPE,
}),
}
}
}
};
}
native!(i8, S8);
native!(i16, S16);
native!(i32, I32);
native!(i64, I64);
native!(u8, U8);
native!(u16, U16);
native!(u32, U32);
native!(u64, U64);
native!(f32, F32);
native!(f64, F64);
native!(String, String);

View File

@ -0,0 +1,20 @@
#[cfg(feature = "impls")]
mod impls;
pub mod ne_vec;
mod types;
mod values;
// types
pub use types::IType;
pub use types::RecordFieldType as IRecordFieldType;
pub use types::RecordType as IRecordType;
#[cfg(feature = "impls")]
pub use impls::NativeType;
// values
pub use values::IValue;
// errors
#[cfg(feature = "impls")]
pub use impls::WasmValueNativeCastError;

View File

@ -1,4 +1,4 @@
//! `Vec1<T>` represents a non-empty `Vec<T>`.
//! `NEVec<T>` represents a non-empty `Vec<T>`.
use serde::{Deserialize, Serialize};
use std::{
@ -7,14 +7,14 @@ use std::{
ops,
};
/// `Vec1<T>` represents a non-empty `Vec<T>`. It derefs to `Vec<T>`
/// `NEVec<T>` represents a non-empty `Vec<T>`. It derefs to `Vec<T>`
/// directly.
#[derive(Clone, PartialEq, Eq, Serialize, Hash, Deserialize, Default)]
pub struct Vec1<T>(Vec<T>)
pub struct NEVec<T>(Vec<T>)
where
T: Debug;
/// Represents the only error that can be emitted by `Vec1`, i.e. when
/// Represents the only error that can be emitted by `NEVec`, i.e. when
/// the number of items is zero.
#[derive(Debug)]
pub struct EmptyVec;
@ -23,11 +23,14 @@ impl error::Error for EmptyVec {}
impl fmt::Display for EmptyVec {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "Vec1 must as least contain one item, zero given")
write!(
formatter,
"NEVec must as least contain one item, zero given"
)
}
}
impl<T> Vec1<T>
impl<T> NEVec<T>
where
T: Debug,
{
@ -41,13 +44,13 @@ where
}
}
/// Converts this Vec1 into Vec
/// Converts this NEVec into Vec
pub fn into_vec(self) -> Vec<T> {
self.0
}
}
impl<T> fmt::Debug for Vec1<T>
impl<T> fmt::Debug for NEVec<T>
where
T: Debug,
{
@ -56,7 +59,7 @@ where
}
}
impl<T> ops::Deref for Vec1<T>
impl<T> ops::Deref for NEVec<T>
where
T: Debug,
{

View File

@ -0,0 +1,140 @@
//! This module defines the WIT types.
use crate::ne_vec::NEVec;
use serde::Deserialize;
use serde::Serialize;
/// Represents the types supported by WIT.
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub enum IType {
/// A 8-bits signed integer.
S8,
/// A 16-bits signed integer.
S16,
/// A 32-bits signed integer.
S32,
/// A 64-bits signed integer.
S64,
/// A 8-bits unsigned integer.
U8,
/// A 16-bits unsigned integer.
U16,
/// A 32-bits unsigned integer.
U32,
/// A 64-bits unsigned integer.
U64,
/// A 32-bits float.
F32,
/// A 64-bits float.
F64,
/// A string.
String,
/// An array of values of the same type.
Array(Box<IType>),
/// An `any` reference.
Anyref,
/// A 32-bits integer (as defined in WebAssembly core).
I32,
/// A 64-bits integer (as defined in WebAssembly core).
I64,
/// A record contains record index from interfaces AST.
Record(u64),
}
/// Represents a record field type.
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub struct RecordFieldType {
// TODO: make name optional to support structures with anonymous fields in Rust
/// A field name.
pub name: String,
/// A field type.
pub ty: IType,
}
/// Represents a record type.
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub struct RecordType {
/// A record name.
pub name: String,
/// Types and names representing the fields.
/// A record must have at least one field, hence the
/// [`Vec1`][crate::vec1::Vec1].
pub fields: NEVec<RecordFieldType>,
}
impl Default for RecordType {
fn default() -> Self {
Self {
name: String::new(),
fields: NEVec::new(vec![RecordFieldType {
name: String::new(),
ty: IType::S8,
}])
.unwrap(),
}
}
}
/// Encode an `IType` into a string.
// TODO: consider change to impl Display
impl ToString for &IType {
fn to_string(&self) -> String {
match &self {
IType::S8 => "s8".to_string(),
IType::S16 => "s16".to_string(),
IType::S32 => "s32".to_string(),
IType::S64 => "s64".to_string(),
IType::U8 => "u8".to_string(),
IType::U16 => "u16".to_string(),
IType::U32 => "u32".to_string(),
IType::U64 => "u64".to_string(),
IType::F32 => "f32".to_string(),
IType::F64 => "f64".to_string(),
IType::String => "string".to_string(),
IType::Array(ty) => format!("array ({})", ty.as_ref().to_string()),
IType::Anyref => "anyref".to_string(),
IType::I32 => "i32".to_string(),
IType::I64 => "i64".to_string(),
IType::Record(record_type_id) => format!("record {}", record_type_id),
}
}
}
impl ToString for &RecordType {
fn to_string(&self) -> String {
format!(
"record ${} (\n{fields})",
self.name,
fields = self
.fields
.iter()
.fold(String::new(), |mut accumulator, field_type| {
accumulator.push(' ');
accumulator.push_str(&format!(
"field ${}: {}\n",
field_type.name,
(&field_type.ty).to_string()
));
accumulator
}),
)
}
}

View File

@ -0,0 +1,59 @@
//! Defines WIT values and associated operations.
use crate::ne_vec::NEVec;
/// A WIT value.
#[derive(Debug, Clone, PartialEq)]
pub enum IValue {
/// A 8-bits signed integer.
S8(i8),
/// A 16-bits signed integer.
S16(i16),
/// A 32-bits signed integer.
S32(i32),
/// A 64-bits signed integer.
S64(i64),
/// A 8-bits unsigned integer.
U8(u8),
/// A 16-bits unsigned integer.
U16(u16),
/// A 32-bits unsigned integer.
U32(u32),
/// A 64-bits unsigned integer.
U64(u64),
/// A 32-bits float.
F32(f32),
/// A 64-bits float.
F64(f64),
/// A string.
String(String),
/// A byte array.
Array(Vec<IValue>),
//Anyref(?),
/// A 32-bits integer (as defined in WebAssembly core).
I32(i32),
/// A 64-bits integer (as defiend in WebAssembly core).
I64(i64),
/// A record.
Record(NEVec<IValue>),
}
impl Default for IValue {
fn default() -> Self {
Self::I32(0)
}
}

View File

@ -0,0 +1,7 @@
[package]
name = "it-to-bytes"
version = "0.1.0"
authors = ["Fluence Labs"]
description = "Defines trait ToBytes used for IT serialization"
edition = "2018"
license = "Apache-2.0"

104
crates/to-bytes/src/lib.rs Normal file
View File

@ -0,0 +1,104 @@
use std::io;
use std::io::Write;
/// A trait for converting a value to bytes.
pub trait ToBytes<W>
where
W: Write,
{
/// Converts the given value into `&[u8]` in the given `writer`.
fn to_bytes(&self, writer: &mut W) -> io::Result<()>;
}
/// Encode a `u8` into a byte (well, it's already a byte!).
impl<W> ToBytes<W> for u8
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
writer.write_all(&[*self])
}
}
/// Encode a `u64` into bytes with a LEB128 representation.
///
/// Decoder is `decoders::binary::uleb`.
impl<W> ToBytes<W> for u64
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
let mut value = *self;
// Code adapted from the Rust' `serialize` library.
loop {
if value < 0x80 {
writer.write_all(&[value as u8])?;
break;
}
writer.write_all(&[((value & 0x7f) | 0x80) as u8])?;
value >>= 7;
}
Ok(())
}
}
/// Encode a `str` into bytes.
///
/// Decoder is `decoders::binary::string`.
impl<W> ToBytes<W> for &str
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
// Size first.
writer.write_all(&[self.len() as u8])?;
// Then the string.
writer.write_all(self.as_bytes())?;
Ok(())
}
}
/// Encode a String into bytes.
///
/// Decoder is `decoders::binary::string`.
impl<W> ToBytes<W> for String
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
// Size first.
writer.write_all(&[self.len() as u8])?;
// Then the string.
writer.write_all(self.as_bytes())?;
Ok(())
}
}
/// Encode a vector into bytes.
///
/// Decoder is `decoders::binary::list`.
impl<W, I> ToBytes<W> for Vec<I>
where
W: Write,
I: ToBytes<W>,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
// Size first.
(self.len() as u64).to_bytes(writer)?;
// Then the items.
for item in self {
item.to_bytes(writer)?;
}
Ok(())
}
}

View File

@ -1,92 +0,0 @@
//! This module defines the WIT types.
use crate::vec1::Vec1;
use serde::{Deserialize, Serialize};
/// Represents the types supported by WIT.
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub enum InterfaceType {
/// A 8-bits signed integer.
S8,
/// A 16-bits signed integer.
S16,
/// A 32-bits signed integer.
S32,
/// A 64-bits signed integer.
S64,
/// A 8-bits unsigned integer.
U8,
/// A 16-bits unsigned integer.
U16,
/// A 32-bits unsigned integer.
U32,
/// A 64-bits unsigned integer.
U64,
/// A 32-bits float.
F32,
/// A 64-bits float.
F64,
/// A string.
String,
/// An array of values of the same type.
Array(Box<InterfaceType>),
/// An `any` reference.
Anyref,
/// A 32-bits integer (as defined in WebAssembly core).
I32,
/// A 64-bits integer (as defined in WebAssembly core).
I64,
/// A record contains record index from interfaces AST.
Record(u64),
}
/// Represents a record field type.
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub struct RecordFieldType {
// TODO: make name optional to support structures with anonymous fields in Rust
/// A field name.
pub name: String,
/// A field type.
pub ty: InterfaceType,
}
/// Represents a record type.
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub struct RecordType {
/// A record name.
pub name: String,
/// Types and names representing the fields.
/// A record must have at least one field, hence the
/// [`Vec1`][crate::vec1::Vec1].
pub fields: Vec1<RecordFieldType>,
}
impl Default for RecordType {
fn default() -> Self {
Self {
name: String::new(),
fields: Vec1::new(vec![RecordFieldType {
name: String::new(),
ty: InterfaceType::S8,
}])
.unwrap(),
}
}
}

View File

@ -1,218 +0,0 @@
//! Defines WIT values and associated operations.
use crate::{errors::WasmValueNativeCastError, types::InterfaceType, vec1::Vec1};
use std::{convert::TryFrom, slice::Iter};
#[cfg(feature = "serde")]
pub use crate::serde::{de::from_interface_values, ser::to_interface_value};
/// A WIT value.
#[derive(Debug, Clone, PartialEq)]
pub enum InterfaceValue {
/// A 8-bits signed integer.
S8(i8),
/// A 16-bits signed integer.
S16(i16),
/// A 32-bits signed integer.
S32(i32),
/// A 64-bits signed integer.
S64(i64),
/// A 8-bits unsigned integer.
U8(u8),
/// A 16-bits unsigned integer.
U16(u16),
/// A 32-bits unsigned integer.
U32(u32),
/// A 64-bits unsigned integer.
U64(u64),
/// A 32-bits float.
F32(f32),
/// A 64-bits float.
F64(f64),
/// A string.
String(String),
/// A byte array.
Array(Vec<InterfaceValue>),
//Anyref(?),
/// A 32-bits integer (as defined in WebAssembly core).
I32(i32),
/// A 64-bits integer (as defiend in WebAssembly core).
I64(i64),
/// A record.
Record(Vec1<InterfaceValue>),
}
impl Default for InterfaceValue {
fn default() -> Self {
Self::I32(0)
}
}
/// Represents a native type supported by WIT.
pub trait NativeType {
/// The associated interface type that maps to the native type.
const INTERFACE_TYPE: InterfaceType;
}
macro_rules! native {
($native_type:ty, $variant:ident) => {
impl NativeType for $native_type {
const INTERFACE_TYPE: InterfaceType = InterfaceType::$variant;
}
impl From<$native_type> for InterfaceValue {
fn from(n: $native_type) -> Self {
Self::$variant(n)
}
}
impl TryFrom<&InterfaceValue> for $native_type {
type Error = WasmValueNativeCastError;
fn try_from(w: &InterfaceValue) -> Result<Self, Self::Error> {
match w {
InterfaceValue::$variant(n) => Ok(n.clone()),
_ => Err(WasmValueNativeCastError {
from: w.clone(),
to: <$native_type>::INTERFACE_TYPE,
}),
}
}
}
};
}
native!(i8, S8);
native!(i16, S16);
native!(i32, I32);
native!(i64, I64);
native!(u8, U8);
native!(u16, U16);
native!(u32, U32);
native!(u64, U64);
native!(f32, F32);
native!(f64, F64);
native!(String, String);
/// Iterates over a vector of `InterfaceValues` but flatten all the
/// values. So `I32(1), Record([I32(2), I32(3)]), I32(4)` will be
/// iterated like `I32(1), I32(2), I32(3), I32(4)`.
pub(crate) struct FlattenInterfaceValueIterator<'a> {
iterators: Vec<Iter<'a, InterfaceValue>>,
}
impl<'a> FlattenInterfaceValueIterator<'a> {
pub(crate) fn new(values: &'a [InterfaceValue]) -> Self {
Self {
iterators: vec![values.iter()],
}
}
}
impl<'a> Iterator for FlattenInterfaceValueIterator<'a> {
type Item = &'a InterfaceValue;
fn next(&mut self) -> Option<Self::Item> {
match self.iterators.last_mut()?.next() {
// End of the current iterator, go back to the previous
// one.
None => {
self.iterators.pop();
self.next()
}
// Recursively iterate over the record.
Some(InterfaceValue::Record(fields)) => {
self.iterators.push(fields.iter());
self.next()
}
// A regular item.
e @ Some(_) => e,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
macro_rules! value_to_type {
($test_name:ident, $ty:ident, $value:expr) => {
#[test]
#[allow(non_snake_case)]
fn $test_name() {
assert_eq!(
InterfaceType::from(&InterfaceValue::$ty($value)),
InterfaceType::$ty
);
}
};
}
value_to_type!(interface_type_from_interface_value__s8, S8, 42);
value_to_type!(interface_type_from_interface_value__s16, S16, 42);
value_to_type!(interface_type_from_interface_value__s32, S32, 42);
value_to_type!(interface_type_from_interface_value__s64, S64, 42);
value_to_type!(interface_type_from_interface_value__u8, U8, 42);
value_to_type!(interface_type_from_interface_value__u16, U16, 42);
value_to_type!(interface_type_from_interface_value__u32, U32, 42);
value_to_type!(interface_type_from_interface_value__u64, U64, 42);
value_to_type!(interface_type_from_interface_value__f32, F32, 42.);
value_to_type!(interface_type_from_interface_value__f64, F64, 42.);
value_to_type!(
interface_type_from_interface_value__string,
String,
"foo".to_string()
);
value_to_type!(interface_type_from_interface_value__i32, I32, 42);
value_to_type!(interface_type_from_interface_value__i64, I64, 42);
#[test]
#[allow(non_snake_case)]
fn interface_type_from_interface_value__record() {
assert_eq!(
InterfaceType::from(&InterfaceValue::Record(vec1![
InterfaceValue::I32(1),
InterfaceValue::S8(2)
])),
InterfaceType::Record(RecordType {
fields: vec1![InterfaceType::I32, InterfaceType::S8]
})
);
assert_eq!(
InterfaceType::from(&InterfaceValue::Record(vec1![
InterfaceValue::I32(1),
InterfaceValue::Record(vec1![
InterfaceValue::String("a".to_string()),
InterfaceValue::F64(42.)
]),
InterfaceValue::S8(2)
])),
InterfaceType::Record(RecordType {
fields: vec1![
InterfaceType::I32,
InterfaceType::Record(RecordType {
fields: vec1![InterfaceType::String, InterfaceType::F64]
}),
InterfaceType::S8
]
})
);
}
}

View File

@ -13,11 +13,11 @@ fn test_binary_encoding_decoding_roundtrip() {
outputs: vec![],
},
Type::Function {
inputs: vec![InterfaceType::I32, InterfaceType::I32],
outputs: vec![InterfaceType::S32],
inputs: vec![IType::I32, IType::I32],
outputs: vec![IType::S32],
},
Type::Record(RecordType {
fields: vec1![InterfaceType::String, InterfaceType::I32],
fields: vec1![IType::String, IType::I32],
}),
],
imports: vec![Import {

26
wasmer-it/Cargo.toml Normal file
View File

@ -0,0 +1,26 @@
[package]
name = "wasmer-interface-types-fl"
version = "0.17.22"
description = "WebAssembly Interface Types library for Wasmer"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
repository = "https://github.com/wasmerio/wasmer"
edition = "2018"
[dependencies]
fluence-it-types = { path = "../crates/it-types", version = "0.1.0", features = ["impls"] }
it-to-bytes = { path = "../crates/to-bytes", version = "0.1.0" }
nom = "5.1"
wast = "8.0"
# `serde` is useful only to simplify the users' life. It is not
# required by WIT itself, is is used to cross the boundary between the
# host and WIT more easily, but it is not used inside Wasm.
serde = { version = "1.0", features = ["derive", "rc"], optional = true }
serde_json = "1.0"
safe-transmute = "0.11.0"
log = "0.4.11"
[features]
default = ["serde"]

View File

@ -1,10 +1,7 @@
//! Represents the WIT language as a tree. This is the central
//! representation of the language.
use crate::{
interpreter::Instruction,
types::{InterfaceType, RecordType},
};
use crate::{interpreter::Instruction, IRecordType, IType};
use serde::Deserialize;
use serde::Serialize;
@ -28,7 +25,7 @@ pub struct FunctionArg {
pub name: String,
/// A function argument type.
pub ty: InterfaceType,
pub ty: IType,
}
/// Represents a type.
@ -44,7 +41,7 @@ pub enum Type {
arguments: Rc<Vec<FunctionArg>>,
/// Types for the results (`(result …)`).
output_types: Rc<Vec<InterfaceType>>,
output_types: Rc<Vec<IType>>,
},
/// A record type, like:
@ -52,7 +49,7 @@ pub enum Type {
/// ```wasm,ignore
/// (@interface type (record string i32))
/// ```
Record(Rc<RecordType>),
Record(Rc<IRecordType>),
}
/// Represents an imported function.
@ -100,7 +97,7 @@ pub struct Implementation {
/// Represents the kind of interface.
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub(crate) enum InterfaceKind {
pub enum InterfaceKind {
/// A type.
Type,

View File

@ -1,6 +1,9 @@
//! Parse the WIT binary representation into an [AST](crate::ast).
use crate::{ast::*, interpreter::Instruction, types::*};
use crate::IRecordFieldType;
use crate::IRecordType;
use crate::IType;
use crate::{ast::*, interpreter::Instruction};
use nom::{
error::{make_error, ErrorKind, ParseError},
Err, IResult,
@ -73,7 +76,7 @@ fn uleb<'input, E: ParseError<&'input [u8]>>(input: &'input [u8]) -> IResult<&'i
fn record_field<'input, E: ParseError<&'input [u8]>>(
mut input: &'input [u8],
) -> IResult<&'input [u8], RecordFieldType, E> {
) -> IResult<&'input [u8], IRecordFieldType, E> {
if input.is_empty() {
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
}
@ -81,7 +84,7 @@ fn record_field<'input, E: ParseError<&'input [u8]>>(
consume!((input, name) = owned_string(input)?);
consume!((input, ty) = ty(input)?);
Ok((input, RecordFieldType { name, ty }))
Ok((input, IRecordFieldType { name, ty }))
}
fn function_arg<'input, E: ParseError<&'input [u8]>>(
@ -100,7 +103,7 @@ fn function_arg<'input, E: ParseError<&'input [u8]>>(
/// Parse an interface type.
fn ty<'input, E: ParseError<&'input [u8]>>(
mut input: &'input [u8],
) -> IResult<&'input [u8], InterfaceType, E> {
) -> IResult<&'input [u8], IType, E> {
if input.is_empty() {
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
}
@ -108,29 +111,29 @@ fn ty<'input, E: ParseError<&'input [u8]>>(
consume!((input, opcode) = byte(input)?);
let ty = match opcode {
0x00 => InterfaceType::S8,
0x01 => InterfaceType::S16,
0x02 => InterfaceType::S32,
0x03 => InterfaceType::S64,
0x04 => InterfaceType::U8,
0x05 => InterfaceType::U16,
0x06 => InterfaceType::U32,
0x07 => InterfaceType::U64,
0x08 => InterfaceType::F32,
0x09 => InterfaceType::F64,
0x0a => InterfaceType::String,
0x00 => IType::S8,
0x01 => IType::S16,
0x02 => IType::S32,
0x03 => IType::S64,
0x04 => IType::U8,
0x05 => IType::U16,
0x06 => IType::U32,
0x07 => IType::U64,
0x08 => IType::F32,
0x09 => IType::F64,
0x0a => IType::String,
0x36 => {
consume!((input, array_value_type) = ty(input)?);
InterfaceType::Array(Box::new(array_value_type))
IType::Array(Box::new(array_value_type))
}
0x0b => InterfaceType::Anyref,
0x0c => InterfaceType::I32,
0x0d => InterfaceType::I64,
0x0b => IType::Anyref,
0x0c => IType::I32,
0x0d => IType::I64,
0x0e => {
consume!((input, record_id) = uleb(input)?);
InterfaceType::Record(record_id)
IType::Record(record_id)
}
_ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))),
};
@ -141,17 +144,17 @@ fn ty<'input, E: ParseError<&'input [u8]>>(
/// Parse a record type.
fn record_type<'input, E: ParseError<&'input [u8]>>(
input: &'input [u8],
) -> IResult<&'input [u8], RecordType, E> {
use crate::vec1::Vec1;
) -> IResult<&'input [u8], IRecordType, E> {
use crate::NEVec;
let (output, name) = owned_string(input)?;
let (output, fields) = list(output, record_field)?;
Ok((
output,
RecordType {
IRecordType {
name,
fields: Vec1::new(fields).expect("Record must have at least one field, zero given."),
fields: NEVec::new(fields).expect("Record must have at least one field, zero given."),
},
))
}
@ -547,7 +550,7 @@ fn interfaces<'input, E: ParseError<&'input [u8]>>(
/// ast::{Adapter, Export, Implementation, Import, Interfaces, Type},
/// decoders::binary::parse,
/// interpreter::Instruction,
/// types::InterfaceType,
/// types::IType,
/// };
///
/// let input = &[
@ -588,8 +591,8 @@ fn interfaces<'input, E: ParseError<&'input [u8]>>(
/// &[] as &[u8],
/// Interfaces {
/// types: vec![Type::Function {
/// inputs: vec![InterfaceType::S8],
/// outputs: vec![InterfaceType::S16],
/// inputs: vec![IType::S8],
/// outputs: vec![IType::S16],
/// }],
/// imports: vec![Import {
/// namespace: "ab",
@ -721,22 +724,22 @@ mod tests {
let output = Ok((
&[0x01][..],
vec![
InterfaceType::S8,
InterfaceType::S16,
InterfaceType::S32,
InterfaceType::S64,
InterfaceType::U8,
InterfaceType::U16,
InterfaceType::U32,
InterfaceType::U64,
InterfaceType::F32,
InterfaceType::F64,
InterfaceType::String,
InterfaceType::Anyref,
InterfaceType::I32,
InterfaceType::I64,
InterfaceType::Record(RecordType {
fields: vec1![InterfaceType::S32],
IType::S8,
IType::S16,
IType::S32,
IType::S64,
IType::U8,
IType::U16,
IType::U32,
IType::U64,
IType::F32,
IType::F64,
IType::String,
IType::Anyref,
IType::I32,
IType::I64,
IType::Record(RecordType {
fields: vec1![IType::S32],
}),
],
));
@ -766,18 +769,18 @@ mod tests {
&[0x01][..],
vec![
RecordType {
fields: vec1![InterfaceType::String],
fields: vec1![IType::String],
},
RecordType {
fields: vec1![InterfaceType::String, InterfaceType::I32],
fields: vec1![IType::String, IType::I32],
},
RecordType {
fields: vec1![
InterfaceType::String,
InterfaceType::Record(RecordType {
fields: vec1![InterfaceType::I32, InterfaceType::I32],
IType::String,
IType::Record(RecordType {
fields: vec1![IType::I32, IType::I32],
}),
InterfaceType::F64,
IType::F64,
],
},
],
@ -959,11 +962,11 @@ mod tests {
&[] as &[u8],
vec![
Type::Function {
inputs: vec![InterfaceType::S32, InterfaceType::S32],
outputs: vec![InterfaceType::S32],
inputs: vec![IType::S32, IType::S32],
outputs: vec![IType::S32],
},
Type::Record(RecordType {
fields: vec1![InterfaceType::S32, InterfaceType::S32],
fields: vec1![IType::S32, IType::S32],
}),
],
));
@ -1064,8 +1067,8 @@ mod tests {
&[] as &[u8],
Interfaces {
types: vec![Type::Function {
inputs: vec![InterfaceType::S8],
outputs: vec![InterfaceType::S16],
inputs: vec![IType::S8],
outputs: vec![IType::S16],
}],
imports: vec![Import {
namespace: "ab",

View File

@ -1,6 +1,7 @@
//! Parse the WIT textual representation into an [AST](crate::ast).
use crate::{ast::*, interpreter::Instruction, types::*, vec1::Vec1};
use crate::IType;
use crate::{ast::*, interpreter::Instruction};
use std::rc::Rc;
pub use wast::parser::ParseBuffer as Buffer;
use wast::parser::{self, Cursor, Parse, Parser, Peek, Result};
@ -83,133 +84,6 @@ mod keyword {
custom_keyword!(swap2 = "swap2");
}
impl Parse<'_> for InterfaceType {
fn parse(parser: Parser<'_>) -> Result<Self> {
let mut lookahead = parser.lookahead1();
if lookahead.peek::<keyword::s8>() {
parser.parse::<keyword::s8>()?;
Ok(InterfaceType::S8)
} else if lookahead.peek::<keyword::s16>() {
parser.parse::<keyword::s16>()?;
Ok(InterfaceType::S16)
} else if lookahead.peek::<keyword::s32>() {
parser.parse::<keyword::s32>()?;
Ok(InterfaceType::S32)
} else if lookahead.peek::<keyword::s64>() {
parser.parse::<keyword::s64>()?;
Ok(InterfaceType::S64)
} else if lookahead.peek::<keyword::u8>() {
parser.parse::<keyword::u8>()?;
Ok(InterfaceType::U8)
} else if lookahead.peek::<keyword::u16>() {
parser.parse::<keyword::u16>()?;
Ok(InterfaceType::U16)
} else if lookahead.peek::<keyword::u32>() {
parser.parse::<keyword::u32>()?;
Ok(InterfaceType::U32)
} else if lookahead.peek::<keyword::u64>() {
parser.parse::<keyword::u64>()?;
Ok(InterfaceType::U64)
} else if lookahead.peek::<keyword::f32>() {
parser.parse::<keyword::f32>()?;
Ok(InterfaceType::F32)
} else if lookahead.peek::<keyword::f64>() {
parser.parse::<keyword::f64>()?;
Ok(InterfaceType::F64)
} else if lookahead.peek::<keyword::string>() {
parser.parse::<keyword::string>()?;
Ok(InterfaceType::String)
} else if lookahead.peek::<keyword::array>() {
parser.parse::<keyword::array>()?;
let array_type = parser.parens(|p| p.parse())?;
Ok(InterfaceType::Array(Box::new(array_type)))
} else if lookahead.peek::<keyword::anyref>() {
parser.parse::<keyword::anyref>()?;
Ok(InterfaceType::Anyref)
} else if lookahead.peek::<keyword::i32>() {
parser.parse::<keyword::i32>()?;
Ok(InterfaceType::I32)
} else if lookahead.peek::<keyword::i64>() {
parser.parse::<keyword::i64>()?;
Ok(InterfaceType::I64)
} else if lookahead.peek::<keyword::record>() {
parser.parse::<keyword::record>()?;
Ok(InterfaceType::Record(parser.parse()?))
} else {
Err(lookahead.error())
}
}
}
impl Parse<'_> for RecordType {
fn parse(parser: Parser<'_>) -> Result<Self> {
parser.parse::<keyword::record>()?;
let record_name = parser
.step(|cursor| {
cursor
.id()
.ok_or_else(|| cursor.error("expecting argument identifier"))
})?
.to_string();
let mut fields = vec![];
parser.parens(|parser| {
while !parser.is_empty() {
parser.parse::<keyword::field>()?;
let name = parser
.step(|cursor| {
cursor
.id()
.ok_or_else(|| cursor.error("expecting argument identifier"))
})?
.to_string();
if !name.ends_with(':') {
parser.step(|cursor| {
if let Some((":", rest)) = cursor.reserved() {
return Ok(("", rest));
}
Err(cursor.error("expected : between an argument and a type"))
})?;
}
let ty = parser.parse()?;
fields.push(RecordFieldType {
name: name.trim_end_matches(":").to_string(),
ty,
});
}
Ok(())
})?;
Ok(RecordType {
name: record_name,
fields: Vec1::new(fields).expect("Record must have at least one field, zero given."),
})
}
}
#[allow(clippy::suspicious_else_formatting)]
impl<'a> Parse<'a> for Instruction {
#[allow(clippy::cognitive_complexity)]
@ -449,7 +323,7 @@ impl Parse<'_> for AtInterface {
#[derive(PartialEq, Debug)]
enum FunctionType {
Header(Vec<FunctionArg>),
Output(Vec<InterfaceType>),
Output(Vec<IType>),
}
impl Parse<'_> for FunctionType {
@ -478,7 +352,7 @@ impl Parse<'_> for FunctionType {
})?;
}
let arg_type: InterfaceType = parser.parse()?;
let arg_type: IType = parser.parse()?;
arguments.push(FunctionArg {
name: arg_name.trim_end_matches(':').to_string(),
@ -705,7 +579,7 @@ impl<'a> Parse<'a> for Interfaces<'a> {
/// ast::{Adapter, Export, Implementation, Import, Interfaces, Type},
/// decoders::wat::{parse, Buffer},
/// interpreter::Instruction,
/// types::InterfaceType,
/// types::IType,
/// };
///
/// let input = Buffer::new(
@ -722,8 +596,8 @@ impl<'a> Parse<'a> for Interfaces<'a> {
/// .unwrap();
/// let output = Interfaces {
/// types: vec![Type::Function {
/// inputs: vec![InterfaceType::I32],
/// outputs: vec![InterfaceType::S8],
/// inputs: vec![IType::I32],
/// outputs: vec![IType::S8],
/// }],
/// imports: vec![Import {
/// namespace: "ns",
@ -779,32 +653,29 @@ mod tests {
"record (field string)",
];
let outputs = vec![
InterfaceType::S8,
InterfaceType::S16,
InterfaceType::S32,
InterfaceType::S64,
InterfaceType::U8,
InterfaceType::U16,
InterfaceType::U32,
InterfaceType::U64,
InterfaceType::F32,
InterfaceType::F64,
InterfaceType::String,
InterfaceType::Anyref,
InterfaceType::I32,
InterfaceType::I64,
InterfaceType::Record(RecordType {
fields: vec1![InterfaceType::String],
IType::S8,
IType::S16,
IType::S32,
IType::S64,
IType::U8,
IType::U16,
IType::U32,
IType::U64,
IType::F32,
IType::F64,
IType::String,
IType::Anyref,
IType::I32,
IType::I64,
IType::Record(RecordType {
fields: vec1![IType::String],
}),
];
assert_eq!(inputs.len(), outputs.len());
for (input, output) in inputs.iter().zip(outputs.iter()) {
assert_eq!(
&parser::parse::<InterfaceType>(&buffer(input)).unwrap(),
output
);
assert_eq!(&parser::parse::<IType>(&buffer(input)).unwrap(), output);
}
}
@ -817,18 +688,18 @@ mod tests {
];
let outputs = vec![
RecordType {
fields: vec1![InterfaceType::String],
fields: vec1![IType::String],
},
RecordType {
fields: vec1![InterfaceType::String, InterfaceType::I32],
fields: vec1![IType::String, IType::I32],
},
RecordType {
fields: vec1![
InterfaceType::String,
InterfaceType::Record(RecordType {
fields: vec1![InterfaceType::I32, InterfaceType::I32],
IType::String,
IType::Record(RecordType {
fields: vec1![IType::I32, IType::I32],
}),
InterfaceType::F64,
IType::F64,
],
},
];
@ -951,7 +822,7 @@ mod tests {
#[test]
fn test_param() {
let input = buffer("(param i32 string)");
let output = FunctionType::InputTypes(vec![InterfaceType::I32, InterfaceType::String]);
let output = FunctionType::InputTypes(vec![IType::I32, IType::String]);
assert_eq!(parser::parse::<FunctionType>(&input).unwrap(), output);
}
@ -967,7 +838,7 @@ mod tests {
#[test]
fn test_result() {
let input = buffer("(result i32 string)");
let output = FunctionType::Output(vec![InterfaceType::I32, InterfaceType::String]);
let output = FunctionType::Output(vec![IType::I32, IType::String]);
assert_eq!(parser::parse::<FunctionType>(&input).unwrap(), output);
}
@ -976,8 +847,8 @@ mod tests {
fn test_type_function() {
let input = buffer(r#"(@interface type (func (param i32 i32) (result i32)))"#);
let output = Interface::Type(Type::Function {
inputs: vec![InterfaceType::I32, InterfaceType::I32],
outputs: vec![InterfaceType::I32],
inputs: vec![IType::I32, IType::I32],
outputs: vec![IType::I32],
});
assert_eq!(parser::parse::<Interface>(&input).unwrap(), output);
@ -987,7 +858,7 @@ mod tests {
fn test_type_record() {
let input = buffer(r#"(@interface type (record (field string) (field i32)))"#);
let output = Interface::Type(Type::Record(RecordType {
fields: vec1![InterfaceType::String, InterfaceType::I32],
fields: vec1![IType::String, IType::I32],
}));
assert_eq!(parser::parse::<Interface>(&input).unwrap(), output);
@ -1064,8 +935,8 @@ mod tests {
);
let output = Interfaces {
types: vec![Type::Function {
inputs: vec![InterfaceType::I32],
outputs: vec![InterfaceType::S8],
inputs: vec![IType::I32],
outputs: vec![IType::S8],
}],
imports: vec![Import {
namespace: "ns",

View File

@ -1,164 +1,12 @@
//! Writes the AST into bytes representing WIT with its binary format.
use crate::{ast::*, interpreter::Instruction, types::*};
use std::io::{self, Write};
use crate::ast::*;
use crate::interpreter::Instruction;
/// A trait for converting a value to bytes.
pub trait ToBytes<W>
where
W: Write,
{
/// Converts the given value into `&[u8]` in the given `writer`.
fn to_bytes(&self, writer: &mut W) -> io::Result<()>;
}
use it_to_bytes::ToBytes;
/// Encode a `u8` into a byte (well, it's already a byte!).
impl<W> ToBytes<W> for u8
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
writer.write_all(&[*self])
}
}
/// Encode a `u64` into bytes with a LEB128 representation.
///
/// Decoder is `decoders::binary::uleb`.
impl<W> ToBytes<W> for u64
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
let mut value = *self;
// Code adapted from the Rust' `serialize` library.
loop {
if value < 0x80 {
writer.write_all(&[value as u8])?;
break;
}
writer.write_all(&[((value & 0x7f) | 0x80) as u8])?;
value >>= 7;
}
Ok(())
}
}
/// Encode a `str` into bytes.
///
/// Decoder is `decoders::binary::string`.
impl<W> ToBytes<W> for &str
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
// Size first.
writer.write_all(&[self.len() as u8])?;
// Then the string.
writer.write_all(self.as_bytes())?;
Ok(())
}
}
/// Encode a String into bytes.
///
/// Decoder is `decoders::binary::string`.
impl<W> ToBytes<W> for String
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
// Size first.
writer.write_all(&[self.len() as u8])?;
// Then the string.
writer.write_all(self.as_bytes())?;
Ok(())
}
}
/// Encode a vector into bytes.
///
/// Decoder is `decoders::binary::list`.
impl<W, I> ToBytes<W> for Vec<I>
where
W: Write,
I: ToBytes<W>,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
// Size first.
(self.len() as u64).to_bytes(writer)?;
// Then the items.
for item in self {
item.to_bytes(writer)?;
}
Ok(())
}
}
/// Encode an `InterfaceType` into bytes.
impl<W> ToBytes<W> for InterfaceType
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
match self {
InterfaceType::S8 => 0x00_u8.to_bytes(writer),
InterfaceType::S16 => 0x01_u8.to_bytes(writer),
InterfaceType::S32 => 0x02_u8.to_bytes(writer),
InterfaceType::S64 => 0x03_u8.to_bytes(writer),
InterfaceType::U8 => 0x04_u8.to_bytes(writer),
InterfaceType::U16 => 0x05_u8.to_bytes(writer),
InterfaceType::U32 => 0x06_u8.to_bytes(writer),
InterfaceType::U64 => 0x07_u8.to_bytes(writer),
InterfaceType::F32 => 0x08_u8.to_bytes(writer),
InterfaceType::F64 => 0x09_u8.to_bytes(writer),
InterfaceType::String => 0x0a_u8.to_bytes(writer),
InterfaceType::Array(ty) => {
0x36_u8.to_bytes(writer)?;
ty.to_bytes(writer)
}
InterfaceType::Anyref => 0x0b_u8.to_bytes(writer),
InterfaceType::I32 => 0x0c_u8.to_bytes(writer),
InterfaceType::I64 => 0x0d_u8.to_bytes(writer),
InterfaceType::Record(record_id) => {
0x0e_u8.to_bytes(writer)?;
record_id.to_bytes(writer)
}
}
}
}
/// Encode a `RecordType` into bytes.
impl<W> ToBytes<W> for RecordFieldType
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
self.name.as_str().to_bytes(writer)?;
self.ty.to_bytes(writer)
}
}
/// Encode a `RecordType` into bytes.
impl<W> ToBytes<W> for RecordType
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
self.name.as_str().to_bytes(writer)?;
self.fields.to_bytes(writer)
}
}
use std::io;
use std::io::Write;
/// Encode a `TypeKind` into bytes.
impl<W> ToBytes<W> for TypeKind
@ -498,23 +346,23 @@ mod tests {
#[test]
fn test_interface_type() {
assert_to_bytes!(InterfaceType::S8, &[0x00]);
assert_to_bytes!(InterfaceType::S16, &[0x01]);
assert_to_bytes!(InterfaceType::S32, &[0x02]);
assert_to_bytes!(InterfaceType::S64, &[0x03]);
assert_to_bytes!(InterfaceType::U8, &[0x04]);
assert_to_bytes!(InterfaceType::U16, &[0x05]);
assert_to_bytes!(InterfaceType::U32, &[0x06]);
assert_to_bytes!(InterfaceType::U64, &[0x07]);
assert_to_bytes!(InterfaceType::F32, &[0x08]);
assert_to_bytes!(InterfaceType::F64, &[0x09]);
assert_to_bytes!(InterfaceType::String, &[0x0a]);
assert_to_bytes!(InterfaceType::Anyref, &[0x0b]);
assert_to_bytes!(InterfaceType::I32, &[0x0c]);
assert_to_bytes!(InterfaceType::I64, &[0x0d]);
assert_to_bytes!(IType::S8, &[0x00]);
assert_to_bytes!(IType::S16, &[0x01]);
assert_to_bytes!(IType::S32, &[0x02]);
assert_to_bytes!(IType::S64, &[0x03]);
assert_to_bytes!(IType::U8, &[0x04]);
assert_to_bytes!(IType::U16, &[0x05]);
assert_to_bytes!(IType::U32, &[0x06]);
assert_to_bytes!(IType::U64, &[0x07]);
assert_to_bytes!(IType::F32, &[0x08]);
assert_to_bytes!(IType::F64, &[0x09]);
assert_to_bytes!(IType::String, &[0x0a]);
assert_to_bytes!(IType::Anyref, &[0x0b]);
assert_to_bytes!(IType::I32, &[0x0c]);
assert_to_bytes!(IType::I64, &[0x0d]);
assert_to_bytes!(
InterfaceType::Record(RecordType {
fields: vec1![InterfaceType::String]
IType::Record(RecordType {
fields: vec1![IType::String]
}),
&[0x0e, 0x01, 0x0a]
);
@ -524,7 +372,7 @@ mod tests {
fn test_record_type() {
assert_to_bytes!(
RecordType {
fields: vec1![InterfaceType::String]
fields: vec1![IType::String]
},
&[
0x01, // 1 field
@ -533,7 +381,7 @@ mod tests {
);
assert_to_bytes!(
RecordType {
fields: vec1![InterfaceType::String, InterfaceType::I32]
fields: vec1![IType::String, IType::I32]
},
&[
0x02, // 2 fields
@ -544,11 +392,11 @@ mod tests {
assert_to_bytes!(
RecordType {
fields: vec1![
InterfaceType::String,
InterfaceType::Record(RecordType {
fields: vec1![InterfaceType::I32, InterfaceType::I32],
IType::String,
IType::Record(RecordType {
fields: vec1![IType::I32, IType::I32],
}),
InterfaceType::F64,
IType::F64,
],
},
&[
@ -593,8 +441,8 @@ mod tests {
fn test_type_function() {
assert_to_bytes!(
Type::Function {
inputs: vec![InterfaceType::I32, InterfaceType::I64],
outputs: vec![InterfaceType::S32],
inputs: vec![IType::I32, IType::I64],
outputs: vec![IType::S32],
},
&[
0x00, // function type
@ -611,7 +459,7 @@ mod tests {
fn test_type_record() {
assert_to_bytes!(
Type::Record(RecordType {
fields: vec1![InterfaceType::I32, InterfaceType::I64],
fields: vec1![IType::I32, IType::I64],
}),
&[
0x01, // record type
@ -660,8 +508,8 @@ mod tests {
assert_to_bytes!(
Interfaces {
types: vec![Type::Function {
inputs: vec![InterfaceType::S8],
outputs: vec![InterfaceType::S16],
inputs: vec![IType::S8],
outputs: vec![IType::S16],
}],
imports: vec![Import {
namespace: "ab",

View File

@ -7,13 +7,13 @@
//! ast::{Adapter, Export, Implementation, Import, Interfaces, Type},
//! encoders::wat::*,
//! interpreter::Instruction,
//! types::InterfaceType,
//! types::IType,
//! };
//!
//! let input: String = (&Interfaces {
//! types: vec![Type::Function {
//! inputs: vec![InterfaceType::I32],
//! outputs: vec![InterfaceType::S8],
//! inputs: vec![IType::I32],
//! outputs: vec![IType::S8],
//! }],
//! imports: vec![Import {
//! namespace: "ns",
@ -55,54 +55,10 @@
//! assert_eq!(input, output);
//! ```
use crate::{ast::*, interpreter::Instruction, types::*};
use crate::IType;
use crate::{ast::*, interpreter::Instruction};
use std::string::ToString;
/// Encode an `InterfaceType` into a string.
impl ToString for &InterfaceType {
fn to_string(&self) -> String {
match self {
InterfaceType::S8 => "s8".to_string(),
InterfaceType::S16 => "s16".to_string(),
InterfaceType::S32 => "s32".to_string(),
InterfaceType::S64 => "s64".to_string(),
InterfaceType::U8 => "u8".to_string(),
InterfaceType::U16 => "u16".to_string(),
InterfaceType::U32 => "u32".to_string(),
InterfaceType::U64 => "u64".to_string(),
InterfaceType::F32 => "f32".to_string(),
InterfaceType::F64 => "f64".to_string(),
InterfaceType::String => "string".to_string(),
InterfaceType::Array(ty) => format!("array ({})", ty.as_ref().to_string()),
InterfaceType::Anyref => "anyref".to_string(),
InterfaceType::I32 => "i32".to_string(),
InterfaceType::I64 => "i64".to_string(),
InterfaceType::Record(record_type_id) => format!("record {}", record_type_id),
}
}
}
impl ToString for &RecordType {
fn to_string(&self) -> String {
format!(
"record ${} (\n{fields})",
self.name,
fields = self
.fields
.iter()
.fold(String::new(), |mut accumulator, field_type| {
accumulator.push(' ');
accumulator.push_str(&format!(
"field ${}: {}\n",
field_type.name,
(&field_type.ty).to_string()
));
accumulator
}),
)
}
}
/// Encode an `Instruction` into a string.
impl ToString for &Instruction {
fn to_string(&self) -> String {
@ -167,7 +123,7 @@ impl ToString for &Instruction {
}
}
/// Encode a list of `InterfaceType` representing inputs into a
/// Encode a list of `IType` representing inputs into a
/// string.
fn encode_function_arguments(arguments: &[FunctionArg]) -> String {
// here we know that arg_names and arg_types have the same length
@ -190,9 +146,9 @@ fn encode_function_arguments(arguments: &[FunctionArg]) -> String {
}
}
/// Encode a list of `InterfaceType` representing outputs into a
/// Encode a list of `IType` representing outputs into a
/// string.
fn output_types_to_result(output_types: &[InterfaceType]) -> String {
fn output_types_to_result(output_types: &[IType]) -> String {
if output_types.is_empty() {
"".into()
} else {
@ -384,22 +340,22 @@ mod tests {
#[test]
fn test_interface_types() {
let inputs: Vec<String> = vec![
(&InterfaceType::S8).to_string(),
(&InterfaceType::S16).to_string(),
(&InterfaceType::S32).to_string(),
(&InterfaceType::S64).to_string(),
(&InterfaceType::U8).to_string(),
(&InterfaceType::U16).to_string(),
(&InterfaceType::U32).to_string(),
(&InterfaceType::U64).to_string(),
(&InterfaceType::F32).to_string(),
(&InterfaceType::F64).to_string(),
(&InterfaceType::String).to_string(),
(&InterfaceType::Anyref).to_string(),
(&InterfaceType::I32).to_string(),
(&InterfaceType::I64).to_string(),
(&InterfaceType::Record(RecordType {
fields: vec1![InterfaceType::String],
(&IType::S8).to_string(),
(&IType::S16).to_string(),
(&IType::S32).to_string(),
(&IType::S64).to_string(),
(&IType::U8).to_string(),
(&IType::U16).to_string(),
(&IType::U32).to_string(),
(&IType::U64).to_string(),
(&IType::F32).to_string(),
(&IType::F64).to_string(),
(&IType::String).to_string(),
(&IType::Anyref).to_string(),
(&IType::I32).to_string(),
(&IType::I64).to_string(),
(&IType::Record(RecordType {
fields: vec1![IType::String],
}))
.to_string(),
];
@ -428,20 +384,20 @@ mod tests {
fn test_record_type() {
let inputs = vec![
(&RecordType {
fields: vec1![InterfaceType::String],
fields: vec1![IType::String],
})
.to_string(),
(&RecordType {
fields: vec1![InterfaceType::String, InterfaceType::I32],
fields: vec1![IType::String, IType::I32],
})
.to_string(),
(&RecordType {
fields: vec1![
InterfaceType::String,
InterfaceType::Record(RecordType {
fields: vec1![InterfaceType::I32, InterfaceType::I32],
IType::String,
IType::Record(RecordType {
fields: vec1![IType::I32, IType::I32],
}),
InterfaceType::F64,
IType::F64,
],
})
.to_string(),
@ -549,18 +505,18 @@ mod tests {
fn test_types() {
let inputs: Vec<String> = vec![
(&Type::Function {
inputs: vec![InterfaceType::I32, InterfaceType::F32],
outputs: vec![InterfaceType::I32],
inputs: vec![IType::I32, IType::F32],
outputs: vec![IType::I32],
})
.to_string(),
(&Type::Function {
inputs: vec![InterfaceType::I32],
inputs: vec![IType::I32],
outputs: vec![],
})
.to_string(),
(&Type::Function {
inputs: vec![],
outputs: vec![InterfaceType::I32],
outputs: vec![IType::I32],
})
.to_string(),
(&Type::Function {
@ -569,7 +525,7 @@ mod tests {
})
.to_string(),
(&Type::Record(RecordType {
fields: vec1![InterfaceType::String, InterfaceType::I32],
fields: vec1![IType::String, IType::I32],
}))
.to_string(),
];
@ -630,8 +586,8 @@ mod tests {
fn test_interfaces() {
let input: String = (&Interfaces {
types: vec![Type::Function {
inputs: vec![InterfaceType::I32],
outputs: vec![InterfaceType::S8],
inputs: vec![IType::I32],
outputs: vec![IType::S8],
}],
imports: vec![Import {
namespace: "ns",

View File

@ -1,8 +1,9 @@
//! The error module contains all the data structures that represent
//! an error.
use crate::values::InterfaceValue;
use crate::{ast::TypeKind, interpreter::Instruction, types::InterfaceType};
use crate::IType;
use crate::IValue;
use crate::{ast::TypeKind, interpreter::Instruction};
use std::{
error::Error,
fmt::{self, Display, Formatter},
@ -11,34 +12,14 @@ use std::{
string::{self, ToString},
};
pub use fluence_it_types::WasmValueNativeCastError;
/// A type alias for instruction's results.
pub type InstructionResult<T> = Result<T, InstructionError>;
/// A type alias for the interpreter result.
pub type InterpreterResult<T> = Result<T, InstructionError>;
/// Structure to represent errors when casting from an `InterfaceType`
/// to a native value.
#[derive(Debug)]
pub struct WasmValueNativeCastError {
/// The initial type.
pub from: InterfaceValue,
/// The targeted type.
///
/// `InterfaceType` is used to represent the native type by
/// associativity.
pub to: InterfaceType,
}
impl Error for WasmValueNativeCastError {}
impl Display for WasmValueNativeCastError {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "{:?}", self)
}
}
/// Structure to represent the errors for instructions.
#[derive(Debug)]
pub struct InstructionError {
@ -86,20 +67,20 @@ pub enum InstructionErrorKind {
/// Failed to cast from `from` to `to`.
LoweringLifting {
/// The initial type.
from: InterfaceType,
from: IType,
/// The targeted type.
to: InterfaceType,
to: IType,
},
/// Read a value from the stack, but it doesn't have the expected
/// type.
InvalidValueOnTheStack {
/// The expected type.
expected_type: InterfaceType,
expected_type: IType,
/// The received type.
received_value: InterfaceValue,
received_value: IValue,
},
/// Need to read some values from the stack, but it doesn't
@ -122,10 +103,10 @@ pub enum InstructionErrorKind {
function_index: u32,
/// The expected signature.
expected: (Vec<InterfaceType>, Vec<InterfaceType>),
expected: (Vec<IType>, Vec<IType>),
/// The received signature.
received: (Vec<InterfaceType>, Vec<InterfaceType>),
received: (Vec<IType>, Vec<IType>),
},
/// Failed to call a local or import function.

View File

@ -29,9 +29,9 @@ mod tests {
test_executable_instruction!(
test_argument_get =
instructions: [Instruction::ArgumentGet { index: 0 }],
invocation_inputs: [InterfaceValue::I32(42)],
invocation_inputs: [IValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
stack: [IValue::I32(42)],
);
test_executable_instruction!(
@ -41,20 +41,20 @@ mod tests {
Instruction::ArgumentGet { index: 1 },
],
invocation_inputs: [
InterfaceValue::I32(7),
InterfaceValue::I32(42),
IValue::I32(7),
IValue::I32(42),
],
instance: Instance::new(),
stack: [
InterfaceValue::I32(7),
InterfaceValue::I32(42),
IValue::I32(7),
IValue::I32(42),
],
);
test_executable_instruction!(
test_argument_get__invalid_index =
instructions: [Instruction::ArgumentGet { index: 1 }],
invocation_inputs: [InterfaceValue::I32(42)],
invocation_inputs: [IValue::I32(42)],
instance: Instance::new(),
error: "`arg.get 1` cannot access invocation inputs #1 because it doesn't exist"
);

View File

@ -6,19 +6,18 @@ use crate::interpreter::instructions::to_native;
use crate::{
errors::{InstructionError, InstructionErrorKind},
interpreter::Instruction,
types::InterfaceType,
values::InterfaceValue,
IType, IValue,
};
use std::convert::TryInto;
pub(super) fn array_lift_memory_<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance Instance,
value_type: &InterfaceType,
value_type: &IType,
offset: usize,
size: usize,
instruction: Instruction,
) -> Result<Vec<InterfaceValue>, InstructionError>
) -> Result<Vec<IValue>, InstructionError>
where
Export: crate::interpreter::wasm::structures::Export,
LocalImport: crate::interpreter::wasm::structures::LocalImport,
@ -38,74 +37,58 @@ where
let data = read_from_instance_mem(instance, instruction.clone(), offset, size)?;
let result_array = match value_type {
InterfaceType::S8 => {
IType::S8 => {
let data = transmute_vec::<u8, i8>(data).unwrap();
data.into_iter().map(InterfaceValue::S8).collect::<Vec<_>>()
data.into_iter().map(IValue::S8).collect::<Vec<_>>()
}
InterfaceType::S16 => {
IType::S16 => {
let data = transmute_many::<i16, AllOrNothingGuard>(&data).unwrap();
data.iter()
.map(|v| InterfaceValue::S16(*v))
.collect::<Vec<_>>()
data.iter().map(|v| IValue::S16(*v)).collect::<Vec<_>>()
}
InterfaceType::S32 => {
IType::S32 => {
let data = transmute_many::<i32, AllOrNothingGuard>(&data).unwrap();
data.iter()
.map(|v| InterfaceValue::S32(*v))
.collect::<Vec<_>>()
data.iter().map(|v| IValue::S32(*v)).collect::<Vec<_>>()
}
InterfaceType::S64 => {
IType::S64 => {
let data = transmute_many::<i64, AllOrNothingGuard>(&data).unwrap();
data.iter()
.map(|v| InterfaceValue::S64(*v))
.collect::<Vec<_>>()
data.iter().map(|v| IValue::S64(*v)).collect::<Vec<_>>()
}
InterfaceType::I32 => {
IType::I32 => {
let data = transmute_many::<i32, AllOrNothingGuard>(&data).unwrap();
data.iter()
.map(|v| InterfaceValue::I32(*v))
.collect::<Vec<_>>()
data.iter().map(|v| IValue::I32(*v)).collect::<Vec<_>>()
}
InterfaceType::I64 => {
IType::I64 => {
let data = transmute_many::<i64, AllOrNothingGuard>(&data).unwrap();
data.iter()
.map(|v| InterfaceValue::S64(*v))
.collect::<Vec<_>>()
data.iter().map(|v| IValue::S64(*v)).collect::<Vec<_>>()
}
InterfaceType::U8 => data.into_iter().map(InterfaceValue::U8).collect::<Vec<_>>(),
InterfaceType::U16 => {
IType::U8 => data.into_iter().map(IValue::U8).collect::<Vec<_>>(),
IType::U16 => {
let data = transmute_many::<u16, AllOrNothingGuard>(&data).unwrap();
data.iter()
.map(|v| InterfaceValue::U16(*v))
.collect::<Vec<_>>()
data.iter().map(|v| IValue::U16(*v)).collect::<Vec<_>>()
}
InterfaceType::U32 => {
IType::U32 => {
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
data.iter().map(|v| IValue::U32(*v)).collect::<Vec<_>>()
}
IType::U64 => {
let data = transmute_many::<u64, AllOrNothingGuard>(&data).unwrap();
data.iter().map(|v| IValue::U64(*v)).collect::<Vec<_>>()
}
IType::F32 => {
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
data.iter()
.map(|v| InterfaceValue::U32(*v))
.map(|v| IValue::F32(f32::from_bits(*v)))
.collect::<Vec<_>>()
}
InterfaceType::U64 => {
IType::F64 => {
let data = transmute_many::<u64, AllOrNothingGuard>(&data).unwrap();
data.iter()
.map(|v| InterfaceValue::U64(*v))
.map(|v| IValue::F64(f64::from_bits(*v)))
.collect::<Vec<_>>()
}
InterfaceType::F32 => {
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
data.iter()
.map(|v| InterfaceValue::F32(f32::from_bits(*v)))
.collect::<Vec<_>>()
}
InterfaceType::F64 => {
let data = transmute_many::<u64, AllOrNothingGuard>(&data).unwrap();
data.iter()
.map(|v| InterfaceValue::F64(f64::from_bits(*v)))
.collect::<Vec<_>>()
}
InterfaceType::Anyref => unimplemented!(),
InterfaceType::String => {
IType::Anyref => unimplemented!(),
IType::String => {
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
if data.is_empty() {
@ -134,12 +117,12 @@ where
// TODO: check
let string = String::from_utf8(string_mem).unwrap();
result.push(InterfaceValue::String(string));
result.push(IValue::String(string));
}
result
}
InterfaceType::Array(ty) => {
IType::Array(ty) => {
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
if data.is_empty() {
@ -167,12 +150,12 @@ where
instruction.clone(),
)?;
result.push(InterfaceValue::Array(value));
result.push(IValue::Array(value));
}
result
}
InterfaceType::Record(record_type_id) => {
IType::Record(record_type_id) => {
let record_type = instance.wit_record_by_id(*record_type_id).ok_or_else(|| {
InstructionError::new(
instruction.clone(),
@ -205,7 +188,7 @@ where
pub(crate) fn array_lift_memory<Instance, Export, LocalImport, Memory, MemoryView>(
instruction: Instruction,
value_type: InterfaceType,
value_type: IType,
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>
where
Export: crate::interpreter::wasm::structures::Export,
@ -253,7 +236,7 @@ where
)?;
log::trace!("array.lift_memory: pushing {:?} on the stack", array);
runtime.stack.push(InterfaceValue::Array(array));
runtime.stack.push(IValue::Array(array));
Ok(())
}
@ -263,7 +246,7 @@ where
pub(super) fn array_lower_memory_<Instance, Export, LocalImport, Memory, MemoryView>(
instance: &mut Instance,
instruction: Instruction,
array_values: Vec<InterfaceValue>,
array_values: Vec<IValue>,
) -> Result<(usize, usize), InstructionError>
where
Export: crate::interpreter::wasm::structures::Export,
@ -278,19 +261,19 @@ where
// here it's known that all interface values have the same type
for value in array_values {
match value {
InterfaceValue::S8(value) => result.push(value as _),
InterfaceValue::S16(value) => result.push(value as _),
InterfaceValue::S32(value) => result.push(value as _),
InterfaceValue::S64(value) => result.push(value as _),
InterfaceValue::U8(value) => result.push(value as _),
InterfaceValue::U16(value) => result.push(value as _),
InterfaceValue::U32(value) => result.push(value as _),
InterfaceValue::U64(value) => result.push(value as _),
InterfaceValue::I32(value) => result.push(value as _),
InterfaceValue::I64(value) => result.push(value as _),
InterfaceValue::F32(value) => result.push(value as _),
InterfaceValue::F64(value) => result.push(value.to_bits()),
InterfaceValue::String(value) => {
IValue::S8(value) => result.push(value as _),
IValue::S16(value) => result.push(value as _),
IValue::S32(value) => result.push(value as _),
IValue::S64(value) => result.push(value as _),
IValue::U8(value) => result.push(value as _),
IValue::U16(value) => result.push(value as _),
IValue::U32(value) => result.push(value as _),
IValue::U64(value) => result.push(value as _),
IValue::I32(value) => result.push(value as _),
IValue::I64(value) => result.push(value as _),
IValue::F32(value) => result.push(value as _),
IValue::F64(value) => result.push(value.to_bits()),
IValue::String(value) => {
let string_pointer = if !value.is_empty() {
write_to_instance_mem(instance, instruction.clone(), value.as_bytes())?
} else {
@ -301,7 +284,7 @@ where
result.push(value.len() as _);
}
InterfaceValue::Array(values) => {
IValue::Array(values) => {
let (array_offset, array_size) = if !values.is_empty() {
array_lower_memory_(instance, instruction.clone(), values)?
} else {
@ -312,7 +295,7 @@ where
result.push(array_size as _);
}
InterfaceValue::Record(values) => {
IValue::Record(values) => {
let record_offset =
super::record_lower_memory_(instance, instruction.clone(), values)?;
result.push(record_offset as _);
@ -328,7 +311,7 @@ where
pub(crate) fn array_lower_memory<Instance, Export, LocalImport, Memory, MemoryView>(
instruction: Instruction,
value_type: InterfaceType,
value_type: IType,
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>
where
Export: crate::interpreter::wasm::structures::Export,
@ -351,7 +334,7 @@ where
})?;
match stack_value {
InterfaceValue::Array(values) => {
IValue::Array(values) => {
log::trace!("array.lower_memory: obtained {:?} values on the stack for interface type {:?}", values, value_type);
for value in values.iter() {
@ -371,15 +354,15 @@ where
offset,
size
);
runtime.stack.push(InterfaceValue::I32(offset as _));
runtime.stack.push(InterfaceValue::I32(size as _));
runtime.stack.push(IValue::I32(offset as _));
runtime.stack.push(IValue::I32(size as _));
Ok(())
}
_ => Err(InstructionError::new(
instruction.clone(),
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: InterfaceType::Array(Box::new(value_type.clone())),
expected_type: IType::Array(Box::new(value_type.clone())),
received_value: stack_value.clone(),
},
)),

View File

@ -31,7 +31,7 @@ executable_instruction!(
super::check_function_signature(&**instance, local_or_import, &inputs, instruction.clone())?;
log::info!("call-core: calling {} with arguments: {:?}", local_or_import.name(), inputs);
log::debug!("call-core: calling {} with arguments: {:?}", local_or_import.name(), inputs);
let outputs = local_or_import.call(&inputs).map_err(|_| {
InstructionError::new(
@ -42,7 +42,7 @@ executable_instruction!(
)
})?;
log::info!("call-core: call to {} succeeded with result {:?}", local_or_import.name(), outputs);
log::debug!("call-core: call to {} succeeded with result {:?}", local_or_import.name(), outputs);
for output in outputs.into_iter() {
runtime.stack.push(output)
@ -63,11 +63,11 @@ mod tests {
Instruction::CallCore { function_index: 42 },
],
invocation_inputs: [
InterfaceValue::I32(3),
InterfaceValue::I32(4),
IValue::I32(3),
IValue::I32(4),
],
instance: Instance::new(),
stack: [InterfaceValue::I32(12)],
stack: [IValue::I32(12)],
);
test_executable_instruction!(
@ -76,8 +76,8 @@ mod tests {
Instruction::CallCore { function_index: 42 },
],
invocation_inputs: [
InterfaceValue::I32(3),
InterfaceValue::I32(4),
IValue::I32(3),
IValue::I32(4),
],
instance: Default::default(),
error: r#"`call-core 42` the local or import function `42` doesn't exist"#,
@ -91,8 +91,8 @@ mod tests {
// ^^ `42` expects 2 values on the stack, only one is present
],
invocation_inputs: [
InterfaceValue::I32(3),
InterfaceValue::I32(4),
IValue::I32(3),
IValue::I32(4),
],
instance: Instance::new(),
error: r#"`call-core 42` needed to read `2` value(s) from the stack, but it doesn't contain enough data"#,
@ -106,8 +106,8 @@ mod tests {
Instruction::CallCore { function_index: 42 },
],
invocation_inputs: [
InterfaceValue::I32(3),
InterfaceValue::I64(4),
IValue::I32(3),
IValue::I64(4),
// ^^^ mismatch with `42` signature
],
instance: Instance::new(),
@ -122,8 +122,8 @@ mod tests {
Instruction::CallCore { function_index: 42 },
],
invocation_inputs: [
InterfaceValue::I32(3),
InterfaceValue::I32(4),
IValue::I32(3),
IValue::I32(4),
],
instance: Instance {
locals_or_imports: {
@ -131,8 +131,8 @@ mod tests {
hashmap.insert(
42,
LocalImport {
inputs: vec![InterfaceType::I32, InterfaceType::I32],
outputs: vec![InterfaceType::I32],
inputs: vec![IType::I32, IType::I32],
outputs: vec![IType::I32],
function: |_| Err(()),
// ^^^^^^^ function fails
},
@ -153,8 +153,8 @@ mod tests {
Instruction::CallCore { function_index: 42 },
],
invocation_inputs: [
InterfaceValue::I32(3),
InterfaceValue::I32(4),
IValue::I32(3),
IValue::I32(4),
],
instance: Instance {
locals_or_imports: {
@ -162,8 +162,8 @@ mod tests {
hashmap.insert(
42,
LocalImport {
inputs: vec![InterfaceType::I32, InterfaceType::I32],
outputs: vec![InterfaceType::I32],
inputs: vec![IType::I32, IType::I32],
outputs: vec![IType::I32],
function: |_| Ok(vec![]),
// ^^^^^^^^^^ void
},

View File

@ -8,27 +8,29 @@ mod strings;
mod swap2;
mod utils;
use crate::interpreter::wasm;
use crate::types::InterfaceType;
use crate::vec1::Vec1;
use crate::{
errors::{InstructionError, InstructionErrorKind, InstructionResult, WasmValueNativeCastError},
values::{InterfaceValue, NativeType},
use crate::errors::{
InstructionError, InstructionErrorKind, InstructionResult, WasmValueNativeCastError,
};
use crate::interpreter::wasm;
use crate::IType;
use crate::IValue;
use crate::NEVec;
pub(crate) use argument_get::argument_get;
pub(crate) use arrays::*;
pub(crate) use call_core::call_core;
pub(crate) use dup::dup;
pub(crate) use numbers::*;
pub(crate) use records::*;
use std::convert::TryFrom;
pub(crate) use strings::*;
pub(crate) use swap2::swap2;
pub(self) use utils::*;
use fluence_it_types::NativeType;
use serde::Deserialize;
use serde::Serialize;
use std::convert::TryFrom;
pub(self) const ALLOCATE_FUNC_INDEX: u32 = 0;
pub(self) const DEALLOCATE_FUNC_INDEX: u32 = 1;
@ -155,13 +157,13 @@ pub enum Instruction {
/// The `array.lift_memory` instruction.
ArrayLiftMemory {
/// Array value type.
value_type: InterfaceType,
value_type: IType,
},
/// The `array.lower_memory` instruction.
ArrayLowerMemory {
/// Array value type.
value_type: InterfaceType,
value_type: IType,
},
/*
@ -198,13 +200,13 @@ pub enum Instruction {
}
/// Just a short helper to map the error of a cast from an
/// `InterfaceValue` to a native value.
/// `IValue` to a native value.
pub(crate) fn to_native<'a, T>(
wit_value: &'a InterfaceValue,
wit_value: &'a IValue,
instruction: Instruction,
) -> InstructionResult<T>
where
T: NativeType + TryFrom<&'a InterfaceValue, Error = WasmValueNativeCastError>,
T: NativeType + TryFrom<&'a IValue, Error = WasmValueNativeCastError>,
{
T::try_from(wit_value)
.map_err(|error| InstructionError::new(instruction, InstructionErrorKind::ToNative(error)))
@ -220,7 +222,7 @@ pub(crate) fn check_function_signature<
>(
instance: &'instance Instance,
local_import: &LocalImport,
values: &[InterfaceValue],
values: &[IValue],
instruction: Instruction,
) -> Result<(), InstructionError>
where
@ -249,8 +251,8 @@ pub(crate) fn is_value_compatible_to_type<
MemoryView,
>(
instance: &'instance Instance,
interface_type: &InterfaceType,
interface_value: &InterfaceValue,
interface_type: &IType,
interface_value: &IValue,
instruction: Instruction,
) -> Result<(), InstructionError>
where
@ -261,27 +263,27 @@ where
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
{
match (&interface_type, interface_value) {
(InterfaceType::S8, InterfaceValue::S8(_)) => Ok(()),
(InterfaceType::S16, InterfaceValue::S16(_)) => Ok(()),
(InterfaceType::S32, InterfaceValue::S32(_)) => Ok(()),
(InterfaceType::S64, InterfaceValue::S64(_)) => Ok(()),
(InterfaceType::U8, InterfaceValue::U8(_)) => Ok(()),
(InterfaceType::U16, InterfaceValue::U16(_)) => Ok(()),
(InterfaceType::U32, InterfaceValue::U32(_)) => Ok(()),
(InterfaceType::U64, InterfaceValue::U64(_)) => Ok(()),
(InterfaceType::I32, InterfaceValue::I32(_)) => Ok(()),
(InterfaceType::I64, InterfaceValue::I64(_)) => Ok(()),
(InterfaceType::F32, InterfaceValue::F32(_)) => Ok(()),
(InterfaceType::F64, InterfaceValue::F64(_)) => Ok(()),
(InterfaceType::String, InterfaceValue::String(_)) => Ok(()),
(InterfaceType::Array(ty), InterfaceValue::Array(values)) => {
(IType::S8, IValue::S8(_)) => Ok(()),
(IType::S16, IValue::S16(_)) => Ok(()),
(IType::S32, IValue::S32(_)) => Ok(()),
(IType::S64, IValue::S64(_)) => Ok(()),
(IType::U8, IValue::U8(_)) => Ok(()),
(IType::U16, IValue::U16(_)) => Ok(()),
(IType::U32, IValue::U32(_)) => Ok(()),
(IType::U64, IValue::U64(_)) => Ok(()),
(IType::I32, IValue::I32(_)) => Ok(()),
(IType::I64, IValue::I64(_)) => Ok(()),
(IType::F32, IValue::F32(_)) => Ok(()),
(IType::F64, IValue::F64(_)) => Ok(()),
(IType::String, IValue::String(_)) => Ok(()),
(IType::Array(ty), IValue::Array(values)) => {
for value in values {
is_value_compatible_to_type(instance, ty, value, instruction.clone())?
}
Ok(())
}
(InterfaceType::Record(ref record_type_id), InterfaceValue::Record(record_fields)) => {
(IType::Record(ref record_type_id), IValue::Record(record_fields)) => {
is_record_fields_compatible_to_type(
instance,
*record_type_id,
@ -311,7 +313,7 @@ pub(crate) fn is_record_fields_compatible_to_type<
>(
instance: &'instance Instance,
record_type_id: u64,
record_fields: &[InterfaceValue],
record_fields: &[IValue],
instruction: Instruction,
) -> Result<(), InstructionError>
where
@ -332,9 +334,9 @@ where
return Err(InstructionError::new(
instruction.clone(),
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: InterfaceType::Record(record_type_id),
expected_type: IType::Record(record_type_id),
// unwrap is safe here - len's been already checked
received_value: InterfaceValue::Record(Vec1::new(record_fields.to_vec()).unwrap()),
received_value: IValue::Record(NEVec::new(record_fields.to_vec()).unwrap()),
},
));
}
@ -359,9 +361,9 @@ pub(crate) mod tests {
use std::{cell::Cell, collections::HashMap, convert::TryInto, ops::Deref, rc::Rc};
pub(crate) struct Export {
pub(crate) inputs: Vec<InterfaceType>,
pub(crate) outputs: Vec<InterfaceType>,
pub(crate) function: fn(arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()>,
pub(crate) inputs: Vec<IType>,
pub(crate) outputs: Vec<IType>,
pub(crate) function: fn(arguments: &[IValue]) -> Result<Vec<IValue>, ()>,
}
impl wasm::structures::Export for Export {
@ -373,23 +375,23 @@ pub(crate) mod tests {
self.outputs.len()
}
fn arguments(&self) -> &[InterfaceType] {
fn arguments(&self) -> &[IType] {
&self.inputs
}
fn outputs(&self) -> &[InterfaceType] {
fn outputs(&self) -> &[IType] {
&self.outputs
}
fn call(&self, arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()> {
fn call(&self, arguments: &[IValue]) -> Result<Vec<IValue>, ()> {
(self.function)(arguments)
}
}
pub(crate) struct LocalImport {
pub(crate) inputs: Vec<InterfaceType>,
pub(crate) outputs: Vec<InterfaceType>,
pub(crate) function: fn(arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()>,
pub(crate) inputs: Vec<IType>,
pub(crate) outputs: Vec<IType>,
pub(crate) function: fn(arguments: &[IValue]) -> Result<Vec<IValue>, ()>,
}
impl wasm::structures::LocalImport for LocalImport {
@ -401,15 +403,15 @@ pub(crate) mod tests {
self.outputs.len()
}
fn arguments(&self) -> &[InterfaceType] {
fn arguments(&self) -> &[IType] {
&self.inputs
}
fn outputs(&self) -> &[InterfaceType] {
fn outputs(&self) -> &[IType] {
&self.outputs
}
fn call(&self, arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()> {
fn call(&self, arguments: &[IValue]) -> Result<Vec<IValue>, ()> {
(self.function)(arguments)
}
}
@ -462,13 +464,13 @@ pub(crate) mod tests {
hashmap.insert(
"sum".into(),
Export {
inputs: vec![InterfaceType::I32, InterfaceType::I32],
outputs: vec![InterfaceType::I32],
function: |arguments: &[InterfaceValue]| {
inputs: vec![IType::I32, IType::I32],
outputs: vec![IType::I32],
function: |arguments: &[IValue]| {
let a: i32 = (&arguments[0]).try_into().unwrap();
let b: i32 = (&arguments[1]).try_into().unwrap();
Ok(vec![InterfaceValue::I32(a + b)])
Ok(vec![IValue::I32(a + b)])
},
},
);
@ -481,13 +483,13 @@ pub(crate) mod tests {
hashmap.insert(
42,
LocalImport {
inputs: vec![InterfaceType::I32, InterfaceType::I32],
outputs: vec![InterfaceType::I32],
function: |arguments: &[InterfaceValue]| {
inputs: vec![IType::I32, IType::I32],
outputs: vec![IType::I32],
function: |arguments: &[IValue]| {
let a: i32 = (&arguments[0]).try_into().unwrap();
let b: i32 = (&arguments[1]).try_into().unwrap();
Ok(vec![InterfaceValue::I32(a * b)])
Ok(vec![IValue::I32(a * b)])
},
},
);
@ -495,12 +497,12 @@ pub(crate) mod tests {
hashmap.insert(
43,
LocalImport {
inputs: vec![InterfaceType::I32],
outputs: vec![InterfaceType::I32],
function: |arguments: &[InterfaceValue]| {
inputs: vec![IType::I32],
outputs: vec![IType::I32],
function: |arguments: &[IValue]| {
let _size: i32 = (&arguments[0]).try_into().unwrap();
Ok(vec![InterfaceValue::I32(0)])
Ok(vec![IValue::I32(0)])
},
},
);
@ -513,27 +515,27 @@ pub(crate) mod tests {
fields: vec1![
RecordFieldType {
name: String::from("field_0"),
ty: InterfaceType::I32,
ty: IType::I32,
},
RecordFieldType {
name: String::from("field_1"),
ty: InterfaceType::Record(RecordType {
ty: IType::Record(RecordType {
name: String::from("RecordType1"),
fields: vec1![
RecordFieldType {
name: String::from("field_0"),
ty: InterfaceType::String,
ty: IType::String,
},
RecordFieldType {
name: String::from("field1"),
ty: InterfaceType::F32
ty: IType::F32
}
],
}),
},
RecordFieldType {
name: String::from("field_2"),
ty: InterfaceType::I64,
ty: IType::I64,
}
],
})],

View File

@ -1,8 +1,8 @@
use crate::IType;
use crate::IValue;
use crate::{
errors::{InstructionError, InstructionErrorKind},
interpreter::Instruction,
types::InterfaceType,
values::InterfaceValue,
};
use std::convert::TryInto;
@ -12,17 +12,17 @@ macro_rules! lowering_lifting {
$instruction_function_name(instruction: Instruction) -> _ {
move |runtime| -> _ {
match runtime.stack.pop1() {
Some(InterfaceValue::$from_variant(value)) => {
Some(IValue::$from_variant(value)) => {
runtime
.stack
.push({
let converted_value = InterfaceValue::$to_variant(value.try_into().map_err(
let converted_value = IValue::$to_variant(value.try_into().map_err(
|_| {
InstructionError::new(
instruction.clone(),
InstructionErrorKind::LoweringLifting {
from: InterfaceType::$from_variant,
to: InterfaceType::$to_variant
from: IType::$from_variant,
to: IType::$to_variant
},
)
},
@ -37,7 +37,7 @@ macro_rules! lowering_lifting {
return Err(InstructionError::new(
instruction.clone(),
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: InterfaceType::$from_variant,
expected_type: IType::$from_variant,
received_value: wrong_value,
}
))
@ -96,7 +96,7 @@ mod tests {
test_executable_instruction!(
test_convert_fails =
instructions: [Instruction::ArgumentGet { index: 0}, Instruction::S8FromI32],
invocation_inputs: [InterfaceValue::I32(128)],
invocation_inputs: [IValue::I32(128)],
instance: Instance::new(),
error: "`s8.from_i32` failed to cast `I32` to `S8`"
);
@ -104,7 +104,7 @@ mod tests {
test_executable_instruction!(
test_type_mismatch =
instructions: [Instruction::ArgumentGet { index: 0}, Instruction::S8FromI32],
invocation_inputs: [InterfaceValue::I64(42)],
invocation_inputs: [IValue::I64(42)],
instance: Instance::new(),
error: "`s8.from_i32` read a value of type `I64` from the stack, but the type `I32` was expected"
);
@ -112,7 +112,7 @@ mod tests {
test_executable_instruction!(
test_no_value_on_the_stack =
instructions: [Instruction::S8FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
invocation_inputs: [IValue::I32(42)],
instance: Instance::new(),
error: "`s8.from_i32` needed to read `1` value(s) from the stack, but it doesn't contain enough data"
);
@ -120,256 +120,256 @@ mod tests {
test_executable_instruction!(
test_s8_from_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S8FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
invocation_inputs: [IValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::S8(42)],
stack: [IValue::S8(42)],
);
test_executable_instruction!(
test_s8_from_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S8FromI64],
invocation_inputs: [InterfaceValue::I64(42)],
invocation_inputs: [IValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::S8(42)],
stack: [IValue::S8(42)],
);
test_executable_instruction!(
test_s16_from_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S16FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
invocation_inputs: [IValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::S16(42)],
stack: [IValue::S16(42)],
);
test_executable_instruction!(
test_s16_from_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S16FromI64],
invocation_inputs: [InterfaceValue::I64(42)],
invocation_inputs: [IValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::S16(42)],
stack: [IValue::S16(42)],
);
test_executable_instruction!(
test_s32_from_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S32FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
invocation_inputs: [IValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::S32(42)],
stack: [IValue::S32(42)],
);
test_executable_instruction!(
test_s32_from_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S32FromI64],
invocation_inputs: [InterfaceValue::I64(42)],
invocation_inputs: [IValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::S32(42)],
stack: [IValue::S32(42)],
);
test_executable_instruction!(
test_s64_from_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S64FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
invocation_inputs: [IValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::S64(42)],
stack: [IValue::S64(42)],
);
test_executable_instruction!(
test_s64_from_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S64FromI64],
invocation_inputs: [InterfaceValue::I64(42)],
invocation_inputs: [IValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::S64(42)],
stack: [IValue::S64(42)],
);
test_executable_instruction!(
test_i32_from_s8 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromS8],
invocation_inputs: [InterfaceValue::S8(42)],
invocation_inputs: [IValue::S8(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
stack: [IValue::I32(42)],
);
test_executable_instruction!(
test_i32_from_s16 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromS16],
invocation_inputs: [InterfaceValue::S16(42)],
invocation_inputs: [IValue::S16(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
stack: [IValue::I32(42)],
);
test_executable_instruction!(
test_i32_from_s32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromS32],
invocation_inputs: [InterfaceValue::S32(42)],
invocation_inputs: [IValue::S32(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
stack: [IValue::I32(42)],
);
test_executable_instruction!(
test_i32_from_s64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromS64],
invocation_inputs: [InterfaceValue::S64(42)],
invocation_inputs: [IValue::S64(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
stack: [IValue::I32(42)],
);
test_executable_instruction!(
test_i64_from_s8 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromS8],
invocation_inputs: [InterfaceValue::S8(42)],
invocation_inputs: [IValue::S8(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
stack: [IValue::I64(42)],
);
test_executable_instruction!(
test_i64_from_s16 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromS16],
invocation_inputs: [InterfaceValue::S16(42)],
invocation_inputs: [IValue::S16(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
stack: [IValue::I64(42)],
);
test_executable_instruction!(
test_i64_from_s32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromS32],
invocation_inputs: [InterfaceValue::S32(42)],
invocation_inputs: [IValue::S32(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
stack: [IValue::I64(42)],
);
test_executable_instruction!(
test_i64_from_s64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromS64],
invocation_inputs: [InterfaceValue::S64(42)],
invocation_inputs: [IValue::S64(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
stack: [IValue::I64(42)],
);
test_executable_instruction!(
test_u8_from_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U8FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
invocation_inputs: [IValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::U8(42)],
stack: [IValue::U8(42)],
);
test_executable_instruction!(
test_u8_from_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U8FromI64],
invocation_inputs: [InterfaceValue::I64(42)],
invocation_inputs: [IValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::U8(42)],
stack: [IValue::U8(42)],
);
test_executable_instruction!(
test_u16_from_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U16FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
invocation_inputs: [IValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::U16(42)],
stack: [IValue::U16(42)],
);
test_executable_instruction!(
test_u16_from_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U16FromI64],
invocation_inputs: [InterfaceValue::I64(42)],
invocation_inputs: [IValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::U16(42)],
stack: [IValue::U16(42)],
);
test_executable_instruction!(
test_u32_from_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U32FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
invocation_inputs: [IValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::U32(42)],
stack: [IValue::U32(42)],
);
test_executable_instruction!(
test_u32_from_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U32FromI64],
invocation_inputs: [InterfaceValue::I64(42)],
invocation_inputs: [IValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::U32(42)],
stack: [IValue::U32(42)],
);
test_executable_instruction!(
test_u64_from_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U64FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
invocation_inputs: [IValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::U64(42)],
stack: [IValue::U64(42)],
);
test_executable_instruction!(
test_u64_from_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U64FromI64],
invocation_inputs: [InterfaceValue::I64(42)],
invocation_inputs: [IValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::U64(42)],
stack: [IValue::U64(42)],
);
test_executable_instruction!(
test_i32_from_u8 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromU8],
invocation_inputs: [InterfaceValue::U8(42)],
invocation_inputs: [IValue::U8(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
stack: [IValue::I32(42)],
);
test_executable_instruction!(
test_i32_from_u16 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromU16],
invocation_inputs: [InterfaceValue::U16(42)],
invocation_inputs: [IValue::U16(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
stack: [IValue::I32(42)],
);
test_executable_instruction!(
test_i32_from_u32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromU32],
invocation_inputs: [InterfaceValue::U32(42)],
invocation_inputs: [IValue::U32(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
stack: [IValue::I32(42)],
);
test_executable_instruction!(
test_i32_from_u64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromU64],
invocation_inputs: [InterfaceValue::U64(42)],
invocation_inputs: [IValue::U64(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
stack: [IValue::I32(42)],
);
test_executable_instruction!(
test_i64_from_u8 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromU8],
invocation_inputs: [InterfaceValue::U8(42)],
invocation_inputs: [IValue::U8(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
stack: [IValue::I64(42)],
);
test_executable_instruction!(
test_i64_from_u16 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromU16],
invocation_inputs: [InterfaceValue::U16(42)],
invocation_inputs: [IValue::U16(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
stack: [IValue::I64(42)],
);
test_executable_instruction!(
test_i64_from_u32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromU32],
invocation_inputs: [InterfaceValue::U32(42)],
invocation_inputs: [IValue::U32(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
stack: [IValue::I64(42)],
);
test_executable_instruction!(
test_i64_from_u64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromU64],
invocation_inputs: [InterfaceValue::U64(42)],
invocation_inputs: [IValue::U64(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
stack: [IValue::I64(42)],
);
}

View File

@ -2,18 +2,31 @@ use super::read_from_instance_mem;
use super::write_to_instance_mem;
use crate::interpreter::instructions::{is_record_fields_compatible_to_type, to_native};
use crate::IRecordType;
use crate::IType;
use crate::IValue;
use crate::NEVec;
use crate::{
errors::{InstructionError, InstructionErrorKind},
interpreter::Instruction,
types::{InterfaceType, RecordType},
values::InterfaceValue,
vec1::Vec1,
};
use std::convert::TryInto;
/*
struct Record1 {
field1: String,
field2: i32,
}
// export
fn foo(t: Record1) {
// import
*/
/*
/// Build an `InterfaceValue::Record` based on values on the stack.
/// Build an `IValue::Record` based on values on the stack.
///
/// To fill a record, every field `field_1` to `field_n` must get its
/// value from the stack with `value_1` to `value_n`. It is not
@ -27,14 +40,14 @@ use std::convert::TryInto;
/// is possible to access to last positions). So a `VecDeque` type is
/// used: it is a double-ended queue.
fn record_lift_(
stack: &mut Stack<InterfaceValue>,
stack: &mut Stack<IValue>,
record_type: &RecordType,
) -> Result<InterfaceValue, InstructionErrorKind> {
) -> Result<IValue, InstructionErrorKind> {
let length = record_type.fields.len();
let mut values = VecDeque::with_capacity(length);
for field in record_type.fields.iter().rev() {
match field {
InterfaceType::Record(record_type) => {
IType::Record(record_type) => {
values.push_front(record_lift_(stack, &record_type)?)
}
ty => {
@ -50,8 +63,8 @@ fn record_lift_(
}
}
}
Ok(InterfaceValue::Record(
Vec1::new(values.into_iter().collect())
Ok(IValue::Record(
NEVec::new(values.into_iter().collect())
.expect("Record must have at least one field, zero given"),
))
}
@ -101,10 +114,10 @@ where
pub(super) fn record_lift_memory_<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance Instance,
record_type: &RecordType,
record_type: &IRecordType,
offset: usize,
instruction: Instruction,
) -> Result<InterfaceValue, InstructionError>
) -> Result<IValue, InstructionError>
where
Export: crate::interpreter::wasm::structures::Export,
LocalImport: crate::interpreter::wasm::structures::LocalImport,
@ -113,12 +126,12 @@ where
Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>
+ 'instance,
{
fn record_size(record_type: &RecordType) -> usize {
fn record_size(record_type: &IRecordType) -> usize {
let mut record_size = 0;
for field_type in record_type.fields.iter() {
let params_count = match field_type.ty {
InterfaceType::String | InterfaceType::Array(_) => 2,
IType::String | IType::Array(_) => 2,
_ => 1,
};
@ -140,42 +153,42 @@ where
for field in (*record_type.fields).iter() {
let value = data[field_id];
match &field.ty {
InterfaceType::S8 => {
values.push(InterfaceValue::S8(value as _));
IType::S8 => {
values.push(IValue::S8(value as _));
}
InterfaceType::S16 => {
values.push(InterfaceValue::S16(value as _));
IType::S16 => {
values.push(IValue::S16(value as _));
}
InterfaceType::S32 => {
values.push(InterfaceValue::S32(value as _));
IType::S32 => {
values.push(IValue::S32(value as _));
}
InterfaceType::S64 => {
values.push(InterfaceValue::S64(value as _));
IType::S64 => {
values.push(IValue::S64(value as _));
}
InterfaceType::I32 => {
values.push(InterfaceValue::I32(value as _));
IType::I32 => {
values.push(IValue::I32(value as _));
}
InterfaceType::I64 => {
values.push(InterfaceValue::I64(value as _));
IType::I64 => {
values.push(IValue::I64(value as _));
}
InterfaceType::U8 => {
values.push(InterfaceValue::U8(value as _));
IType::U8 => {
values.push(IValue::U8(value as _));
}
InterfaceType::U16 => {
values.push(InterfaceValue::U16(value as _));
IType::U16 => {
values.push(IValue::U16(value as _));
}
InterfaceType::U32 => {
values.push(InterfaceValue::U32(value as _));
IType::U32 => {
values.push(IValue::U32(value as _));
}
InterfaceType::U64 => {
values.push(InterfaceValue::U64(value as _));
IType::U64 => {
values.push(IValue::U64(value as _));
}
InterfaceType::F32 => {
values.push(InterfaceValue::F32(value as _));
IType::F32 => {
values.push(IValue::F32(value as _));
}
InterfaceType::F64 => values.push(InterfaceValue::F64(f64::from_bits(value))),
InterfaceType::Anyref => {}
InterfaceType::String => {
IType::F64 => values.push(IValue::F64(f64::from_bits(value))),
IType::Anyref => {}
IType::String => {
let string_offset = value;
field_id += 1;
let string_size = data[field_id];
@ -190,12 +203,12 @@ where
// TODO: check
let string = String::from_utf8(string_mem).unwrap();
values.push(InterfaceValue::String(string));
values.push(IValue::String(string));
} else {
values.push(InterfaceValue::String(String::new()));
values.push(IValue::String(String::new()));
}
}
InterfaceType::Array(ty) => {
IType::Array(ty) => {
let array_offset = value;
field_id += 1;
let array_size = data[field_id];
@ -208,12 +221,12 @@ where
array_size as _,
instruction.clone(),
)?;
values.push(InterfaceValue::Array(array));
values.push(IValue::Array(array));
} else {
values.push(InterfaceValue::Array(vec![]));
values.push(IValue::Array(vec![]));
}
}
InterfaceType::Record(record_type_id) => {
IType::Record(record_type_id) => {
let offset = value;
let record_type = instance.wit_record_by_id(*record_type_id).ok_or_else(|| {
@ -238,8 +251,8 @@ where
super::deallocate(instance, instruction, offset as _, size as _)?;
Ok(InterfaceValue::Record(
Vec1::new(values.into_iter().collect())
Ok(IValue::Record(
NEVec::new(values.into_iter().collect())
.expect("Record must have at least one field, zero given"),
))
}
@ -301,7 +314,7 @@ where
pub(super) fn record_lower_memory_<Instance, Export, LocalImport, Memory, MemoryView>(
instance: &mut Instance,
instruction: Instruction,
values: Vec1<InterfaceValue>,
values: NEVec<IValue>,
) -> Result<i32, InstructionError>
where
Export: crate::interpreter::wasm::structures::Export,
@ -315,19 +328,19 @@ where
for value in values.into_vec() {
match value {
InterfaceValue::S8(value) => result.push(value as _),
InterfaceValue::S16(value) => result.push(value as _),
InterfaceValue::S32(value) => result.push(value as _),
InterfaceValue::S64(value) => result.push(value as _),
InterfaceValue::U8(value) => result.push(value as _),
InterfaceValue::U16(value) => result.push(value as _),
InterfaceValue::U32(value) => result.push(value as _),
InterfaceValue::U64(value) => result.push(value as _),
InterfaceValue::I32(value) => result.push(value as _),
InterfaceValue::I64(value) => result.push(value as _),
InterfaceValue::F32(value) => result.push(value as _),
InterfaceValue::F64(value) => result.push(value.to_bits()),
InterfaceValue::String(value) => {
IValue::S8(value) => result.push(value as _),
IValue::S16(value) => result.push(value as _),
IValue::S32(value) => result.push(value as _),
IValue::S64(value) => result.push(value as _),
IValue::U8(value) => result.push(value as _),
IValue::U16(value) => result.push(value as _),
IValue::U32(value) => result.push(value as _),
IValue::U64(value) => result.push(value as _),
IValue::I32(value) => result.push(value as _),
IValue::I64(value) => result.push(value as _),
IValue::F32(value) => result.push(value as _),
IValue::F64(value) => result.push(value.to_bits()),
IValue::String(value) => {
let string_pointer = if !value.is_empty() {
write_to_instance_mem(instance, instruction.clone(), value.as_bytes())?
} else {
@ -338,7 +351,7 @@ where
result.push(value.len() as _);
}
InterfaceValue::Array(values) => {
IValue::Array(values) => {
let (offset, size) = if !values.is_empty() {
super::array_lower_memory_(instance, instruction.clone(), values)?
} else {
@ -349,7 +362,7 @@ where
result.push(size as _);
}
InterfaceValue::Record(values) => {
IValue::Record(values) => {
let record_ptr = record_lower_memory_(instance, instruction.clone(), values)?;
result.push(record_ptr as _);
@ -382,7 +395,7 @@ where
let instance = &mut runtime.wasm_instance;
match runtime.stack.pop1() {
Some(InterfaceValue::Record(record_fields)) => {
Some(IValue::Record(record_fields)) => {
is_record_fields_compatible_to_type(
&**instance,
record_type_id,
@ -396,14 +409,14 @@ where
record_lower_memory_(*instance, instruction.clone(), record_fields)?;
log::debug!("record.lower_memory: pushing {} on the stack", offset);
runtime.stack.push(InterfaceValue::I32(offset));
runtime.stack.push(IValue::I32(offset));
Ok(())
}
Some(value) => Err(InstructionError::new(
instruction.clone(),
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: InterfaceType::Record(record_type_id),
expected_type: IType::Record(record_type_id),
received_value: value,
},
)),
@ -452,10 +465,10 @@ where
}
};
match runtime.stack.pop1() {
Some(InterfaceValue::Record(record_values))
Some(IValue::Record(record_values))
if record_type == &(&*record_values).into() =>
{
let values = FlattenInterfaceValueIterator::new(&record_values);
let values = FlattenIValueIterator::new(&record_values);
for value in values {
runtime.stack.push(value.clone());
}
@ -464,7 +477,7 @@ where
Some(value) => Err(InstructionError::new(
instruction.clone(),
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: InterfaceType::Record(record_type.clone()),
expected_type: IType::Record(record_type.clone()),
received_type: (&value).into(),
},
)),

View File

@ -1,9 +1,9 @@
use super::to_native;
use crate::IType;
use crate::IValue;
use crate::{
errors::{InstructionError, InstructionErrorKind},
interpreter::Instruction,
types::InterfaceType,
values::InterfaceValue,
};
use std::{cell::Cell, convert::TryInto};
@ -39,7 +39,7 @@ executable_instruction!(
let memory_view = memory.view();
if length == 0 {
runtime.stack.push(InterfaceValue::String("".into()));
runtime.stack.push(IValue::String("".into()));
return Ok(())
}
@ -63,7 +63,7 @@ executable_instruction!(
.map_err(|error| InstructionError::new(instruction.clone(), InstructionErrorKind::String(error)))?;
log::debug!("string.lift_memory: pushing {:?} on the stack", string);
runtime.stack.push(InterfaceValue::String(string));
runtime.stack.push(IValue::String(string));
Ok(())
}
@ -110,8 +110,8 @@ executable_instruction!(
}
log::debug!("string.lower_memory: pushing {}, {} on the stack", string_pointer, string_length);
runtime.stack.push(InterfaceValue::I32(string_pointer as i32));
runtime.stack.push(InterfaceValue::I32(string_length));
runtime.stack.push(IValue::I32(string_pointer as i32));
runtime.stack.push(IValue::I32(string_length));
Ok(())
}
@ -122,11 +122,11 @@ executable_instruction!(
string_size(instruction: Instruction) -> _ {
move |runtime| -> _ {
match runtime.stack.pop1() {
Some(InterfaceValue::String(string)) => {
Some(IValue::String(string)) => {
let length = string.len() as i32;
log::debug!("string.size: pushing {} on the stack", length);
runtime.stack.push(InterfaceValue::I32(length));
runtime.stack.push(IValue::I32(length));
Ok(())
},
@ -134,7 +134,7 @@ executable_instruction!(
Some(value) => Err(InstructionError::new(
instruction.clone(),
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: InterfaceType::String,
expected_type: IType::String,
received_value: (&value).clone(),
},
)),
@ -158,16 +158,16 @@ mod tests {
Instruction::StringLiftMemory,
],
invocation_inputs: [
InterfaceValue::I32(0),
IValue::I32(0),
// ^^^^^^ pointer
InterfaceValue::I32(13),
IValue::I32(13),
// ^^^^^^^ length
],
instance: Instance {
memory: Memory::new("Hello, World!".as_bytes().iter().map(|u| Cell::new(*u)).collect()),
..Default::default()
},
stack: [InterfaceValue::String("Hello, World!".into())],
stack: [IValue::String("Hello, World!".into())],
);
test_executable_instruction!(
@ -178,14 +178,14 @@ mod tests {
Instruction::StringLiftMemory,
],
invocation_inputs: [
InterfaceValue::I32(0),
InterfaceValue::I32(0),
IValue::I32(0),
IValue::I32(0),
],
instance: Instance {
memory: Memory::new(vec![]),
..Default::default()
},
stack: [InterfaceValue::String("".into())],
stack: [IValue::String("".into())],
);
test_executable_instruction!(
@ -196,8 +196,8 @@ mod tests {
Instruction::StringLiftMemory,
],
invocation_inputs: [
InterfaceValue::I32(-42),
InterfaceValue::I32(13),
IValue::I32(-42),
IValue::I32(13),
],
instance: Instance {
memory: Memory::new("Hello!".as_bytes().iter().map(|u| Cell::new(*u)).collect()),
@ -214,8 +214,8 @@ mod tests {
Instruction::StringLiftMemory,
],
invocation_inputs: [
InterfaceValue::I32(0),
InterfaceValue::I32(-1),
IValue::I32(0),
IValue::I32(-1),
],
instance: Instance {
memory: Memory::new("Hello!".as_bytes().iter().map(|u| Cell::new(*u)).collect()),
@ -232,9 +232,9 @@ mod tests {
Instruction::StringLiftMemory,
],
invocation_inputs: [
InterfaceValue::I32(0),
IValue::I32(0),
// ^^^^^^ pointer
InterfaceValue::I32(13),
IValue::I32(13),
// ^^^^^^^ length is too long
],
instance: Instance {
@ -252,9 +252,9 @@ mod tests {
Instruction::StringLiftMemory,
],
invocation_inputs: [
InterfaceValue::I32(0),
IValue::I32(0),
// ^^^^^^ pointer
InterfaceValue::I32(4),
IValue::I32(4),
// ^^^^^^ length is too long
],
instance: Instance {
@ -272,8 +272,8 @@ mod tests {
// ^^^^^^^^^^^^^^^^ `string.lift_memory` expects 2 values on the stack, only one is present.
],
invocation_inputs: [
InterfaceValue::I32(0),
InterfaceValue::I32(13),
IValue::I32(0),
IValue::I32(13),
],
instance: Instance::new(),
error: r#"`string.lift_memory` needed to read `2` value(s) from the stack, but it doesn't contain enough data"#,
@ -289,12 +289,12 @@ mod tests {
Instruction::StringLowerMemory,
],
invocation_inputs: [InterfaceValue::String("Hello, World!".into())],
invocation_inputs: [IValue::String("Hello, World!".into())],
instance: Instance::new(),
stack: [
InterfaceValue::I32(0),
IValue::I32(0),
// ^^^^^^ pointer
InterfaceValue::I32(13),
IValue::I32(13),
// ^^^^^^^ length
]
);
@ -309,9 +309,9 @@ mod tests {
Instruction::StringLowerMemory,
Instruction::StringLiftMemory,
],
invocation_inputs: [InterfaceValue::String("Hello, World!".into())],
invocation_inputs: [IValue::String("Hello, World!".into())],
instance: Instance::new(),
stack: [InterfaceValue::String("Hello, World!".into())],
stack: [IValue::String("Hello, World!".into())],
);
test_executable_instruction!(
@ -330,9 +330,9 @@ mod tests {
Instruction::ArgumentGet { index: 0 },
Instruction::StringSize,
],
invocation_inputs: [InterfaceValue::String("Hello, World!".into())],
invocation_inputs: [IValue::String("Hello, World!".into())],
instance: Instance::new(),
stack: [InterfaceValue::I32(13)],
stack: [IValue::I32(13)],
);
test_executable_instruction!(
@ -351,7 +351,7 @@ mod tests {
Instruction::ArgumentGet { index: 0 },
Instruction::StringSize,
],
invocation_inputs: [InterfaceValue::I32(42)],
invocation_inputs: [IValue::I32(42)],
instance: Instance::new(),
error: r#"`string.size` read a value of type `I32` from the stack, but the type `String` was expected"#,
);

View File

@ -4,11 +4,11 @@ use crate::interpreter::wasm;
use crate::interpreter::wasm::structures::{FunctionIndex, TypedIndex};
use crate::interpreter::instructions::to_native;
use crate::IType;
use crate::IValue;
use crate::{
errors::{InstructionError, InstructionErrorKind},
interpreter::Instruction,
types::InterfaceType,
values::InterfaceValue,
};
pub(super) fn read_from_instance_mem<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
@ -115,14 +115,14 @@ where
instance,
ALLOCATE_FUNC_INDEX,
instruction.clone(),
vec![InterfaceValue::I32(size as _)],
vec![IValue::I32(size as _)],
)?;
if values.len() != 1 {
return Err(InstructionError::new(
instruction,
InstructionErrorKind::LocalOrImportSignatureMismatch {
function_index: ALLOCATE_FUNC_INDEX,
expected: (vec![InterfaceType::I32], vec![]),
expected: (vec![IType::I32], vec![]),
received: (vec![], vec![]),
},
));
@ -147,7 +147,7 @@ where
instance,
DEALLOCATE_FUNC_INDEX,
instruction,
vec![InterfaceValue::I32(mem_ptr), InterfaceValue::I32(size)],
vec![IValue::I32(mem_ptr), IValue::I32(size)],
)?;
Ok(())
@ -157,8 +157,8 @@ fn call_core<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance Instance,
function_index: u32,
instruction: Instruction,
inputs: Vec<InterfaceValue>,
) -> Result<Vec<InterfaceValue>, InstructionError>
inputs: Vec<IValue>,
) -> Result<Vec<IValue>, InstructionError>
where
Export: wasm::structures::Export + 'instance,
LocalImport: wasm::structures::LocalImport + 'instance,

View File

@ -4,10 +4,8 @@ mod instructions;
pub mod stack;
pub mod wasm;
use crate::{
errors::{InstructionResult, InterpreterResult},
values::InterfaceValue,
};
use crate::errors::{InstructionResult, InterpreterResult};
use crate::IValue;
pub use instructions::Instruction;
use stack::Stack;
use std::{convert::TryFrom, marker::PhantomData};
@ -24,10 +22,10 @@ where
{
/// The invocation inputs are all the arguments received by an
/// adapter.
invocation_inputs: &'invocation [InterfaceValue],
invocation_inputs: &'invocation [IValue],
/// Each runtime (so adapter) has its own stack instance.
stack: Stack<InterfaceValue>,
stack: Stack<IValue>,
/// The WebAssembly module instance. It is used by adapter's
/// instructions.
@ -68,8 +66,8 @@ pub(crate) type ExecutableInstruction<Instance, Export, LocalImport, Memory, Mem
/// stack::Stackable,
/// Instruction, Interpreter,
/// },
/// types::InterfaceType,
/// values::InterfaceValue,
/// types::IType,
/// values::IValue,
/// };
///
/// // 1. Creates an interpreter from a set of instructions. They will
@ -83,7 +81,7 @@ pub(crate) type ExecutableInstruction<Instance, Export, LocalImport, Memory, Mem
/// .unwrap();
///
/// // 2. Defines the arguments of the adapter.
/// let invocation_inputs = vec![InterfaceValue::I32(3), InterfaceValue::I32(4)];
/// let invocation_inputs = vec![IValue::I32(3), IValue::I32(4)];
///
/// // 3. Creates a WebAssembly instance.
/// let mut instance = Instance {
@ -94,17 +92,17 @@ pub(crate) type ExecutableInstruction<Instance, Export, LocalImport, Memory, Mem
/// 42,
/// LocalImport {
/// // Defines the argument types of the function.
/// inputs: vec![InterfaceType::I32, InterfaceType::I32],
/// inputs: vec![IType::I32, IType::I32],
///
/// // Defines the result types.
/// outputs: vec![InterfaceType::I32],
/// outputs: vec![IType::I32],
///
/// // Defines the function implementation.
/// function: |arguments: &[InterfaceValue]| {
/// function: |arguments: &[IValue]| {
/// let a: i32 = (&arguments[0]).try_into().unwrap();
/// let b: i32 = (&arguments[1]).try_into().unwrap();
///
/// Ok(vec![InterfaceValue::I32(a + b)])
/// Ok(vec![IValue::I32(a + b)])
/// },
/// },
/// );
@ -120,7 +118,7 @@ pub(crate) type ExecutableInstruction<Instance, Export, LocalImport, Memory, Mem
/// let stack = run.unwrap();
///
/// // 5. Read the stack to get the result.
/// assert_eq!(stack.as_slice(), &[InterfaceValue::I32(7)]);
/// assert_eq!(stack.as_slice(), &[IValue::I32(7)]);
/// ```
pub struct Interpreter<Instance, Export, LocalImport, Memory, MemoryView>
where
@ -158,9 +156,9 @@ where
/// returns the stack.
pub fn run(
&self,
invocation_inputs: &[InterfaceValue],
invocation_inputs: &[IValue],
wasm_instance: &mut Instance,
) -> InterpreterResult<Stack<InterfaceValue>> {
) -> InterpreterResult<Stack<IValue>> {
let mut runtime = Runtime {
invocation_inputs,
stack: Stack::new(),

View File

@ -1,8 +1,9 @@
#![allow(missing_docs)]
use crate::ast::FunctionArg;
use crate::types::RecordType;
use crate::{types::InterfaceType, values::InterfaceValue};
use crate::IRecordType;
use crate::IType;
use crate::IValue;
use std::rc::Rc;
use std::{cell::Cell, ops::Deref};
@ -47,8 +48,8 @@ pub trait Export {
fn inputs_cardinality(&self) -> usize;
fn outputs_cardinality(&self) -> usize;
fn arguments(&self) -> &[FunctionArg];
fn outputs(&self) -> &[InterfaceType];
fn call(&self, arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()>;
fn outputs(&self) -> &[IType];
fn call(&self, arguments: &[IValue]) -> Result<Vec<IValue>, ()>;
}
pub trait LocalImport {
@ -56,8 +57,8 @@ pub trait LocalImport {
fn inputs_cardinality(&self) -> usize;
fn outputs_cardinality(&self) -> usize;
fn arguments(&self) -> &[FunctionArg];
fn outputs(&self) -> &[InterfaceType];
fn call(&self, arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()>;
fn outputs(&self) -> &[IType];
fn call(&self, arguments: &[IValue]) -> Result<Vec<IValue>, ()>;
}
pub trait MemoryView: Deref<Target = [Cell<u8>]> {}
@ -79,7 +80,7 @@ where
fn export(&self, export_name: &str) -> Option<&E>;
fn local_or_import<I: TypedIndex + LocalImportIndex>(&self, index: I) -> Option<&LI>;
fn memory(&self, index: usize) -> Option<&M>;
fn wit_record_by_id(&self, index: u64) -> Option<&Rc<RecordType>>;
fn wit_record_by_id(&self, index: u64) -> Option<&Rc<IRecordType>>;
}
impl Export for () {
@ -99,11 +100,11 @@ impl Export for () {
&[]
}
fn outputs(&self) -> &[InterfaceType] {
fn outputs(&self) -> &[IType] {
&[]
}
fn call(&self, _arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()> {
fn call(&self, _arguments: &[IValue]) -> Result<Vec<IValue>, ()> {
Err(())
}
}
@ -125,11 +126,11 @@ impl LocalImport for () {
&[]
}
fn outputs(&self) -> &[InterfaceType] {
fn outputs(&self) -> &[IType] {
&[]
}
fn call(&self, _arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()> {
fn call(&self, _arguments: &[IValue]) -> Result<Vec<IValue>, ()> {
Err(())
}
}
@ -171,7 +172,7 @@ where
None
}
fn wit_record_by_id(&self, _index: u64) -> Option<&Rc<RecordType>> {
fn wit_record_by_id(&self, _index: u64) -> Option<&Rc<IRecordType>> {
None
}
}

View File

@ -53,8 +53,7 @@
#![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")]
#![doc(html_logo_url = "https://github.com/wasmerio.png")]
pub mod ast;
pub mod types;
mod ast;
#[macro_use]
mod macros;
pub mod decoders;
@ -63,5 +62,16 @@ pub mod errors;
pub mod interpreter;
#[cfg(feature = "serde")]
mod serde;
pub mod values;
pub mod vec1;
mod values;
pub use fluence_it_types::ne_vec::NEVec;
pub use fluence_it_types::IRecordFieldType;
pub use fluence_it_types::IRecordType;
pub use fluence_it_types::IType;
pub use fluence_it_types::IValue;
#[cfg(feature = "serde")]
pub use crate::serde::de::from_interface_values;
#[cfg(feature = "serde")]
pub use crate::serde::ser::to_interface_value;

View File

@ -14,13 +14,13 @@ macro_rules! vec1 {
($item:expr; $length:expr) => {
{
crate::vec1::Vec1::new(vec![$item; $length]).unwrap()
crate::vec1::NEVec::new(vec![$item; $length]).unwrap()
}
};
($($item:expr),+ $(,)?) => {
{
crate::vec1::Vec1::new(vec![$($item),*]).unwrap()
crate::vec1::NEVec::new(vec![$($item),*]).unwrap()
}
};
}
@ -104,8 +104,8 @@ macro_rules! test_executable_instruction {
stack::Stackable,
Instruction, Interpreter,
},
types::InterfaceType,
values::InterfaceValue,
types::IType,
values::IValue,
};
use std::{cell::Cell, collections::HashMap, convert::TryInto};
@ -146,8 +146,8 @@ macro_rules! test_executable_instruction {
stack::Stackable,
Instruction, Interpreter,
},
types::InterfaceType,
values::InterfaceValue,
types::IType,
values::IValue,
};
use std::{cell::Cell, collections::HashMap, convert::TryInto};

View File

@ -1,16 +1,13 @@
//! Provides a deserializer from WIT values to Rust value.
use crate::{
types::InterfaceType,
values::{FlattenInterfaceValueIterator, InterfaceValue},
};
use crate::{values::FlattenIRecordIterator, IType, IValue};
use serde::{de, Deserialize};
use std::{
fmt::{self, Display},
iter::Peekable,
};
/// Deserialize a set of `InterfaceValue`s to a type `T` that
/// Deserialize a set of `IValue`s to a type `T` that
/// implements the `Deserialize` trait.
///
/// This is not a requirement to use WIT, but Serde provides an even
@ -21,7 +18,7 @@ use std::{
///
/// ```rust
/// use wasmer_interface_types::{
/// values::{InterfaceValue, from_interface_values},
/// values::{IValue, from_interface_values},
/// vec1::Vec1,
/// };
/// use serde::Deserialize;
@ -36,10 +33,10 @@ use std::{
/// y: f32,
/// };
///
/// let values = vec![InterfaceValue::Record(Vec1::new(vec![
/// InterfaceValue::String("abc".to_string()),
/// InterfaceValue::Record(Vec1::new(vec![InterfaceValue::I32(1), InterfaceValue::I64(2)]).unwrap()),
/// InterfaceValue::F32(3.),
/// let values = vec![IValue::Record(NEVec::new(vec![
/// IValue::String("abc".to_string()),
/// IValue::Record(NEVec::new(vec![IValue::I32(1), IValue::I64(2)]).unwrap()),
/// IValue::F32(3.),
/// ]).unwrap())];
/// let t = from_interface_values::<T>(&values).unwrap();
///
@ -52,7 +49,7 @@ use std::{
/// }
/// );
/// ```
pub fn from_interface_values<'a, T>(values: &'a [InterfaceValue]) -> Result<T, DeserializeError>
pub fn from_interface_values<'a, T>(values: &'a [IValue]) -> Result<T, DeserializeError>
where
T: Deserialize<'a>,
{
@ -65,16 +62,16 @@ where
}
}
/// The deserializer. The iterator iterates over `InterfaceValue`s,
/// all flatten, see `FlattenInterfaceValueIterator`.
/// The deserializer. The iterator iterates over `IValue`s,
/// all flatten, see `FlattenIValueIterator`.
struct Deserializer<'de> {
iterator: Peekable<FlattenInterfaceValueIterator<'de>>,
iterator: Peekable<FlattenIRecordIterator<'de>>,
}
impl<'de> Deserializer<'de> {
pub fn new(input: &'de [InterfaceValue]) -> Deserializer<'de> {
pub fn new(input: &'de [IValue]) -> Deserializer<'de> {
Deserializer {
iterator: FlattenInterfaceValueIterator::new(input).peekable(),
iterator: FlattenIRecordIterator::new(input).peekable(),
}
}
}
@ -83,14 +80,14 @@ macro_rules! next {
($method_name:ident, $variant:ident, $type:ty) => {
fn $method_name(&mut self) -> Result<$type, DeserializeError> {
match self.iterator.peek() {
Some(InterfaceValue::$variant(value)) => {
Some(IValue::$variant(value)) => {
self.iterator.next();
Ok(*value)
}
Some(wrong_value) => Err(DeserializeError::TypeMismatch {
expected_type: InterfaceType::$variant,
expected_type: IType::$variant,
received_value: (*wrong_value).clone(),
}),
@ -114,14 +111,14 @@ impl<'de> Deserializer<'de> {
fn next_string(&mut self) -> Result<&'de str, DeserializeError> {
match self.iterator.peek() {
Some(InterfaceValue::String(v)) => {
Some(IValue::String(v)) => {
self.iterator.next();
Ok(v)
}
Some(wrong_value) => Err(DeserializeError::TypeMismatch {
expected_type: InterfaceType::String,
expected_type: IType::String,
received_value: (*wrong_value).clone(),
}),
@ -131,7 +128,7 @@ impl<'de> Deserializer<'de> {
fn next_array(&mut self) -> Result<&'de [u8], DeserializeError> {
match self.iterator.peek() {
Some(InterfaceValue::Array(_)) => {
Some(IValue::Array(_)) => {
self.iterator.next();
// Ok(v)
@ -141,7 +138,7 @@ impl<'de> Deserializer<'de> {
Some(wrong_value) => Err(DeserializeError::TypeMismatch {
// TODO: change default
expected_type: InterfaceType::Array(Box::new(InterfaceType::S8)),
expected_type: IType::Array(Box::new(IType::S8)),
received_value: (*wrong_value).clone(),
}),
@ -165,10 +162,10 @@ pub enum DeserializeError {
/// The current value hasn't the expected type.
TypeMismatch {
/// The expected type.
expected_type: InterfaceType,
expected_type: IType,
/// The received type.
received_value: InterfaceValue,
received_value: IValue,
},
/// Arbitrary message.
@ -209,21 +206,21 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
V: de::Visitor<'de>,
{
match self.iterator.peek() {
Some(InterfaceValue::S8(_)) => self.deserialize_i8(visitor),
Some(InterfaceValue::S16(_)) => self.deserialize_i16(visitor),
Some(InterfaceValue::S32(_)) => self.deserialize_i32(visitor),
Some(InterfaceValue::S64(_)) => self.deserialize_i64(visitor),
Some(InterfaceValue::U8(_)) => self.deserialize_u8(visitor),
Some(InterfaceValue::U16(_)) => self.deserialize_u16(visitor),
Some(InterfaceValue::U32(_)) => self.deserialize_u32(visitor),
Some(InterfaceValue::U64(_)) => self.deserialize_u64(visitor),
Some(InterfaceValue::F32(_)) => self.deserialize_f32(visitor),
Some(InterfaceValue::F64(_)) => self.deserialize_f64(visitor),
Some(InterfaceValue::String(_)) => self.deserialize_string(visitor),
Some(InterfaceValue::Array(_)) => self.deserialize_bytes(visitor),
Some(InterfaceValue::I32(_)) => self.deserialize_i32(visitor),
Some(InterfaceValue::I64(_)) => self.deserialize_i64(visitor),
Some(InterfaceValue::Record(..)) => unreachable!("Records should have been flattened."), // already flattened
Some(IValue::S8(_)) => self.deserialize_i8(visitor),
Some(IValue::S16(_)) => self.deserialize_i16(visitor),
Some(IValue::S32(_)) => self.deserialize_i32(visitor),
Some(IValue::S64(_)) => self.deserialize_i64(visitor),
Some(IValue::U8(_)) => self.deserialize_u8(visitor),
Some(IValue::U16(_)) => self.deserialize_u16(visitor),
Some(IValue::U32(_)) => self.deserialize_u32(visitor),
Some(IValue::U64(_)) => self.deserialize_u64(visitor),
Some(IValue::F32(_)) => self.deserialize_f32(visitor),
Some(IValue::F64(_)) => self.deserialize_f64(visitor),
Some(IValue::String(_)) => self.deserialize_string(visitor),
Some(IValue::Array(_)) => self.deserialize_bytes(visitor),
Some(IValue::I32(_)) => self.deserialize_i32(visitor),
Some(IValue::I64(_)) => self.deserialize_i64(visitor),
Some(IValue::Record(..)) => unreachable!("Records should have been flattened."), // already flattened
None => Err(DeserializeError::InputEmpty),
}
}
@ -253,7 +250,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: de::Visitor<'de>,
{
// Both `InterfaceValue::S32` and `InterfaceValue::I32`
// Both `IValue::S32` and `IValue::I32`
// represent `i32`.
visitor.visit_i32(self.next_s32().or_else(|_| self.next_i32())?)
}
@ -262,7 +259,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: de::Visitor<'de>,
{
// Both `InterfaceValue::S64` and `InterfaceValue::I64`
// Both `IValue::S64` and `IValue::I64`
// represent `i64`.
visitor.visit_i64(self.next_s64().or_else(|_| self.next_i64())?)
}
@ -489,7 +486,7 @@ mod tests {
#[test]
#[allow(non_snake_case)]
fn $test_name() {
let input = vec![InterfaceValue::$variant($value)];
let input = vec![IValue::$variant($value)];
let output: $ty = $value;
assert_eq!(from_interface_values::<$ty>(&input).unwrap(), output);
@ -518,7 +515,7 @@ mod tests {
#[allow(non_snake_case)]
fn test_deserialize_value__str() {
let foo = "foo".to_string();
let values = vec![InterfaceValue::String(foo)];
let values = vec![IValue::String(foo)];
let input: &str = from_interface_values(&values).unwrap();
let output: &str = "foo";
@ -534,7 +531,7 @@ mod tests {
#[derive(Deserialize, Debug, PartialEq)]
struct S(i8);
let input = vec![InterfaceValue::Record(vec1![InterfaceValue::S8(42)])];
let input = vec![IValue::Record(vec1![IValue::S8(42)])];
let output = S(42);
assert_eq!(from_interface_values::<S>(&input).unwrap(), output);
@ -546,10 +543,7 @@ mod tests {
#[derive(Deserialize, Debug, PartialEq)]
struct S(i8, f32);
let input = vec![InterfaceValue::Record(vec1![
InterfaceValue::S8(7),
InterfaceValue::F32(42.),
])];
let input = vec![IValue::Record(vec1![IValue::S8(7), IValue::F32(42.),])];
let output = S(7, 42.);
assert_eq!(from_interface_values::<S>(&input).unwrap(), output);
@ -564,10 +558,7 @@ mod tests {
y: f32,
}
let input = vec![InterfaceValue::Record(vec1![
InterfaceValue::S8(7),
InterfaceValue::F32(42.),
])];
let input = vec![IValue::Record(vec1![IValue::S8(7), IValue::F32(42.),])];
let output = S { x: 7, y: 42. };
assert_eq!(from_interface_values::<S>(&input).unwrap(), output);
@ -589,17 +580,9 @@ mod tests {
p2: Point,
}
let input = vec![InterfaceValue::Record(vec1![
InterfaceValue::Record(vec1![
InterfaceValue::I32(1),
InterfaceValue::I32(2),
InterfaceValue::I32(3),
]),
InterfaceValue::Record(vec1![
InterfaceValue::I32(4),
InterfaceValue::I32(5),
InterfaceValue::I32(6),
]),
let input = vec![IValue::Record(vec1![
IValue::Record(vec1![IValue::I32(1), IValue::I32(2), IValue::I32(3),]),
IValue::Record(vec1![IValue::I32(4), IValue::I32(5), IValue::I32(6),]),
])];
let output = Line {
p1: Point { x: 1, y: 2, z: 3 },

View File

@ -1,11 +1,12 @@
//! Provides a serializer from Rust value to WIT values.
use crate::{values::InterfaceValue, vec1::Vec1};
use crate::IValue;
use crate::NEVec;
use serde::{ser, Serialize};
use std::fmt::{self, Display};
/// Serialize a type `T` that implements the `Serialize` trait to an
/// `InterfaceValue`.
/// `IValue`.
///
/// This is not a requirement to use WIT, but Serde provides an even
/// nicer API to the user to send its complex types to WIT.
@ -14,7 +15,7 @@ use std::fmt::{self, Display};
///
/// ```rust
/// use wasmer_interface_types::{
/// values::{InterfaceValue, to_interface_value},
/// values::{IValue, to_interface_value},
/// vec1::Vec1,
/// };
/// use serde::Serialize;
@ -37,14 +38,14 @@ use std::fmt::{self, Display};
///
/// assert_eq!(
/// to_interface_value(&input).unwrap(),
/// InterfaceValue::Record(Vec1::new(vec![
/// InterfaceValue::String("abc".to_string()),
/// InterfaceValue::Record(Vec1::new(vec![InterfaceValue::I32(1), InterfaceValue::I64(2)]).unwrap()),
/// InterfaceValue::F32(3.),
/// IValue::Record(NEVec::new(vec![
/// IValue::String("abc".to_string()),
/// IValue::Record(NEVec::new(vec![IValue::I32(1), IValue::I64(2)]).unwrap()),
/// IValue::F32(3.),
/// ]).unwrap()),
/// );
/// ```
pub fn to_interface_value<T>(value: &T) -> Result<InterfaceValue, SerializeError>
pub fn to_interface_value<T>(value: &T) -> Result<IValue, SerializeError>
where
T: Serialize,
{
@ -68,7 +69,7 @@ where
/// The serializer.
struct Serializer {
values: Vec<Vec<InterfaceValue>>,
values: Vec<Vec<IValue>>,
}
impl Serializer {
@ -78,7 +79,7 @@ impl Serializer {
}
}
fn last(&mut self) -> &mut Vec<InterfaceValue> {
fn last(&mut self) -> &mut Vec<IValue> {
self.values.last_mut().unwrap()
}
@ -86,7 +87,7 @@ impl Serializer {
self.values.push(Vec::with_capacity(capacity));
}
fn pop(&mut self) -> Result<Vec<InterfaceValue>, SerializeError> {
fn pop(&mut self) -> Result<Vec<IValue>, SerializeError> {
// The first `vec` contains the final result. It is forbidden
// to `pop` it as is.
if self.values.len() < 2 {
@ -361,9 +362,7 @@ impl<'a> ser::SerializeSeq for &'a mut Serializer {
}
fn end(self) -> Result<Self::Ok, Self::Error> {
let record = InterfaceValue::Record(
Vec1::new(self.pop()?).map_err(|_| Self::Error::RecordNeedsAtLeastOneField)?,
);
let record = IValue::Array(self.pop()?);
self.last().push(record);
Ok(())
@ -398,8 +397,8 @@ impl<'a> ser::SerializeTupleStruct for &'a mut Serializer {
}
fn end(self) -> Result<Self::Ok, Self::Error> {
let record = InterfaceValue::Record(
Vec1::new(self.pop()?).map_err(|_| Self::Error::RecordNeedsAtLeastOneField)?,
let record = IValue::Record(
NEVec::new(self.pop()?).map_err(|_| Self::Error::RecordNeedsAtLeastOneField)?,
);
self.last().push(record);
@ -442,8 +441,8 @@ impl<'a> ser::SerializeMap for &'a mut Serializer {
}
fn end(self) -> Result<Self::Ok, Self::Error> {
let record = InterfaceValue::Record(
Vec1::new(self.pop()?).map_err(|_| Self::Error::RecordNeedsAtLeastOneField)?,
let record = IValue::Record(
NEVec::new(self.pop()?).map_err(|_| Self::Error::RecordNeedsAtLeastOneField)?,
);
self.last().push(record);
@ -463,8 +462,8 @@ impl<'a> ser::SerializeStruct for &'a mut Serializer {
}
fn end(self) -> Result<Self::Ok, Self::Error> {
let record = InterfaceValue::Record(
Vec1::new(self.pop()?).map_err(|_| Self::Error::RecordNeedsAtLeastOneField)?,
let record = IValue::Record(
NEVec::new(self.pop()?).map_err(|_| Self::Error::RecordNeedsAtLeastOneField)?,
);
self.last().push(record);
@ -502,7 +501,7 @@ mod tests {
#[allow(non_snake_case)]
fn $test_name() {
let input: $ty = $value;
let output = InterfaceValue::$variant($value);
let output = IValue::$variant($value);
assert_eq!(to_interface_value(&input).unwrap(), output);
}
@ -533,7 +532,7 @@ mod tests {
struct S(i8);
let input = S(42);
let output = InterfaceValue::S8(42);
let output = IValue::S8(42);
assert_eq!(to_interface_value(&input).unwrap(), output);
}
@ -545,7 +544,7 @@ mod tests {
struct S(i8, f32);
let input = S(7, 42.);
let output = InterfaceValue::Record(vec1![InterfaceValue::S8(7), InterfaceValue::F32(42.)]);
let output = IValue::Record(vec1![IValue::S8(7), IValue::F32(42.)]);
assert_eq!(to_interface_value(&input).unwrap(), output);
}
@ -560,7 +559,7 @@ mod tests {
}
let input = S { x: 7, y: 42. };
let output = InterfaceValue::Record(vec1![InterfaceValue::S8(7), InterfaceValue::F32(42.)]);
let output = IValue::Record(vec1![IValue::S8(7), IValue::F32(42.)]);
assert_eq!(to_interface_value(&input).unwrap(), output);
}
@ -585,17 +584,9 @@ mod tests {
p1: Point { x: 1, y: 2, z: 3 },
p2: Point { x: 4, y: 5, z: 6 },
};
let output = InterfaceValue::Record(vec1![
InterfaceValue::Record(vec1![
InterfaceValue::I32(1),
InterfaceValue::I32(2),
InterfaceValue::I32(3),
]),
InterfaceValue::Record(vec1![
InterfaceValue::I32(4),
InterfaceValue::I32(5),
InterfaceValue::I32(6),
]),
let output = IValue::Record(vec1![
IValue::Record(vec1![IValue::I32(1), IValue::I32(2), IValue::I32(3),]),
IValue::Record(vec1![IValue::I32(4), IValue::I32(5), IValue::I32(6),]),
]);
assert_eq!(to_interface_value(&input).unwrap(), output);

45
wasmer-it/src/values.rs Normal file
View File

@ -0,0 +1,45 @@
use crate::IValue;
use std::slice::Iter;
#[cfg(feature = "serde")]
pub use crate::serde::{de::from_interface_values, ser::to_interface_value};
/// Iterates over a vector of `IValues` but flatten all the
/// values. So `I32(1), Record([I32(2), I32(3)]), I32(4)` will be
/// iterated like `I32(1), I32(2), I32(3), I32(4)`.
pub(crate) struct FlattenIRecordIterator<'a> {
iterators: Vec<Iter<'a, IValue>>,
}
impl<'a> FlattenIRecordIterator<'a> {
pub(crate) fn new(values: &'a [IValue]) -> Self {
Self {
iterators: vec![values.iter()],
}
}
}
impl<'a> Iterator for FlattenIRecordIterator<'a> {
type Item = &'a IValue;
fn next(&mut self) -> Option<Self::Item> {
match self.iterators.last_mut()?.next() {
// End of the current iterator, go back to the previous
// one.
None => {
self.iterators.pop();
self.next()
}
// Recursively iterate over the record.
Some(IValue::Record(fields)) => {
self.iterators.push(fields.iter());
self.next()
}
// A regular item.
e @ Some(_) => e,
}
}
}