diff --git a/src/elements/mod.rs b/src/elements/mod.rs index 988a6ae..fca2dae 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -16,7 +16,10 @@ pub use self::section::Section; pub use self::import_entry::{ImportEntry, MemoryType, TableType, GlobalType, External}; pub use self::export_entry::{ExportEntry, Internal}; pub use self::global_entry::GlobalEntry; -pub use self::primitives::{VarUint32, VarUint7, VarUint1, VarInt7, Uint32, Uint64, VarUint64, CountedList}; +pub use self::primitives::{ + VarUint32, VarUint7, VarUint1, VarInt7, Uint32, + Uint64, VarUint64, CountedList, CountedWriter, +}; pub use self::types::{ValueType, BlockType}; pub use self::ops::{Opcode, Opcodes, InitExpr}; pub use self::func::{Func, FuncBody, Local}; @@ -29,7 +32,7 @@ pub trait Deserialize : Sized { pub trait Serialize { type Error; - fn serialize(&self, writer: &mut W) -> Result<(), Self::Error>; + fn serialize(self, writer: &mut W) -> Result<(), Self::Error>; } #[derive(Debug)] diff --git a/src/elements/primitives.rs b/src/elements/primitives.rs index 7a473af..18f1364 100644 --- a/src/elements/primitives.rs +++ b/src/elements/primitives.rs @@ -1,6 +1,6 @@ use std::io; use byteorder::{LittleEndian, ByteOrder}; -use super::{Error, Deserialize}; +use super::{Error, Deserialize, Serialize}; #[derive(Copy, Clone)] pub struct VarUint32(u32); @@ -17,6 +17,19 @@ impl From for u32 { } } +impl From for VarUint32 { + fn from(i: u32) -> VarUint32 { + VarUint32(i) + } +} + +impl From for VarUint32 { + fn from(i: usize) -> VarUint32 { + assert!(i <= ::std::u32::MAX as usize); + VarUint32(i as u32) + } +} + impl Deserialize for VarUint32 { type Error = Error; @@ -37,6 +50,24 @@ impl Deserialize for VarUint32 { } } +impl Serialize for VarUint32 { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + let mut buf = [0u8; 1]; + let mut v = self.0; + while v >= 0x80 { + buf[0] = ((v & 0xff) as u8) | 0x80; + writer.write_all(&buf[..])?; + v >>= 7; + } + buf[0] = (v & 0xff) as u8; + writer.write_all(&buf[..])?; + + Ok(()) + } +} + #[derive(Copy, Clone)] pub struct VarUint64(u64); @@ -201,11 +232,83 @@ impl Deserialize for CountedList where T::Error : From } } +pub struct CountedWriter<'a, W: 'a + io::Write> { + writer: &'a mut W, + data: Vec, +} + +impl<'a, W: 'a + io::Write> CountedWriter<'a, W> { + pub fn new(writer: &'a mut W) -> Self { + CountedWriter { + writer: writer, + data: Vec::new(), + } + } + + pub fn done(self) -> io::Result<()> { + let writer = self.writer; + let data = self.data; + VarUint32::from(data.len()) + .serialize(writer) + .map_err( + |_| io::Error::new( + io::ErrorKind::Other, + "Length serialization error", + ) + )?; + writer.write_all(&data[..])?; + Ok(()) + } +} + +impl<'a, W: 'a + io::Write> io::Write for CountedWriter<'a, W> { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.data.extend(buf.to_vec()); + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + #[cfg(test)] mod tests { - use super::super::deserialize_buffer; - use super::{CountedList, VarInt7}; + use super::super::{deserialize_buffer, Serialize}; + use super::{CountedList, VarInt7, VarUint32}; + + fn varuint32_ser_test(val: u32, expected: Vec) { + let mut buf = Vec::new(); + let v1: VarUint32 = val.into(); + v1.serialize(&mut buf).expect("to be serialized ok"); + assert_eq!(expected, buf); + } + + fn varuint32_de_test(dt: Vec, expected: u32) { + let val: VarUint32 = super::super::deserialize_buffer(dt).expect("buf to be serialized"); + assert_eq!(expected, val.into()); + } + + fn varuint32_serde_test(dt: Vec, val: u32) { + varuint32_de_test(dt.clone(), val); + varuint32_ser_test(val, dt); + } + + #[test] + fn varuint32_0() { + varuint32_serde_test(vec![0u8; 1], 0); + } + + #[test] + fn varuint32_1() { + varuint32_serde_test(vec![1u8; 1], 1); + } + + #[test] + fn varuint32_135() { + varuint32_serde_test(vec![135u8, 0x01], 135); + } #[test] fn counted_list() { diff --git a/src/elements/section.rs b/src/elements/section.rs index 47e1470..1699f2e 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -1,5 +1,7 @@ use std::io; +use std::io::Write; use super::{ + Serialize, Deserialize, Unparsed, Error, @@ -15,6 +17,7 @@ use super::{ FuncBody, ElementSegment, DataSegment, + CountedWriter, }; use super::types::Type; @@ -279,7 +282,7 @@ impl DataSection { } impl Deserialize for DataSection { - type Error = Error; + type Error = Error; fn deserialize(reader: &mut R) -> Result { // todo: maybe use reader.take(section_length) @@ -289,6 +292,18 @@ impl Deserialize for DataSection { } } +impl Serialize for DataSection { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + let mut counted_writer = CountedWriter::new(writer); + let test = vec![0u8; 12]; + counted_writer.write(&test[..])?; + counted_writer.done()?; + Ok(()) + } +} + #[cfg(test)] mod tests {