use crate::{BinaryReader, BinaryReaderError, Result, ValType};
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BlockType {
Empty,
Type(ValType),
FuncType(u32),
}
#[derive(Debug, Copy, Clone)]
pub struct MemArg {
pub align: u8,
pub offset: u64,
pub memory: u32,
}
#[derive(Clone)]
pub struct BrTable<'a> {
pub(crate) reader: crate::BinaryReader<'a>,
pub(crate) cnt: u32,
pub(crate) default: u32,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct Ieee32(pub(crate) u32);
impl Ieee32 {
pub fn bits(self) -> u32 {
self.0
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct Ieee64(pub(crate) u64);
impl Ieee64 {
pub fn bits(self) -> u64 {
self.0
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct V128(pub(crate) [u8; 16]);
impl V128 {
pub fn bytes(&self) -> &[u8; 16] {
&self.0
}
pub fn i128(&self) -> i128 {
i128::from_le_bytes(self.0)
}
}
macro_rules! define_operator {
($($op:ident $({ $($payload:tt)* })? => $visit:ident)*) => {
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub enum Operator<'a> {
$(
$op $({ $($payload)* })?,
)*
}
}
}
for_each_operator!(define_operator);
#[derive(Clone)]
pub struct OperatorsReader<'a> {
pub(crate) reader: BinaryReader<'a>,
}
impl<'a> OperatorsReader<'a> {
pub(crate) fn new<'b>(data: &'a [u8], offset: usize) -> OperatorsReader<'b>
where
'a: 'b,
{
OperatorsReader {
reader: BinaryReader::new_with_offset(data, offset),
}
}
pub fn eof(&self) -> bool {
self.reader.eof()
}
pub fn original_position(&self) -> usize {
self.reader.original_position()
}
pub fn allow_memarg64(&mut self, allow: bool) {
self.reader.allow_memarg64(allow);
}
pub fn ensure_end(&self) -> Result<()> {
if self.eof() {
return Ok(());
}
Err(BinaryReaderError::new(
"unexpected data at the end of operators",
self.reader.original_position(),
))
}
pub fn read<'b>(&mut self) -> Result<Operator<'b>>
where
'a: 'b,
{
self.reader.read_operator()
}
pub fn into_iter_with_offsets<'b>(self) -> OperatorsIteratorWithOffsets<'b>
where
'a: 'b,
{
OperatorsIteratorWithOffsets {
reader: self,
err: false,
}
}
pub fn read_with_offset<'b>(&mut self) -> Result<(Operator<'b>, usize)>
where
'a: 'b,
{
let pos = self.reader.original_position();
Ok((self.read()?, pos))
}
pub fn visit_with_offset<T>(
&mut self,
visitor: &mut T,
) -> Result<<T as VisitOperator<'a>>::Output>
where
T: VisitOperator<'a>,
{
self.reader.visit_operator(visitor)
}
pub fn get_binary_reader(&self) -> BinaryReader<'a> {
self.reader.clone()
}
}
impl<'a> IntoIterator for OperatorsReader<'a> {
type Item = Result<Operator<'a>>;
type IntoIter = OperatorsIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
OperatorsIterator {
reader: self,
err: false,
}
}
}
pub struct OperatorsIterator<'a> {
reader: OperatorsReader<'a>,
err: bool,
}
impl<'a> Iterator for OperatorsIterator<'a> {
type Item = Result<Operator<'a>>;
fn next(&mut self) -> Option<Self::Item> {
if self.err || self.reader.eof() {
return None;
}
let result = self.reader.read();
self.err = result.is_err();
Some(result)
}
}
pub struct OperatorsIteratorWithOffsets<'a> {
reader: OperatorsReader<'a>,
err: bool,
}
impl<'a> Iterator for OperatorsIteratorWithOffsets<'a> {
type Item = Result<(Operator<'a>, usize)>;
fn next(&mut self) -> Option<Self::Item> {
if self.err || self.reader.eof() {
return None;
}
let result = self.reader.read_with_offset();
self.err = result.is_err();
Some(result)
}
}
macro_rules! define_visit_operator {
($($op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
$(
fn $visit(&mut self, offset: usize $($(,$arg: $argty)*)?) -> Self::Output;
)*
}
}
#[allow(missing_docs)]
pub trait VisitOperator<'a> {
type Output: 'a;
fn visit_operator(&mut self, offset: usize, op: &Operator<'a>) -> Self::Output {
macro_rules! visit_operator {
($($op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
match op {
$(
Operator::$op $({ $($arg),* })? => self.$visit(offset, $($($arg.clone()),*)?),
)*
}
}
}
for_each_operator!(visit_operator)
}
for_each_operator!(define_visit_operator);
}