use alloc::{borrow::ToOwned, vec::Vec, string::String};
use crate::io;
use super::{deserialize_buffer, serialize, Deserialize, Serialize, Error, Uint32, External};
use super::section::{
Section, CodeSection, TypeSection, ImportSection, ExportSection, FunctionSection,
GlobalSection, TableSection, ElementSection, DataSection, MemorySection,
CustomSection,
};
use super::name_section::NameSection;
use super::reloc_section::RelocSection;
use core::cmp;
const WASM_MAGIC_NUMBER: [u8; 4] = [0x00, 0x61, 0x73, 0x6d];
#[derive(Debug, Clone, PartialEq)]
pub struct Module {
magic: u32,
version: u32,
sections: Vec<Section>,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ImportCountType {
Function,
Global,
Table,
Memory,
}
impl Default for Module {
fn default() -> Self {
Module {
magic: u32::from_le_bytes(WASM_MAGIC_NUMBER),
version: 1,
sections: Vec::with_capacity(16),
}
}
}
impl Module {
pub fn new(sections: Vec<Section>) -> Self {
Module {
sections: sections, ..Default::default()
}
}
pub fn from_bytes<T: AsRef<[u8]>>(input: T) -> Result<Self, Error> {
Ok(deserialize_buffer::<Module>(input.as_ref())?)
}
pub fn to_bytes(self) -> Result<Vec<u8>, Error> {
Ok(serialize::<Module>(self)?)
}
pub fn into_sections(self) -> Vec<Section> {
self.sections
}
pub fn version(&self) -> u32 { self.version }
pub fn sections(&self) -> &[Section] {
&self.sections
}
pub fn sections_mut(&mut self) -> &mut Vec<Section> {
&mut self.sections
}
pub fn insert_section(&mut self, section: Section) -> Result<(), Error> {
let sections = self.sections_mut();
if section.order() == 0 {
sections.push(section);
return Ok(());
}
if sections.iter().position(|s| s.order() == section.order()).is_some() {
return Err(Error::DuplicatedSections(section.order()));
}
if let Some(pos) = sections.iter().position(|s| section.order() < s.order()) {
sections.insert(pos, section);
} else {
sections.push(section);
}
Ok(())
}
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
}
pub fn code_section_mut(&mut self) -> Option<&mut CodeSection> {
for section in self.sections_mut() {
if let Section::Code(ref mut code_section) = *section { return Some(code_section); }
}
None
}
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
}
pub fn type_section_mut(&mut self) -> Option<&mut TypeSection> {
for section in self.sections_mut() {
if let Section::Type(ref mut type_section) = *section { return Some(type_section); }
}
None
}
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
}
pub fn import_section_mut(&mut self) -> Option<&mut ImportSection> {
for section in self.sections_mut() {
if let Section::Import(ref mut import_section) = *section { return Some(import_section); }
}
None
}
pub fn global_section(&self) -> Option<&GlobalSection> {
for section in self.sections() {
if let &Section::Global(ref section) = section { return Some(section); }
}
None
}
pub fn global_section_mut(&mut self) -> Option<&mut GlobalSection> {
for section in self.sections_mut() {
if let Section::Global(ref mut section) = *section { return Some(section); }
}
None
}
pub fn export_section(&self) -> Option<&ExportSection> {
for section in self.sections() {
if let &Section::Export(ref export_section) = section { return Some(export_section); }
}
None
}
pub fn export_section_mut(&mut self) -> Option<&mut ExportSection> {
for section in self.sections_mut() {
if let Section::Export(ref mut export_section) = *section { return Some(export_section); }
}
None
}
pub fn table_section(&self) -> Option<&TableSection> {
for section in self.sections() {
if let &Section::Table(ref section) = section { return Some(section); }
}
None
}
pub fn table_section_mut(&mut self) -> Option<&mut TableSection> {
for section in self.sections_mut() {
if let Section::Table(ref mut section) = *section { return Some(section); }
}
None
}
pub fn data_section(&self) -> Option<&DataSection> {
for section in self.sections() {
if let &Section::Data(ref section) = section { return Some(section); }
}
None
}
pub fn data_section_mut(&mut self) -> Option<&mut DataSection> {
for section in self.sections_mut() {
if let Section::Data(ref mut section) = *section { return Some(section); }
}
None
}
pub fn elements_section(&self) -> Option<&ElementSection> {
for section in self.sections() {
if let &Section::Element(ref section) = section { return Some(section); }
}
None
}
pub fn elements_section_mut(&mut self) -> Option<&mut ElementSection> {
for section in self.sections_mut() {
if let Section::Element(ref mut section) = *section { return Some(section); }
}
None
}
pub fn memory_section(&self) -> Option<&MemorySection> {
for section in self.sections() {
if let &Section::Memory(ref section) = section { return Some(section); }
}
None
}
pub fn memory_section_mut(&mut self) -> Option<&mut MemorySection> {
for section in self.sections_mut() {
if let Section::Memory(ref mut section) = *section { return Some(section); }
}
None
}
pub fn function_section(&self) -> Option<&FunctionSection> {
for section in self.sections() {
if let &Section::Function(ref sect) = section { return Some(sect); }
}
None
}
pub fn function_section_mut(&mut self) -> Option<&mut FunctionSection> {
for section in self.sections_mut() {
if let Section::Function(ref mut sect) = *section { return Some(sect); }
}
None
}
pub fn start_section(&self) -> Option<u32> {
for section in self.sections() {
if let &Section::Start(sect) = section { return Some(sect); }
}
None
}
pub fn set_start_section(&mut self, new_start: u32) {
for section in self.sections_mut().iter_mut() {
if let &mut Section::Start(_sect) = section {
*section = Section::Start(new_start);
return
}
}
self.insert_section(Section::Start(new_start)).expect("insert_section should not fail");
}
pub fn clear_start_section(&mut self) {
let sections = self.sections_mut();
let mut rmidx = sections.len();
for (index, section) in sections.iter_mut().enumerate() {
if let Section::Start(_sect) = section {
rmidx = index;
break;
}
}
if rmidx < sections.len() {
sections.remove(rmidx);
}
}
pub fn custom_sections(&self) -> impl Iterator<Item=&CustomSection> {
self.sections().iter().filter_map(|s| {
if let Section::Custom(s) = s {
Some(s)
} else {
None
}
})
}
pub fn set_custom_section(&mut self, name: impl Into<String>, payload: Vec<u8>) {
let name: String = name.into();
for section in self.sections_mut() {
if let &mut Section::Custom(ref mut sect) = section {
if sect.name() == name {
*sect = CustomSection::new(name, payload);
return
}
}
}
self.sections_mut().push(Section::Custom(CustomSection::new(name, payload)));
}
pub fn clear_custom_section(&mut self, name: impl AsRef<str>) -> Option<CustomSection> {
let name: &str = name.as_ref();
let sections = self.sections_mut();
for i in 0..sections.len() {
let mut remove = false;
if let Section::Custom(ref sect) = sections[i] {
if sect.name() == name {
remove = true;
}
}
if remove {
let removed = sections.remove(i);
match removed {
Section::Custom(sect) => return Some(sect),
_ => unreachable!(),
}
}
}
None
}
pub fn has_names_section(&self) -> bool {
self.sections().iter().any(|e| {
match e {
Section::Custom(custom) => custom.name() == "name",
Section::Name(_) => true,
_ => false,
}
})
}
pub fn names_section(&self) -> Option<&NameSection> {
for section in self.sections() {
if let Section::Name(ref sect) = *section { return Some(sect); }
}
None
}
pub fn names_section_mut(&mut self) -> Option<&mut NameSection> {
for section in self.sections_mut() {
if let Section::Name(ref mut sect) = *section { return Some(sect); }
}
None
}
pub fn parse_names(mut self) -> Result<Self, (Vec<(usize, Error)>, Self)> {
let mut parse_errors = Vec::new();
for i in 0..self.sections.len() {
if let Some(name_section) = {
let section = self.sections.get(i).expect("cannot fail because i in range 0..len; qed");
if let Section::Custom(ref custom) = *section {
if custom.name() == "name" {
let mut rdr = io::Cursor::new(custom.payload());
let name_section = match NameSection::deserialize(&self, &mut rdr) {
Ok(ns) => ns,
Err(e) => { parse_errors.push((i, e)); continue; }
};
Some(name_section)
} else {
None
}
} else { None }
} {
*self.sections.get_mut(i).expect("cannot fail because i in range 0..len; qed") = Section::Name(name_section);
}
}
if parse_errors.len() > 0 {
Err((parse_errors, self))
} else {
Ok(self)
}
}
pub fn parse_reloc(mut self) -> Result<Self, (Vec<(usize, Error)>, Self)> {
let mut parse_errors = Vec::new();
for (i, section) in self.sections.iter_mut().enumerate() {
if let Some(relocation_section) = {
if let Section::Custom(ref custom) = *section {
if custom.name().starts_with("reloc.") {
let mut rdr = io::Cursor::new(custom.payload());
let reloc_section = match RelocSection::deserialize(custom.name().to_owned(), &mut rdr) {
Ok(reloc_section) => reloc_section,
Err(e) => { parse_errors.push((i, e)); continue; }
};
if rdr.position() != custom.payload().len() {
parse_errors.push((i, io::Error::InvalidData.into()));
continue;
}
Some(Section::Reloc(reloc_section))
}
else {
None
}
}
else {
None
}
} {
*section = relocation_section;
}
}
if parse_errors.len() > 0 {
Err((parse_errors, self))
} else {
Ok(self)
}
}
pub fn import_count(&self, count_type: ImportCountType) -> usize {
self.import_section()
.map(|is|
is.entries().iter().filter(|import| match (count_type, *import.external()) {
(ImportCountType::Function, External::Function(_)) => true,
(ImportCountType::Global, External::Global(_)) => true,
(ImportCountType::Table, External::Table(_)) => true,
(ImportCountType::Memory, External::Memory(_)) => true,
_ => false
}).count())
.unwrap_or(0)
}
pub fn functions_space(&self) -> usize {
self.import_count(ImportCountType::Function) +
self.function_section().map(|fs| fs.entries().len()).unwrap_or(0)
}
pub fn globals_space(&self) -> usize {
self.import_count(ImportCountType::Global) +
self.global_section().map(|gs| gs.entries().len()).unwrap_or(0)
}
pub fn table_space(&self) -> usize {
self.import_count(ImportCountType::Table) +
self.table_section().map(|ts| ts.entries().len()).unwrap_or(0)
}
pub fn memory_space(&self) -> usize {
self.import_count(ImportCountType::Memory) +
self.memory_section().map(|ms| ms.entries().len()).unwrap_or(0)
}
}
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 mut magic = [0u8; 4];
reader.read(&mut magic)?;
if magic != WASM_MAGIC_NUMBER {
return Err(Error::InvalidMagic);
}
let version: u32 = Uint32::deserialize(reader)?.into();
if version != 1 {
return Err(Error::UnsupportedVersion(version));
}
let mut last_section_order = 0;
loop {
match Section::deserialize(reader) {
Err(Error::UnexpectedEof) => { break; },
Err(e) => { return Err(e) },
Ok(section) => {
if section.order() != 0 {
if last_section_order > section.order() {
return Err(Error::SectionsOutOfOrder);
} else if last_section_order == section.order() {
return Err(Error::DuplicatedSections(last_section_order));
}
last_section_order = section.order();
}
sections.push(section);
}
}
}
let module = Module {
magic: u32::from_le_bytes(magic),
version: version,
sections: sections,
};
if module.code_section().map(|cs| cs.bodies().len()).unwrap_or(0) !=
module.function_section().map(|fs| fs.entries().len()).unwrap_or(0)
{
return Err(Error::InconsistentCode);
}
Ok(module)
}
}
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(())
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
struct PeekSection<'a> {
cursor: usize,
region: &'a [u8],
}
impl<'a> io::Read for PeekSection<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<()> {
let available = cmp::min(buf.len(), self.region.len() - self.cursor);
if available < buf.len() {
return Err(io::Error::UnexpectedEof);
}
let range = self.cursor..self.cursor + buf.len();
buf.copy_from_slice(&self.region[range]);
self.cursor += available;
Ok(())
}
}
pub fn peek_size(source: &[u8]) -> usize {
if source.len() < 9 {
return 0;
}
let mut cursor = 8;
loop {
let (new_cursor, section_id, section_len) = {
let mut peek_section = PeekSection { cursor: 0, region: &source[cursor..] };
let section_id: u8 = match super::VarUint7::deserialize(&mut peek_section) {
Ok(res) => res.into(),
Err(_) => { break; },
};
let section_len: u32 = match super::VarUint32::deserialize(&mut peek_section) {
Ok(res) => res.into(),
Err(_) => { break; },
};
(peek_section.cursor, section_id, section_len)
};
if section_id <= 11 && section_len > 0 {
let next_cursor = cursor + new_cursor + section_len as usize;
if next_cursor > source.len() {
break;
} else if next_cursor == source.len() {
cursor = next_cursor;
break;
}
cursor = next_cursor;
} else {
break;
}
}
cursor
}
#[cfg(test)]
mod integration_tests {
use super::super::{deserialize_file, serialize, deserialize_buffer, Section, TypeSection, FunctionSection, ExportSection, CodeSection};
use super::Module;
#[test]
fn hello() {
let module = deserialize_file("./res/cases/v1/hello.wasm").expect("Should be deserialized");
assert_eq!(module.version(), 1);
assert_eq!(module.sections().len(), 8);
}
#[test]
fn serde() {
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
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.sections().len(), module_new.sections().len());
}
#[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"
);
}
#[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 { return true }
if let &Section::Function(_) = 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"
);
}
#[test]
fn const_() {
use super::super::Instruction::*;
let module = deserialize_file("./res/cases/v1/const.wasm").expect("Should be deserialized");
let func = &module.code_section().expect("Code section to exist").bodies()[0];
assert_eq!(func.code().elements().len(), 20);
assert_eq!(I64Const(9223372036854775807), func.code().elements()[0]);
assert_eq!(I64Const(-9223372036854775808), func.code().elements()[1]);
assert_eq!(I64Const(-1152894205662152753), func.code().elements()[2]);
assert_eq!(I64Const(-8192), func.code().elements()[3]);
assert_eq!(I32Const(1024), func.code().elements()[4]);
assert_eq!(I32Const(2048), func.code().elements()[5]);
assert_eq!(I32Const(4096), func.code().elements()[6]);
assert_eq!(I32Const(8192), func.code().elements()[7]);
assert_eq!(I32Const(16384), func.code().elements()[8]);
assert_eq!(I32Const(32767), func.code().elements()[9]);
assert_eq!(I32Const(-1024), func.code().elements()[10]);
assert_eq!(I32Const(-2048), func.code().elements()[11]);
assert_eq!(I32Const(-4096), func.code().elements()[12]);
assert_eq!(I32Const(-8192), func.code().elements()[13]);
assert_eq!(I32Const(-16384), func.code().elements()[14]);
assert_eq!(I32Const(-32768), func.code().elements()[15]);
assert_eq!(I32Const(-2147483648), func.code().elements()[16]);
assert_eq!(I32Const(2147483647), func.code().elements()[17]);
}
#[test]
fn store() {
use super::super::Instruction::*;
let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
let func = &module.code_section().expect("Code section to exist").bodies()[0];
assert_eq!(func.code().elements().len(), 5);
assert_eq!(I64Store(0, 32), func.code().elements()[2]);
}
#[test]
fn peek() {
use super::peek_size;
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
let mut buf = serialize(module).expect("serialization to succeed");
buf.extend_from_slice(&[1, 5, 12, 17]);
assert_eq!(peek_size(&buf), buf.len() - 4);
}
#[test]
fn peek_2() {
use super::peek_size;
let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
let mut buf = serialize(module).expect("serialization to succeed");
buf.extend_from_slice(&[0, 0, 0, 0, 0, 1, 5, 12, 17]);
assert_eq!(peek_size(&buf), buf.len() - 9);
}
#[test]
fn peek_3() {
use super::peek_size;
let module = deserialize_file("./res/cases/v1/peek_sample.wasm").expect("Should be deserialized");
let buf = serialize(module).expect("serialization to succeed");
assert_eq!(peek_size(&buf), buf.len());
}
#[test]
fn module_default_round_trip() {
let module1 = Module::default();
let buf = serialize(module1).expect("Serialization should succeed");
let module2: Module = deserialize_buffer(&buf).expect("Deserialization should succeed");
assert_eq!(Module::default().magic, module2.magic);
}
#[test]
fn names() {
let module = deserialize_file("./res/cases/v1/with_names.wasm")
.expect("Should be deserialized")
.parse_names()
.expect("Names to be parsed");
let mut found_section = false;
for section in module.sections() {
match *section {
Section::Name(ref name_section) => {
let function_name_subsection = name_section
.functions()
.expect("function_name_subsection should be present");
assert_eq!(
function_name_subsection.names().get(0).expect("Should be entry #0"),
"elog"
);
assert_eq!(
function_name_subsection.names().get(11).expect("Should be entry #0"),
"_ZN48_$LT$pwasm_token_contract..Endpoint$LT$T$GT$$GT$3new17hc3ace6dea0978cd9E"
);
found_section = true;
},
_ => {},
}
}
assert!(found_section, "Name section should be present in dedicated example");
}
#[test]
fn shared_memory_flag() {
let module = deserialize_file("./res/cases/v1/varuint1_1.wasm");
assert_eq!(module.is_ok(), cfg!(feature="atomics"));
}
#[test]
fn memory_space() {
let module = deserialize_file("./res/cases/v1/two-mems.wasm").expect("failed to deserialize");
assert_eq!(module.memory_space(), 2);
}
#[test]
fn add_custom_section() {
let mut module = deserialize_file("./res/cases/v1/start_mut.wasm").expect("failed to deserialize");
assert!(module.custom_sections().next().is_none());
module.set_custom_section("mycustomsection".to_string(), vec![1, 2, 3, 4]);
{
let sections = module.custom_sections().collect::<Vec<_>>();
assert_eq!(sections.len(), 1);
assert_eq!(sections[0].name(), "mycustomsection");
assert_eq!(sections[0].payload(), &[1, 2, 3, 4]);
}
let old_section = module.clear_custom_section("mycustomsection");
assert_eq!(old_section.expect("Did not find custom section").payload(), &[1, 2, 3, 4]);
assert!(module.custom_sections().next().is_none());
}
#[test]
fn mut_start() {
let mut module = deserialize_file("./res/cases/v1/start_mut.wasm").expect("failed to deserialize");
assert_eq!(module.start_section().expect("Did not find any start section"), 1);
module.set_start_section(0);
assert_eq!(module.start_section().expect("Did not find any start section"), 0);
module.clear_start_section();
assert_eq!(None, module.start_section());
}
#[test]
fn add_start() {
let mut module = deserialize_file("./res/cases/v1/start_add.wasm").expect("failed to deserialize");
assert!(module.start_section().is_none());
module.set_start_section(0);
assert_eq!(module.start_section().expect("Did not find any start section"), 0);
let sections = module.sections().iter().map(|s| s.order()).collect::<Vec<_>>();
assert_eq!(sections, vec![1, 2, 3, 6, 7, 8, 9, 11, 12]);
}
#[test]
fn add_start_custom() {
let mut module = deserialize_file("./res/cases/v1/start_add_custom.wasm").expect("failed to deserialize");
let sections = module.sections().iter().map(|s| s.order()).collect::<Vec<_>>();
assert_eq!(sections, vec![1, 2, 3, 6, 7, 9, 11, 12, 0]);
assert!(module.start_section().is_none());
module.set_start_section(0);
assert_eq!(module.start_section().expect("Dorder not find any start section"), 0);
let sections = module.sections().iter().map(|s| s.order()).collect::<Vec<_>>();
assert_eq!(sections, vec![1, 2, 3, 6, 7, 8, 9, 11, 12, 0]);
}
#[test]
fn names_section_present() {
let mut module = deserialize_file("./res/cases/v1/names.wasm").expect("failed to deserialize");
assert!(module.names_section().is_none());
assert!(module.names_section_mut().is_none());
assert!(module.has_names_section());
let mut module = module.parse_names().expect("failed to parse names section");
assert!(module.names_section().is_some());
assert!(module.names_section_mut().is_some());
assert!(module.has_names_section());
}
#[test]
fn names_section_not_present() {
let mut module = deserialize_file("./res/cases/v1/test.wasm").expect("failed to deserialize");
assert!(module.names_section().is_none());
assert!(module.names_section_mut().is_none());
assert!(!module.has_names_section());
let mut module = module.parse_names().expect("failed to parse names section");
assert!(module.names_section().is_none());
assert!(module.names_section_mut().is_none());
assert!(!module.has_names_section());
}
#[test]
fn insert_sections() {
let mut module = Module::default();
assert!(module.insert_section(Section::Function(FunctionSection::with_entries(vec![]))).is_ok());
assert!(module.insert_section(Section::Function(FunctionSection::with_entries(vec![]))).is_err());
assert!(module.insert_section(Section::Type(TypeSection::with_types(vec![]))).is_ok());
assert!(module.insert_section(Section::Type(TypeSection::with_types(vec![]))).is_err());
assert!(module.insert_section(Section::Export(ExportSection::with_entries(vec![]))).is_ok());
assert!(module.insert_section(Section::Export(ExportSection::with_entries(vec![]))).is_err());
assert!(module.insert_section(Section::Code(CodeSection::with_bodies(vec![]))).is_ok());
assert!(module.insert_section(Section::Code(CodeSection::with_bodies(vec![]))).is_err());
let serialized = serialize(module).expect("serialization to succeed");
assert!(deserialize_buffer::<Module>(&serialized).is_ok());
}
#[test]
fn serialization_roundtrip() {
let module = deserialize_file("./res/cases/v1/test.wasm").expect("failed to deserialize");
let module_copy = module.clone().to_bytes().expect("failed to serialize");
let module_copy = Module::from_bytes(&module_copy).expect("failed to deserialize");
assert_eq!(module, module_copy);
}
}