2017-03-29 18:16:58 +03:00
|
|
|
use std::io;
|
2017-04-03 23:08:13 +03:00
|
|
|
use super::{Deserialize, Serialize, Error, Uint32};
|
2017-04-06 16:00:12 +03:00
|
|
|
use super::section::{Section, CodeSection, TypeSection, ImportSection, FunctionsSection};
|
2017-03-29 18:16:58 +03:00
|
|
|
|
2017-04-04 03:03:57 +03:00
|
|
|
/// WebAssembly module
|
2017-03-29 18:16:58 +03:00
|
|
|
pub struct Module {
|
2017-04-03 23:08:13 +03:00
|
|
|
magic: u32,
|
2017-03-29 18:16:58 +03:00
|
|
|
version: u32,
|
|
|
|
sections: Vec<Section>,
|
|
|
|
}
|
|
|
|
|
2017-04-06 16:00:12 +03:00
|
|
|
impl Default for Module {
|
|
|
|
fn default() -> Self {
|
|
|
|
Module {
|
|
|
|
magic: 0x6d736100,
|
|
|
|
version: 1,
|
|
|
|
sections: Vec::with_capacity(16),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-29 18:16:58 +03:00
|
|
|
impl Module {
|
2017-04-06 11:34:31 +03:00
|
|
|
/// New module with sections
|
|
|
|
pub fn new(sections: Vec<Section>) -> Self {
|
|
|
|
Module {
|
2017-04-06 16:00:12 +03:00
|
|
|
sections: sections, ..Default::default()
|
2017-04-06 11:34:31 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-06 16:00:12 +03:00
|
|
|
/// Destructure the module, yielding sections
|
|
|
|
pub fn into_sections(self) -> Vec<Section> {
|
|
|
|
self.sections
|
|
|
|
}
|
|
|
|
|
2017-04-04 00:27:31 +03:00
|
|
|
/// Version of module.
|
2017-03-29 18:16:58 +03:00
|
|
|
pub fn version(&self) -> u32 { self.version }
|
2017-03-29 19:40:51 +03:00
|
|
|
|
2017-04-04 00:27:31 +03:00
|
|
|
/// Sections list.
|
|
|
|
/// Each known section is optional and may appear at most once.
|
2017-03-29 19:40:51 +03:00
|
|
|
pub fn sections(&self) -> &[Section] {
|
|
|
|
&self.sections
|
|
|
|
}
|
2017-04-03 22:58:00 +03:00
|
|
|
|
2017-04-04 00:27:31 +03:00
|
|
|
/// Sections list (mutable)
|
|
|
|
/// Each known section is optional and may appear at most once.
|
2017-04-03 22:58:00 +03:00
|
|
|
pub fn sections_mut(&mut self) -> &mut Vec<Section> {
|
|
|
|
&mut self.sections
|
|
|
|
}
|
2017-04-03 23:56:21 +03:00
|
|
|
|
2017-04-04 00:27:31 +03:00
|
|
|
/// Code section, if any.
|
2017-04-03 23:56:21 +03:00
|
|
|
pub fn code_section(&self) -> Option<&CodeSection> {
|
|
|
|
for section in self.sections() {
|
|
|
|
if let &Section::Code(ref code_section) = section { return Some(code_section); }
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
2017-04-04 00:22:08 +03:00
|
|
|
|
2017-04-04 00:27:31 +03:00
|
|
|
/// Types section, if any.
|
2017-04-04 00:22:08 +03:00
|
|
|
pub fn type_section(&self) -> Option<&TypeSection> {
|
|
|
|
for section in self.sections() {
|
|
|
|
if let &Section::Type(ref type_section) = section { return Some(type_section); }
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2017-04-04 00:27:31 +03:00
|
|
|
/// Imports section, if any.
|
2017-04-04 00:22:08 +03:00
|
|
|
pub fn import_section(&self) -> Option<&ImportSection> {
|
|
|
|
for section in self.sections() {
|
|
|
|
if let &Section::Import(ref import_section) = section { return Some(import_section); }
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
2017-04-06 16:00:12 +03:00
|
|
|
|
|
|
|
/// Functions signatures section, if any.
|
|
|
|
pub fn functions_section(&self) -> Option<&FunctionsSection> {
|
|
|
|
for section in self.sections() {
|
|
|
|
if let &Section::Function(ref sect) = section { return Some(sect); }
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
2017-03-29 18:16:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Deserialize for Module {
|
|
|
|
type Error = super::Error;
|
|
|
|
|
|
|
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
|
|
|
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 {
|
2017-04-03 23:08:13 +03:00
|
|
|
magic: magic.into(),
|
2017-03-29 23:13:54 +03:00
|
|
|
version: version.into(),
|
2017-03-29 18:16:58 +03:00
|
|
|
sections: sections,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-03 23:08:13 +03:00
|
|
|
impl Serialize for Module {
|
|
|
|
type Error = Error;
|
|
|
|
|
|
|
|
fn serialize<W: io::Write>(self, w: &mut W) -> Result<(), Self::Error> {
|
|
|
|
Uint32::from(self.magic).serialize(w)?;
|
|
|
|
Uint32::from(self.version).serialize(w)?;
|
|
|
|
for section in self.sections.into_iter() {
|
|
|
|
section.serialize(w)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-29 18:16:58 +03:00
|
|
|
#[cfg(test)]
|
|
|
|
mod integration_tests {
|
|
|
|
|
2017-04-03 23:56:21 +03:00
|
|
|
use super::super::{deserialize_file, serialize, deserialize_buffer, Section};
|
2017-04-03 23:08:13 +03:00
|
|
|
use super::Module;
|
2017-03-29 18:16:58 +03:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn hello() {
|
2017-03-30 20:55:25 +03:00
|
|
|
let module = deserialize_file("./res/cases/v1/hello.wasm").expect("Should be deserialized");
|
2017-03-29 18:16:58 +03:00
|
|
|
|
|
|
|
assert_eq!(module.version(), 1);
|
2017-03-29 19:40:51 +03:00
|
|
|
assert_eq!(module.sections().len(), 8);
|
2017-03-29 18:16:58 +03:00
|
|
|
}
|
2017-04-03 23:08:13 +03:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn serde() {
|
2017-04-03 23:56:21 +03:00
|
|
|
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
2017-04-03 23:08:13 +03:00
|
|
|
let buf = serialize(module).expect("serialization to succeed");
|
|
|
|
|
|
|
|
let module_new: Module = deserialize_buffer(buf).expect("deserialization to succeed");
|
2017-04-03 23:56:21 +03:00
|
|
|
let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
2017-04-03 23:08:13 +03:00
|
|
|
|
|
|
|
assert_eq!(module_old.sections().len(), module_new.sections().len());
|
|
|
|
}
|
2017-04-03 23:56:21 +03:00
|
|
|
|
2017-04-04 00:22:08 +03:00
|
|
|
#[test]
|
|
|
|
fn serde_type() {
|
|
|
|
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
|
|
|
module.sections_mut().retain(|x| {
|
|
|
|
if let &Section::Type(_) = x { true } else { false }
|
|
|
|
});
|
|
|
|
|
|
|
|
let buf = serialize(module).expect("serialization to succeed");
|
|
|
|
|
|
|
|
let module_new: Module = deserialize_buffer(buf).expect("deserialization to succeed");
|
|
|
|
let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
|
|
|
assert_eq!(
|
|
|
|
module_old.type_section().expect("type section exists").types().len(),
|
|
|
|
module_new.type_section().expect("type section exists").types().len(),
|
|
|
|
"There should be equal amount of types before and after serialization"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn serde_import() {
|
|
|
|
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
|
|
|
module.sections_mut().retain(|x| {
|
|
|
|
if let &Section::Import(_) = x { true } else { false }
|
|
|
|
});
|
|
|
|
|
|
|
|
let buf = serialize(module).expect("serialization to succeed");
|
|
|
|
|
|
|
|
let module_new: Module = deserialize_buffer(buf).expect("deserialization to succeed");
|
|
|
|
let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
|
|
|
assert_eq!(
|
|
|
|
module_old.import_section().expect("import section exists").entries().len(),
|
|
|
|
module_new.import_section().expect("import section exists").entries().len(),
|
|
|
|
"There should be equal amount of import entries before and after serialization"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-04-03 23:56:21 +03:00
|
|
|
#[test]
|
|
|
|
fn serde_code() {
|
|
|
|
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
|
|
|
module.sections_mut().retain(|x| {
|
|
|
|
if let &Section::Code(_) = x { true } else { false }
|
|
|
|
});
|
|
|
|
|
|
|
|
let buf = serialize(module).expect("serialization to succeed");
|
|
|
|
|
|
|
|
let module_new: Module = deserialize_buffer(buf).expect("deserialization to succeed");
|
|
|
|
let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
|
|
|
assert_eq!(
|
|
|
|
module_old.code_section().expect("code section exists").bodies().len(),
|
|
|
|
module_new.code_section().expect("code section exists").bodies().len(),
|
|
|
|
"There should be equal amount of function bodies before and after serialization"
|
|
|
|
);
|
|
|
|
}
|
2017-03-29 18:16:58 +03:00
|
|
|
}
|