use smallvec::{smallvec, SmallVec};
use wasmparser::{BlockType, ValType};
const ALIGNMENT_MASK: usize = 31;
pub trait Type {
fn align(&self) -> usize {
(self.size() + ALIGNMENT_MASK) & !ALIGNMENT_MASK
}
fn size(&self) -> usize;
}
impl Type for &ValType {
fn size(&self) -> usize {
match self {
ValType::I32 | ValType::F32 => 4,
ValType::I64 | ValType::F64 => 8,
_ => unimplemented!("unknown unsupported type {self}"),
}
}
}
impl Type for ValType {
fn size(&self) -> usize {
(&self).size()
}
}
impl Type for &[ValType] {
fn size(&self) -> usize {
self.as_ref().iter().map(|t| t.align()).sum::<usize>()
}
}
impl Type for usize {
fn align(&self) -> usize {
(*self + ALIGNMENT_MASK) & !ALIGNMENT_MASK
}
fn size(&self) -> usize {
self.to_le_bytes().len()
}
}
pub trait ToLSBytes {
type Output: AsRef<[u8]>;
fn to_ls_bytes(&self) -> Self::Output;
}
macro_rules! offset {
($number:ident, $size:expr) => {
impl ToLSBytes for $number {
type Output = SmallVec<[u8; $size]>;
fn to_ls_bytes(&self) -> Self::Output {
if *self == 0 {
return smallvec![0];
}
self.to_le_bytes()
.into_iter()
.rev()
.skip_while(|b| *b == 0)
.collect::<Vec<_>>()
.into()
}
}
};
($(($number:ident, $size:expr)),+) => {
$(offset!($number, $size);)+
};
}
offset! {
(usize, 8),
(u64, 8),
(i64, 8),
(i32, 4),
(u32, 4),
(u16, 2),
(u8, 1)
}
impl ToLSBytes for BlockType {
type Output = SmallVec<[u8; 8]>;
fn to_ls_bytes(&self) -> Self::Output {
match self {
BlockType::Empty => Default::default(),
BlockType::Type(val) => val.size().to_ls_bytes(),
BlockType::FuncType(val) => Self::Output::from_slice(&val.to_ls_bytes()),
}
}
}
impl ToLSBytes for &ValType {
type Output = SmallVec<[u8; 8]>;
fn to_ls_bytes(&self) -> Self::Output {
self.align().to_ls_bytes()
}
}
impl ToLSBytes for &[ValType] {
type Output = SmallVec<[u8; 8]>;
fn to_ls_bytes(&self) -> Self::Output {
self.as_ref()
.iter()
.map(|t| t.align())
.sum::<usize>()
.to_ls_bytes()
}
}
#[test]
fn test_usize_to_ls_bytes() {
assert_eq!(363usize.to_ls_bytes().to_vec(), vec![0x01, 0x6b]);
assert_eq!(255usize.to_ls_bytes().to_vec(), vec![0xff]);
}