#![allow(non_camel_case_types)]
mod op;
use self::op::{
BinaryOp,
BranchTableOp,
CallIndirect,
CmpBranchOp,
GlobalGet,
GlobalSet,
LoadAtOp,
LoadOp,
LoadOpMem0Offset16,
SelectOp,
StoreAtOp,
StoreOp,
StoreOpMem0Offset16,
TableGet,
TableSet,
UnaryOp,
};
#[cfg(feature = "simd")]
use self::op::{
StoreLaneOp,
StoreLaneOpMem0Offset16,
TernaryOp,
V128ExtractLaneOp,
V128ReplaceLaneOp,
};
#[cfg(feature = "simd")]
use crate::core::{V128, simd::ImmLaneIdx};
use crate::{
Address,
BlockFuel,
BoundedSlotSpan,
BranchOffset,
BranchTableTarget,
FixedSlotSpan,
Local,
Offset,
Offset16,
OpCode,
Reg,
Slot,
SlotAndReg,
SlotSpan,
core::{ShiftAmount, TrapCode},
index::{
DataAddr,
ElemAddr,
FuncAddr,
FuncType,
GlobalAddr,
InternalFunc,
MemoryAddr,
RawSlot,
TableAddr,
},
primitive::OffsetRepr,
};
use core::{
error::Error as CoreError,
fmt,
mem::{self, MaybeUninit},
num::NonZero,
};
pub trait Decoder {
fn read_bytes(&mut self, buffer: &mut [u8]) -> Result<(), DecodeError>;
}
#[derive(Debug, Copy, Clone)]
pub enum DecodeError {
OutOfBytes,
InvalidBitPattern,
}
impl CoreError for DecodeError {}
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
DecodeError::OutOfBytes => "ran out of bytes to decode",
DecodeError::InvalidBitPattern => "encountered invalid bit pattern",
};
f.write_str(s)
}
}
impl Decoder for &'_ [u8] {
fn read_bytes(&mut self, buffer: &mut [u8]) -> Result<(), DecodeError> {
let Some((bytes, rest)) = self.split_at_checked(buffer.len()) else {
return Err(DecodeError::OutOfBytes);
};
buffer.copy_from_slice(bytes);
*self = rest;
Ok(())
}
}
pub trait Decode: Sized {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError>;
}
impl Decode for BoundedSlotSpan {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
let span = SlotSpan::decode(decoder)?;
let len = u16::decode(decoder)?;
Ok(Self::new(span, len))
}
}
impl<const N: u16> Decode for FixedSlotSpan<N> {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
let span = SlotSpan::decode(decoder)?;
Self::new(span).map_err(|_| DecodeError::InvalidBitPattern)
}
}
impl Decode for BranchTableTarget {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
let results = SlotSpan::decode(decoder)?;
let offset = BranchOffset::decode(decoder)?;
Ok(Self::new(results, offset))
}
}
macro_rules! impl_decode_for_primitive {
( $($ty:ty),* $(,)? ) => {
$(
impl Decode for $ty {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
let mut bytes = [0_u8; mem::size_of::<$ty>()];
decoder.read_bytes(&mut bytes)?;
Ok(Self::from_ne_bytes(bytes))
}
}
)*
};
}
impl_decode_for_primitive!(
u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64
);
impl Decode for RawSlot {
#[inline]
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
Ok(Self(<_ as Decode>::decode(decoder)?))
}
}
impl Decode for Slot {
#[inline]
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
Ok(Self(<RawSlot as Decode>::decode(decoder)?))
}
}
macro_rules! impl_decode_using {
( $($ty:ty as $as:ty = $e:expr),* $(,)? ) => {
$(
impl Decode for $ty {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
Ok($e(<$as as Decode>::decode(decoder)?))
}
}
)*
};
}
impl_decode_using! {
bool as u8 = |value| value != 0,
Offset16 as u16 = Offset16,
BranchOffset as i32 = Into::into,
Offset as OffsetRepr = Offset,
BlockFuel as u64 = Into::into,
FuncType as u32 = Into::into,
InternalFunc as usize = Into::into,
FuncAddr as u32 = Into::into,
GlobalAddr as u32 = Into::into,
MemoryAddr as u16 = Into::into,
TableAddr as u32 = Into::into,
DataAddr as u32 = Into::into,
ElemAddr as u32 = Into::into,
ShiftAmount as u8 = Into::into,
SlotSpan as Slot = SlotSpan::new,
}
#[cfg(feature = "simd")]
impl_decode_using! {
V128 as u128 = Into::into,
}
macro_rules! impl_decode_fallible_using {
( $($ty:ty as $as:ty = $e:expr),* $(,)? ) => {
$(
impl Decode for $ty {
#[inline(always)]
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
$e(<$as as Decode>::decode(decoder)?)
}
}
)*
};
}
impl_decode_fallible_using! {
Address as u64 = |address| {
Address::new(address).ok_or(DecodeError::InvalidBitPattern)
},
NonZero<i32> as i32 = |value| {
NonZero::new(value).ok_or(DecodeError::InvalidBitPattern)
},
NonZero<i64> as i64 = |value| {
NonZero::new(value).ok_or(DecodeError::InvalidBitPattern)
},
NonZero<u32> as u32 = |value| {
NonZero::new(value).ok_or(DecodeError::InvalidBitPattern)
},
NonZero<u64> as u64 = |value| {
NonZero::new(value).ok_or(DecodeError::InvalidBitPattern)
},
TrapCode as u8 = |code: u8| {
TrapCode::try_from(code).map_err(|_| DecodeError::InvalidBitPattern)
},
OpCode as u16 = |code: u16| {
OpCode::new(code).ok_or(DecodeError::InvalidBitPattern)
}
}
impl<const N: usize, T: Decode> Decode for [T; N] {
#[inline]
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
let mut array = <MaybeUninit<[T; N]>>::uninit();
let items = unsafe { &mut *array.as_mut_ptr() };
for item in items {
*item = <T as Decode>::decode(decoder)?;
}
let array = unsafe { array.assume_init() };
Ok(array)
}
}
#[cfg(feature = "simd")]
impl<const N: u8> Decode for ImmLaneIdx<N> {
#[inline]
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
let byte = u8::decode(decoder)?;
let lane = ImmLaneIdx::try_from(byte).map_err(|_| DecodeError::InvalidBitPattern)?;
Ok(lane)
}
}
impl<const N: u16> Decode for Local<N> {
#[inline]
fn decode<D: Decoder>(_decoder: &mut D) -> Result<Self, DecodeError> {
Ok(Self::default())
}
}
impl<T> Decode for SlotAndReg<T> {
#[inline]
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
Ok(Self {
slot: <Slot as Decode>::decode(decoder)?,
reg: <Reg<T> as Decode>::decode(decoder)?,
})
}
}
include!(concat!(env!("OUT_DIR"), "/decode.rs"));
impl<T> Decode for Reg<T> {
#[inline]
fn decode<D: Decoder>(_decoder: &mut D) -> Result<Self, DecodeError> {
Ok(Self::default())
}
}
impl Decode for () {
#[inline]
fn decode<D: Decoder>(_decoder: &mut D) -> Result<Self, DecodeError> {
Ok(())
}
}