mirror of
https://github.com/fluencelabs/interface-types
synced 2024-12-04 15:20:20 +00:00
refactor Record type
This commit is contained in:
parent
458adc2534
commit
eb11794240
@ -1,6 +1,6 @@
|
||||
//! Parse the WIT binary representation into an [AST](crate::ast).
|
||||
|
||||
use crate::{ast::*, interpreter::Instruction, types::*, vec1::Vec1};
|
||||
use crate::{ast::*, interpreter::Instruction, types::*};
|
||||
use nom::{
|
||||
error::{make_error, ErrorKind, ParseError},
|
||||
Err, IResult,
|
||||
@ -70,6 +70,25 @@ 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> {
|
||||
if input.is_empty() {
|
||||
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
|
||||
}
|
||||
|
||||
consume!((input, name) = string(input)?);
|
||||
consume!((input, ty) = ty(input)?);
|
||||
|
||||
Ok((
|
||||
input,
|
||||
RecordFieldType {
|
||||
name: name.to_owned(),
|
||||
ty,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
/// Parse an interface type.
|
||||
fn ty<'input, E: ParseError<&'input [u8]>>(
|
||||
mut input: &'input [u8],
|
||||
@ -97,9 +116,9 @@ fn ty<'input, E: ParseError<&'input [u8]>>(
|
||||
0x0c => InterfaceType::I32,
|
||||
0x0d => InterfaceType::I64,
|
||||
0x0e => {
|
||||
consume!((input, record_type) = record_type(input)?);
|
||||
consume!((input, record_name) = string(input)?);
|
||||
|
||||
InterfaceType::Record(record_type)
|
||||
InterfaceType::Record(record_name.to_owned())
|
||||
}
|
||||
_ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))),
|
||||
};
|
||||
@ -111,11 +130,15 @@ fn ty<'input, E: ParseError<&'input [u8]>>(
|
||||
fn record_type<'input, E: ParseError<&'input [u8]>>(
|
||||
input: &'input [u8],
|
||||
) -> IResult<&'input [u8], RecordType, E> {
|
||||
let (output, fields) = list(input, ty)?;
|
||||
use crate::vec1::Vec1;
|
||||
|
||||
let (output, name) = string(input)?;
|
||||
let (output, fields) = list(output, record_field)?;
|
||||
|
||||
Ok((
|
||||
output,
|
||||
RecordType {
|
||||
name: name.to_owned(),
|
||||
fields: Vec1::new(fields).expect("Record must have at least one field, zero given."),
|
||||
},
|
||||
))
|
||||
@ -240,6 +263,7 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
|
||||
0x38 => (input, Instruction::ByteArrayLowerMemory),
|
||||
0x39 => (input, Instruction::ByteArraySize),
|
||||
|
||||
/*
|
||||
0x25 => {
|
||||
consume!((input, argument_0) = uleb(input)?);
|
||||
|
||||
@ -260,6 +284,7 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
|
||||
},
|
||||
)
|
||||
}
|
||||
*/
|
||||
|
||||
0x3A => {
|
||||
consume!((input, argument_0) = uleb(input)?);
|
||||
@ -832,8 +857,11 @@ mod tests {
|
||||
Instruction::StringLiftMemory,
|
||||
Instruction::StringLowerMemory,
|
||||
Instruction::StringSize,
|
||||
/*
|
||||
Instruction::RecordLift { type_index: 1 },
|
||||
Instruction::RecordLower { type_index: 1 },
|
||||
|
||||
*/
|
||||
],
|
||||
));
|
||||
|
||||
|
@ -154,17 +154,25 @@ impl Parse<'_> for RecordType {
|
||||
fn parse(parser: Parser<'_>) -> Result<Self> {
|
||||
parser.parse::<keyword::record>()?;
|
||||
|
||||
parser.parse::<keyword::string>()?;
|
||||
let record_name = parser.parse()?;
|
||||
|
||||
let mut fields = vec![];
|
||||
|
||||
while !parser.is_empty() {
|
||||
fields.push(parser.parens(|parser| {
|
||||
parser.parse::<keyword::field>()?;
|
||||
parser.parse::<keyword::string>()?;
|
||||
let name = parser.parse()?;
|
||||
|
||||
parser.parse()
|
||||
parser.parse::<keyword::field>()?;
|
||||
let ty = parser.parse()?;
|
||||
|
||||
Ok(RecordFieldType { name, ty })
|
||||
})?);
|
||||
}
|
||||
|
||||
Ok(RecordType {
|
||||
name: record_name,
|
||||
fields: Vec1::new(fields).expect("Record must have at least one field, zero given."),
|
||||
})
|
||||
}
|
||||
@ -339,7 +347,9 @@ impl<'a> Parse<'a> for Instruction {
|
||||
parser.parse::<keyword::byte_array_size>()?;
|
||||
|
||||
Ok(Instruction::ByteArraySize)
|
||||
} else if lookahead.peek::<keyword::record_lift>() {
|
||||
}
|
||||
/*
|
||||
else if lookahead.peek::<keyword::record_lift>() {
|
||||
parser.parse::<keyword::record_lift>()?;
|
||||
|
||||
Ok(Instruction::RecordLift {
|
||||
@ -351,7 +361,9 @@ impl<'a> Parse<'a> for Instruction {
|
||||
Ok(Instruction::RecordLower {
|
||||
type_index: parser.parse()?,
|
||||
})
|
||||
} else if lookahead.peek::<keyword::record_lift_memory>() {
|
||||
}
|
||||
*/
|
||||
else if lookahead.peek::<keyword::record_lift_memory>() {
|
||||
parser.parse::<keyword::record_lift_memory>()?;
|
||||
|
||||
Ok(Instruction::RecordLiftMemory {
|
||||
@ -857,8 +869,10 @@ mod tests {
|
||||
Instruction::StringLiftMemory,
|
||||
Instruction::StringLowerMemory,
|
||||
Instruction::StringSize,
|
||||
/*
|
||||
Instruction::RecordLift { type_index: 42 },
|
||||
Instruction::RecordLower { type_index: 42 },
|
||||
*/
|
||||
];
|
||||
|
||||
assert_eq!(inputs.len(), outputs.len());
|
||||
|
@ -111,18 +111,30 @@ where
|
||||
InterfaceType::I64 => 0x0d_u8.to_bytes(writer),
|
||||
InterfaceType::Record(record_type) => {
|
||||
0x0e_u8.to_bytes(writer)?;
|
||||
record_type.to_bytes(writer)
|
||||
record_type.as_str().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)
|
||||
}
|
||||
}
|
||||
@ -338,7 +350,7 @@ where
|
||||
Instruction::ByteArrayLiftMemory => 0x37_u8.to_bytes(writer)?,
|
||||
Instruction::ByteArrayLowerMemory => 0x38_u8.to_bytes(writer)?,
|
||||
Instruction::ByteArraySize => 0x39_u8.to_bytes(writer)?,
|
||||
|
||||
/*
|
||||
Instruction::RecordLift { type_index } => {
|
||||
0x25_u8.to_bytes(writer)?;
|
||||
(*type_index as u64).to_bytes(writer)?
|
||||
@ -347,6 +359,7 @@ where
|
||||
0x26_u8.to_bytes(writer)?;
|
||||
(*type_index as u64).to_bytes(writer)?
|
||||
}
|
||||
*/
|
||||
Instruction::RecordLiftMemory { type_index } => {
|
||||
0x3A_u8.to_bytes(writer)?;
|
||||
(*type_index as u64).to_bytes(writer)?
|
||||
|
@ -85,13 +85,18 @@ impl ToString for &InterfaceType {
|
||||
impl ToString for &RecordType {
|
||||
fn to_string(&self) -> String {
|
||||
format!(
|
||||
"record{fields}",
|
||||
"record {} {fields}",
|
||||
self.name,
|
||||
fields = self
|
||||
.fields
|
||||
.iter()
|
||||
.fold(String::new(), |mut accumulator, interface_type| {
|
||||
.fold(String::new(), |mut accumulator, field_type| {
|
||||
accumulator.push(' ');
|
||||
accumulator.push_str(&format!("(field {})", &interface_type.to_string()));
|
||||
accumulator.push_str(&format!(
|
||||
"{}: {}\n",
|
||||
field_type.name,
|
||||
(&field_type.ty).to_string()
|
||||
));
|
||||
accumulator
|
||||
}),
|
||||
)
|
||||
@ -142,8 +147,10 @@ impl ToString for &Instruction {
|
||||
Instruction::ByteArrayLiftMemory => "byte_array.lift_memory".into(),
|
||||
Instruction::ByteArrayLowerMemory => "byte_array.lower_memory".into(),
|
||||
Instruction::ByteArraySize => "byte_array.size".into(),
|
||||
/*
|
||||
Instruction::RecordLift { type_index } => format!("record.lift {}", type_index),
|
||||
Instruction::RecordLower { type_index } => format!("record.lower {}", type_index),
|
||||
*/
|
||||
Instruction::RecordLiftMemory { type_index } => {
|
||||
format!("record.lift_memory {}", type_index)
|
||||
}
|
||||
@ -475,8 +482,10 @@ mod tests {
|
||||
(&Instruction::StringLiftMemory).to_string(),
|
||||
(&Instruction::StringLowerMemory).to_string(),
|
||||
(&Instruction::StringSize).to_string(),
|
||||
/*
|
||||
(&Instruction::RecordLift { type_index: 42 }).to_string(),
|
||||
(&Instruction::RecordLower { type_index: 42 }).to_string(),
|
||||
*/
|
||||
];
|
||||
let outputs = vec![
|
||||
"arg.get 7",
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! 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 std::{
|
||||
error::Error,
|
||||
@ -21,7 +22,7 @@ pub type InterpreterResult<T> = Result<T, InstructionError>;
|
||||
#[derive(Debug)]
|
||||
pub struct WasmValueNativeCastError {
|
||||
/// The initial type.
|
||||
pub from: InterfaceType,
|
||||
pub from: InterfaceValue,
|
||||
|
||||
/// The targeted type.
|
||||
///
|
||||
@ -98,7 +99,7 @@ pub enum InstructionErrorKind {
|
||||
expected_type: InterfaceType,
|
||||
|
||||
/// The received type.
|
||||
received_type: InterfaceType,
|
||||
received_value: InterfaceValue,
|
||||
},
|
||||
|
||||
/// Need to read some values from the stack, but it doesn't
|
||||
@ -163,6 +164,12 @@ pub enum InstructionErrorKind {
|
||||
type_index: u32,
|
||||
},
|
||||
|
||||
/// The searched by name type doesn't exist.
|
||||
RecordTypeByNameIsMissing {
|
||||
/// The record type name.
|
||||
type_name: String,
|
||||
},
|
||||
|
||||
/// Read a type that has an unexpected type.
|
||||
InvalidTypeKind {
|
||||
/// The expected kind.
|
||||
@ -199,11 +206,11 @@ impl Display for InstructionErrorKind {
|
||||
|
||||
Self::InvalidValueOnTheStack {
|
||||
expected_type,
|
||||
received_type,
|
||||
received_value,
|
||||
} => write!(
|
||||
formatter,
|
||||
"read a value of type `{:?}` from the stack, but the type `{:?}` was expected",
|
||||
received_type, expected_type,
|
||||
"read a value `{:?}` from the stack, that can't be converted to `{:?}`",
|
||||
received_value, expected_type,
|
||||
),
|
||||
|
||||
Self::StackIsTooSmall { needed } => write!(
|
||||
@ -261,6 +268,12 @@ impl Display for InstructionErrorKind {
|
||||
"read a type of kind `{:?}`, but the kind `{:?}` was expected",
|
||||
received_kind, expected_kind
|
||||
),
|
||||
|
||||
Self::RecordTypeByNameIsMissing { type_name } => write!(
|
||||
formatter,
|
||||
"type with `{}` is missing in a Wasm binary",
|
||||
type_name
|
||||
),
|
||||
Self::SerdeError(err) => write!(
|
||||
formatter,
|
||||
"serde error: {}", err,
|
||||
|
@ -127,7 +127,7 @@ executable_instruction!(
|
||||
instruction,
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: InterfaceType::ByteArray,
|
||||
received_type: (&value).into(),
|
||||
received_value: value,
|
||||
},
|
||||
)),
|
||||
|
||||
|
@ -2,13 +2,12 @@ use crate::{
|
||||
errors::{InstructionError, InstructionErrorKind},
|
||||
interpreter::wasm::structures::{FunctionIndex, TypedIndex},
|
||||
interpreter::Instruction,
|
||||
types::InterfaceType,
|
||||
};
|
||||
|
||||
executable_instruction!(
|
||||
call_core(function_index: u32, instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let instance = &runtime.wasm_instance;
|
||||
let index = FunctionIndex::new(function_index as usize);
|
||||
|
||||
let local_or_import = instance.local_or_import(index).ok_or_else(|| {
|
||||
@ -29,21 +28,8 @@ executable_instruction!(
|
||||
},
|
||||
)
|
||||
})?;
|
||||
let input_types = inputs
|
||||
.iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<InterfaceType>>();
|
||||
|
||||
if input_types != local_or_import.inputs() {
|
||||
return Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::LocalOrImportSignatureMismatch {
|
||||
function_index,
|
||||
expected: (local_or_import.inputs().to_vec(), vec![]),
|
||||
received: (input_types, vec![]),
|
||||
},
|
||||
));
|
||||
}
|
||||
super::check_function_signature(&**instance, local_or_import, &inputs, instruction)?;
|
||||
|
||||
let outputs = local_or_import.call(&inputs).map_err(|_| {
|
||||
InstructionError::new(
|
||||
|
@ -7,6 +7,8 @@ mod records;
|
||||
mod strings;
|
||||
mod swap2;
|
||||
|
||||
use crate::interpreter::wasm;
|
||||
use crate::types::InterfaceType;
|
||||
use crate::{
|
||||
errors::{InstructionError, InstructionErrorKind, InstructionResult, WasmValueNativeCastError},
|
||||
values::{InterfaceValue, NativeType},
|
||||
@ -153,6 +155,7 @@ pub enum Instruction {
|
||||
/// The `string.size` instruction.
|
||||
ByteArraySize,
|
||||
|
||||
/*
|
||||
/// The `record.lift` instruction.
|
||||
RecordLift {
|
||||
/// The type index of the record.
|
||||
@ -165,6 +168,8 @@ pub enum Instruction {
|
||||
type_index: u32,
|
||||
},
|
||||
|
||||
*/
|
||||
|
||||
/// The `record.lift_memory` instruction.
|
||||
RecordLiftMemory {
|
||||
/// The type index of the record.
|
||||
@ -197,6 +202,114 @@ where
|
||||
.map_err(|error| InstructionError::new(instruction, InstructionErrorKind::ToNative(error)))
|
||||
}
|
||||
|
||||
pub(crate) fn check_function_signature<
|
||||
'instance,
|
||||
Instance,
|
||||
Export,
|
||||
LocalImport,
|
||||
Memory,
|
||||
MemoryView,
|
||||
>(
|
||||
instance: &'instance Instance,
|
||||
local_import: &LocalImport,
|
||||
values: &[InterfaceValue],
|
||||
instruction: Instruction,
|
||||
) -> Result<(), InstructionError>
|
||||
where
|
||||
Export: wasm::structures::Export + 'instance,
|
||||
LocalImport: wasm::structures::LocalImport + 'instance,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'instance,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
let func_inputs = local_import.inputs();
|
||||
|
||||
for (func_input_arg, value) in func_inputs.iter().zip(values.iter()) {
|
||||
is_value_compatible_to_type(instance, &func_input_arg, value, instruction)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check whether the provided value could be a value of the provided type.
|
||||
pub(crate) fn is_value_compatible_to_type<
|
||||
'instance,
|
||||
Instance,
|
||||
Export,
|
||||
LocalImport,
|
||||
Memory,
|
||||
MemoryView,
|
||||
>(
|
||||
instance: &'instance Instance,
|
||||
interface_type: &InterfaceType,
|
||||
interface_value: &InterfaceValue,
|
||||
instruction: Instruction,
|
||||
) -> Result<(), InstructionError>
|
||||
where
|
||||
Export: wasm::structures::Export + 'instance,
|
||||
LocalImport: wasm::structures::LocalImport + 'instance,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'instance,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
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::ByteArray, InterfaceValue::ByteArray(_)) => Ok(()),
|
||||
(InterfaceType::Record(ref record_name), InterfaceValue::Record(record_fields)) => {
|
||||
let record_type = instance.wit_record_by_name(record_name).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::RecordTypeByNameIsMissing {
|
||||
type_name: record_name.to_owned(),
|
||||
},
|
||||
)
|
||||
})?;
|
||||
|
||||
if record_fields.len() != record_type.fields.len() {
|
||||
return Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: interface_type.clone(),
|
||||
received_value: interface_value.clone(),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
for (record_type_field, record_value_field) in
|
||||
record_type.fields.iter().zip(record_fields.iter())
|
||||
{
|
||||
is_value_compatible_to_type(
|
||||
instance,
|
||||
&record_type_field.ty,
|
||||
record_value_field,
|
||||
instruction,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: interface_type.clone(),
|
||||
received_value: interface_value.clone(),
|
||||
},
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use crate::{ast::*, interpreter::wasm, types::*, values::*};
|
||||
@ -381,7 +494,7 @@ pub(crate) mod tests {
|
||||
Some(&self.memory)
|
||||
}
|
||||
|
||||
fn wit_type(&self, index: u32) -> Option<&Type> {
|
||||
fn wit_type_by_id(&self, index: u32) -> Option<&Type> {
|
||||
self.wit_types.get(index as usize)
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ macro_rules! lowering_lifting {
|
||||
instruction,
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: InterfaceType::$from_variant,
|
||||
received_type: (&wrong_value).into(),
|
||||
received_value: wrong_value,
|
||||
}
|
||||
))
|
||||
},
|
||||
|
@ -9,18 +9,16 @@ use crate::interpreter::instructions::to_native;
|
||||
use crate::{
|
||||
ast::{Type, TypeKind},
|
||||
errors::{InstructionError, InstructionErrorKind},
|
||||
interpreter::{
|
||||
stack::{Stack, Stackable},
|
||||
Instruction,
|
||||
},
|
||||
interpreter::Instruction,
|
||||
types::{InterfaceType, RecordType},
|
||||
values::{FlattenInterfaceValueIterator, InterfaceValue},
|
||||
values::InterfaceValue,
|
||||
vec1::Vec1,
|
||||
};
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryInto;
|
||||
|
||||
/*
|
||||
/// Build an `InterfaceValue::Record` based on values on the stack.
|
||||
///
|
||||
/// To fill a record, every field `field_1` to `field_n` must get its
|
||||
@ -105,10 +103,11 @@ where
|
||||
}
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
fn record_lift_memory_<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance mut Instance,
|
||||
record_type: RecordType,
|
||||
instance: &'instance Instance,
|
||||
record_type: &RecordType,
|
||||
offset: usize,
|
||||
instruction: Instruction,
|
||||
) -> Result<InterfaceValue, InstructionError>
|
||||
@ -123,8 +122,8 @@ where
|
||||
fn record_size(record_type: &RecordType) -> usize {
|
||||
let mut record_size = 0;
|
||||
|
||||
for ty in record_type.fields.iter() {
|
||||
let params_count = match ty {
|
||||
for field_type in record_type.fields.iter() {
|
||||
let params_count = match field_type.ty {
|
||||
InterfaceType::String | InterfaceType::ByteArray => 2,
|
||||
_ => 1,
|
||||
};
|
||||
@ -137,16 +136,16 @@ where
|
||||
|
||||
let length = record_type.fields.len();
|
||||
let mut values = VecDeque::with_capacity(length);
|
||||
let size = record_size(&record_type);
|
||||
let size = record_size(record_type);
|
||||
let data = read_from_instance_mem(instance, instruction, offset, size)?;
|
||||
// TODO: add error handling
|
||||
let data =
|
||||
safe_transmute::transmute_many::<u64, safe_transmute::SingleManyGuard>(&data).unwrap();
|
||||
|
||||
let mut field_id = 0;
|
||||
for field in record_type.fields.into_vec() {
|
||||
for field in (*record_type.fields).iter() {
|
||||
let value = data[field_id];
|
||||
match field {
|
||||
match &field.ty {
|
||||
InterfaceType::S8 => {
|
||||
values.push_back(InterfaceValue::S8(value as _));
|
||||
}
|
||||
@ -201,7 +200,7 @@ where
|
||||
|
||||
utils::deallocate(instance, instruction, string_offset as _, string_size as _)?;
|
||||
} else {
|
||||
values.push_back(InterfaceValue::String("".to_string()));
|
||||
values.push_back(InterfaceValue::String(String::new()));
|
||||
}
|
||||
}
|
||||
InterfaceType::ByteArray => {
|
||||
@ -224,9 +223,21 @@ where
|
||||
values.push_back(InterfaceValue::ByteArray(vec![]));
|
||||
}
|
||||
}
|
||||
InterfaceType::Record(record_type) => {
|
||||
InterfaceType::Record(record_type_name) => {
|
||||
let offset = value;
|
||||
|
||||
let record_type =
|
||||
instance
|
||||
.wit_record_by_name(&record_type_name)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::RecordTypeByNameIsMissing {
|
||||
type_name: record_type_name.to_owned(),
|
||||
},
|
||||
)
|
||||
})?;
|
||||
|
||||
values.push_back(record_lift_memory_(
|
||||
instance,
|
||||
record_type,
|
||||
@ -275,8 +286,8 @@ where
|
||||
.map_err(|k| InstructionError::new(instruction, k))?;
|
||||
|
||||
// TODO: size = 0
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let record_type = match instance.wit_type(type_index).ok_or_else(|| {
|
||||
let instance = &runtime.wasm_instance;
|
||||
let record_type = match instance.wit_type_by_id(type_index).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::TypeIsMissing { type_index },
|
||||
@ -294,7 +305,7 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
let record = record_lift_memory_(*instance, record_type, offset, instruction)?;
|
||||
let record = record_lift_memory_(&**instance, &record_type, offset, instruction)?;
|
||||
runtime.stack.push(record);
|
||||
|
||||
Ok(())
|
||||
@ -353,8 +364,8 @@ where
|
||||
result.push(value.len() as _);
|
||||
}
|
||||
|
||||
InterfaceValue::Record(record) => {
|
||||
let record_ptr = record_lower_memory_(instance, instruction, record)?;
|
||||
InterfaceValue::Record(values) => {
|
||||
let record_ptr = record_lower_memory_(instance, instruction, values)?;
|
||||
|
||||
result.push(record_ptr as _);
|
||||
}
|
||||
@ -384,7 +395,7 @@ where
|
||||
Box::new({
|
||||
move |runtime| -> _ {
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let record_type = match instance.wit_type(type_index).ok_or_else(|| {
|
||||
let record_type = match instance.wit_type_by_id(type_index).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::TypeIsMissing { type_index },
|
||||
@ -401,10 +412,9 @@ where
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
match runtime.stack.pop1() {
|
||||
Some(InterfaceValue::Record(record_values))
|
||||
if record_type == &(&*record_values).into() =>
|
||||
{
|
||||
Some(InterfaceValue::Record(record_values)) => {
|
||||
/*
|
||||
let value: Vec<u8> = crate::serde::de::from_interface_values(&record_values)
|
||||
.map_err(|e| {
|
||||
@ -426,8 +436,8 @@ where
|
||||
Some(value) => Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: InterfaceType::Record(record_type.clone()),
|
||||
received_type: (&value).into(),
|
||||
expected_type: InterfaceType::Record(record_type.name.clone()),
|
||||
received_value: value,
|
||||
},
|
||||
)),
|
||||
None => Err(InstructionError::new(
|
||||
@ -439,6 +449,7 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
pub(crate) fn record_lower<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
type_index: u32,
|
||||
instruction: Instruction,
|
||||
@ -498,3 +509,4 @@ where
|
||||
}
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
@ -42,7 +42,7 @@ where
|
||||
}
|
||||
|
||||
pub(super) fn write_to_instance_mem<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance mut Instance,
|
||||
instance: &'instance Instance,
|
||||
instruction: Instruction,
|
||||
bytes: &[u8],
|
||||
) -> Result<i32, InstructionError>
|
||||
@ -74,7 +74,7 @@ where
|
||||
}
|
||||
|
||||
pub(super) fn allocate<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance mut Instance,
|
||||
instance: &'instance Instance,
|
||||
instruction: Instruction,
|
||||
size: i32,
|
||||
) -> Result<i32, InstructionError>
|
||||
@ -105,7 +105,7 @@ where
|
||||
}
|
||||
|
||||
pub(super) fn deallocate<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance mut Instance,
|
||||
instance: &'instance Instance,
|
||||
instruction: Instruction,
|
||||
mem_ptr: i32,
|
||||
size: i32,
|
||||
@ -128,7 +128,7 @@ where
|
||||
}
|
||||
|
||||
fn call_core<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance mut Instance,
|
||||
instance: &'instance Instance,
|
||||
function_index: u32,
|
||||
instruction: Instruction,
|
||||
inputs: Vec<InterfaceValue>,
|
||||
@ -147,20 +147,9 @@ where
|
||||
InstructionErrorKind::LocalOrImportIsMissing { function_index },
|
||||
)
|
||||
})?;
|
||||
let input_types = inputs
|
||||
.iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<InterfaceType>>();
|
||||
if input_types != local_or_import.inputs() {
|
||||
return Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::LocalOrImportSignatureMismatch {
|
||||
function_index,
|
||||
expected: (local_or_import.inputs().to_vec(), vec![]),
|
||||
received: (input_types, vec![]),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
crate::interpreter::instructions::check_function_signature(instance, local_or_import, &inputs, instruction)?;
|
||||
|
||||
let outputs = local_or_import.call(&inputs).map_err(|_| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
|
@ -131,7 +131,7 @@ executable_instruction!(
|
||||
instruction,
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: InterfaceType::String,
|
||||
received_type: (&value).into(),
|
||||
received_value: (&value).clone(),
|
||||
},
|
||||
)),
|
||||
|
||||
|
@ -245,13 +245,14 @@ where
|
||||
}
|
||||
Instruction::ByteArraySize => instructions::byte_array_size(*instruction),
|
||||
|
||||
/*
|
||||
Instruction::RecordLift { type_index } => {
|
||||
instructions::record_lift(*type_index, *instruction)
|
||||
}
|
||||
Instruction::RecordLower { type_index } => {
|
||||
instructions::record_lower(*type_index, *instruction)
|
||||
}
|
||||
|
||||
*/
|
||||
Instruction::RecordLiftMemory { type_index } => {
|
||||
instructions::record_lift_memory(*type_index, *instruction)
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use crate::types::RecordType;
|
||||
use crate::{ast, types::InterfaceType, values::InterfaceValue};
|
||||
use std::{cell::Cell, ops::Deref};
|
||||
|
||||
@ -72,9 +73,10 @@ where
|
||||
MV: MemoryView,
|
||||
{
|
||||
fn export(&self, export_name: &str) -> Option<&E>;
|
||||
fn local_or_import<I: TypedIndex + LocalImportIndex>(&mut self, index: I) -> Option<&LI>;
|
||||
fn local_or_import<I: TypedIndex + LocalImportIndex>(&self, index: I) -> Option<&LI>;
|
||||
fn memory(&self, index: usize) -> Option<&M>;
|
||||
fn wit_type(&self, index: u32) -> Option<&ast::Type>;
|
||||
fn wit_type_by_id(&self, index: u32) -> Option<&ast::Type>;
|
||||
fn wit_record_by_name(&self, name: &str) -> Option<&RecordType>;
|
||||
}
|
||||
|
||||
impl Export for () {
|
||||
@ -154,11 +156,15 @@ where
|
||||
None
|
||||
}
|
||||
|
||||
fn local_or_import<I: TypedIndex + LocalImportIndex>(&mut self, _index: I) -> Option<&LI> {
|
||||
fn local_or_import<I: TypedIndex + LocalImportIndex>(&self, _index: I) -> Option<&LI> {
|
||||
None
|
||||
}
|
||||
|
||||
fn wit_type(&self, _index: u32) -> Option<&ast::Type> {
|
||||
fn wit_type_by_id(&self, _index: u32) -> Option<&ast::Type> {
|
||||
None
|
||||
}
|
||||
|
||||
fn wit_record_by_name(&self, _name: &str) -> Option<&RecordType> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ macro_rules! next {
|
||||
|
||||
Some(wrong_value) => Err(DeserializeError::TypeMismatch {
|
||||
expected_type: InterfaceType::$variant,
|
||||
received_type: (*wrong_value).into(),
|
||||
received_value: (*wrong_value).clone(),
|
||||
}),
|
||||
|
||||
None => Err(DeserializeError::InputEmpty),
|
||||
@ -122,7 +122,7 @@ impl<'de> Deserializer<'de> {
|
||||
|
||||
Some(wrong_value) => Err(DeserializeError::TypeMismatch {
|
||||
expected_type: InterfaceType::String,
|
||||
received_type: (*wrong_value).into(),
|
||||
received_value: (*wrong_value).clone(),
|
||||
}),
|
||||
|
||||
None => Err(DeserializeError::InputEmpty),
|
||||
@ -139,7 +139,7 @@ impl<'de> Deserializer<'de> {
|
||||
|
||||
Some(wrong_value) => Err(DeserializeError::TypeMismatch {
|
||||
expected_type: InterfaceType::ByteArray,
|
||||
received_type: (*wrong_value).into(),
|
||||
received_value: (*wrong_value).clone(),
|
||||
}),
|
||||
|
||||
None => Err(DeserializeError::InputEmpty),
|
||||
@ -165,7 +165,7 @@ pub enum DeserializeError {
|
||||
expected_type: InterfaceType,
|
||||
|
||||
/// The received type.
|
||||
received_type: InterfaceType,
|
||||
received_value: InterfaceValue,
|
||||
},
|
||||
|
||||
/// Arbitrary message.
|
||||
@ -186,11 +186,11 @@ impl Display for DeserializeError {
|
||||
Self::InputEmpty => write!(formatter, "Unexpected end of input"),
|
||||
Self::TypeMismatch {
|
||||
ref expected_type,
|
||||
ref received_type,
|
||||
ref received_value,
|
||||
} => write!(
|
||||
formatter,
|
||||
"Type mismatch detected, expected `{:?}` but received `{:?}`",
|
||||
expected_type, received_type
|
||||
"Type mismatch detected: `{:?}` can't be converted to `{:?}`",
|
||||
received_value, expected_type,
|
||||
),
|
||||
}
|
||||
}
|
||||
@ -220,7 +220,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||
Some(InterfaceValue::ByteArray(_)) => 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(InterfaceValue::Record(..)) => unreachable!("Records should have been flattened."), // already flattened
|
||||
None => Err(DeserializeError::InputEmpty),
|
||||
}
|
||||
}
|
||||
|
23
src/types.rs
23
src/types.rs
@ -51,15 +51,30 @@ pub enum InterfaceType {
|
||||
/// A 64-bits integer (as defiend in WebAssembly core).
|
||||
I64,
|
||||
|
||||
/// A record.
|
||||
Record(RecordType),
|
||||
/// A record contains type name.
|
||||
// TODO: consider making it &str
|
||||
Record(String),
|
||||
}
|
||||
|
||||
/// Represents a record field type.
|
||||
#[derive(PartialEq, Debug, Clone, 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, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RecordType {
|
||||
/// Types representing the fields.
|
||||
/// 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<InterfaceType>,
|
||||
pub fields: Vec1<RecordFieldType>,
|
||||
}
|
||||
|
@ -1,10 +1,6 @@
|
||||
//! Defines WIT values and associated operations.
|
||||
|
||||
use crate::{
|
||||
errors::WasmValueNativeCastError,
|
||||
types::{InterfaceType, RecordType},
|
||||
vec1::Vec1,
|
||||
};
|
||||
use crate::{errors::WasmValueNativeCastError, types::InterfaceType, vec1::Vec1};
|
||||
use std::{convert::TryFrom, slice::Iter};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
@ -60,6 +56,7 @@ pub enum InterfaceValue {
|
||||
Record(Vec1<InterfaceValue>),
|
||||
}
|
||||
|
||||
/*
|
||||
impl From<&InterfaceValue> for InterfaceType {
|
||||
fn from(value: &InterfaceValue) -> Self {
|
||||
match value {
|
||||
@ -78,10 +75,11 @@ impl From<&InterfaceValue> for InterfaceType {
|
||||
//InterfaceValue::Anyref(_) => Self::Anyref,
|
||||
InterfaceValue::I32(_) => Self::I32,
|
||||
InterfaceValue::I64(_) => Self::I64,
|
||||
InterfaceValue::Record(values) => Self::Record((&**values).into()),
|
||||
InterfaceValue::Record(name) => Self::Record(name.to_owned()),
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl Default for InterfaceValue {
|
||||
fn default() -> Self {
|
||||
@ -89,6 +87,7 @@ impl Default for InterfaceValue {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl From<&Vec<InterfaceValue>> for RecordType {
|
||||
fn from(values: &Vec<InterfaceValue>) -> Self {
|
||||
RecordType {
|
||||
@ -97,6 +96,7 @@ impl From<&Vec<InterfaceValue>> for RecordType {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/// Represents a native type supported by WIT.
|
||||
pub trait NativeType {
|
||||
@ -123,7 +123,7 @@ macro_rules! native {
|
||||
match w {
|
||||
InterfaceValue::$variant(n) => Ok(n.clone()),
|
||||
_ => Err(WasmValueNativeCastError {
|
||||
from: w.into(),
|
||||
from: w.clone(),
|
||||
to: <$native_type>::INTERFACE_TYPE,
|
||||
}),
|
||||
}
|
||||
@ -173,8 +173,8 @@ impl<'a> Iterator for FlattenInterfaceValueIterator<'a> {
|
||||
}
|
||||
|
||||
// Recursively iterate over the record.
|
||||
Some(InterfaceValue::Record(values)) => {
|
||||
self.iterators.push(values.iter());
|
||||
Some(InterfaceValue::Record(fields)) => {
|
||||
self.iterators.push(fields.iter());
|
||||
self.next()
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user