mirror of
https://github.com/fluencelabs/interface-types
synced 2024-12-04 15:20:20 +00:00
add byte array handler
This commit is contained in:
parent
689c6757fb
commit
bb9e4dbdfc
@ -92,6 +92,7 @@ fn ty<'input, E: ParseError<&'input [u8]>>(
|
||||
0x08 => InterfaceType::F32,
|
||||
0x09 => InterfaceType::F64,
|
||||
0x0a => InterfaceType::String,
|
||||
0x36 => InterfaceType::ByteArray,
|
||||
0x0b => InterfaceType::Anyref,
|
||||
0x0c => InterfaceType::I32,
|
||||
0x0d => InterfaceType::I64,
|
||||
@ -235,6 +236,10 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
|
||||
0x23 => (input, Instruction::StringLowerMemory),
|
||||
0x24 => (input, Instruction::StringSize),
|
||||
|
||||
0x37 => (input, Instruction::ByteArrayLiftMemory),
|
||||
0x38 => (input, Instruction::ByteArrayLowerMemory),
|
||||
0x39 => (input, Instruction::ByteArraySize),
|
||||
|
||||
0x25 => {
|
||||
consume!((input, argument_0) = uleb(input)?);
|
||||
|
||||
|
@ -27,6 +27,7 @@ mod keyword {
|
||||
custom_keyword!(u32);
|
||||
custom_keyword!(u64);
|
||||
custom_keyword!(string);
|
||||
custom_keyword!(byte_array);
|
||||
|
||||
// Instructions.
|
||||
custom_keyword!(argument_get = "arg.get");
|
||||
@ -66,6 +67,9 @@ mod keyword {
|
||||
custom_keyword!(string_lift_memory = "string.lift_memory");
|
||||
custom_keyword!(string_lower_memory = "string.lower_memory");
|
||||
custom_keyword!(string_size = "string.size");
|
||||
custom_keyword!(byte_array_lift_memory = "byte_array.lift_memory");
|
||||
custom_keyword!(byte_array_lower_memory = "byte_array.lower_memory");
|
||||
custom_keyword!(byte_array_size = "byte_array.size");
|
||||
custom_keyword!(record_lift = "record.lift");
|
||||
custom_keyword!(record_lower = "record.lower");
|
||||
custom_keyword!(dup = "dup");
|
||||
@ -120,6 +124,10 @@ impl Parse<'_> for InterfaceType {
|
||||
parser.parse::<keyword::string>()?;
|
||||
|
||||
Ok(InterfaceType::String)
|
||||
} else if lookahead.peek::<keyword::byte_array>() {
|
||||
parser.parse::<keyword::byte_array>()?;
|
||||
|
||||
Ok(InterfaceType::ByteArray)
|
||||
} else if lookahead.peek::<keyword::anyref>() {
|
||||
parser.parse::<keyword::anyref>()?;
|
||||
|
||||
|
@ -105,6 +105,7 @@ where
|
||||
InterfaceType::F32 => 0x08_u8.to_bytes(writer),
|
||||
InterfaceType::F64 => 0x09_u8.to_bytes(writer),
|
||||
InterfaceType::String => 0x0a_u8.to_bytes(writer),
|
||||
InterfaceType::ByteArray => 0x36_u8.to_bytes(writer),
|
||||
InterfaceType::Anyref => 0x0b_u8.to_bytes(writer),
|
||||
InterfaceType::I32 => 0x0c_u8.to_bytes(writer),
|
||||
InterfaceType::I64 => 0x0d_u8.to_bytes(writer),
|
||||
@ -334,6 +335,10 @@ where
|
||||
Instruction::StringLowerMemory => 0x23_u8.to_bytes(writer)?,
|
||||
Instruction::StringSize => 0x24_u8.to_bytes(writer)?,
|
||||
|
||||
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)?
|
||||
|
@ -73,6 +73,7 @@ impl ToString for &InterfaceType {
|
||||
InterfaceType::F32 => "f32".to_string(),
|
||||
InterfaceType::F64 => "f64".to_string(),
|
||||
InterfaceType::String => "string".to_string(),
|
||||
InterfaceType::ByteArray => "byteArray".to_string(),
|
||||
InterfaceType::Anyref => "anyref".to_string(),
|
||||
InterfaceType::I32 => "i32".to_string(),
|
||||
InterfaceType::I64 => "i64".to_string(),
|
||||
@ -138,6 +139,9 @@ impl ToString for &Instruction {
|
||||
Instruction::StringLiftMemory => "string.lift_memory".into(),
|
||||
Instruction::StringLowerMemory => "string.lower_memory".into(),
|
||||
Instruction::StringSize => "string.size".into(),
|
||||
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::Dup => "dup".into(),
|
||||
|
141
src/interpreter/instructions/byte_arrays.rs
Normal file
141
src/interpreter/instructions/byte_arrays.rs
Normal file
@ -0,0 +1,141 @@
|
||||
use super::to_native;
|
||||
use crate::{
|
||||
errors::{InstructionError, InstructionErrorKind},
|
||||
interpreter::Instruction,
|
||||
types::InterfaceType,
|
||||
values::InterfaceValue,
|
||||
};
|
||||
use std::{cell::Cell, convert::TryInto};
|
||||
|
||||
executable_instruction!(
|
||||
byte_array_lift_memory(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
let inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 2 },
|
||||
)
|
||||
})?;
|
||||
|
||||
let memory_index: u32 = 0;
|
||||
let memory = runtime
|
||||
.wasm_instance
|
||||
.memory(memory_index as usize)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?;
|
||||
|
||||
let pointer: usize = to_native::<i32>(&inputs[0], instruction)?
|
||||
.try_into()
|
||||
.map_err(|e| (e, "pointer").into())
|
||||
.map_err(|k| InstructionError::new(instruction, k))?;
|
||||
let length: usize = to_native::<i32>(&inputs[1], instruction)?
|
||||
.try_into()
|
||||
.map_err(|e| (e, "length").into())
|
||||
.map_err(|k| InstructionError::new(instruction, k))?;
|
||||
let memory_view = memory.view();
|
||||
|
||||
if length == 0 {
|
||||
runtime.stack.push(InterfaceValue::String("".into()));
|
||||
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
if memory_view.len() < pointer + length {
|
||||
return Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::MemoryOutOfBoundsAccess {
|
||||
index: pointer + length,
|
||||
length: memory_view.len(),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
let data: Vec<u8> = (&memory_view[pointer..pointer + length])
|
||||
.iter()
|
||||
.map(Cell::get)
|
||||
.collect();
|
||||
|
||||
runtime.stack.push(InterfaceValue::ByteArray(data));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
executable_instruction!(
|
||||
byte_array_lower_memory(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
let inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 2 },
|
||||
)
|
||||
})?;
|
||||
|
||||
let byte_array_pointer: usize = to_native::<i32>(&inputs[0], instruction)?
|
||||
.try_into()
|
||||
.map_err(|e| (e, "pointer").into())
|
||||
.map_err(|k| InstructionError::new(instruction, k))?;
|
||||
let byte_array: Vec<u8> = to_native(&inputs[1], instruction)?;
|
||||
let byte_array_length: i32 = byte_array.len().try_into().map_err(|_| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::NegativeValue { subject: "string_length" },
|
||||
)
|
||||
})?;
|
||||
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let memory_index: u32 = 0;
|
||||
let memory_view = instance
|
||||
.memory(memory_index as usize)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?
|
||||
.view();
|
||||
|
||||
for (nth, byte) in byte_array.iter().enumerate() {
|
||||
memory_view[byte_array_pointer as usize + nth].set(*byte);
|
||||
}
|
||||
|
||||
runtime.stack.push(InterfaceValue::I32(byte_array_pointer as i32));
|
||||
runtime.stack.push(InterfaceValue::I32(byte_array_length));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
executable_instruction!(
|
||||
byte_array_size(instruction: Instruction) -> _ {
|
||||
move |runtime| -> _ {
|
||||
match runtime.stack.pop1() {
|
||||
Some(InterfaceValue::ByteArray(byte_array)) => {
|
||||
let length = byte_array.len() as i32;
|
||||
runtime.stack.push(InterfaceValue::I32(length));
|
||||
|
||||
Ok(())
|
||||
},
|
||||
|
||||
Some(value) => Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: InterfaceType::ByteArray,
|
||||
received_type: (&value).into(),
|
||||
},
|
||||
)),
|
||||
|
||||
None => Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 },
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
@ -1,4 +1,5 @@
|
||||
mod argument_get;
|
||||
mod byte_arrays;
|
||||
mod call_core;
|
||||
mod numbers;
|
||||
mod records;
|
||||
@ -11,6 +12,7 @@ use crate::{
|
||||
values::{InterfaceValue, NativeType},
|
||||
};
|
||||
pub(crate) use argument_get::argument_get;
|
||||
pub(crate) use byte_arrays::*;
|
||||
pub(crate) use call_core::call_core;
|
||||
pub(crate) use numbers::*;
|
||||
pub(crate) use records::*;
|
||||
@ -139,6 +141,15 @@ pub enum Instruction {
|
||||
/// The `string.size` instruction.
|
||||
StringSize,
|
||||
|
||||
/// The `string.lift_memory` instruction.
|
||||
ByteArrayLiftMemory,
|
||||
|
||||
/// The `string.lower_memory` instruction.
|
||||
ByteArrayLowerMemory,
|
||||
|
||||
/// The `string.size` instruction.
|
||||
ByteArraySize,
|
||||
|
||||
/// The `record.lift` instruction.
|
||||
RecordLift {
|
||||
/// The type index of the record.
|
||||
|
@ -238,6 +238,10 @@ where
|
||||
Instruction::StringLowerMemory => instructions::string_lower_memory(*instruction),
|
||||
Instruction::StringSize => instructions::string_size(*instruction),
|
||||
|
||||
Instruction::ByteArrayLiftMemory => instructions::byte_array_lift_memory(*instruction),
|
||||
Instruction::ByteArrayLowerMemory => instructions::byte_array_lower_memory(*instruction),
|
||||
Instruction::ByteArraySize => instructions::byte_array_size(*instruction),
|
||||
|
||||
Instruction::RecordLift { type_index } => {
|
||||
instructions::record_lift(*type_index, *instruction)
|
||||
}
|
||||
|
@ -129,6 +129,23 @@ impl<'de> Deserializer<'de> {
|
||||
}
|
||||
}
|
||||
|
||||
fn next_byte_array(&mut self) -> Result<&'de [u8], DeserializeError> {
|
||||
match self.iterator.peek() {
|
||||
Some(InterfaceValue::ByteArray(v)) => {
|
||||
self.iterator.next();
|
||||
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
Some(wrong_value) => Err(DeserializeError::TypeMismatch {
|
||||
expected_type: InterfaceType::ByteArray,
|
||||
received_type: (*wrong_value).into(),
|
||||
}),
|
||||
|
||||
None => Err(DeserializeError::InputEmpty),
|
||||
}
|
||||
}
|
||||
|
||||
next!(next_i32, I32, i32);
|
||||
next!(next_i64, I64, i64);
|
||||
}
|
||||
@ -200,6 +217,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||
Some(InterfaceValue::F32(_)) => self.deserialize_f32(visitor),
|
||||
Some(InterfaceValue::F64(_)) => self.deserialize_f64(visitor),
|
||||
Some(InterfaceValue::String(_)) => self.deserialize_string(visitor),
|
||||
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
|
||||
@ -309,11 +327,11 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||
self.deserialize_str(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
todo!("`bytes` is not supported by WIT for the moment.")
|
||||
visitor.visit_bytes(self.next_byte_array()?)
|
||||
}
|
||||
|
||||
fn deserialize_byte_buf<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
|
@ -39,6 +39,9 @@ pub enum InterfaceType {
|
||||
/// A string.
|
||||
String,
|
||||
|
||||
/// A byte array.
|
||||
ByteArray,
|
||||
|
||||
/// An `any` reference.
|
||||
Anyref,
|
||||
|
||||
|
@ -46,6 +46,9 @@ pub enum InterfaceValue {
|
||||
/// A string.
|
||||
String(String),
|
||||
|
||||
/// A byte array.
|
||||
ByteArray(Vec<u8>),
|
||||
|
||||
//Anyref(?),
|
||||
/// A 32-bits integer (as defined in WebAssembly core).
|
||||
I32(i32),
|
||||
@ -71,6 +74,7 @@ impl From<&InterfaceValue> for InterfaceType {
|
||||
InterfaceValue::F32(_) => Self::F32,
|
||||
InterfaceValue::F64(_) => Self::F64,
|
||||
InterfaceValue::String(_) => Self::String,
|
||||
InterfaceValue::ByteArray(_) => Self::ByteArray,
|
||||
//InterfaceValue::Anyref(_) => Self::Anyref,
|
||||
InterfaceValue::I32(_) => Self::I32,
|
||||
InterfaceValue::I64(_) => Self::I64,
|
||||
@ -139,6 +143,7 @@ native!(u64, U64);
|
||||
native!(f32, F32);
|
||||
native!(f64, F64);
|
||||
native!(String, String);
|
||||
native!(Vec<u8>, ByteArray);
|
||||
|
||||
/// Iterates over a vector of `InterfaceValues` but flatten all the
|
||||
/// values. So `I32(1), Record([I32(2), I32(3)]), I32(4)` will be
|
||||
|
Loading…
Reference in New Issue
Block a user