From b504dbc61cecfdb1cd939ccdcc4adff7c9f357a2 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 29 Mar 2017 23:13:54 +0300 Subject: [PATCH] types deserialization --- src/elements/mod.rs | 65 ++++----------- src/elements/module.rs | 4 +- src/elements/primitives.rs | 166 +++++++++++++++++++++++++++++++++++++ src/elements/section.rs | 86 +++++++++++++++++-- src/elements/types.rs | 73 ++++++++++++++++ 5 files changed, 335 insertions(+), 59 deletions(-) create mode 100644 src/elements/primitives.rs create mode 100644 src/elements/types.rs diff --git a/src/elements/mod.rs b/src/elements/mod.rs index 2082f50..3053eea 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -2,11 +2,12 @@ use std::io; mod module; mod section; +mod primitives; +mod types; pub use self::module::Module; pub use self::section::Section; - -use byteorder::{LittleEndian, ByteOrder}; +pub use self::primitives::{VarUint32, VarUint7, VarUint1, VarInt7, Uint32, CountedList}; pub trait Deserialize : Sized { type Error; @@ -19,6 +20,7 @@ pub enum Error { InconsistentLength { expected: usize, actual: usize }, Other(&'static str), HeapOther(String), + UnknownValueType(i8), } impl From for Error { @@ -40,55 +42,22 @@ impl Deserialize for Unparsed { } } -struct VarUint32(u32); - -impl From for usize { - fn from(var: VarUint32) -> usize { - var.0 as usize +impl From for Vec { + fn from(u: Unparsed) -> Vec { + u.0 } } -impl Deserialize for VarUint32 { - type Error = Error; +fn deserialize_file>(p: P) -> Result { + use std::io::Read; - 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)) - } + let mut contents = Vec::new(); + ::std::fs::File::open(p)?.read_to_end(&mut contents)?; + + deserialize_buffer(contents) } -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))) - } -} +fn deserialize_buffer(contents: Vec) -> Result { + let mut reader = io::Cursor::new(contents); + T::deserialize(&mut reader) +} \ No newline at end of file diff --git a/src/elements/module.rs b/src/elements/module.rs index 54c4913..d0edf22 100644 --- a/src/elements/module.rs +++ b/src/elements/module.rs @@ -35,8 +35,8 @@ impl Deserialize for Module { } Ok(Module { - magic: magic.0, - version: version.0, + magic: magic.into(), + version: version.into(), sections: sections, }) } diff --git a/src/elements/primitives.rs b/src/elements/primitives.rs new file mode 100644 index 0000000..57be051 --- /dev/null +++ b/src/elements/primitives.rs @@ -0,0 +1,166 @@ +use std::io; +use byteorder::{LittleEndian, ByteOrder}; +use super::{Error, Deserialize}; + +#[derive(Copy, Clone)] +pub struct VarUint32(u32); + +impl From for usize { + fn from(var: VarUint32) -> usize { + var.0 as usize + } +} + +impl From for u32 { + fn from(var: VarUint32) -> u32 { + var.0 + } +} + +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 { + println!("read 1 byte"); + 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)) + } +} + +#[derive(Copy, Clone)] +pub struct VarUint7(u8); + +impl From for u8 { + fn from(v: VarUint7) -> u8 { + v.0 + } +} + +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])) + } +} + +#[derive(Copy, Clone)] +pub struct VarInt7(i8); + +impl From for i8 { + fn from(v: VarInt7) -> i8 { + v.0 + } +} + +impl Deserialize for VarInt7 { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut u8buf = [0u8; 1]; + reader.read_exact(&mut u8buf)?; + // expand sign + if u8buf[0] & 0b0100_0000 == 0b0100_0000 { u8buf[0] |= 0b1000_0000 } + // todo check range + Ok(VarInt7(unsafe { ::std::mem::transmute (u8buf[0]) })) + } +} + +#[derive(Copy, Clone)] +pub 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)?; + // todo check range + Ok(Uint32(LittleEndian::read_u32(&buf))) + } +} + +impl From for u32 { + fn from(var: Uint32) -> u32 { + var.0 + } +} + +#[derive(Copy, Clone)] +pub struct VarUint1(bool); + +impl From for bool { + fn from(v: VarUint1) -> bool { + v.0 + } +} + +impl Deserialize for VarUint1 { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut u8buf = [0u8; 1]; + reader.read_exact(&mut u8buf)?; + // todo check range + Ok(VarUint1(u8buf[0] == 1)) + } +} + +pub struct CountedList(Vec); + +impl CountedList { + pub fn into_inner(self) -> Vec { self.0 } +} + +impl Deserialize for CountedList where T::Error : From { + type Error = T::Error; + + fn deserialize(reader: &mut R) -> Result { + let count: usize = VarUint32::deserialize(reader)?.into(); + println!("count={}", count); + let mut result = Vec::new(); + for _ in 0..count { result.push(T::deserialize(reader)?); } + Ok(CountedList(result)) + } +} + +mod tests { + + use super::super::deserialize_buffer; + use super::{CountedList, VarInt7}; + + #[test] + fn counted_list() { + let payload = vec![ + 133u8, //(128+5), length is 5 + 0x80, 0x80, 0x80, 0x0, // padding + 0x01, + 0x7d, + 0x05, + 0x07, + 0x09, + ]; + + let list: CountedList = + deserialize_buffer(payload).expect("type_section be deserialized"); + + let vars = list.into_inner(); + assert_eq!(5, vars.len()); + let v3: i8 = (*vars.get(1).unwrap()).into(); + assert_eq!(-0x03i8, v3); + } + +} diff --git a/src/elements/section.rs b/src/elements/section.rs index e3372b3..fa2d55a 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -1,9 +1,14 @@ use std::io; -use super::{Deserialize, Unparsed, Error, VarUint7}; +use super::{Deserialize, Unparsed, Error, VarUint7, VarUint32, CountedList}; +use super::types::Type; -pub struct Section { - id: u8, - unparsed: Unparsed, +pub enum Section { + Unparsed { + id: u8, + payload: Vec, + }, + Custom(Vec), + Type(TypeSection), } impl Deserialize for Section { @@ -15,10 +20,73 @@ impl Deserialize for Section { Err(_) => { return Err(Error::UnexpectedEof); }, Ok(id) => id, }; - let unparsed = Unparsed::deserialize(reader)?; - Ok(Section { - id: id.0, - unparsed: unparsed, - }) + + Ok( + match id.into() { + 0 => { + Section::Custom(Unparsed::deserialize(reader)?.into()) + }, + 1 => { + Section::Type(TypeSection::deserialize(reader)?) + }, + _ => { + Section::Unparsed { id: id.into(), payload: Unparsed::deserialize(reader)?.into() } + } + } + ) } +} + +pub struct TypeSection { + types: Vec, +} + +impl TypeSection { + fn types(&self) -> &[Type] { + &self.types + } +} + +impl Deserialize for TypeSection { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + // todo: maybe use reader.take(section_length) + let _section_length = VarUint32::deserialize(reader)?; + let types: Vec = CountedList::deserialize(reader)?.into_inner(); + Ok(TypeSection { types: types }) + } +} + +#[cfg(test)] +mod tests { + + use super::super::{deserialize_buffer}; + use super::{TypeSection, Type}; + + #[test] + fn type_section() { + let payload = vec![ + 129u8, 0x80, 0x80, 0x80, 0x0, + // func 1 + // form=1 + 0x01, + // param_count=1 + 129u8, 0x80, 0x80, 0x80, 0x0, + // first param + 0x7e, // i64 + // no return params + 0u8 + ]; + + let type_section: TypeSection = + deserialize_buffer(payload).expect("type_section be deserialized"); + + assert_eq!(type_section.types().len(), 1); + match type_section.types()[0] { + Type::Function(_) => {}, + _ => panic!("Type should be a function") + } + } + } \ No newline at end of file diff --git a/src/elements/types.rs b/src/elements/types.rs new file mode 100644 index 0000000..c02f7d7 --- /dev/null +++ b/src/elements/types.rs @@ -0,0 +1,73 @@ +use std::io; +use super::{Deserialize, Unparsed, Error, VarUint7, VarInt7, VarUint32, VarUint1}; + +pub enum Type { + Function(FunctionType), +} + +impl Deserialize for Type { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + Ok(Type::Function(FunctionType::deserialize(reader)?)) + } +} + +pub enum ValueType { + I32, + I64, + F32, + F64, +} + +impl Deserialize for ValueType { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let val = VarInt7::deserialize(reader)?; + + match val.into() { + -0x01 => Ok(ValueType::I32), + -0x02 => Ok(ValueType::I64), + -0x03 => Ok(ValueType::F32), + -0x04 => Ok(ValueType::F64), + _ => Err(Error::UnknownValueType(val.into())), + } + } +} + +pub struct FunctionType { + form: u8, + params: Vec, + return_type: Option, +} + +impl Deserialize for FunctionType { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let form: u8 = VarUint7::deserialize(reader)?.into(); + println!("function form {}", form); + let param_count: usize = VarUint32::deserialize(reader)?.into(); + + println!("type param count {}", param_count); + + let mut params = Vec::new(); + for _ in 0..param_count { + params.push(ValueType::deserialize(reader)?); + } + + let has_return_type = VarUint1::deserialize(reader)?; + let return_type = if has_return_type.into() { + Some(ValueType::deserialize(reader)?) + } else { + None + }; + + Ok(FunctionType { + form: form, + params: params, + return_type: return_type, + }) + } +}