use crate::limits::*;
use crate::prelude::*;
use crate::RecGroup;
use crate::{
BinaryReader, ComponentAlias, ComponentExportName, ComponentImport, ComponentTypeRef,
FromReader, Import, Result, SectionLimited, TypeRef, ValType,
};
use core::fmt;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum OuterAliasKind {
Type,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum CoreType<'a> {
Rec(RecGroup),
Module(Box<[ModuleTypeDeclaration<'a>]>),
}
impl<'a> FromReader<'a> for CoreType<'a> {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
Ok(match reader.peek()? {
0x00 => {
reader.read_u8()?;
let x = reader.peek()?;
if x != 0x50 {
return reader.invalid_leading_byte(x, "non-final sub type");
}
CoreType::Rec(reader.read()?)
}
0x50 => {
reader.read_u8()?;
CoreType::Module(
reader
.read_iter(MAX_WASM_MODULE_TYPE_DECLS, "module type declaration")?
.collect::<Result<_>>()?,
)
}
_ => CoreType::Rec(reader.read()?),
})
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ModuleTypeDeclaration<'a> {
Type(RecGroup),
Export {
name: &'a str,
ty: TypeRef,
},
OuterAlias {
kind: OuterAliasKind,
count: u32,
index: u32,
},
Import(Import<'a>),
}
impl<'a> FromReader<'a> for ModuleTypeDeclaration<'a> {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
Ok(match reader.read_u8()? {
0x00 => ModuleTypeDeclaration::Import(reader.read()?),
0x01 => ModuleTypeDeclaration::Type(reader.read()?),
0x02 => {
let kind = match reader.read_u8()? {
0x10 => OuterAliasKind::Type,
x => {
return reader.invalid_leading_byte(x, "outer alias kind");
}
};
match reader.read_u8()? {
0x01 => ModuleTypeDeclaration::OuterAlias {
kind,
count: reader.read()?,
index: reader.read()?,
},
x => {
return reader.invalid_leading_byte(x, "outer alias target");
}
}
}
0x03 => ModuleTypeDeclaration::Export {
name: reader.read()?,
ty: reader.read()?,
},
x => return reader.invalid_leading_byte(x, "type definition"),
})
}
}
pub type CoreTypeSectionReader<'a> = SectionLimited<'a, CoreType<'a>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ComponentValType {
Primitive(PrimitiveValType),
Type(u32),
}
impl<'a> FromReader<'a> for ComponentValType {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
if let Some(ty) = PrimitiveValType::from_byte(reader.peek()?) {
reader.read_u8()?;
return Ok(ComponentValType::Primitive(ty));
}
Ok(ComponentValType::Type(reader.read_var_s33()? as u32))
}
}
impl<'a> FromReader<'a> for Option<ComponentValType> {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
match reader.read_u8()? {
0x0 => Ok(None),
0x1 => Ok(Some(reader.read()?)),
x => reader.invalid_leading_byte(x, "optional component value type"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PrimitiveValType {
Bool,
S8,
U8,
S16,
U16,
S32,
U32,
S64,
U64,
F32,
F64,
Char,
String,
}
impl PrimitiveValType {
fn from_byte(byte: u8) -> Option<PrimitiveValType> {
Some(match byte {
0x7f => PrimitiveValType::Bool,
0x7e => PrimitiveValType::S8,
0x7d => PrimitiveValType::U8,
0x7c => PrimitiveValType::S16,
0x7b => PrimitiveValType::U16,
0x7a => PrimitiveValType::S32,
0x79 => PrimitiveValType::U32,
0x78 => PrimitiveValType::S64,
0x77 => PrimitiveValType::U64,
0x76 => PrimitiveValType::F32,
0x75 => PrimitiveValType::F64,
0x74 => PrimitiveValType::Char,
0x73 => PrimitiveValType::String,
_ => return None,
})
}
#[cfg(feature = "validate")]
pub(crate) fn contains_ptr(&self) -> bool {
matches!(self, Self::String)
}
pub fn is_subtype_of(a: Self, b: Self) -> bool {
a == b
}
}
impl fmt::Display for PrimitiveValType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use PrimitiveValType::*;
let s = match self {
Bool => "bool",
S8 => "s8",
U8 => "u8",
S16 => "s16",
U16 => "u16",
S32 => "s32",
U32 => "u32",
S64 => "s64",
U64 => "u64",
F32 => "f32",
F64 => "f64",
Char => "char",
String => "string",
};
s.fmt(f)
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ComponentType<'a> {
Defined(ComponentDefinedType<'a>),
Func(ComponentFuncType<'a>),
Component(Box<[ComponentTypeDeclaration<'a>]>),
Instance(Box<[InstanceTypeDeclaration<'a>]>),
Resource {
rep: ValType,
dtor: Option<u32>,
},
}
impl<'a> FromReader<'a> for ComponentType<'a> {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
Ok(match reader.read_u8()? {
0x3f => ComponentType::Resource {
rep: reader.read()?,
dtor: match reader.read_u8()? {
0x00 => None,
0x01 => Some(reader.read()?),
b => return reader.invalid_leading_byte(b, "resource destructor"),
},
},
0x40 => {
let params = reader
.read_iter(MAX_WASM_FUNCTION_PARAMS, "component function parameters")?
.collect::<Result<_>>()?;
let results = reader.read()?;
ComponentType::Func(ComponentFuncType { params, results })
}
0x41 => ComponentType::Component(
reader
.read_iter(MAX_WASM_COMPONENT_TYPE_DECLS, "component type declaration")?
.collect::<Result<_>>()?,
),
0x42 => ComponentType::Instance(
reader
.read_iter(MAX_WASM_INSTANCE_TYPE_DECLS, "instance type declaration")?
.collect::<Result<_>>()?,
),
x => {
if let Some(ty) = PrimitiveValType::from_byte(x) {
ComponentType::Defined(ComponentDefinedType::Primitive(ty))
} else {
ComponentType::Defined(ComponentDefinedType::read(reader, x)?)
}
}
})
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ComponentTypeDeclaration<'a> {
CoreType(CoreType<'a>),
Type(ComponentType<'a>),
Alias(ComponentAlias<'a>),
Export {
name: ComponentExportName<'a>,
ty: ComponentTypeRef,
},
Import(ComponentImport<'a>),
}
impl<'a> FromReader<'a> for ComponentTypeDeclaration<'a> {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
if reader.peek()? == 0x03 {
reader.read_u8()?;
return Ok(ComponentTypeDeclaration::Import(reader.read()?));
}
Ok(match reader.read()? {
InstanceTypeDeclaration::CoreType(t) => ComponentTypeDeclaration::CoreType(t),
InstanceTypeDeclaration::Type(t) => ComponentTypeDeclaration::Type(t),
InstanceTypeDeclaration::Alias(a) => ComponentTypeDeclaration::Alias(a),
InstanceTypeDeclaration::Export { name, ty } => {
ComponentTypeDeclaration::Export { name, ty }
}
})
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum InstanceTypeDeclaration<'a> {
CoreType(CoreType<'a>),
Type(ComponentType<'a>),
Alias(ComponentAlias<'a>),
Export {
name: ComponentExportName<'a>,
ty: ComponentTypeRef,
},
}
impl<'a> FromReader<'a> for InstanceTypeDeclaration<'a> {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
Ok(match reader.read_u8()? {
0x00 => InstanceTypeDeclaration::CoreType(reader.read()?),
0x01 => InstanceTypeDeclaration::Type(reader.read()?),
0x02 => InstanceTypeDeclaration::Alias(reader.read()?),
0x04 => InstanceTypeDeclaration::Export {
name: reader.read()?,
ty: reader.read()?,
},
x => return reader.invalid_leading_byte(x, "component or instance type declaration"),
})
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ComponentFuncResult<'a> {
Unnamed(ComponentValType),
Named(Box<[(&'a str, ComponentValType)]>),
}
impl<'a> FromReader<'a> for ComponentFuncResult<'a> {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
Ok(match reader.read_u8()? {
0x00 => ComponentFuncResult::Unnamed(reader.read()?),
0x01 => ComponentFuncResult::Named(
reader
.read_iter(MAX_WASM_FUNCTION_RETURNS, "component function results")?
.collect::<Result<_>>()?,
),
x => return reader.invalid_leading_byte(x, "component function results"),
})
}
}
impl ComponentFuncResult<'_> {
pub fn type_count(&self) -> usize {
match self {
Self::Unnamed(_) => 1,
Self::Named(vec) => vec.len(),
}
}
pub fn iter(&self) -> impl Iterator<Item = (Option<&str>, &ComponentValType)> {
enum Either<L, R> {
Left(L),
Right(R),
}
impl<L, R> Iterator for Either<L, R>
where
L: Iterator,
R: Iterator<Item = L::Item>,
{
type Item = L::Item;
fn next(&mut self) -> Option<Self::Item> {
match self {
Either::Left(l) => l.next(),
Either::Right(r) => r.next(),
}
}
}
match self {
Self::Unnamed(ty) => Either::Left(core::iter::once(ty).map(|ty| (None, ty))),
Self::Named(vec) => Either::Right(vec.iter().map(|(n, ty)| (Some(*n), ty))),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ComponentFuncType<'a> {
pub params: Box<[(&'a str, ComponentValType)]>,
pub results: ComponentFuncResult<'a>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VariantCase<'a> {
pub name: &'a str,
pub ty: Option<ComponentValType>,
pub refines: Option<u32>,
}
impl<'a> FromReader<'a> for VariantCase<'a> {
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
Ok(VariantCase {
name: reader.read()?,
ty: reader.read()?,
refines: match reader.read_u8()? {
0x0 => None,
0x1 => Some(reader.read_var_u32()?),
x => return reader.invalid_leading_byte(x, "variant case refines"),
},
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ComponentDefinedType<'a> {
Primitive(PrimitiveValType),
Record(Box<[(&'a str, ComponentValType)]>),
Variant(Box<[VariantCase<'a>]>),
List(ComponentValType),
Tuple(Box<[ComponentValType]>),
Flags(Box<[&'a str]>),
Enum(Box<[&'a str]>),
Option(ComponentValType),
Result {
ok: Option<ComponentValType>,
err: Option<ComponentValType>,
},
Own(u32),
Borrow(u32),
}
impl<'a> ComponentDefinedType<'a> {
fn read(reader: &mut BinaryReader<'a>, byte: u8) -> Result<ComponentDefinedType<'a>> {
Ok(match byte {
0x72 => ComponentDefinedType::Record(
reader
.read_iter(MAX_WASM_RECORD_FIELDS, "record field")?
.collect::<Result<_>>()?,
),
0x71 => ComponentDefinedType::Variant(
reader
.read_iter(MAX_WASM_VARIANT_CASES, "variant cases")?
.collect::<Result<_>>()?,
),
0x70 => ComponentDefinedType::List(reader.read()?),
0x6f => ComponentDefinedType::Tuple(
reader
.read_iter(MAX_WASM_TUPLE_TYPES, "tuple types")?
.collect::<Result<_>>()?,
),
0x6e => ComponentDefinedType::Flags(
reader
.read_iter(MAX_WASM_FLAG_NAMES, "flag names")?
.collect::<Result<_>>()?,
),
0x6d => ComponentDefinedType::Enum(
reader
.read_iter(MAX_WASM_ENUM_CASES, "enum cases")?
.collect::<Result<_>>()?,
),
0x6b => ComponentDefinedType::Option(reader.read()?),
0x6a => ComponentDefinedType::Result {
ok: reader.read()?,
err: reader.read()?,
},
0x69 => ComponentDefinedType::Own(reader.read()?),
0x68 => ComponentDefinedType::Borrow(reader.read()?),
x => return reader.invalid_leading_byte(x, "component defined type"),
})
}
}
pub type ComponentTypeSectionReader<'a> = SectionLimited<'a, ComponentType<'a>>;