commit 4ab9e569d1ae1c3b13501028ac44b48d30d4a94b Author: NikVolf Date: Wed Mar 29 18:16:58 2017 +0300 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a9d37c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..917bdb4 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "parity-wasm" +version = "0.1.0" +authors = ["NikVolf "] + +[dependencies] +byteorder = "1.0" \ No newline at end of file diff --git a/res/cases/v1/hello.wasm b/res/cases/v1/hello.wasm new file mode 100644 index 0000000..e0384a0 Binary files /dev/null and b/res/cases/v1/hello.wasm differ diff --git a/src/elements/mod.rs b/src/elements/mod.rs new file mode 100644 index 0000000..6a4499d --- /dev/null +++ b/src/elements/mod.rs @@ -0,0 +1,93 @@ +use std::io; + +mod module; +mod section; + +pub use self::module::Module; +pub use self::section::Section; + +use byteorder::{LittleEndian, ByteOrder}; + +pub trait Deserialize : Sized { + type Error; + fn deserialize(reader: &mut R) -> Result; +} + +#[derive(Debug)] +pub enum Error { + UnexpectedEof, + InconsistentLength { expected: usize, actual: usize }, + Other(&'static str), + HeapOther(String), +} + +impl From for Error { + fn from(err: io::Error) -> Self { + Error::HeapOther(format!("I/O Error: {}", err)) + } +} + +struct Unparsed(pub Vec); + +impl Deserialize for Unparsed { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let len = VarUint32::deserialize(reader)?.into(); + let vec = vec![0u8; len]; + Ok(Unparsed(vec)) + } +} + +struct VarUint32(u32); + +impl From for usize { + fn from(var: VarUint32) -> usize { + var.0 as usize + } +} + +impl Deserialize for VarUint32 { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut res = 0; + let mut shift = 0; + let mut u8buf = [0u8; 1]; + loop { + reader.read_exact(&mut u8buf)?; + let b = u8buf[0] as u32; + res |= (b & 0x7f) << shift; + shift += 7; + if (b >> 7) == 0 { + break; + } + } + Ok(VarUint32(res)) + } +} + +struct VarUint7(u8); + +impl Deserialize for VarUint7 { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut u8buf = [0u8; 1]; + reader.read_exact(&mut u8buf)?; + Ok(VarUint7(u8buf[0])) + } +} + +struct Uint32(u32); + +impl Deserialize for Uint32 { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut buf = [0u8; 4]; + reader.read_exact(&mut buf)?; + ; + Ok(Uint32(LittleEndian::read_u32(&buf))) + } +} diff --git a/src/elements/module.rs b/src/elements/module.rs new file mode 100644 index 0000000..942a9f5 --- /dev/null +++ b/src/elements/module.rs @@ -0,0 +1,62 @@ +use std::io; +use super::{Deserialize, VarUint32, Error, Uint32}; +use super::section::Section; + +pub struct Module { + magic: u32, + version: u32, + sections: Vec
, +} + +impl Module { + pub fn version(&self) -> u32 { self.version } +} + +impl Deserialize for Module { + type Error = super::Error; + + fn deserialize(reader: &mut R) -> Result { + let mut sections = Vec::new(); + + let magic = Uint32::deserialize(reader)?; + let version = Uint32::deserialize(reader)?; + + loop { + match Section::deserialize(reader) { + Err(Error::UnexpectedEof) => { break; }, + Err(e) => { return Err(e) }, + Ok(section) => { sections.push(section); } + } + } + + Ok(Module { + magic: magic.0, + version: version.0, + sections: sections, + }) + } +} + +#[cfg(test)] +mod integration_tests { + + use std::io::{self, Read}; + use std::fs::File; + + use super::super::Deserialize; + use super::Module; + + #[test] + fn hello() { + let mut contents = Vec::new(); + File::open("./res/cases/v1/hello.wasm") + .expect("readable file") + .read_to_end(&mut contents) + .expect("read succeeds"); + + let mut reader = io::Cursor::new(contents); + let module = Module::deserialize(&mut reader).expect("Should be deserialized"); + + assert_eq!(module.version(), 1); + } +} \ No newline at end of file diff --git a/src/elements/section.rs b/src/elements/section.rs new file mode 100644 index 0000000..6973d8d --- /dev/null +++ b/src/elements/section.rs @@ -0,0 +1,21 @@ +use std::io; +use super::{Deserialize, Unparsed, Error, VarUint7}; + +pub struct Section { + id: u8, + unparsed: Unparsed, +} + +impl Deserialize for Section { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let id = VarUint7::deserialize(reader)?; + let unparsed = Unparsed::deserialize(reader)?; + + Ok(Section { + id: id.0, + unparsed: unparsed, + }) + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..94e17b6 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,5 @@ +extern crate byteorder; + +mod elements; + +pub use elements::{Section, Module, Error as DeserializeError}; \ No newline at end of file