This commit is contained in:
NikVolf
2017-04-04 03:03:57 +03:00
parent 15035de380
commit 321d1cf4e6
12 changed files with 155 additions and 2 deletions

View File

@ -1,10 +1,15 @@
use std::io;
use super::{Deserialize, Serialize, Error, VarUint7, VarUint32};
/// Internal reference of the exported entry.
pub enum Internal {
/// Function reference.
Function(u32),
/// Table reference.
Table(u32),
/// Memory reference.
Memory(u32),
/// Global reference.
Global(u32),
}
@ -41,13 +46,16 @@ impl Serialize for Internal {
}
}
/// Export entry.
pub struct ExportEntry {
field_str: String,
internal: Internal,
}
impl ExportEntry {
/// Public name
pub fn field(&self) -> &str { &self.field_str }
/// Internal reference of the export entry.
pub fn internal(&self) -> &Internal { &self.internal }
}

View File

@ -8,25 +8,31 @@ use super::{
pub struct Func(u32);
impl Func {
/// New function signature
pub fn new(type_ref: u32) -> Self { Func(type_ref) }
/// Function signature type reference.
pub fn type_ref(&self) -> u32 {
self.0
}
}
/// Local definition inside the function body.
pub struct Local {
count: u32,
value_type: ValueType,
}
impl Local {
/// New local with `count` and `value_type`.
pub fn new(count: u32, value_type: ValueType) -> Self {
Local { count: count, value_type: value_type }
}
/// Number of locals with the shared type.
pub fn count(&self) -> u32 { self.count }
/// Type of the locals.
pub fn value_type(&self) -> ValueType { self.value_type }
}
@ -50,18 +56,23 @@ impl Serialize for Local {
}
}
/// Function body definition.
pub struct FuncBody {
locals: Vec<Local>,
opcodes: Opcodes,
}
impl FuncBody {
/// New function body with given `locals` and `opcodes`
pub fn new(locals: Vec<Local>, opcodes: Opcodes) -> Self {
FuncBody { locals: locals, opcodes: opcodes }
}
/// Locals declared in function body.
pub fn locals(&self) -> &[Local] { &self.locals }
/// Opcode sequence of the function body. Minimal opcode sequence
/// is just `&[Opcode::End]`
pub fn code(&self) -> &Opcodes { &self.opcodes }
}

View File

@ -1,13 +1,16 @@
use std::io;
use super::{Deserialize, Serialize, Error, GlobalType, InitExpr};
/// Global entry in the module.
pub struct GlobalEntry {
global_type: GlobalType,
init_expr: InitExpr,
}
impl GlobalEntry {
/// Global type.
pub fn global_type(&self) -> &GlobalType { &self.global_type }
/// Initialization expression (opcodes) for global.
pub fn init_expr(&self) -> &InitExpr { &self.init_expr }
}

View File

@ -4,13 +4,16 @@ use super::{
ValueType
};
/// Global definition struct
pub struct GlobalType {
content_type: ValueType,
is_mutable: bool,
}
impl GlobalType {
/// Type of the global entry
pub fn content_type(&self) -> ValueType { self.content_type }
/// Is global entry is declared as mutable
pub fn is_mutable(&self) -> bool { self.is_mutable }
}
@ -37,12 +40,14 @@ impl Serialize for GlobalType {
}
}
/// Table entry
pub struct TableType {
elem_type: i8,
limits: ResizableLimits,
}
impl TableType {
/// Table memory specification
pub fn limits(&self) -> &ResizableLimits { &self.limits }
}
@ -68,6 +73,7 @@ impl Serialize for TableType {
}
}
/// Memory limits
#[derive(Debug)]
pub struct ResizableLimits {
initial: u32,
@ -75,7 +81,9 @@ pub struct ResizableLimits {
}
impl ResizableLimits {
/// Initial size
pub fn initial(&self) -> u32 { self.initial }
/// Maximum size
pub fn maximum(&self) -> Option<u32> { self.maximum }
}
@ -112,9 +120,11 @@ impl Serialize for ResizableLimits {
}
}
/// Memory entry.
pub struct MemoryType(ResizableLimits);
impl MemoryType {
/// Limits of the memory entry.
pub fn limits(&self) -> &ResizableLimits {
&self.0
}
@ -136,10 +146,15 @@ impl Serialize for MemoryType {
}
}
/// External to local binding.
pub enum External {
/// Binds to function with index.
Function(u32),
/// Describes local table definition to be imported as.
Table(TableType),
/// Describes local memory definition to be imported as.
Memory(MemoryType),
/// Describes local global entry to be imported as.
Global(GlobalType),
}
@ -187,6 +202,7 @@ impl Serialize for External {
}
}
/// Import entry.
pub struct ImportEntry {
module_str: String,
field_str: String,
@ -194,8 +210,11 @@ pub struct ImportEntry {
}
impl ImportEntry {
/// Module reference of the import entry.
pub fn module(&self) -> &str { &self.module_str }
/// Field reference of the import entry.
pub fn field(&self) -> &str { &self.field_str }
/// Local binidng of the import entry.
pub fn external(&self) -> &External { &self.external }
}

View File

@ -1,3 +1,5 @@
//! Elemets of the WebAssembly binary format.
use std::io;
mod module;
@ -25,26 +27,47 @@ pub use self::ops::{Opcode, Opcodes, InitExpr};
pub use self::func::{Func, FuncBody, Local};
pub use self::segment::{ElementSegment, DataSegment};
/// Deserialization from serial i/o
pub trait Deserialize : Sized {
/// Serialization error produced by deserialization routine.
type Error;
/// Deserialize type from serial i/o
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error>;
}
/// Serialization to serial i/o
pub trait Serialize {
/// Serialization error produced by serialization routine.
type Error;
/// Serialize type to serial i/o
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error>;
}
/// Deserialization/serialization error
#[derive(Debug)]
pub enum Error {
/// Unexpected end of input
UnexpectedEof,
InconsistentLength { expected: usize, actual: usize },
/// Inconsistence between declared and actual length
InconsistentLength {
/// Expected length of the definition
expected: usize,
/// Actual length of the definition
actual: usize
},
/// Other static error
Other(&'static str),
/// Other allocated error
HeapOther(String),
/// Invalid/unknown value type declaration
UnknownValueType(i8),
/// Non-utf8 string
NonUtf8String,
/// Unknown external kind code
UnknownExternalKind(u8),
/// Unknown internal kind code
UnknownInternalKind(u8),
/// Unknown opcode encountered
UnknownOpcode(u8),
}
@ -54,7 +77,8 @@ impl From<io::Error> for Error {
}
}
struct Unparsed(pub Vec<u8>);
/// Unparsed part of the module/section
pub struct Unparsed(pub Vec<u8>);
impl Deserialize for Unparsed {
type Error = Error;
@ -73,6 +97,7 @@ impl From<Unparsed> for Vec<u8> {
}
}
/// Deserialize module from file.
pub fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error> {
use std::io::Read;
@ -82,11 +107,13 @@ pub fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Err
deserialize_buffer(contents)
}
/// Deserialize deserializable type from buffer.
pub fn deserialize_buffer<T: Deserialize>(contents: Vec<u8>) -> Result<T, T::Error> {
let mut reader = io::Cursor::new(contents);
T::deserialize(&mut reader)
}
/// Create buffer with serialized value.
pub fn serialize<T: Serialize>(val: T) -> Result<Vec<u8>, T::Error> {
let mut buf = Vec::new();
val.serialize(&mut buf)?;

View File

@ -2,6 +2,7 @@ use std::io;
use super::{Deserialize, Serialize, Error, Uint32};
use super::section::{Section, CodeSection, TypeSection, ImportSection};
/// WebAssembly module
pub struct Module {
magic: u32,
version: u32,

View File

@ -5,14 +5,17 @@ use super::{
Uint32, VarUint64, Uint64, CountedListWriter
};
/// Collection of opcodes (usually inside a block section).
#[derive(Debug)]
pub struct Opcodes(Vec<Opcode>);
impl Opcodes {
/// New list of opcodes from vector of opcodes
pub fn new(elements: Vec<Opcode>) -> Self {
Opcodes(elements)
}
/// List of individual opcodes
pub fn elements(&self) -> &[Opcode] { &self.0 }
}
@ -35,17 +38,22 @@ impl Deserialize for Opcodes {
}
}
/// Initialization expression.
pub struct InitExpr(Vec<Opcode>);
impl InitExpr {
/// New initialization expression from list of opcodes.
/// `code` must end with the `Opcode::End` opcode!
pub fn new(code: Vec<Opcode>) -> Self {
InitExpr(code)
}
/// Empty expression with only `Opcode::End` opcode
pub fn empty() -> Self {
InitExpr(vec![Opcode::End])
}
/// List of opcodes used in the expression.
pub fn code(&self) -> &[Opcode] {
&self.0
}
@ -71,7 +79,9 @@ impl Deserialize for InitExpr {
}
}
/// Opcode
#[derive(Debug)]
#[allow(missing_docs)]
pub enum Opcode {
Unreachable,
Nop,
@ -261,6 +271,8 @@ pub enum Opcode {
}
impl Opcode {
/// Is this opcode determines the termination of opcode sequence
/// `true` for `Opcode::End`
pub fn is_terminal(&self) -> bool {
match self {
&Opcode::End => true,

View File

@ -2,6 +2,8 @@ use std::io;
use byteorder::{LittleEndian, ByteOrder};
use super::{Error, Deserialize, Serialize};
/// Unsigned variable-length integer, limited to 32 bits,
/// represented by at most 5 bytes that may contain padding 0x80 bytes.
#[derive(Copy, Clone)]
pub struct VarUint32(u32);
@ -68,6 +70,8 @@ impl Serialize for VarUint32 {
}
}
/// Unsigned variable-length integer, limited to 64 bits,
/// represented by at most 9 bytes that may contain padding 0x80 bytes.
#[derive(Copy, Clone)]
pub struct VarUint64(u64);
@ -121,6 +125,7 @@ impl From<u64> for VarUint64 {
}
}
/// 7-bit unsigned integer, encoded in LEB128 (always 1 byte length)
#[derive(Copy, Clone)]
pub struct VarUint7(u8);
@ -156,6 +161,7 @@ impl Serialize for VarUint7 {
}
}
/// 7-bit signed integer, encoded in LEB128 (always 1 byte length)
#[derive(Copy, Clone)]
pub struct VarInt7(i8);
@ -196,6 +202,7 @@ impl Serialize for VarInt7 {
}
}
/// 32-bit unsigned integer, encoded in little endian
#[derive(Copy, Clone)]
pub struct Uint32(u32);
@ -231,6 +238,7 @@ impl From<u32> for Uint32 {
fn from(u: u32) -> Self { Uint32(u) }
}
/// 64-bit unsigned integer, encoded in little endian
#[derive(Copy, Clone)]
pub struct Uint64(u64);
@ -267,6 +275,7 @@ impl From<Uint64> for u64 {
}
/// VarUint1, 1-bit value (0/1)
#[derive(Copy, Clone)]
pub struct VarUint1(bool);
@ -330,9 +339,12 @@ impl Serialize for String {
}
}
/// List for reading sequence of elements typed `T`, given
/// they are preceded by length (serialized as VarUint32)
pub struct CountedList<T: Deserialize>(Vec<T>);
impl<T: Deserialize> CountedList<T> {
/// Destroy counted list returing inner vector.
pub fn into_inner(self) -> Vec<T> { self.0 }
}
@ -347,12 +359,15 @@ impl<T: Deserialize> Deserialize for CountedList<T> where T::Error: From<Error>
}
}
/// Helper struct to write payload which is preceded by
/// it's own length in bytes.
pub struct CountedWriter<'a, W: 'a + io::Write> {
writer: &'a mut W,
data: Vec<u8>,
}
impl<'a, W: 'a + io::Write> CountedWriter<'a, W> {
/// New counted writer on top of the given serial writer
pub fn new(writer: &'a mut W) -> Self {
CountedWriter {
writer: writer,
@ -360,6 +375,8 @@ impl<'a, W: 'a + io::Write> CountedWriter<'a, W> {
}
}
/// Finish counted writer routing, which writes accumulated length
/// and actual payload.
pub fn done(self) -> io::Result<()> {
let writer = self.writer;
let data = self.data;
@ -387,6 +404,8 @@ impl<'a, W: 'a + io::Write> io::Write for CountedWriter<'a, W> {
}
}
/// Helper struct to write series of `T` preceded by the length of the sequence
/// serialized as VarUint32
pub struct CountedListWriter<I: Serialize<Error=::elements::Error>, T: IntoIterator<Item=I>>(pub usize, pub T);
impl<I: Serialize<Error=::elements::Error>, T: IntoIterator<Item=I>> Serialize for CountedListWriter<I, T> {

View File

@ -22,22 +22,38 @@ use super::{
use super::types::Type;
/// Section in the WebAssembly module.
pub enum Section {
/// Section is unparsed.
Unparsed {
/// id of the unparsed section
id: u8,
/// raw bytes of the unparsed section
payload: Vec<u8>,
},
/// Custom section (`id=0`)
Custom(Vec<u8>),
/// Types section
Type(TypeSection),
/// Import section
Import(ImportSection),
/// Function signatures section
Function(FunctionsSection),
/// Table definition section
Table(TableSection),
/// Memory definition section
Memory(MemorySection),
/// Global entries section
Global(GlobalSection),
/// Export definitions
Export(ExportSection),
/// Entry reference of the module
Start(u32),
/// Elements section
Element(ElementSection),
/// Function bodies section
Code(CodeSection),
/// Data definition section
Data(DataSection),
}
@ -195,6 +211,7 @@ impl Serialize for TypeSection {
}
}
/// Section of the imports definition.
pub struct ImportSection(Vec<ImportEntry>);
impl ImportSection {
@ -230,6 +247,7 @@ impl Serialize for ImportSection {
}
}
/// Section with function signatures definition.
pub struct FunctionsSection(Vec<Func>);
impl FunctionsSection {
@ -269,6 +287,7 @@ impl Serialize for FunctionsSection {
}
}
/// Section with table definition (currently only one is allowed).
pub struct TableSection(Vec<TableType>);
impl TableSection {
@ -304,6 +323,7 @@ impl Serialize for TableSection {
}
}
/// Section with table definition (currently only one entry is allowed).
pub struct MemorySection(Vec<MemoryType>);
impl MemorySection {
@ -339,6 +359,7 @@ impl Serialize for MemorySection {
}
}
/// Globals definition section.
pub struct GlobalSection(Vec<GlobalEntry>);
impl GlobalSection {
@ -374,6 +395,7 @@ impl Serialize for GlobalSection {
}
}
/// List of exports definition.
pub struct ExportSection(Vec<ExportEntry>);
impl ExportSection {
@ -409,6 +431,7 @@ impl Serialize for ExportSection {
}
}
/// Section with function bodies of the module.
pub struct CodeSection(Vec<FuncBody>);
impl CodeSection {
@ -448,6 +471,7 @@ impl Serialize for CodeSection {
}
}
/// Element entries section.
pub struct ElementSection(Vec<ElementSegment>);
impl ElementSection {
@ -487,6 +511,7 @@ impl Serialize for ElementSection {
}
}
/// Data entries definitions.
pub struct DataSection(Vec<DataSegment>);
impl DataSection {

View File

@ -1,6 +1,7 @@
use std::io;
use super::{Deserialize, Serialize, Error, VarUint32, CountedList, InitExpr, CountedListWriter};
/// Entry in the element section.
pub struct ElementSegment {
index: u32,
offset: InitExpr,
@ -8,14 +9,18 @@ pub struct ElementSegment {
}
impl ElementSegment {
/// New element segment.
pub fn new(index: u32, offset: InitExpr, members: Vec<u32>) -> Self {
ElementSegment { index: index, offset: offset, members: members }
}
/// Sequence of function indices.
pub fn members(&self) -> &[u32] { &self.members }
/// Table index (currently valid only value of `0`)
pub fn index(&self) -> u32 { self.index }
/// An i32 initializer expression that computes the offset at which to place the elements.
pub fn offset(&self) -> &InitExpr { &self.offset }
}
@ -55,6 +60,7 @@ impl Serialize for ElementSegment {
}
}
/// Data segment definition.
pub struct DataSegment {
index: u32,
offset: InitExpr,
@ -62,6 +68,7 @@ pub struct DataSegment {
}
impl DataSegment {
/// New data segments.
pub fn new(index: u32, offset: InitExpr, value: Vec<u8>) -> Self {
DataSegment {
index: index,
@ -70,8 +77,11 @@ impl DataSegment {
}
}
/// Linear memory index (currently the only valid value is `0`).
pub fn index(&self) -> u32 { self.index }
/// An i32 initializer expression that computes the offset at which to place the data.
pub fn offset(&self) -> &InitExpr { &self.offset }
/// Initial value of the data segment.
pub fn value(&self) -> &[u8] { &self.value }
}

View File

@ -4,7 +4,9 @@ use super::{
CountedListWriter
};
/// Type definition in types section. Currently can be only of the function type.
pub enum Type {
/// Function type.
Function(FunctionType),
}
@ -26,11 +28,16 @@ impl Serialize for Type {
}
}
/// Value type.
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ValueType {
/// 32-bit signed integer
I32,
/// 64-bit signed integer
I64,
/// 32-bit float
F32,
/// 64-bit float
F64,
}
@ -65,9 +72,12 @@ impl Serialize for ValueType {
}
}
/// Block type which is basically `ValueType` + NoResult (to define blocks that have no return type)
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum BlockType {
/// Value-type specified block type
Value(ValueType),
/// No specified block type
NoResult,
}
@ -104,6 +114,7 @@ impl Serialize for BlockType {
}
}
/// Function signature type.
pub struct FunctionType {
form: u8,
params: Vec<ValueType>,
@ -111,8 +122,11 @@ pub struct FunctionType {
}
impl FunctionType {
/// Function form (currently only valid value is `0x60`)
pub fn form(&self) -> u8 { self.form }
/// Parameters in the function signature.
pub fn params(&self) -> &[ValueType] { &self.params }
/// Return type in the function signature, if any.
pub fn return_type(&self) -> Option<ValueType> { self.return_type }
}

View File

@ -1,3 +1,7 @@
//! WebAssembly format library
#![warn(missing_docs)]
extern crate byteorder;
pub mod elements;