use crate::component::{MAX_FLAT_PARAMS, MAX_FLAT_RESULTS};
use crate::{EntityType, ModuleInternedTypeIndex, ModuleTypes, PrimaryMap};
use crate::{TypeTrace, prelude::*};
use core::hash::{Hash, Hasher};
use core::ops::Index;
use serde_derive::{Deserialize, Serialize};
use wasmparser::component_types::ComponentAnyTypeId;
use wasmtime_component_util::{DiscriminantSize, FlagsSize};
pub use crate::StaticModuleIndex;
macro_rules! indices {
($(
$(#[$a:meta])*
pub struct $name:ident(u32);
)*) => ($(
$(#[$a])*
#[derive(
Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug,
Serialize, Deserialize,
)]
#[repr(transparent)]
pub struct $name(u32);
cranelift_entity::entity_impl!($name);
)*);
}
indices! {
pub struct ComponentTypeIndex(u32);
pub struct ModuleIndex(u32);
pub struct ComponentIndex(u32);
pub struct ModuleInstanceIndex(u32);
pub struct ComponentInstanceIndex(u32);
pub struct ComponentFuncIndex(u32);
pub struct TypeComponentIndex(u32);
pub struct TypeComponentInstanceIndex(u32);
pub struct TypeModuleIndex(u32);
pub struct TypeFuncIndex(u32);
pub struct TypeRecordIndex(u32);
pub struct TypeVariantIndex(u32);
pub struct TypeTupleIndex(u32);
pub struct TypeFlagsIndex(u32);
pub struct TypeEnumIndex(u32);
pub struct TypeOptionIndex(u32);
pub struct TypeResultIndex(u32);
pub struct TypeListIndex(u32);
pub struct TypeFixedLengthListIndex(u32);
pub struct TypeFutureIndex(u32);
pub struct TypeFutureTableIndex(u32);
pub struct TypeStreamIndex(u32);
pub struct TypeStreamTableIndex(u32);
pub struct TypeComponentLocalErrorContextTableIndex(u32);
pub struct TypeComponentGlobalErrorContextTableIndex(u32);
pub struct TypeResourceTableIndex(u32);
pub struct ResourceIndex(u32);
pub struct DefinedResourceIndex(u32);
pub struct ModuleUpvarIndex(u32);
pub struct ComponentUpvarIndex(u32);
pub struct StaticComponentIndex(u32);
pub struct RuntimeInstanceIndex(u32);
pub struct RuntimeComponentInstanceIndex(u32);
pub struct ImportIndex(u32);
pub struct RuntimeImportIndex(u32);
pub struct LoweredIndex(u32);
pub struct RuntimeMemoryIndex(u32);
pub struct RuntimeReallocIndex(u32);
pub struct RuntimeCallbackIndex(u32);
pub struct RuntimePostReturnIndex(u32);
pub struct RuntimeTableIndex(u32);
pub struct TrampolineIndex(u32);
pub struct ExportIndex(u32);
pub struct OptionsIndex(u32);
pub struct AbstractResourceIndex(u32);
}
pub use crate::{FuncIndex, GlobalIndex, MemoryIndex, TableIndex};
#[derive(Debug, Clone, Copy)]
#[expect(missing_docs, reason = "self-describing variants")]
pub enum ComponentItem {
Func(ComponentFuncIndex),
Module(ModuleIndex),
Component(ComponentIndex),
ComponentInstance(ComponentInstanceIndex),
Type(ComponentAnyTypeId),
}
#[derive(Default, Serialize, Deserialize)]
pub struct ComponentTypes {
pub(super) modules: PrimaryMap<TypeModuleIndex, TypeModule>,
pub(super) components: PrimaryMap<TypeComponentIndex, TypeComponent>,
pub(super) component_instances: PrimaryMap<TypeComponentInstanceIndex, TypeComponentInstance>,
pub(super) functions: PrimaryMap<TypeFuncIndex, TypeFunc>,
pub(super) lists: PrimaryMap<TypeListIndex, TypeList>,
pub(super) records: PrimaryMap<TypeRecordIndex, TypeRecord>,
pub(super) variants: PrimaryMap<TypeVariantIndex, TypeVariant>,
pub(super) tuples: PrimaryMap<TypeTupleIndex, TypeTuple>,
pub(super) enums: PrimaryMap<TypeEnumIndex, TypeEnum>,
pub(super) flags: PrimaryMap<TypeFlagsIndex, TypeFlags>,
pub(super) options: PrimaryMap<TypeOptionIndex, TypeOption>,
pub(super) results: PrimaryMap<TypeResultIndex, TypeResult>,
pub(super) resource_tables: PrimaryMap<TypeResourceTableIndex, TypeResourceTable>,
pub(super) module_types: Option<ModuleTypes>,
pub(super) futures: PrimaryMap<TypeFutureIndex, TypeFuture>,
pub(super) future_tables: PrimaryMap<TypeFutureTableIndex, TypeFutureTable>,
pub(super) streams: PrimaryMap<TypeStreamIndex, TypeStream>,
pub(super) stream_tables: PrimaryMap<TypeStreamTableIndex, TypeStreamTable>,
pub(super) error_context_tables:
PrimaryMap<TypeComponentLocalErrorContextTableIndex, TypeErrorContextTable>,
pub(super) fixed_length_lists: PrimaryMap<TypeFixedLengthListIndex, TypeFixedLengthList>,
}
impl TypeTrace for ComponentTypes {
fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
where
F: FnMut(crate::EngineOrModuleTypeIndex) -> Result<(), E>,
{
for (_, m) in &self.modules {
m.trace(func)?;
}
if let Some(m) = self.module_types.as_ref() {
m.trace(func)?;
}
Ok(())
}
fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
where
F: FnMut(&mut crate::EngineOrModuleTypeIndex) -> Result<(), E>,
{
for (_, m) in &mut self.modules {
m.trace_mut(func)?;
}
if let Some(m) = self.module_types.as_mut() {
m.trace_mut(func)?;
}
Ok(())
}
}
impl ComponentTypes {
pub fn module_types(&self) -> &ModuleTypes {
self.module_types.as_ref().unwrap()
}
pub fn module_types_mut(&mut self) -> &mut ModuleTypes {
self.module_types.as_mut().unwrap()
}
pub fn canonical_abi(&self, ty: &InterfaceType) -> &CanonicalAbiInfo {
match ty {
InterfaceType::U8 | InterfaceType::S8 | InterfaceType::Bool => {
&CanonicalAbiInfo::SCALAR1
}
InterfaceType::U16 | InterfaceType::S16 => &CanonicalAbiInfo::SCALAR2,
InterfaceType::U32
| InterfaceType::S32
| InterfaceType::Float32
| InterfaceType::Char
| InterfaceType::Own(_)
| InterfaceType::Borrow(_)
| InterfaceType::Future(_)
| InterfaceType::Stream(_)
| InterfaceType::ErrorContext(_) => &CanonicalAbiInfo::SCALAR4,
InterfaceType::U64 | InterfaceType::S64 | InterfaceType::Float64 => {
&CanonicalAbiInfo::SCALAR8
}
InterfaceType::String | InterfaceType::List(_) => &CanonicalAbiInfo::POINTER_PAIR,
InterfaceType::Record(i) => &self[*i].abi,
InterfaceType::Variant(i) => &self[*i].abi,
InterfaceType::Tuple(i) => &self[*i].abi,
InterfaceType::Flags(i) => &self[*i].abi,
InterfaceType::Enum(i) => &self[*i].abi,
InterfaceType::Option(i) => &self[*i].abi,
InterfaceType::Result(i) => &self[*i].abi,
InterfaceType::FixedLengthList(i) => &self[*i].abi,
}
}
pub fn push_resource_table(&mut self, table: TypeResourceTable) -> TypeResourceTableIndex {
self.resource_tables.push(table)
}
}
macro_rules! impl_index {
($(impl Index<$ty:ident> for ComponentTypes { $output:ident => $field:ident })*) => ($(
impl core::ops::Index<$ty> for ComponentTypes {
type Output = $output;
#[inline]
fn index(&self, idx: $ty) -> &$output {
&self.$field[idx]
}
}
#[cfg(feature = "compile")]
impl core::ops::Index<$ty> for super::ComponentTypesBuilder {
type Output = $output;
#[inline]
fn index(&self, idx: $ty) -> &$output {
&self.component_types()[idx]
}
}
)*)
}
impl_index! {
impl Index<TypeModuleIndex> for ComponentTypes { TypeModule => modules }
impl Index<TypeComponentIndex> for ComponentTypes { TypeComponent => components }
impl Index<TypeComponentInstanceIndex> for ComponentTypes { TypeComponentInstance => component_instances }
impl Index<TypeFuncIndex> for ComponentTypes { TypeFunc => functions }
impl Index<TypeRecordIndex> for ComponentTypes { TypeRecord => records }
impl Index<TypeVariantIndex> for ComponentTypes { TypeVariant => variants }
impl Index<TypeTupleIndex> for ComponentTypes { TypeTuple => tuples }
impl Index<TypeEnumIndex> for ComponentTypes { TypeEnum => enums }
impl Index<TypeFlagsIndex> for ComponentTypes { TypeFlags => flags }
impl Index<TypeOptionIndex> for ComponentTypes { TypeOption => options }
impl Index<TypeResultIndex> for ComponentTypes { TypeResult => results }
impl Index<TypeListIndex> for ComponentTypes { TypeList => lists }
impl Index<TypeResourceTableIndex> for ComponentTypes { TypeResourceTable => resource_tables }
impl Index<TypeFutureIndex> for ComponentTypes { TypeFuture => futures }
impl Index<TypeStreamIndex> for ComponentTypes { TypeStream => streams }
impl Index<TypeFutureTableIndex> for ComponentTypes { TypeFutureTable => future_tables }
impl Index<TypeStreamTableIndex> for ComponentTypes { TypeStreamTable => stream_tables }
impl Index<TypeComponentLocalErrorContextTableIndex> for ComponentTypes { TypeErrorContextTable => error_context_tables }
impl Index<TypeFixedLengthListIndex> for ComponentTypes { TypeFixedLengthList => fixed_length_lists }
}
impl<T> Index<T> for ComponentTypes
where
ModuleTypes: Index<T>,
{
type Output = <ModuleTypes as Index<T>>::Output;
fn index(&self, idx: T) -> &Self::Output {
self.module_types.as_ref().unwrap().index(idx)
}
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub enum TypeDef {
Component(TypeComponentIndex),
ComponentInstance(TypeComponentInstanceIndex),
ComponentFunc(TypeFuncIndex),
Interface(InterfaceType),
Module(TypeModuleIndex),
CoreFunc(ModuleInternedTypeIndex),
Resource(TypeResourceTableIndex),
}
impl TypeDef {
pub fn desc(&self) -> &str {
match self {
TypeDef::Component(_) => "component",
TypeDef::ComponentInstance(_) => "instance",
TypeDef::ComponentFunc(_) => "function",
TypeDef::Interface(_) => "type",
TypeDef::Module(_) => "core module",
TypeDef::CoreFunc(_) => "core function",
TypeDef::Resource(_) => "resource",
}
}
}
#[derive(Serialize, Deserialize, Default)]
pub struct TypeModule {
pub imports: IndexMap<(String, String), EntityType>,
pub exports: IndexMap<String, EntityType>,
}
impl TypeTrace for TypeModule {
fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
where
F: FnMut(crate::EngineOrModuleTypeIndex) -> Result<(), E>,
{
for ty in self.imports.values() {
ty.trace(func)?;
}
for ty in self.exports.values() {
ty.trace(func)?;
}
Ok(())
}
fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
where
F: FnMut(&mut crate::EngineOrModuleTypeIndex) -> Result<(), E>,
{
for ty in self.imports.values_mut() {
ty.trace_mut(func)?;
}
for ty in self.exports.values_mut() {
ty.trace_mut(func)?;
}
Ok(())
}
}
#[derive(Serialize, Deserialize, Default)]
pub struct TypeComponent {
pub imports: IndexMap<String, TypeDef>,
pub exports: IndexMap<String, TypeDef>,
}
#[derive(Serialize, Deserialize, Default)]
pub struct TypeComponentInstance {
pub exports: IndexMap<String, TypeDef>,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeFunc {
pub async_: bool,
pub param_names: Vec<String>,
pub params: TypeTupleIndex,
pub results: TypeTupleIndex,
}
#[derive(Serialize, Deserialize, Copy, Clone, Hash, Eq, PartialEq, Debug)]
#[expect(missing_docs, reason = "self-describing variants")]
pub enum InterfaceType {
Bool,
S8,
U8,
S16,
U16,
S32,
U32,
S64,
U64,
Float32,
Float64,
Char,
String,
Record(TypeRecordIndex),
Variant(TypeVariantIndex),
List(TypeListIndex),
Tuple(TypeTupleIndex),
Flags(TypeFlagsIndex),
Enum(TypeEnumIndex),
Option(TypeOptionIndex),
Result(TypeResultIndex),
Own(TypeResourceTableIndex),
Borrow(TypeResourceTableIndex),
Future(TypeFutureTableIndex),
Stream(TypeStreamTableIndex),
ErrorContext(TypeComponentLocalErrorContextTableIndex),
FixedLengthList(TypeFixedLengthListIndex),
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct CanonicalAbiInfo {
pub size32: u32,
pub align32: u32,
pub size64: u32,
pub align64: u32,
pub flat_count: Option<u8>,
}
impl Default for CanonicalAbiInfo {
fn default() -> CanonicalAbiInfo {
CanonicalAbiInfo {
size32: 0,
align32: 1,
size64: 0,
align64: 1,
flat_count: Some(0),
}
}
}
const fn align_to(a: u32, b: u32) -> u32 {
assert!(b.is_power_of_two());
(a + (b - 1)) & !(b - 1)
}
const fn max(a: u32, b: u32) -> u32 {
if a > b { a } else { b }
}
impl CanonicalAbiInfo {
pub const ZERO: CanonicalAbiInfo = CanonicalAbiInfo {
size32: 0,
align32: 1,
size64: 0,
align64: 1,
flat_count: Some(0),
};
pub const SCALAR1: CanonicalAbiInfo = CanonicalAbiInfo::scalar(1);
pub const SCALAR2: CanonicalAbiInfo = CanonicalAbiInfo::scalar(2);
pub const SCALAR4: CanonicalAbiInfo = CanonicalAbiInfo::scalar(4);
pub const SCALAR8: CanonicalAbiInfo = CanonicalAbiInfo::scalar(8);
const fn scalar(size: u32) -> CanonicalAbiInfo {
CanonicalAbiInfo {
size32: size,
align32: size,
size64: size,
align64: size,
flat_count: Some(1),
}
}
pub const POINTER_PAIR: CanonicalAbiInfo = CanonicalAbiInfo {
size32: 8,
align32: 4,
size64: 16,
align64: 8,
flat_count: Some(2),
};
pub fn record<'a>(fields: impl Iterator<Item = &'a CanonicalAbiInfo>) -> CanonicalAbiInfo {
let mut ret = CanonicalAbiInfo::default();
for field in fields {
ret.size32 = align_to(ret.size32, field.align32) + field.size32;
ret.align32 = ret.align32.max(field.align32);
ret.size64 = align_to(ret.size64, field.align64) + field.size64;
ret.align64 = ret.align64.max(field.align64);
ret.flat_count = add_flat(ret.flat_count, field.flat_count);
}
ret.size32 = align_to(ret.size32, ret.align32);
ret.size64 = align_to(ret.size64, ret.align64);
return ret;
}
pub const fn record_static(fields: &[CanonicalAbiInfo]) -> CanonicalAbiInfo {
let mut ret = CanonicalAbiInfo::ZERO;
let mut i = 0;
while i < fields.len() {
let field = &fields[i];
ret.size32 = align_to(ret.size32, field.align32) + field.size32;
ret.align32 = max(ret.align32, field.align32);
ret.size64 = align_to(ret.size64, field.align64) + field.size64;
ret.align64 = max(ret.align64, field.align64);
ret.flat_count = add_flat(ret.flat_count, field.flat_count);
i += 1;
}
ret.size32 = align_to(ret.size32, ret.align32);
ret.size64 = align_to(ret.size64, ret.align64);
return ret;
}
pub fn next_field32(&self, offset: &mut u32) -> u32 {
*offset = align_to(*offset, self.align32) + self.size32;
*offset - self.size32
}
pub fn next_field32_size(&self, offset: &mut usize) -> usize {
let cur = u32::try_from(*offset).unwrap();
let cur = align_to(cur, self.align32) + self.size32;
*offset = usize::try_from(cur).unwrap();
usize::try_from(cur - self.size32).unwrap()
}
pub fn next_field64(&self, offset: &mut u32) -> u32 {
*offset = align_to(*offset, self.align64) + self.size64;
*offset - self.size64
}
pub fn next_field64_size(&self, offset: &mut usize) -> usize {
let cur = u32::try_from(*offset).unwrap();
let cur = align_to(cur, self.align64) + self.size64;
*offset = usize::try_from(cur).unwrap();
usize::try_from(cur - self.size64).unwrap()
}
pub const fn flags(count: usize) -> CanonicalAbiInfo {
let (size, align, flat_count) = match FlagsSize::from_count(count) {
FlagsSize::Size0 => (0, 1, 0),
FlagsSize::Size1 => (1, 1, 1),
FlagsSize::Size2 => (2, 2, 1),
FlagsSize::Size4Plus(n) => ((n as u32) * 4, 4, n),
};
CanonicalAbiInfo {
size32: size,
align32: align,
size64: size,
align64: align,
flat_count: Some(flat_count),
}
}
fn variant<'a, I>(cases: I) -> CanonicalAbiInfo
where
I: IntoIterator<Item = Option<&'a CanonicalAbiInfo>>,
I::IntoIter: ExactSizeIterator,
{
let cases = cases.into_iter();
let discrim_size = u32::from(DiscriminantSize::from_count(cases.len()).unwrap());
let mut max_size32 = 0;
let mut max_align32 = discrim_size;
let mut max_size64 = 0;
let mut max_align64 = discrim_size;
let mut max_case_count = Some(0);
for case in cases {
if let Some(case) = case {
max_size32 = max_size32.max(case.size32);
max_align32 = max_align32.max(case.align32);
max_size64 = max_size64.max(case.size64);
max_align64 = max_align64.max(case.align64);
max_case_count = max_flat(max_case_count, case.flat_count);
}
}
CanonicalAbiInfo {
size32: align_to(
align_to(discrim_size, max_align32) + max_size32,
max_align32,
),
align32: max_align32,
size64: align_to(
align_to(discrim_size, max_align64) + max_size64,
max_align64,
),
align64: max_align64,
flat_count: add_flat(max_case_count, Some(1)),
}
}
pub const fn variant_static(cases: &[Option<CanonicalAbiInfo>]) -> CanonicalAbiInfo {
let discrim_size = match DiscriminantSize::from_count(cases.len()) {
Some(size) => size.byte_size(),
None => unreachable!(),
};
let mut max_size32 = 0;
let mut max_align32 = discrim_size;
let mut max_size64 = 0;
let mut max_align64 = discrim_size;
let mut max_case_count = Some(0);
let mut i = 0;
while i < cases.len() {
let case = &cases[i];
if let Some(case) = case {
max_size32 = max(max_size32, case.size32);
max_align32 = max(max_align32, case.align32);
max_size64 = max(max_size64, case.size64);
max_align64 = max(max_align64, case.align64);
max_case_count = max_flat(max_case_count, case.flat_count);
}
i += 1;
}
CanonicalAbiInfo {
size32: align_to(
align_to(discrim_size, max_align32) + max_size32,
max_align32,
),
align32: max_align32,
size64: align_to(
align_to(discrim_size, max_align64) + max_size64,
max_align64,
),
align64: max_align64,
flat_count: add_flat(max_case_count, Some(1)),
}
}
pub const fn enum_(cases: usize) -> CanonicalAbiInfo {
let discrim_size = match DiscriminantSize::from_count(cases) {
Some(size) => size.byte_size(),
None => unreachable!(),
};
CanonicalAbiInfo {
size32: discrim_size,
align32: discrim_size,
size64: discrim_size,
align64: discrim_size,
flat_count: Some(1),
}
}
pub fn flat_count(&self, max: usize) -> Option<usize> {
let flat = usize::from(self.flat_count?);
if flat > max { None } else { Some(flat) }
}
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct VariantInfo {
#[serde(with = "serde_discrim_size")]
pub size: DiscriminantSize,
pub payload_offset32: u32,
pub payload_offset64: u32,
}
impl VariantInfo {
pub fn new<'a, I>(cases: I) -> (VariantInfo, CanonicalAbiInfo)
where
I: IntoIterator<Item = Option<&'a CanonicalAbiInfo>>,
I::IntoIter: ExactSizeIterator,
{
let cases = cases.into_iter();
let size = DiscriminantSize::from_count(cases.len()).unwrap();
let abi = CanonicalAbiInfo::variant(cases);
(
VariantInfo {
size,
payload_offset32: align_to(u32::from(size), abi.align32),
payload_offset64: align_to(u32::from(size), abi.align64),
},
abi,
)
}
pub const fn new_static(cases: &[Option<CanonicalAbiInfo>]) -> VariantInfo {
let size = match DiscriminantSize::from_count(cases.len()) {
Some(size) => size,
None => unreachable!(),
};
let abi = CanonicalAbiInfo::variant_static(cases);
VariantInfo {
size,
payload_offset32: align_to(size.byte_size(), abi.align32),
payload_offset64: align_to(size.byte_size(), abi.align64),
}
}
}
mod serde_discrim_size {
use super::DiscriminantSize;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
pub fn serialize<S>(disc: &DiscriminantSize, ser: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
u32::from(*disc).serialize(ser)
}
pub fn deserialize<'de, D>(deser: D) -> Result<DiscriminantSize, D::Error>
where
D: Deserializer<'de>,
{
match u32::deserialize(deser)? {
1 => Ok(DiscriminantSize::Size1),
2 => Ok(DiscriminantSize::Size2),
4 => Ok(DiscriminantSize::Size4),
_ => Err(D::Error::custom("invalid discriminant size")),
}
}
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeRecord {
pub fields: Box<[RecordField]>,
pub abi: CanonicalAbiInfo,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct RecordField {
pub name: String,
pub ty: InterfaceType,
}
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug)]
pub struct TypeVariant {
pub cases: IndexMap<String, Option<InterfaceType>>,
pub abi: CanonicalAbiInfo,
pub info: VariantInfo,
}
impl Hash for TypeVariant {
fn hash<H: Hasher>(&self, h: &mut H) {
let TypeVariant { cases, abi, info } = self;
cases.len().hash(h);
for pair in cases {
pair.hash(h);
}
abi.hash(h);
info.hash(h);
}
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeTuple {
pub types: Box<[InterfaceType]>,
pub abi: CanonicalAbiInfo,
}
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug)]
pub struct TypeFlags {
pub names: IndexSet<String>,
pub abi: CanonicalAbiInfo,
}
impl Hash for TypeFlags {
fn hash<H: Hasher>(&self, h: &mut H) {
let TypeFlags { names, abi } = self;
names.len().hash(h);
for name in names {
name.hash(h);
}
abi.hash(h);
}
}
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug)]
pub struct TypeEnum {
pub names: IndexSet<String>,
pub abi: CanonicalAbiInfo,
pub info: VariantInfo,
}
impl Hash for TypeEnum {
fn hash<H: Hasher>(&self, h: &mut H) {
let TypeEnum { names, abi, info } = self;
names.len().hash(h);
for name in names {
name.hash(h);
}
abi.hash(h);
info.hash(h);
}
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeOption {
pub ty: InterfaceType,
pub abi: CanonicalAbiInfo,
pub info: VariantInfo,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeResult {
pub ok: Option<InterfaceType>,
pub err: Option<InterfaceType>,
pub abi: CanonicalAbiInfo,
pub info: VariantInfo,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeFuture {
pub payload: Option<InterfaceType>,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeFutureTable {
pub ty: TypeFutureIndex,
pub instance: RuntimeComponentInstanceIndex,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeStream {
pub payload: Option<InterfaceType>,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeStreamTable {
pub ty: TypeStreamIndex,
pub instance: RuntimeComponentInstanceIndex,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeErrorContextTable {
pub instance: RuntimeComponentInstanceIndex,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub enum TypeResourceTable {
Concrete {
ty: ResourceIndex,
instance: RuntimeComponentInstanceIndex,
},
Abstract(AbstractResourceIndex),
}
impl TypeResourceTable {
pub fn unwrap_concrete_ty(&self) -> ResourceIndex {
match self {
TypeResourceTable::Concrete { ty, .. } => *ty,
TypeResourceTable::Abstract(_) => panic!("not a concrete resource table"),
}
}
pub fn unwrap_concrete_instance(&self) -> RuntimeComponentInstanceIndex {
match self {
TypeResourceTable::Concrete { instance, .. } => *instance,
TypeResourceTable::Abstract(_) => panic!("not a concrete resource table"),
}
}
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeList {
pub element: InterfaceType,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeFixedLengthList {
pub element: InterfaceType,
pub size: u32,
pub abi: CanonicalAbiInfo,
}
pub const MAX_FLAT_TYPES: usize = if MAX_FLAT_PARAMS > MAX_FLAT_RESULTS {
MAX_FLAT_PARAMS
} else {
MAX_FLAT_RESULTS
};
const fn add_flat(a: Option<u8>, b: Option<u8>) -> Option<u8> {
const MAX: u8 = MAX_FLAT_TYPES as u8;
let sum = match (a, b) {
(Some(a), Some(b)) => match a.checked_add(b) {
Some(c) => c,
None => return None,
},
_ => return None,
};
if sum > MAX { None } else { Some(sum) }
}
const fn max_flat(a: Option<u8>, b: Option<u8>) -> Option<u8> {
match (a, b) {
(Some(a), Some(b)) => {
if a > b {
Some(a)
} else {
Some(b)
}
}
_ => None,
}
}
pub struct FlatTypes<'a> {
pub memory32: &'a [FlatType],
pub memory64: &'a [FlatType],
}
impl FlatTypes<'_> {
pub fn len(&self) -> usize {
assert_eq!(self.memory32.len(), self.memory64.len());
self.memory32.len()
}
}
#[derive(Serialize, Deserialize, Hash, Debug, PartialEq, Eq, Copy, Clone)]
#[expect(missing_docs, reason = "self-describing variants")]
pub enum FlatType {
I32,
I64,
F32,
F64,
}