mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-07-03 16:41:59 +00:00
import section, examples
This commit is contained in:
25
examples/info.rs
Normal file
25
examples/info.rs
Normal file
@ -0,0 +1,25 @@
|
||||
extern crate parity_wasm;
|
||||
|
||||
use std::env;
|
||||
use parity_wasm::Section;
|
||||
|
||||
fn main() {
|
||||
let args = env::args().collect::<Vec<_>>();
|
||||
if args.len() != 2 {
|
||||
println!("Usage: {} somefile.wasm", args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
|
||||
|
||||
println!("Module sections: {}", module.sections().len());
|
||||
|
||||
for section in module.sections() {
|
||||
match section {
|
||||
&Section::Import(ref import_section) => {
|
||||
println!("Imports {}", import_section.entries().len());
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
142
src/elements/import_entry.rs
Normal file
142
src/elements/import_entry.rs
Normal file
@ -0,0 +1,142 @@
|
||||
use std::io;
|
||||
use super::{Deserialize, Error, VarUint7, VarInt7, VarUint32, VarUint1, ValueType};
|
||||
|
||||
pub struct GlobalType {
|
||||
content_type: ValueType,
|
||||
is_mutable: bool,
|
||||
}
|
||||
|
||||
impl GlobalType {
|
||||
pub fn content_type(&self) -> ValueType { self.content_type }
|
||||
pub fn is_mutable(&self) -> bool { self.is_mutable }
|
||||
}
|
||||
|
||||
impl Deserialize for GlobalType {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let content_type = ValueType::deserialize(reader)?;
|
||||
let is_mutable = VarUint1::deserialize(reader)?;
|
||||
Ok(GlobalType {
|
||||
content_type: content_type,
|
||||
is_mutable: is_mutable.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TableType {
|
||||
_elem_type: i8,
|
||||
limits: ResizableLimits,
|
||||
}
|
||||
|
||||
impl TableType {
|
||||
pub fn limits(&self) -> &ResizableLimits { &self.limits }
|
||||
}
|
||||
|
||||
impl Deserialize for TableType {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let elem_type = VarInt7::deserialize(reader)?;
|
||||
let limits = ResizableLimits::deserialize(reader)?;
|
||||
Ok(TableType {
|
||||
_elem_type: elem_type.into(),
|
||||
limits: limits,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ResizableLimits {
|
||||
initial: u32,
|
||||
maximum: Option<u32>,
|
||||
}
|
||||
|
||||
impl ResizableLimits {
|
||||
pub fn initial(&self) -> u32 { self.initial }
|
||||
pub fn maximum(&self) -> Option<u32> { self.maximum }
|
||||
}
|
||||
|
||||
impl Deserialize for ResizableLimits {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let has_max = VarUint1::deserialize(reader)?;
|
||||
let initial = VarUint32::deserialize(reader)?;
|
||||
let maximum = if has_max.into() {
|
||||
Some(VarUint32::deserialize(reader)?.into())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(ResizableLimits {
|
||||
initial: initial.into(),
|
||||
maximum: maximum,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MemoryType(ResizableLimits);
|
||||
|
||||
impl MemoryType {
|
||||
pub fn limits(&self) -> &ResizableLimits {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserialize for MemoryType {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
Ok(MemoryType(ResizableLimits::deserialize(reader)?))
|
||||
}
|
||||
}
|
||||
|
||||
pub enum External {
|
||||
Function(u32),
|
||||
Table(TableType),
|
||||
Memory(MemoryType),
|
||||
Global(GlobalType),
|
||||
}
|
||||
|
||||
impl Deserialize for External {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let kind = VarUint7::deserialize(reader)?;
|
||||
match kind.into() {
|
||||
0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())),
|
||||
0x01 => Ok(External::Table(TableType::deserialize(reader)?)),
|
||||
0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)),
|
||||
0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)),
|
||||
_ => Err(Error::UnknownExternalKind(kind.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ImportEntry {
|
||||
module_str: String,
|
||||
field_str: String,
|
||||
external: External,
|
||||
}
|
||||
|
||||
impl ImportEntry {
|
||||
pub fn module(&self) -> &str { &self.module_str }
|
||||
pub fn field(&self) -> &str { &self.field_str }
|
||||
pub fn external(&self) -> &External { &self.external }
|
||||
}
|
||||
|
||||
impl Deserialize for ImportEntry {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let module_str = String::deserialize(reader)?;
|
||||
let field_str = String::deserialize(reader)?;
|
||||
let external = External::deserialize(reader)?;
|
||||
|
||||
Ok(ImportEntry {
|
||||
module_str: module_str,
|
||||
field_str: field_str,
|
||||
external: external,
|
||||
})
|
||||
}
|
||||
}
|
@ -4,10 +4,13 @@ mod module;
|
||||
mod section;
|
||||
mod primitives;
|
||||
mod types;
|
||||
mod import_entry;
|
||||
|
||||
pub use self::module::Module;
|
||||
pub use self::section::Section;
|
||||
pub use self::import_entry::ImportEntry;
|
||||
pub use self::primitives::{VarUint32, VarUint7, VarUint1, VarInt7, Uint32, CountedList};
|
||||
pub use self::types::ValueType;
|
||||
|
||||
pub trait Deserialize : Sized {
|
||||
type Error;
|
||||
@ -21,6 +24,8 @@ pub enum Error {
|
||||
Other(&'static str),
|
||||
HeapOther(String),
|
||||
UnknownValueType(i8),
|
||||
NonUtf8String,
|
||||
UnknownExternalKind(u8),
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
@ -48,7 +53,7 @@ impl From<Unparsed> for Vec<u8> {
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error> {
|
||||
pub fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error> {
|
||||
use std::io::Read;
|
||||
|
||||
let mut contents = Vec::new();
|
||||
@ -57,7 +62,7 @@ fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error>
|
||||
deserialize_buffer(contents)
|
||||
}
|
||||
|
||||
fn deserialize_buffer<T: Deserialize>(contents: Vec<u8>) -> Result<T, T::Error> {
|
||||
pub fn deserialize_buffer<T: Deserialize>(contents: Vec<u8>) -> Result<T, T::Error> {
|
||||
let mut reader = io::Cursor::new(contents);
|
||||
T::deserialize(&mut reader)
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
use std::io;
|
||||
use super::{Deserialize, VarUint32, Error, Uint32};
|
||||
use super::{Deserialize, Error, Uint32};
|
||||
use super::section::Section;
|
||||
|
||||
pub struct Module {
|
||||
magic: u32,
|
||||
_magic: u32,
|
||||
version: u32,
|
||||
sections: Vec<Section>,
|
||||
}
|
||||
@ -35,7 +35,7 @@ impl Deserialize for Module {
|
||||
}
|
||||
|
||||
Ok(Module {
|
||||
magic: magic.into(),
|
||||
_magic: magic.into(),
|
||||
version: version.into(),
|
||||
sections: sections,
|
||||
})
|
||||
@ -48,19 +48,12 @@ mod integration_tests {
|
||||
use std::io::{self, Read};
|
||||
use std::fs::File;
|
||||
|
||||
use super::super::Deserialize;
|
||||
use super::super::{Deserialize, deserialize_file};
|
||||
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");
|
||||
let module = deserialize_file("./res/cases/v1/hello.wasm").expect("Should be deserialized");
|
||||
|
||||
assert_eq!(module.version(), 1);
|
||||
assert_eq!(module.sections().len(), 8);
|
||||
|
@ -25,7 +25,6 @@ impl Deserialize for VarUint32 {
|
||||
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;
|
||||
@ -119,6 +118,22 @@ impl Deserialize for VarUint1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserialize for String {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let length = VarUint32::deserialize(reader)?.into();
|
||||
if length > 0 {
|
||||
let mut buf = vec![0u8; length];
|
||||
reader.read_exact(&mut buf)?;
|
||||
String::from_utf8(buf).map_err(|_| Error::NonUtf8String)
|
||||
}
|
||||
else {
|
||||
Ok(String::new())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CountedList<T: Deserialize>(Vec<T>);
|
||||
|
||||
impl<T: Deserialize> CountedList<T> {
|
||||
@ -130,13 +145,13 @@ impl<T: Deserialize> Deserialize for CountedList<T> where T::Error : From<Error>
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::super::deserialize_buffer;
|
||||
@ -162,5 +177,4 @@ mod tests {
|
||||
let v3: i8 = (*vars.get(1).unwrap()).into();
|
||||
assert_eq!(-0x03i8, v3);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use std::io;
|
||||
use super::{Deserialize, Unparsed, Error, VarUint7, VarUint32, CountedList};
|
||||
use super::{Deserialize, Unparsed, Error, VarUint7, VarUint32, CountedList, ImportEntry};
|
||||
use super::types::Type;
|
||||
|
||||
pub enum Section {
|
||||
@ -9,6 +9,7 @@ pub enum Section {
|
||||
},
|
||||
Custom(Vec<u8>),
|
||||
Type(TypeSection),
|
||||
Import(ImportSection),
|
||||
}
|
||||
|
||||
impl Deserialize for Section {
|
||||
@ -29,6 +30,9 @@ impl Deserialize for Section {
|
||||
1 => {
|
||||
Section::Type(TypeSection::deserialize(reader)?)
|
||||
},
|
||||
2 => {
|
||||
Section::Import(ImportSection::deserialize(reader)?)
|
||||
},
|
||||
_ => {
|
||||
Section::Unparsed { id: id.into(), payload: Unparsed::deserialize(reader)?.into() }
|
||||
}
|
||||
@ -37,13 +41,11 @@ impl Deserialize for Section {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TypeSection {
|
||||
types: Vec<Type>,
|
||||
}
|
||||
pub struct TypeSection(Vec<Type>);
|
||||
|
||||
impl TypeSection {
|
||||
fn types(&self) -> &[Type] {
|
||||
&self.types
|
||||
pub fn types(&self) -> &[Type] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,15 +56,50 @@ impl Deserialize for TypeSection {
|
||||
// todo: maybe use reader.take(section_length)
|
||||
let _section_length = VarUint32::deserialize(reader)?;
|
||||
let types: Vec<Type> = CountedList::deserialize(reader)?.into_inner();
|
||||
Ok(TypeSection { types: types })
|
||||
Ok(TypeSection(types))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ImportSection(Vec<ImportEntry>);
|
||||
|
||||
impl ImportSection {
|
||||
pub fn entries(&self) -> &[ImportEntry] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserialize for ImportSection {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
// todo: maybe use reader.take(section_length)
|
||||
let _section_length = VarUint32::deserialize(reader)?;
|
||||
let entries: Vec<ImportEntry> = CountedList::deserialize(reader)?.into_inner();
|
||||
Ok(ImportSection(entries))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::super::{deserialize_buffer};
|
||||
use super::{TypeSection, Type};
|
||||
use super::super::{deserialize_buffer, deserialize_file};
|
||||
use super::{Section, TypeSection, Type};
|
||||
|
||||
#[test]
|
||||
fn import_section() {
|
||||
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||
let mut found = false;
|
||||
for section in module.sections() {
|
||||
match section {
|
||||
&Section::Import(ref import_section) => {
|
||||
assert_eq!(25, import_section.entries().len());
|
||||
found = true
|
||||
},
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
assert!(found, "There should be import section in test5.wasm");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_section() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use std::io;
|
||||
use super::{Deserialize, Unparsed, Error, VarUint7, VarInt7, VarUint32, VarUint1};
|
||||
use super::{Deserialize, Error, VarUint7, VarInt7, VarUint1, CountedList};
|
||||
|
||||
pub enum Type {
|
||||
Function(FunctionType),
|
||||
@ -13,6 +13,7 @@ impl Deserialize for Type {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ValueType {
|
||||
I32,
|
||||
I64,
|
||||
@ -42,20 +43,19 @@ pub struct FunctionType {
|
||||
return_type: Option<ValueType>,
|
||||
}
|
||||
|
||||
impl FunctionType {
|
||||
pub fn form(&self) -> u8 { self.form }
|
||||
pub fn params(&self) -> &[ValueType] { &self.params }
|
||||
pub fn return_type(&self) -> Option<ValueType> { self.return_type }
|
||||
}
|
||||
|
||||
impl Deserialize for FunctionType {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
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 params: Vec<ValueType> = CountedList::deserialize(reader)?.into_inner();
|
||||
|
||||
let has_return_type = VarUint1::deserialize(reader)?;
|
||||
let return_type = if has_return_type.into() {
|
||||
|
@ -2,4 +2,4 @@ extern crate byteorder;
|
||||
|
||||
mod elements;
|
||||
|
||||
pub use elements::{Section, Module, Error as DeserializeError};
|
||||
pub use elements::{Section, Module, Error as DeserializeError, deserialize_buffer, deserialize_file};
|
||||
|
Reference in New Issue
Block a user