decouple ToBytes into a separate crate

This commit is contained in:
vms 2020-12-29 12:32:17 +03:00
parent b8ca780473
commit ffbe1a282a
9 changed files with 201 additions and 196 deletions

8
Cargo.lock generated
View File

@ -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",

View File

@ -1,5 +1,6 @@
[workspace]
members = [
"crates/to-bytes",
"crates/it-types",
"wasmer-it",
]

View File

@ -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 }

View File

@ -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<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,

View File

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

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

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

View File

@ -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"

View File

@ -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<W>
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<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 an `IType` into bytes.
impl<W> ToBytes<W> 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<W> ToBytes<W> 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<W> ToBytes<W> 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::<Vec<_>>();
record_type_impl.to_bytes(writer)
}
}
/// 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 a `TypeKind` into bytes.
impl<W> ToBytes<W> 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::<Vec<_>>();
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)?,

View File

@ -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.