mirror of
https://github.com/fluencelabs/interface-types
synced 2025-06-11 22:11:25 +00:00
Merge pull request #7 from fluencelabs/decouple_ivalues
Decouple IType and IValue
This commit is contained in:
42
Cargo.lock
generated
42
Cargo.lock
generated
@ -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",
|
||||
|
35
Cargo.toml
35
Cargo.toml
@ -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"
|
||||
|
18
crates/it-types/Cargo.toml
Normal file
18
crates/it-types/Cargo.toml
Normal 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"]
|
29
crates/it-types/src/impls/errors.rs
Normal file
29
crates/it-types/src/impls/errors.rs
Normal 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)
|
||||
}
|
||||
}
|
6
crates/it-types/src/impls/mod.rs
Normal file
6
crates/it-types/src/impls/mod.rs
Normal file
@ -0,0 +1,6 @@
|
||||
mod errors;
|
||||
mod types;
|
||||
mod values;
|
||||
|
||||
pub use errors::WasmValueNativeCastError;
|
||||
pub use values::NativeType;
|
220
crates/it-types/src/impls/types.rs
Normal file
220
crates/it-types/src/impls/types.rs
Normal 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)
|
||||
}
|
||||
}
|
51
crates/it-types/src/impls/values.rs
Normal file
51
crates/it-types/src/impls/values.rs
Normal 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);
|
20
crates/it-types/src/lib.rs
Normal file
20
crates/it-types/src/lib.rs
Normal 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;
|
@ -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,
|
||||
{
|
140
crates/it-types/src/types.rs
Normal file
140
crates/it-types/src/types.rs
Normal 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
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
59
crates/it-types/src/values.rs
Normal file
59
crates/it-types/src/values.rs
Normal 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)
|
||||
}
|
||||
}
|
7
crates/to-bytes/Cargo.toml
Normal file
7
crates/to-bytes/Cargo.toml
Normal 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
104
crates/to-bytes/src/lib.rs
Normal 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(())
|
||||
}
|
||||
}
|
92
src/types.rs
92
src/types.rs
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
218
src/values.rs
218
src/values.rs
@ -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
|
||||
]
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
@ -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
26
wasmer-it/Cargo.toml
Normal 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"]
|
@ -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,
|
||||
|
@ -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.
|
||||
|
||||
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",
|
@ -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",
|
@ -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",
|
@ -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.
|
@ -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"
|
||||
);
|
@ -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(),
|
||||
},
|
||||
)),
|
@ -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
|
||||
},
|
@ -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,
|
||||
}
|
||||
],
|
||||
})],
|
@ -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)],
|
||||
);
|
||||
}
|
@ -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(),
|
||||
},
|
||||
)),
|
@ -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"#,
|
||||
);
|
@ -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,
|
@ -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(),
|
@ -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
|
||||
}
|
||||
}
|
@ -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;
|
@ -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};
|
||||
|
@ -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 },
|
@ -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
45
wasmer-it/src/values.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user