#[cfg(feature = "simd")]
use crate::core::{V128, simd::ImmLaneIdx};
use crate::{
Address,
BlockFuel,
BoundedSlotSpan,
BranchOffset,
BranchTableTarget,
DataAddr,
ElemAddr,
FixedSlotSpan,
FuncAddr,
FuncType,
GlobalAddr,
InternalFunc,
Local,
MemoryAddr,
Offset,
Offset16,
Op,
OpCode,
Reg,
Slot,
SlotAndReg,
SlotSpan,
TableAddr,
core::{ShiftAmount, TrapCode},
index::RawSlot,
primitive::OffsetRepr,
};
use core::num::NonZero;
pub trait Encoder {
type Pos: Copy;
type Error;
fn write_bytes(&mut self, bytes: &[u8]) -> Result<Self::Pos, Self::Error>;
fn encode_op_code(&mut self, code: OpCode) -> Result<Self::Pos, Self::Error>;
fn branch_offset(
&mut self,
pos: Self::Pos,
branch_offset: BranchOffset,
) -> Result<(), Self::Error>;
fn block_fuel(&mut self, pos: Self::Pos, block_fuel: BlockFuel) -> Result<(), Self::Error>;
}
pub trait Encode {
fn encode<E>(&self, encoder: &mut E) -> Result<E::Pos, E::Error>
where
E: Encoder;
}
impl Encode for OpCode {
fn encode<E>(&self, encoder: &mut E) -> Result<E::Pos, E::Error>
where
E: Encoder,
{
encoder.encode_op_code(*self)
}
}
impl Encode for BranchOffset {
fn encode<E>(&self, encoder: &mut E) -> Result<E::Pos, E::Error>
where
E: Encoder,
{
let pos = i32::from(*self).encode(encoder)?;
encoder.branch_offset(pos, *self)?;
Ok(pos)
}
}
impl Encode for BlockFuel {
fn encode<E>(&self, encoder: &mut E) -> Result<E::Pos, E::Error>
where
E: Encoder,
{
let pos = u64::from(*self).encode(encoder)?;
encoder.block_fuel(pos, *self)?;
Ok(pos)
}
}
impl Encode for BoundedSlotSpan {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<E::Pos, E::Error> {
(self.span(), self.len()).encode(encoder)
}
}
impl<const N: u16> Encode for FixedSlotSpan<N> {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<E::Pos, E::Error> {
self.span().encode(encoder)
}
}
impl Encode for BranchTableTarget {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<E::Pos, E::Error> {
(self.results, self.offset).encode(encoder)
}
}
macro_rules! impl_encode_for_primitive {
( $($ty:ty),* $(,)? ) => {
$(
impl Encode for $ty {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<E::Pos, E::Error> {
encoder.write_bytes(&self.to_ne_bytes())
}
}
)*
};
}
impl_encode_for_primitive!(
u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64
);
impl Encode for RawSlot {
#[inline]
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<E::Pos, E::Error> {
self.0.encode(encoder)
}
}
impl Encode for Slot {
#[inline]
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<E::Pos, E::Error> {
self.0.encode(encoder)
}
}
macro_rules! impl_encode_using {
( $($ty:ty as $prim:ty = $e:expr),* $(,)? ) => {
$(
impl Encode for $ty {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<E::Pos, E::Error> {
let conv = |value: &Self| -> $prim { $e(*value) };
conv(self).encode(encoder)
}
}
)*
};
}
impl_encode_using! {
bool as u8 = Into::into,
Offset16 as u16 = |o: Offset16| o.0,
Offset as OffsetRepr = |o: Offset| o.0,
Address 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::head,
NonZero<i32> as i32 = NonZero::get,
NonZero<i64> as i64 = NonZero::get,
NonZero<u32> as u32 = NonZero::get,
NonZero<u64> as u64 = NonZero::get,
TrapCode as u8 = |code: TrapCode| -> u8 { code as _ },
}
#[cfg(feature = "simd")]
impl_encode_using! {
V128 as u128 = |v128: V128| -> u128 { v128.as_u128() },
}
#[cfg(feature = "simd")]
impl<const N: u8> Encode for ImmLaneIdx<N> {
fn encode<E>(&self, encoder: &mut E) -> Result<E::Pos, E::Error>
where
E: Encoder,
{
u8::from(*self).encode(encoder)
}
}
macro_rules! for_tuple {
( $mac:ident ) => {
$mac! { T0 }
$mac! { T0, T1 }
$mac! { T0, T1, T2 }
$mac! { T0, T1, T2, T3 }
$mac! { T0, T1, T2, T3, T4 }
$mac! { T0, T1, T2, T3, T4, T5 }
$mac! { T0, T1, T2, T3, T4, T5, T6 }
};
}
macro_rules! impl_encode_for_tuple {
( $t0:ident $(, $t:ident)* $(,)? ) => {
impl<$t0: Encode $(, $t: Encode)*> Encode for ($t0, $($t,)*) {
#[inline(always)]
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<E::Pos, E::Error> {
#[allow(non_snake_case)]
let ($t0, $($t,)*) = self;
let pos = $t0.encode(encoder)?;
$( $t.encode(encoder)?; )*
Ok(pos)
}
}
};
}
for_tuple!(impl_encode_for_tuple);
impl<T: Encode> Encode for &'_ T {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<E::Pos, E::Error> {
<T as Encode>::encode(*self, encoder)
}
}
impl<const N: usize, T: Encode> Encode for [T; N] {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<E::Pos, E::Error> {
let Some((first, rest)) = self.split_first() else {
panic!("cannot encode zero-sized arrays")
};
let pos = first.encode(encoder)?;
for item in rest {
item.encode(encoder)?;
}
Ok(pos)
}
}
impl<const N: u16> Encode for Local<N> {
#[inline]
fn encode<E>(&self, encoder: &mut E) -> Result<E::Pos, E::Error>
where
E: Encoder,
{
encoder.write_bytes(&[])
}
}
impl<T> Encode for SlotAndReg<T> {
#[inline]
fn encode<E>(&self, encoder: &mut E) -> Result<E::Pos, E::Error>
where
E: Encoder,
{
let pos = self.slot.encode(encoder)?;
self.reg.encode(encoder)?;
Ok(pos)
}
}
include!(concat!(env!("OUT_DIR"), "/encode.rs"));
impl<T> Encode for Reg<T> {
#[inline]
fn encode<E>(&self, encoder: &mut E) -> Result<E::Pos, E::Error>
where
E: Encoder,
{
encoder.write_bytes(&[])
}
}