From 321d1cf4e6a40c8e136766e447912c949a1c62d3 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 4 Apr 2017 03:03:57 +0300 Subject: [PATCH] docs --- src/elements/export_entry.rs | 8 ++++++++ src/elements/func.rs | 11 +++++++++++ src/elements/global_entry.rs | 3 +++ src/elements/import_entry.rs | 19 +++++++++++++++++++ src/elements/mod.rs | 31 +++++++++++++++++++++++++++++-- src/elements/module.rs | 1 + src/elements/ops.rs | 12 ++++++++++++ src/elements/primitives.rs | 19 +++++++++++++++++++ src/elements/section.rs | 25 +++++++++++++++++++++++++ src/elements/segment.rs | 10 ++++++++++ src/elements/types.rs | 14 ++++++++++++++ src/lib.rs | 4 ++++ 12 files changed, 155 insertions(+), 2 deletions(-) diff --git a/src/elements/export_entry.rs b/src/elements/export_entry.rs index 3f82ac7..2f268f0 100644 --- a/src/elements/export_entry.rs +++ b/src/elements/export_entry.rs @@ -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 } } diff --git a/src/elements/func.rs b/src/elements/func.rs index 54bb2fb..3ae29de 100644 --- a/src/elements/func.rs +++ b/src/elements/func.rs @@ -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, opcodes: Opcodes, } impl FuncBody { + /// New function body with given `locals` and `opcodes` pub fn new(locals: Vec, 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 } } diff --git a/src/elements/global_entry.rs b/src/elements/global_entry.rs index 82a613d..9fb23bb 100644 --- a/src/elements/global_entry.rs +++ b/src/elements/global_entry.rs @@ -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 } } diff --git a/src/elements/import_entry.rs b/src/elements/import_entry.rs index 7d82c14..42bea48 100644 --- a/src/elements/import_entry.rs +++ b/src/elements/import_entry.rs @@ -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 { 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 } } diff --git a/src/elements/mod.rs b/src/elements/mod.rs index 02c916f..b798c7b 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -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(reader: &mut R) -> Result; } +/// Serialization to serial i/o pub trait Serialize { + /// Serialization error produced by serialization routine. type Error; + /// Serialize type to serial i/o fn serialize(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 for Error { } } -struct Unparsed(pub Vec); +/// Unparsed part of the module/section +pub struct Unparsed(pub Vec); impl Deserialize for Unparsed { type Error = Error; @@ -73,6 +97,7 @@ impl From for Vec { } } +/// Deserialize module from file. pub fn deserialize_file>(p: P) -> Result { use std::io::Read; @@ -82,11 +107,13 @@ pub fn deserialize_file>(p: P) -> Result(contents: Vec) -> Result { let mut reader = io::Cursor::new(contents); T::deserialize(&mut reader) } +/// Create buffer with serialized value. pub fn serialize(val: T) -> Result, T::Error> { let mut buf = Vec::new(); val.serialize(&mut buf)?; diff --git a/src/elements/module.rs b/src/elements/module.rs index ebb9344..29a7d50 100644 --- a/src/elements/module.rs +++ b/src/elements/module.rs @@ -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, diff --git a/src/elements/ops.rs b/src/elements/ops.rs index 8947f31..23fcdec 100644 --- a/src/elements/ops.rs +++ b/src/elements/ops.rs @@ -5,14 +5,17 @@ use super::{ Uint32, VarUint64, Uint64, CountedListWriter }; +/// Collection of opcodes (usually inside a block section). #[derive(Debug)] pub struct Opcodes(Vec); impl Opcodes { + /// New list of opcodes from vector of opcodes pub fn new(elements: Vec) -> 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); impl InitExpr { + /// New initialization expression from list of opcodes. + /// `code` must end with the `Opcode::End` opcode! pub fn new(code: Vec) -> 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, diff --git a/src/elements/primitives.rs b/src/elements/primitives.rs index be34484..ecd9d4c 100644 --- a/src/elements/primitives.rs +++ b/src/elements/primitives.rs @@ -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 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 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 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(Vec); impl CountedList { + /// Destroy counted list returing inner vector. pub fn into_inner(self) -> Vec { self.0 } } @@ -347,12 +359,15 @@ impl Deserialize for CountedList where T::Error: From } } +/// 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, } 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, T: IntoIterator>(pub usize, pub T); impl, T: IntoIterator> Serialize for CountedListWriter { diff --git a/src/elements/section.rs b/src/elements/section.rs index 835a59d..693a6b0 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -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, }, + /// Custom section (`id=0`) Custom(Vec), + /// 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); impl ImportSection { @@ -230,6 +247,7 @@ impl Serialize for ImportSection { } } +/// Section with function signatures definition. pub struct FunctionsSection(Vec); impl FunctionsSection { @@ -269,6 +287,7 @@ impl Serialize for FunctionsSection { } } +/// Section with table definition (currently only one is allowed). pub struct TableSection(Vec); impl TableSection { @@ -304,6 +323,7 @@ impl Serialize for TableSection { } } +/// Section with table definition (currently only one entry is allowed). pub struct MemorySection(Vec); impl MemorySection { @@ -339,6 +359,7 @@ impl Serialize for MemorySection { } } +/// Globals definition section. pub struct GlobalSection(Vec); impl GlobalSection { @@ -374,6 +395,7 @@ impl Serialize for GlobalSection { } } +/// List of exports definition. pub struct ExportSection(Vec); impl ExportSection { @@ -409,6 +431,7 @@ impl Serialize for ExportSection { } } +/// Section with function bodies of the module. pub struct CodeSection(Vec); impl CodeSection { @@ -448,6 +471,7 @@ impl Serialize for CodeSection { } } +/// Element entries section. pub struct ElementSection(Vec); impl ElementSection { @@ -487,6 +511,7 @@ impl Serialize for ElementSection { } } +/// Data entries definitions. pub struct DataSection(Vec); impl DataSection { diff --git a/src/elements/segment.rs b/src/elements/segment.rs index d849e5a..fd399b1 100644 --- a/src/elements/segment.rs +++ b/src/elements/segment.rs @@ -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) -> 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) -> 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 } } diff --git a/src/elements/types.rs b/src/elements/types.rs index 3bae55d..9709407 100644 --- a/src/elements/types.rs +++ b/src/elements/types.rs @@ -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, @@ -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 { self.return_type } } diff --git a/src/lib.rs b/src/lib.rs index f8d9720..0263ff2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,7 @@ +//! WebAssembly format library + +#![warn(missing_docs)] + extern crate byteorder; pub mod elements;