//! Writes the AST into bytes representing WIT with its binary format. use crate::{ ast::{Adapter, AdapterKind, Export, Import, InterfaceType, Interfaces, Type}, interpreter::Instruction, }; use std::io::{self, Write}; /// A trait for converting a value to bytes. 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 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 an `InterfaceType` into bytes. impl ToBytes for InterfaceType where W: Write, { fn to_bytes(&self, writer: &mut W) -> io::Result<()> { match self { InterfaceType::Int => 0x7fff_u64.to_bytes(writer), InterfaceType::Float => 0x7ffe_u64.to_bytes(writer), InterfaceType::Any => 0x7ffd_u64.to_bytes(writer), InterfaceType::String => 0x7ffc_u64.to_bytes(writer), InterfaceType::Seq => 0x7ffb_u64.to_bytes(writer), InterfaceType::I32 => 0x7f_u64.to_bytes(writer), InterfaceType::I64 => 0x7e_u64.to_bytes(writer), InterfaceType::F32 => 0x7d_u64.to_bytes(writer), InterfaceType::F64 => 0x7d_u64.to_bytes(writer), InterfaceType::AnyRef => 0x6f_u64.to_bytes(writer), } } } /// Encode an `AdapterKind` into bytes. impl ToBytes for AdapterKind where W: Write, { fn to_bytes(&self, writer: &mut W) -> io::Result<()> { match self { AdapterKind::Import => 0x00_u8.to_bytes(writer), AdapterKind::Export => 0x01_u8.to_bytes(writer), AdapterKind::HelperFunction => 0x02_u8.to_bytes(writer), } } } /// Encode an `Export` into bytes. /// /// Decoder is in `decoders::binary::exports`. impl ToBytes for Export<'_> where W: Write, { fn to_bytes(&self, writer: &mut W) -> io::Result<()> { self.name.to_bytes(writer)?; self.input_types.to_bytes(writer)?; self.output_types.to_bytes(writer)?; Ok(()) } } /// Encode a `Type` into bytes. /// /// Decoder is in `decoders::binary::types`. impl ToBytes for Type<'_> where W: Write, { fn to_bytes(&self, writer: &mut W) -> io::Result<()> { self.name.to_bytes(writer)?; self.field_names().to_bytes(writer)?; self.field_types().to_bytes(writer)?; Ok(()) } } /// Encode an `Import` into bytes. /// /// Decoder is in `decoders::binary::imports`. impl ToBytes for Import<'_> where W: Write, { fn to_bytes(&self, writer: &mut W) -> io::Result<()> { self.namespace.to_bytes(writer)?; self.name.to_bytes(writer)?; self.input_types.to_bytes(writer)?; self.output_types.to_bytes(writer)?; Ok(()) } } /// Encode an `Adapter` into bytes. /// /// Decoder is in `decoders::binary::imports`. impl ToBytes for Adapter<'_> where W: Write, { fn to_bytes(&self, writer: &mut W) -> io::Result<()> { match self { Adapter::Import { namespace, name, input_types, output_types, instructions, } => { AdapterKind::Import.to_bytes(writer)?; namespace.to_bytes(writer)?; name.to_bytes(writer)?; input_types.to_bytes(writer)?; output_types.to_bytes(writer)?; instructions.to_bytes(writer)?; } Adapter::Export { name, input_types, output_types, instructions, } => { AdapterKind::Export.to_bytes(writer)?; name.to_bytes(writer)?; input_types.to_bytes(writer)?; output_types.to_bytes(writer)?; instructions.to_bytes(writer)?; } Adapter::HelperFunction { name, input_types, output_types, instructions, } => { AdapterKind::HelperFunction.to_bytes(writer)?; name.to_bytes(writer)?; input_types.to_bytes(writer)?; output_types.to_bytes(writer)?; instructions.to_bytes(writer)?; } } Ok(()) } } /// Encode an `Interfaces` into bytes. /// /// Decoder is `decoders::binary::parse`. impl ToBytes for Interfaces<'_> where W: Write, { fn to_bytes(&self, writer: &mut W) -> io::Result<()> { self.exports.to_bytes(writer)?; self.types.to_bytes(writer)?; self.imports.to_bytes(writer)?; self.adapters.to_bytes(writer)?; Ok(()) } } /// Encode an `Instruction` into bytes. /// /// Decoder is `decoders::binary::instruction`. impl ToBytes for Instruction<'_> where W: Write, { fn to_bytes(&self, writer: &mut W) -> io::Result<()> { match self { Instruction::ArgumentGet { index } => { 0x00_u8.to_bytes(writer)?; index.to_bytes(writer)?; } Instruction::Call { function_index } => { 0x01_u8.to_bytes(writer)?; (*function_index as u64).to_bytes(writer)?; } Instruction::CallExport { export_name } => { 0x02_u8.to_bytes(writer)?; export_name.to_bytes(writer)?; } Instruction::ReadUtf8 => 0x03_u8.to_bytes(writer)?, Instruction::WriteUtf8 { allocator_name } => { 0x04_u8.to_bytes(writer)?; allocator_name.to_bytes(writer)?; } Instruction::AsWasm(interface_type) => { 0x05_u8.to_bytes(writer)?; interface_type.to_bytes(writer)?; } Instruction::AsInterface(interface_type) => { 0x06_u8.to_bytes(writer)?; interface_type.to_bytes(writer)?; } Instruction::TableRefAdd => 0x07_u8.to_bytes(writer)?, Instruction::TableRefGet => 0x08_u8.to_bytes(writer)?, Instruction::CallMethod(function_index) => { 0x09_u8.to_bytes(writer)?; function_index.to_bytes(writer)?; } Instruction::MakeRecord(interface_type) => { 0x0a_u8.to_bytes(writer)?; interface_type.to_bytes(writer)?; } Instruction::GetField(interface_type, field_index) => { 0x0c_u8.to_bytes(writer)?; interface_type.to_bytes(writer)?; field_index.to_bytes(writer)?; } Instruction::Const(interface_type, index) => { 0x0d_u8.to_bytes(writer)?; interface_type.to_bytes(writer)?; index.to_bytes(writer)?; } Instruction::FoldSeq(index) => { 0x0e_u8.to_bytes(writer)?; index.to_bytes(writer)?; } Instruction::Add(interface_type) => { 0x0f_u8.to_bytes(writer)?; interface_type.to_bytes(writer)?; } Instruction::MemToSeq(interface_type, string) => { 0x10_u8.to_bytes(writer)?; interface_type.to_bytes(writer)?; string.to_bytes(writer)?; } Instruction::Load(interface_type, string) => { 0x11_u8.to_bytes(writer)?; interface_type.to_bytes(writer)?; string.to_bytes(writer)?; } Instruction::SeqNew(interface_type) => { 0x12_u8.to_bytes(writer)?; interface_type.to_bytes(writer)?; } Instruction::ListPush => 0x13_u8.to_bytes(writer)?, Instruction::RepeatUntil(index1, index2) => { 0x14_u8.to_bytes(writer)?; index1.to_bytes(writer)?; index2.to_bytes(writer)?; } } Ok(()) } }