use crate::builtins::WasmbinCountable;
use crate::indices::TypeId;
use crate::io::{Decode, DecodeError, DecodeWithDiscriminant, Encode, Wasmbin};
use crate::visit::Visit;
use crate::wasmbin_discriminants;
use arbitrary::Arbitrary;
use std::convert::TryFrom;
use std::fmt::{self, Debug, Formatter};
const OP_CODE_EMPTY_BLOCK: u8 = 0x40;
#[cfg_attr(feature = "reference-types", wasmbin_discriminants)]
#[derive(Wasmbin, WasmbinCountable, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
#[repr(u8)]
pub enum ValueType {
#[cfg(feature = "simd")]
V128 = 0x7B,
F64 = 0x7C,
F32 = 0x7D,
I64 = 0x7E,
I32 = 0x7F,
#[cfg(feature = "reference-types")]
Ref(RefType),
}
#[derive(Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
#[repr(u8)]
pub enum BlockType {
Empty,
Value(ValueType),
MultiValue(TypeId),
}
impl Encode for BlockType {
fn encode(&self, w: &mut impl std::io::Write) -> std::io::Result<()> {
match self {
BlockType::Empty => OP_CODE_EMPTY_BLOCK.encode(w),
BlockType::Value(ty) => ty.encode(w),
BlockType::MultiValue(id) => i64::from(id.index).encode(w),
}
}
}
impl Decode for BlockType {
fn decode(r: &mut impl std::io::Read) -> Result<Self, DecodeError> {
let discriminant = u8::decode(r)?;
if discriminant == OP_CODE_EMPTY_BLOCK {
return Ok(BlockType::Empty);
}
if let Some(ty) = ValueType::maybe_decode_with_discriminant(discriminant, r)? {
return Ok(BlockType::Value(ty));
}
let buf = [discriminant];
let mut r = std::io::Read::chain(&buf[..], r);
let as_i64 = i64::decode(&mut r)?;
let index = u32::try_from(as_i64)?;
Ok(BlockType::MultiValue(TypeId { index }))
}
}
#[derive(Wasmbin, WasmbinCountable, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
#[wasmbin(discriminant = 0x60)]
pub struct FuncType {
pub params: Vec<ValueType>,
pub results: Vec<ValueType>,
}
impl Debug for FuncType {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fn encode_types(types: &[ValueType], f: &mut Formatter) -> fmt::Result {
f.write_str("(")?;
for (i, ty) in types.iter().enumerate() {
if i != 0 {
f.write_str(", ")?;
}
ty.fmt(f)?;
}
f.write_str(")")
}
encode_types(&self.params, f)?;
f.write_str(" -> ")?;
encode_types(&self.results, f)
}
}
#[derive(Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct Limits {
pub min: u32,
pub max: Option<u32>,
}
impl Debug for Limits {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}..", self.min)?;
if let Some(max) = self.max {
write!(f, "={}", max)?;
}
Ok(())
}
}
#[wasmbin_discriminants]
#[derive(Wasmbin)]
#[repr(u8)]
enum LimitsRepr {
Min { min: u32 } = 0x00,
MinMax { min: u32, max: u32 } = 0x01,
}
encode_decode_as!(Limits, {
(Limits { min, max: None }) <=> (LimitsRepr::Min { min }),
(Limits { min, max: Some(max) }) <=> (LimitsRepr::MinMax { min, max }),
});
#[cfg(feature = "threads")]
#[wasmbin_discriminants]
#[derive(Wasmbin)]
#[repr(u8)]
enum MemTypeRepr {
Unshared(LimitsRepr),
SharedMin { min: u32 } = 0x02,
SharedMinMax { min: u32, max: u32 } = 0x03,
}
#[cfg_attr(not(feature = "threads"), derive(Wasmbin))]
#[derive(WasmbinCountable, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct MemType {
#[cfg(feature = "threads")]
pub is_shared: bool,
pub limits: Limits,
}
#[cfg(feature = "threads")]
encode_decode_as!(MemType, {
(MemType { is_shared: false, limits: Limits { min, max: None } }) <=> (MemTypeRepr::Unshared(LimitsRepr::Min { min })),
(MemType { is_shared: false, limits: Limits { min, max: Some(max) } }) <=> (MemTypeRepr::Unshared(LimitsRepr::MinMax { min, max })),
(MemType { is_shared: true, limits: Limits { min, max: None } }) <=> (MemTypeRepr::SharedMin { min }),
(MemType { is_shared: true, limits: Limits { min, max: Some(max) } }) <=> (MemTypeRepr::SharedMinMax { min, max }),
});
#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
#[repr(u8)]
pub enum RefType {
Func = 0x70,
#[cfg(feature = "reference-types")]
Extern = 0x6F,
}
#[derive(Wasmbin, WasmbinCountable, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct TableType {
pub elem_type: RefType,
pub limits: Limits,
}
#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct GlobalType {
pub value_type: ValueType,
pub mutable: bool,
}