From ffbe1a282a7dea97066b7a83d1e916b92dd3090b Mon Sep 17 00:00:00 2001 From: vms Date: Tue, 29 Dec 2020 12:32:17 +0300 Subject: [PATCH] decouple ToBytes into a separate crate --- Cargo.lock | 8 +- Cargo.toml | 1 + crates/it-types/Cargo.toml | 4 +- crates/it-types/src/impls/types.rs | 59 +++++ crates/to-bytes/Cargo.toml | 7 + crates/to-bytes/src/lib.rs | 104 +++++++++ wasmer-it/Cargo.toml | 1 + wasmer-it/src/encoders/binary.rs | 201 +----------------- .../src/interpreter/instructions/records.rs | 12 ++ 9 files changed, 201 insertions(+), 196 deletions(-) create mode 100644 crates/to-bytes/Cargo.toml create mode 100644 crates/to-bytes/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 2093188..4950fa3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,13 +20,18 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "fluence-it-types" -version = "0.1.0" +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.7" @@ -173,6 +178,7 @@ name = "wasmer-interface-types-fl" version = "0.17.21" dependencies = [ "fluence-it-types", + "it-to-bytes", "log", "nom", "safe-transmute", diff --git a/Cargo.toml b/Cargo.toml index 196e565..1190f48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = [ + "crates/to-bytes", "crates/it-types", "wasmer-it", ] diff --git a/crates/it-types/Cargo.toml b/crates/it-types/Cargo.toml index 64019ad..1d868d6 100644 --- a/crates/it-types/Cargo.toml +++ b/crates/it-types/Cargo.toml @@ -1,12 +1,14 @@ [package] name = "fluence-it-types" -version = "0.1.0" +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 } diff --git a/crates/it-types/src/impls/types.rs b/crates/it-types/src/impls/types.rs index ea74054..963818a 100644 --- a/crates/it-types/src/impls/types.rs +++ b/crates/it-types/src/impls/types.rs @@ -3,10 +3,69 @@ 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 ToBytes 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 ToBytes 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 ToBytes 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, diff --git a/crates/to-bytes/Cargo.toml b/crates/to-bytes/Cargo.toml new file mode 100644 index 0000000..4b03d7a --- /dev/null +++ b/crates/to-bytes/Cargo.toml @@ -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" diff --git a/crates/to-bytes/src/lib.rs b/crates/to-bytes/src/lib.rs new file mode 100644 index 0000000..e35fd8d --- /dev/null +++ b/crates/to-bytes/src/lib.rs @@ -0,0 +1,104 @@ +use std::io; +use std::io::Write; + +/// A trait for converting a value to bytes. +pub trait ToBytes +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 ToBytes 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 ToBytes 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 ToBytes 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 ToBytes 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 ToBytes for Vec +where + W: Write, + I: ToBytes, +{ + 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(()) + } +} diff --git a/wasmer-it/Cargo.toml b/wasmer-it/Cargo.toml index 2032475..0333a1d 100644 --- a/wasmer-it/Cargo.toml +++ b/wasmer-it/Cargo.toml @@ -9,6 +9,7 @@ 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" diff --git a/wasmer-it/src/encoders/binary.rs b/wasmer-it/src/encoders/binary.rs index c55dcba..260c428 100644 --- a/wasmer-it/src/encoders/binary.rs +++ b/wasmer-it/src/encoders/binary.rs @@ -1,191 +1,12 @@ //! Writes the AST into bytes representing WIT with its binary format. -use crate::{ast::*, interpreter::Instruction}; +use crate::ast::*; +use crate::interpreter::Instruction; -use crate::IRecordFieldType; -use crate::IRecordType; -use crate::IType; +use it_to_bytes::ToBytes; use std::io; use std::io::Write; -use std::ops::Deref; - -/// A trait for converting a value to bytes. -pub trait ToBytes -where - W: Write, -{ - /// Converts the given value into `&[u8]` in the given `writer`. - fn to_bytes(&self, writer: &mut W) -> io::Result<()>; -} - -/// Miscellaneous IType wrapper to pass the orphan rule. -pub struct ITypeImpl<'a>(pub &'a IType); - -/// Miscellaneous IRecordType wrapper to pass the orphan rule. -pub struct IRecordTypeImpl<'a>(pub &'a IRecordType); - -/// Miscellaneous IRecordFieldType wrapper to pass the orphan rule. -pub struct IRecordFieldTypeImpl<'a>(pub &'a IRecordFieldType); - -/// Encode a `u8` into a byte (well, it's already a byte!). -impl ToBytes 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 ToBytes 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 an `IType` into bytes. -impl ToBytes for ITypeImpl<'_> -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - match &self.0 { - 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)?; - let itype_impl = ITypeImpl(ty); - itype_impl.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 ToBytes for IRecordFieldTypeImpl<'_> -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - let record_field_type = &self.0; - record_field_type.name.as_str().to_bytes(writer)?; - let itype_impl = ITypeImpl(&record_field_type.ty); - itype_impl.to_bytes(writer) - } -} - -/// Encode a `RecordType` into bytes. -impl ToBytes for IRecordTypeImpl<'_> -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - let record_type = self.0; - record_type.name.as_str().to_bytes(writer)?; - let record_type_impl = record_type - .fields - .deref() - .iter() - .map(|r| IRecordFieldTypeImpl(r)) - .collect::>(); - - record_type_impl.to_bytes(writer) - } -} - -/// Encode a `str` into bytes. -/// -/// Decoder is `decoders::binary::string`. -impl ToBytes 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 ToBytes 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 ToBytes for Vec -where - W: Write, - I: ToBytes, -{ - 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 a `TypeKind` into bytes. impl ToBytes for TypeKind @@ -222,8 +43,7 @@ where { fn to_bytes(&self, writer: &mut W) -> io::Result<()> { self.name.to_bytes(writer)?; - let itype_impl = ITypeImpl(&self.ty); - itype_impl.to_bytes(writer) + self.ty.to_bytes(writer) } } @@ -242,17 +62,12 @@ where } => { TypeKind::Function.to_bytes(writer)?; arguments.to_bytes(writer)?; - let output_types = output_types - .iter() - .map(|t| ITypeImpl(t)) - .collect::>(); output_types.to_bytes(writer)?; } Type::Record(record_type) => { TypeKind::Record.to_bytes(writer)?; - let record_impl = IRecordTypeImpl(record_type.deref()); - record_impl.to_bytes(writer)?; + record_type.to_bytes(writer)?; } } @@ -416,13 +231,11 @@ where Instruction::ArrayLiftMemory { value_type } => { 0x37_u8.to_bytes(writer)?; - let value_type_impl = ITypeImpl(value_type); - value_type_impl.to_bytes(writer)? + value_type.to_bytes(writer)? } Instruction::ArrayLowerMemory { value_type } => { 0x38_u8.to_bytes(writer)?; - let value_type_impl = ITypeImpl(value_type); - value_type_impl.to_bytes(writer)? + value_type.to_bytes(writer)? } /* Instruction::ArraySize => 0x39_u8.to_bytes(writer)?, diff --git a/wasmer-it/src/interpreter/instructions/records.rs b/wasmer-it/src/interpreter/instructions/records.rs index 99f3b38..f5635e2 100644 --- a/wasmer-it/src/interpreter/instructions/records.rs +++ b/wasmer-it/src/interpreter/instructions/records.rs @@ -12,6 +12,18 @@ use crate::{ }; use std::convert::TryInto; +/* + +struct Record1 { +field1: String, +field2: i32, +} + +// export +fn foo(t: Record1) { + +// import + */ /* /// Build an `IValue::Record` based on values on the stack.