Skip to main content

wasmtime_environ/component/
types.rs

1use crate::component::{MAX_FLAT_PARAMS, MAX_FLAT_RESULTS};
2use crate::{EntityType, ModuleInternedTypeIndex, ModuleTypes, PrimaryMap};
3use crate::{TypeTrace, prelude::*};
4use core::hash::{Hash, Hasher};
5use core::ops::Index;
6use serde_derive::{Deserialize, Serialize};
7use wasmparser::component_types::ComponentAnyTypeId;
8use wasmtime_component_util::{DiscriminantSize, FlagsSize};
9
10pub use crate::StaticModuleIndex;
11
12macro_rules! indices {
13    ($(
14        $(#[$a:meta])*
15        pub struct $name:ident(u32);
16    )*) => ($(
17        $(#[$a])*
18        #[derive(
19            Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug,
20            Serialize, Deserialize,
21        )]
22        #[repr(transparent)]
23        pub struct $name(u32);
24        cranelift_entity::entity_impl!($name);
25        impl TryClone for $name {
26            #[inline]
27            fn try_clone(&self) -> Result<Self, OutOfMemory> {
28                Ok(*self)
29            }
30        }
31    )*);
32}
33
34indices! {
35    // ========================================================================
36    // These indices are used during compile time only when we're translating a
37    // component at this time. The actual indices are not persisted beyond the
38    // compile phase to when we're actually working with the component at
39    // runtime.
40
41    /// Index within a component's component type index space.
42    pub struct ComponentTypeIndex(u32);
43
44    /// Index within a component's module index space.
45    pub struct ModuleIndex(u32);
46
47    /// Index within a component's component index space.
48    pub struct ComponentIndex(u32);
49
50    /// Index within a component's module instance index space.
51    pub struct ModuleInstanceIndex(u32);
52
53    /// Index within a component's component instance index space.
54    pub struct ComponentInstanceIndex(u32);
55
56    /// Index within a component's component function index space.
57    pub struct ComponentFuncIndex(u32);
58
59    // ========================================================================
60    // These indices are used to lookup type information within a `TypeTables`
61    // structure. These represent generally deduplicated type information across
62    // an entire component and are a form of RTTI in a sense.
63
64    /// Index pointing to a component's type (exports/imports with
65    /// component-model types)
66    pub struct TypeComponentIndex(u32);
67
68    /// Index pointing to a component instance's type (exports with
69    /// component-model types, no imports)
70    pub struct TypeComponentInstanceIndex(u32);
71
72    /// Index pointing to a core wasm module's type (exports/imports with
73    /// core wasm types)
74    pub struct TypeModuleIndex(u32);
75
76    /// Index pointing to a component model function type with arguments/result
77    /// as interface types.
78    pub struct TypeFuncIndex(u32);
79
80    /// Index pointing to a record type in the component model (aka a struct).
81    pub struct TypeRecordIndex(u32);
82    /// Index pointing to a variant type in the component model (aka an enum).
83    pub struct TypeVariantIndex(u32);
84    /// Index pointing to a tuple type in the component model.
85    pub struct TypeTupleIndex(u32);
86    /// Index pointing to a flags type in the component model.
87    pub struct TypeFlagsIndex(u32);
88    /// Index pointing to an enum type in the component model.
89    pub struct TypeEnumIndex(u32);
90    /// Index pointing to an option type in the component model (aka a
91    /// `Option<T, E>`)
92    pub struct TypeOptionIndex(u32);
93    /// Index pointing to an result type in the component model (aka a
94    /// `Result<T, E>`)
95    pub struct TypeResultIndex(u32);
96    /// Index pointing to a list type in the component model.
97    pub struct TypeListIndex(u32);
98    /// Index pointing to a map type in the component model.
99    pub struct TypeMapIndex(u32);
100    /// Index pointing to a fixed size list type in the component model.
101    pub struct TypeFixedLengthListIndex(u32);
102    /// Index pointing to a future type in the component model.
103    pub struct TypeFutureIndex(u32);
104
105    /// Index pointing to a future table within a component.
106    ///
107    /// This is analogous to `TypeResourceTableIndex` in that it tracks
108    /// ownership of futures within each (sub)component instance.
109    pub struct TypeFutureTableIndex(u32);
110
111    /// Index pointing to a stream type in the component model.
112    pub struct TypeStreamIndex(u32);
113
114    /// Index pointing to a stream table within a component.
115    ///
116    /// This is analogous to `TypeResourceTableIndex` in that it tracks
117    /// ownership of stream within each (sub)component instance.
118    pub struct TypeStreamTableIndex(u32);
119
120    /// Index pointing to a error context table within a component.
121    ///
122    /// This is analogous to `TypeResourceTableIndex` in that it tracks
123    /// ownership of error contexts within each (sub)component instance.
124    pub struct TypeComponentLocalErrorContextTableIndex(u32);
125
126    /// Index pointing to a (component) globally tracked error context table entry
127    ///
128    /// Unlike [`TypeComponentLocalErrorContextTableIndex`], this index refers to
129    /// the global state table for error contexts at the level of the entire component,
130    /// not just a subcomponent.
131    pub struct TypeComponentGlobalErrorContextTableIndex(u32);
132
133    /// Index pointing to a resource table within a component.
134    ///
135    /// This is a Wasmtime-specific type index which isn't part of the component
136    /// model per-se (or at least not the binary format). This index represents
137    /// a pointer to a table of runtime information tracking state for resources
138    /// within a component. Tables are generated per-resource-per-component
139    /// meaning that if the exact same resource is imported into 4 subcomponents
140    /// then that's 5 tables: one for the defining component and one for each
141    /// subcomponent.
142    ///
143    /// All resource-related intrinsics operate on table-local indices which
144    /// indicate which table the intrinsic is modifying. Each resource table has
145    /// an origin resource type (defined by `ResourceIndex`) along with a
146    /// component instance that it's recorded for.
147    pub struct TypeResourceTableIndex(u32);
148
149    /// Index pointing to a resource within a component.
150    ///
151    /// This index space covers all unique resource type definitions. For
152    /// example all unique imports come first and then all locally-defined
153    /// resources come next. Note that this does not count the number of runtime
154    /// tables required to track resources (that's `TypeResourceTableIndex`
155    /// instead). Instead this is a count of the number of unique
156    /// `(type (resource (rep ..)))` declarations within a component, plus
157    /// imports.
158    ///
159    /// This is then used for correlating various information such as
160    /// destructors, origin information, etc.
161    pub struct ResourceIndex(u32);
162
163    /// Index pointing to a local resource defined within a component.
164    ///
165    /// This is similar to `FooIndex` and `DefinedFooIndex` for core wasm and
166    /// the idea here is that this is guaranteed to be a wasm-defined resource
167    /// which is connected to a component instance for example.
168    pub struct DefinedResourceIndex(u32);
169
170    // ========================================================================
171    // Index types used to identify modules and components during compilation.
172
173    /// Index into a "closed over variables" list for components used to
174    /// implement outer aliases. For more information on this see the
175    /// documentation for the `LexicalScope` structure.
176    pub struct ModuleUpvarIndex(u32);
177
178    /// Same as `ModuleUpvarIndex` but for components.
179    pub struct ComponentUpvarIndex(u32);
180
181    /// Same as `StaticModuleIndex` but for components.
182    pub struct StaticComponentIndex(u32);
183
184    // ========================================================================
185    // These indices are actually used at runtime when managing a component at
186    // this time.
187
188    /// Index that represents a core wasm instance created at runtime.
189    ///
190    /// This is used to keep track of when instances are created and is able to
191    /// refer back to previously created instances for exports and such.
192    pub struct RuntimeInstanceIndex(u32);
193
194    /// Same as `RuntimeInstanceIndex` but tracks component instances instead.
195    pub struct RuntimeComponentInstanceIndex(u32);
196
197    /// Used to index imports into a `Component`
198    ///
199    /// This does not correspond to anything in the binary format for the
200    /// component model.
201    pub struct ImportIndex(u32);
202
203    /// Index that represents a leaf item imported into a component where a
204    /// "leaf" means "not an instance".
205    ///
206    /// This does not correspond to anything in the binary format for the
207    /// component model.
208    pub struct RuntimeImportIndex(u32);
209
210    /// Index that represents a lowered host function and is used to represent
211    /// host function lowerings with options and such.
212    ///
213    /// This does not correspond to anything in the binary format for the
214    /// component model.
215    pub struct LoweredIndex(u32);
216
217    /// Index representing a linear memory extracted from a wasm instance
218    /// which is stored in a `VMComponentContext`. This is used to deduplicate
219    /// references to the same linear memory where it's only stored once in a
220    /// `VMComponentContext`.
221    ///
222    /// This does not correspond to anything in the binary format for the
223    /// component model.
224    pub struct RuntimeMemoryIndex(u32);
225
226    /// Same as `RuntimeMemoryIndex` except for the `realloc` function.
227    pub struct RuntimeReallocIndex(u32);
228
229    /// Same as `RuntimeMemoryIndex` except for the `callback` function.
230    pub struct RuntimeCallbackIndex(u32);
231
232    /// Same as `RuntimeMemoryIndex` except for the `post-return` function.
233    pub struct RuntimePostReturnIndex(u32);
234
235    /// Index representing a table extracted from a wasm instance which is
236    /// stored in a `VMComponentContext`. This is used to deduplicate references
237    /// to the same table when it's only stored once in a `VMComponentContext`.
238    ///
239    /// This does not correspond to anything in the binary format for the
240    /// component model.
241    pub struct RuntimeTableIndex(u32);
242
243    /// Index for all trampolines that are compiled in Cranelift for a
244    /// component.
245    ///
246    /// This is used to point to various bits of metadata within a compiled
247    /// component and is stored in the final compilation artifact. This does not
248    /// have a direct correspondence to any wasm definition.
249    pub struct TrampolineIndex(u32);
250
251    /// An index into `Component::export_items` at the end of compilation.
252    pub struct ExportIndex(u32);
253
254    /// An index into `Component::options` at the end of compilation.
255    pub struct OptionsIndex(u32);
256
257    /// An index that doesn't actually index into a list but instead represents
258    /// a unique counter.
259    ///
260    /// This is used for "abstract" resources which aren't actually instantiated
261    /// in the component model. For example this represents a resource in a
262    /// component or instance type, but not an actual concrete instance.
263    pub struct AbstractResourceIndex(u32);
264}
265
266// Reexport for convenience some core-wasm indices which are also used in the
267// component model, typically for when aliasing exports of core wasm modules.
268pub use crate::{FuncIndex, GlobalIndex, MemoryIndex, TableIndex};
269
270/// Equivalent of `EntityIndex` but for the component model instead of core
271/// wasm.
272#[derive(Debug, Clone, Copy)]
273#[expect(missing_docs, reason = "self-describing variants")]
274pub enum ComponentItem {
275    Func(ComponentFuncIndex),
276    Module(ModuleIndex),
277    Component(ComponentIndex),
278    ComponentInstance(ComponentInstanceIndex),
279    Type(ComponentAnyTypeId),
280}
281
282/// Runtime information about the type information contained within a component.
283///
284/// One of these is created per top-level component which describes all of the
285/// types contained within the top-level component itself. Each sub-component
286/// will have a pointer to this value as well.
287#[derive(Default, Serialize, Deserialize)]
288pub struct ComponentTypes {
289    pub(super) modules: PrimaryMap<TypeModuleIndex, TypeModule>,
290    pub(super) components: PrimaryMap<TypeComponentIndex, TypeComponent>,
291    pub(super) component_instances: PrimaryMap<TypeComponentInstanceIndex, TypeComponentInstance>,
292    pub(super) functions: PrimaryMap<TypeFuncIndex, TypeFunc>,
293    pub(super) lists: PrimaryMap<TypeListIndex, TypeList>,
294    pub(super) maps: PrimaryMap<TypeMapIndex, TypeMap>,
295    pub(super) records: PrimaryMap<TypeRecordIndex, TypeRecord>,
296    pub(super) variants: PrimaryMap<TypeVariantIndex, TypeVariant>,
297    pub(super) tuples: PrimaryMap<TypeTupleIndex, TypeTuple>,
298    pub(super) enums: PrimaryMap<TypeEnumIndex, TypeEnum>,
299    pub(super) flags: PrimaryMap<TypeFlagsIndex, TypeFlags>,
300    pub(super) options: PrimaryMap<TypeOptionIndex, TypeOption>,
301    pub(super) results: PrimaryMap<TypeResultIndex, TypeResult>,
302    pub(super) resource_tables: PrimaryMap<TypeResourceTableIndex, TypeResourceTable>,
303    pub(super) module_types: Option<ModuleTypes>,
304    pub(super) futures: PrimaryMap<TypeFutureIndex, TypeFuture>,
305    pub(super) future_tables: PrimaryMap<TypeFutureTableIndex, TypeFutureTable>,
306    pub(super) streams: PrimaryMap<TypeStreamIndex, TypeStream>,
307    pub(super) stream_tables: PrimaryMap<TypeStreamTableIndex, TypeStreamTable>,
308    pub(super) error_context_tables:
309        PrimaryMap<TypeComponentLocalErrorContextTableIndex, TypeErrorContextTable>,
310    pub(super) fixed_length_lists: PrimaryMap<TypeFixedLengthListIndex, TypeFixedLengthList>,
311}
312
313impl TypeTrace for ComponentTypes {
314    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
315    where
316        F: FnMut(crate::EngineOrModuleTypeIndex) -> Result<(), E>,
317    {
318        for (_, m) in &self.modules {
319            m.trace(func)?;
320        }
321        if let Some(m) = self.module_types.as_ref() {
322            m.trace(func)?;
323        }
324        Ok(())
325    }
326
327    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
328    where
329        F: FnMut(&mut crate::EngineOrModuleTypeIndex) -> Result<(), E>,
330    {
331        for (_, m) in &mut self.modules {
332            m.trace_mut(func)?;
333        }
334        if let Some(m) = self.module_types.as_mut() {
335            m.trace_mut(func)?;
336        }
337        Ok(())
338    }
339}
340
341impl ComponentTypes {
342    /// Returns the core wasm module types known within this component.
343    pub fn module_types(&self) -> &ModuleTypes {
344        self.module_types.as_ref().unwrap()
345    }
346
347    /// Returns the core wasm module types known within this component.
348    pub fn module_types_mut(&mut self) -> &mut ModuleTypes {
349        self.module_types.as_mut().unwrap()
350    }
351
352    /// Returns the canonical ABI information about the specified type.
353    pub fn canonical_abi(&self, ty: &InterfaceType) -> &CanonicalAbiInfo {
354        match ty {
355            InterfaceType::U8 | InterfaceType::S8 | InterfaceType::Bool => {
356                &CanonicalAbiInfo::SCALAR1
357            }
358
359            InterfaceType::U16 | InterfaceType::S16 => &CanonicalAbiInfo::SCALAR2,
360
361            InterfaceType::U32
362            | InterfaceType::S32
363            | InterfaceType::Float32
364            | InterfaceType::Char
365            | InterfaceType::Own(_)
366            | InterfaceType::Borrow(_)
367            | InterfaceType::Future(_)
368            | InterfaceType::Stream(_)
369            | InterfaceType::ErrorContext(_) => &CanonicalAbiInfo::SCALAR4,
370
371            InterfaceType::U64 | InterfaceType::S64 | InterfaceType::Float64 => {
372                &CanonicalAbiInfo::SCALAR8
373            }
374
375            InterfaceType::String | InterfaceType::List(_) | InterfaceType::Map(_) => {
376                &CanonicalAbiInfo::POINTER_PAIR
377            }
378
379            InterfaceType::Record(i) => &self[*i].abi,
380            InterfaceType::Variant(i) => &self[*i].abi,
381            InterfaceType::Tuple(i) => &self[*i].abi,
382            InterfaceType::Flags(i) => &self[*i].abi,
383            InterfaceType::Enum(i) => &self[*i].abi,
384            InterfaceType::Option(i) => &self[*i].abi,
385            InterfaceType::Result(i) => &self[*i].abi,
386            InterfaceType::FixedLengthList(i) => &self[*i].abi,
387        }
388    }
389
390    /// Adds a new `table` to the list of resource tables for this component.
391    pub fn push_resource_table(&mut self, table: TypeResourceTable) -> TypeResourceTableIndex {
392        self.resource_tables.push(table)
393    }
394}
395
396macro_rules! impl_index {
397    ($(impl Index<$ty:ident> for ComponentTypes { $output:ident => $field:ident })*) => ($(
398        impl core::ops::Index<$ty> for ComponentTypes {
399            type Output = $output;
400            #[inline]
401            fn index(&self, idx: $ty) -> &$output {
402                &self.$field[idx]
403            }
404        }
405
406        #[cfg(feature = "compile")]
407        impl core::ops::Index<$ty> for super::ComponentTypesBuilder {
408            type Output = $output;
409            #[inline]
410            fn index(&self, idx: $ty) -> &$output {
411                &self.component_types()[idx]
412            }
413        }
414    )*)
415}
416
417impl_index! {
418    impl Index<TypeModuleIndex> for ComponentTypes { TypeModule => modules }
419    impl Index<TypeComponentIndex> for ComponentTypes { TypeComponent => components }
420    impl Index<TypeComponentInstanceIndex> for ComponentTypes { TypeComponentInstance => component_instances }
421    impl Index<TypeFuncIndex> for ComponentTypes { TypeFunc => functions }
422    impl Index<TypeRecordIndex> for ComponentTypes { TypeRecord => records }
423    impl Index<TypeVariantIndex> for ComponentTypes { TypeVariant => variants }
424    impl Index<TypeTupleIndex> for ComponentTypes { TypeTuple => tuples }
425    impl Index<TypeEnumIndex> for ComponentTypes { TypeEnum => enums }
426    impl Index<TypeFlagsIndex> for ComponentTypes { TypeFlags => flags }
427    impl Index<TypeOptionIndex> for ComponentTypes { TypeOption => options }
428    impl Index<TypeResultIndex> for ComponentTypes { TypeResult => results }
429    impl Index<TypeListIndex> for ComponentTypes { TypeList => lists }
430    impl Index<TypeMapIndex> for ComponentTypes { TypeMap => maps }
431    impl Index<TypeResourceTableIndex> for ComponentTypes { TypeResourceTable => resource_tables }
432    impl Index<TypeFutureIndex> for ComponentTypes { TypeFuture => futures }
433    impl Index<TypeStreamIndex> for ComponentTypes { TypeStream => streams }
434    impl Index<TypeFutureTableIndex> for ComponentTypes { TypeFutureTable => future_tables }
435    impl Index<TypeStreamTableIndex> for ComponentTypes { TypeStreamTable => stream_tables }
436    impl Index<TypeComponentLocalErrorContextTableIndex> for ComponentTypes { TypeErrorContextTable => error_context_tables }
437    impl Index<TypeFixedLengthListIndex> for ComponentTypes { TypeFixedLengthList => fixed_length_lists }
438}
439
440// Additionally forward anything that can index `ModuleTypes` to `ModuleTypes`
441// (aka `SignatureIndex`)
442impl<T> Index<T> for ComponentTypes
443where
444    ModuleTypes: Index<T>,
445{
446    type Output = <ModuleTypes as Index<T>>::Output;
447    fn index(&self, idx: T) -> &Self::Output {
448        self.module_types.as_ref().unwrap().index(idx)
449    }
450}
451
452/// TODO
453#[derive(Clone, Debug, Serialize, Deserialize)]
454pub struct ComponentExtern {
455    /// TODO
456    pub data: ComponentExternData,
457    /// TODO
458    pub ty: TypeDef,
459}
460
461/// TODO
462#[derive(Clone, Debug, Serialize, Deserialize)]
463pub struct ComponentExternData {
464    /// TODO
465    pub implements: Option<String>,
466}
467
468/// Types of imports and exports in the component model.
469///
470/// These types are what's available for import and export in components. Note
471/// that all indirect indices contained here are intended to be looked up
472/// through a sibling `ComponentTypes` structure.
473#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
474pub enum TypeDef {
475    /// A component and its type.
476    Component(TypeComponentIndex),
477    /// An instance of a component.
478    ComponentInstance(TypeComponentInstanceIndex),
479    /// A component function, not to be confused with a core wasm function.
480    ComponentFunc(TypeFuncIndex),
481    /// An type in an interface.
482    Interface(InterfaceType),
483    /// A core wasm module and its type.
484    Module(TypeModuleIndex),
485    /// A core wasm function using only core wasm types.
486    CoreFunc(ModuleInternedTypeIndex),
487    /// A resource type which operates on the specified resource table.
488    ///
489    /// Note that different resource tables may point to the same underlying
490    /// actual resource type, but that's a private detail.
491    Resource(TypeResourceTableIndex),
492}
493
494impl TypeDef {
495    /// A human readable description of what kind of type definition this is.
496    pub fn desc(&self) -> &str {
497        match self {
498            TypeDef::Component(_) => "component",
499            TypeDef::ComponentInstance(_) => "instance",
500            TypeDef::ComponentFunc(_) => "function",
501            TypeDef::Interface(_) => "type",
502            TypeDef::Module(_) => "core module",
503            TypeDef::CoreFunc(_) => "core function",
504            TypeDef::Resource(_) => "resource",
505        }
506    }
507}
508
509// NB: Note that maps below are stored as an `IndexMap` now but the order
510// typically does not matter. As a minor implementation detail we want the
511// serialization of this type to always be deterministic and using `IndexMap`
512// gets us that over using a `HashMap` for example.
513
514/// The type of a module in the component model.
515///
516/// Note that this is not to be confused with `TypeComponent` below. This is
517/// intended only for core wasm modules, not for components.
518#[derive(Serialize, Deserialize, Default)]
519pub struct TypeModule {
520    /// The values that this module imports.
521    ///
522    /// Note that the value of this map is a core wasm `EntityType`, not a
523    /// component model `TypeRef`. Additionally note that this reflects the
524    /// two-level namespace of core WebAssembly, but unlike core wasm all import
525    /// names are required to be unique to describe a module in the component
526    /// model.
527    pub imports: IndexMap<(String, String), EntityType>,
528
529    /// The values that this module exports.
530    ///
531    /// Note that the value of this map is the core wasm `EntityType` to
532    /// represent that core wasm items are being exported.
533    pub exports: IndexMap<String, EntityType>,
534}
535
536impl TypeTrace for TypeModule {
537    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
538    where
539        F: FnMut(crate::EngineOrModuleTypeIndex) -> Result<(), E>,
540    {
541        for ty in self.imports.values() {
542            ty.trace(func)?;
543        }
544        for ty in self.exports.values() {
545            ty.trace(func)?;
546        }
547        Ok(())
548    }
549
550    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
551    where
552        F: FnMut(&mut crate::EngineOrModuleTypeIndex) -> Result<(), E>,
553    {
554        for ty in self.imports.values_mut() {
555            ty.trace_mut(func)?;
556        }
557        for ty in self.exports.values_mut() {
558            ty.trace_mut(func)?;
559        }
560        Ok(())
561    }
562}
563
564/// The type of a component in the component model.
565#[derive(Serialize, Deserialize, Default)]
566pub struct TypeComponent {
567    /// The named values that this component imports.
568    pub imports: IndexMap<String, ComponentExtern>,
569    /// The named values that this component exports.
570    pub exports: IndexMap<String, ComponentExtern>,
571}
572
573/// The type of a component instance in the component model, or an instantiated
574/// component.
575///
576/// Component instances only have exports of types in the component model.
577#[derive(Serialize, Deserialize, Default)]
578pub struct TypeComponentInstance {
579    /// The list of exports that this component has along with their types.
580    pub exports: IndexMap<String, ComponentExtern>,
581}
582
583/// A component function type in the component model.
584#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
585pub struct TypeFunc {
586    /// Whether or not this is an async function.
587    pub async_: bool,
588    /// Names of parameters.
589    pub param_names: Vec<String>,
590    /// Parameters to the function represented as a tuple.
591    pub params: TypeTupleIndex,
592    /// Results of the function represented as a tuple.
593    pub results: TypeTupleIndex,
594}
595
596/// All possible interface types that values can have.
597///
598/// This list represents an exhaustive listing of interface types and the
599/// shapes that they can take. Note that this enum is considered an "index" of
600/// forms where for non-primitive types a `ComponentTypes` structure is used to
601/// lookup further information based on the index found here.
602#[derive(Serialize, Deserialize, Copy, Clone, Hash, Eq, PartialEq, Debug)]
603#[expect(missing_docs, reason = "self-describing variants")]
604pub enum InterfaceType {
605    Bool,
606    S8,
607    U8,
608    S16,
609    U16,
610    S32,
611    U32,
612    S64,
613    U64,
614    Float32,
615    Float64,
616    Char,
617    String,
618    Record(TypeRecordIndex),
619    Variant(TypeVariantIndex),
620    List(TypeListIndex),
621    Tuple(TypeTupleIndex),
622    Map(TypeMapIndex),
623    Flags(TypeFlagsIndex),
624    Enum(TypeEnumIndex),
625    Option(TypeOptionIndex),
626    Result(TypeResultIndex),
627    Own(TypeResourceTableIndex),
628    Borrow(TypeResourceTableIndex),
629    Future(TypeFutureTableIndex),
630    Stream(TypeStreamTableIndex),
631    ErrorContext(TypeComponentLocalErrorContextTableIndex),
632    FixedLengthList(TypeFixedLengthListIndex),
633}
634
635/// Bye information about a type in the canonical ABI, with metadata for both
636/// memory32 and memory64-based types.
637#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
638pub struct CanonicalAbiInfo {
639    /// The byte-size of this type in a 32-bit memory.
640    pub size32: u32,
641    /// The byte-alignment of this type in a 32-bit memory.
642    pub align32: u32,
643    /// The byte-size of this type in a 64-bit memory.
644    pub size64: u32,
645    /// The byte-alignment of this type in a 64-bit memory.
646    pub align64: u32,
647    /// The number of types it takes to represents this type in the "flat"
648    /// representation of the canonical abi where everything is passed as
649    /// immediate arguments or results.
650    ///
651    /// If this is `None` then this type is not representable in the flat ABI
652    /// because it is too large.
653    pub flat_count: Option<u8>,
654}
655
656impl Default for CanonicalAbiInfo {
657    fn default() -> CanonicalAbiInfo {
658        CanonicalAbiInfo {
659            size32: 0,
660            align32: 1,
661            size64: 0,
662            align64: 1,
663            flat_count: Some(0),
664        }
665    }
666}
667
668const fn align_to(a: u32, b: u32) -> u32 {
669    assert!(b.is_power_of_two());
670    (a + (b - 1)) & !(b - 1)
671}
672
673const fn max(a: u32, b: u32) -> u32 {
674    if a > b { a } else { b }
675}
676
677impl CanonicalAbiInfo {
678    /// ABI information for zero-sized types.
679    pub const ZERO: CanonicalAbiInfo = CanonicalAbiInfo {
680        size32: 0,
681        align32: 1,
682        size64: 0,
683        align64: 1,
684        flat_count: Some(0),
685    };
686
687    /// ABI information for one-byte scalars.
688    pub const SCALAR1: CanonicalAbiInfo = CanonicalAbiInfo::scalar(1);
689    /// ABI information for two-byte scalars.
690    pub const SCALAR2: CanonicalAbiInfo = CanonicalAbiInfo::scalar(2);
691    /// ABI information for four-byte scalars.
692    pub const SCALAR4: CanonicalAbiInfo = CanonicalAbiInfo::scalar(4);
693    /// ABI information for eight-byte scalars.
694    pub const SCALAR8: CanonicalAbiInfo = CanonicalAbiInfo::scalar(8);
695
696    const fn scalar(size: u32) -> CanonicalAbiInfo {
697        CanonicalAbiInfo {
698            size32: size,
699            align32: size,
700            size64: size,
701            align64: size,
702            flat_count: Some(1),
703        }
704    }
705
706    /// ABI information for lists/strings which are "pointer pairs"
707    pub const POINTER_PAIR: CanonicalAbiInfo = CanonicalAbiInfo {
708        size32: 8,
709        align32: 4,
710        size64: 16,
711        align64: 8,
712        flat_count: Some(2),
713    };
714
715    /// Returns the abi for a record represented by the specified fields.
716    pub fn record<'a>(fields: impl Iterator<Item = &'a CanonicalAbiInfo>) -> CanonicalAbiInfo {
717        // NB: this is basically a duplicate copy of
718        // `CanonicalAbiInfo::record_static` and the two should be kept in sync.
719
720        let mut ret = CanonicalAbiInfo::default();
721        for field in fields {
722            ret.size32 = align_to(ret.size32, field.align32) + field.size32;
723            ret.align32 = ret.align32.max(field.align32);
724            ret.size64 = align_to(ret.size64, field.align64) + field.size64;
725            ret.align64 = ret.align64.max(field.align64);
726            ret.flat_count = add_flat(ret.flat_count, field.flat_count);
727        }
728        ret.size32 = align_to(ret.size32, ret.align32);
729        ret.size64 = align_to(ret.size64, ret.align64);
730        return ret;
731    }
732
733    /// Same as `CanonicalAbiInfo::record` but in a `const`-friendly context.
734    pub const fn record_static(fields: &[CanonicalAbiInfo]) -> CanonicalAbiInfo {
735        // NB: this is basically a duplicate copy of `CanonicalAbiInfo::record`
736        // and the two should be kept in sync.
737
738        let mut ret = CanonicalAbiInfo::ZERO;
739        let mut i = 0;
740        while i < fields.len() {
741            let field = &fields[i];
742            ret.size32 = align_to(ret.size32, field.align32) + field.size32;
743            ret.align32 = max(ret.align32, field.align32);
744            ret.size64 = align_to(ret.size64, field.align64) + field.size64;
745            ret.align64 = max(ret.align64, field.align64);
746            ret.flat_count = add_flat(ret.flat_count, field.flat_count);
747            i += 1;
748        }
749        ret.size32 = align_to(ret.size32, ret.align32);
750        ret.size64 = align_to(ret.size64, ret.align64);
751        return ret;
752    }
753
754    /// Returns the delta from the current value of `offset` to align properly
755    /// and read the next record field of type `abi` for 32-bit memories.
756    pub fn next_field32(&self, offset: &mut u32) -> u32 {
757        *offset = align_to(*offset, self.align32) + self.size32;
758        *offset - self.size32
759    }
760
761    /// Same as `next_field32`, but bumps a usize pointer
762    pub fn next_field32_size(&self, offset: &mut usize) -> usize {
763        let cur = u32::try_from(*offset).unwrap();
764        let cur = align_to(cur, self.align32) + self.size32;
765        *offset = usize::try_from(cur).unwrap();
766        usize::try_from(cur - self.size32).unwrap()
767    }
768
769    /// Returns the delta from the current value of `offset` to align properly
770    /// and read the next record field of type `abi` for 64-bit memories.
771    pub fn next_field64(&self, offset: &mut u32) -> u32 {
772        *offset = align_to(*offset, self.align64) + self.size64;
773        *offset - self.size64
774    }
775
776    /// Same as `next_field64`, but bumps a usize pointer
777    pub fn next_field64_size(&self, offset: &mut usize) -> usize {
778        let cur = u32::try_from(*offset).unwrap();
779        let cur = align_to(cur, self.align64) + self.size64;
780        *offset = usize::try_from(cur).unwrap();
781        usize::try_from(cur - self.size64).unwrap()
782    }
783
784    /// Returns ABI information for a structure which contains `count` flags.
785    pub const fn flags(count: usize) -> CanonicalAbiInfo {
786        let (size, align, flat_count) = match FlagsSize::from_count(count) {
787            FlagsSize::Size0 => (0, 1, 0),
788            FlagsSize::Size1 => (1, 1, 1),
789            FlagsSize::Size2 => (2, 2, 1),
790            FlagsSize::Size4Plus(n) => ((n as u32) * 4, 4, n),
791        };
792        CanonicalAbiInfo {
793            size32: size,
794            align32: align,
795            size64: size,
796            align64: align,
797            flat_count: Some(flat_count),
798        }
799    }
800
801    fn variant<'a, I>(cases: I) -> CanonicalAbiInfo
802    where
803        I: IntoIterator<Item = Option<&'a CanonicalAbiInfo>>,
804        I::IntoIter: ExactSizeIterator,
805    {
806        // NB: this is basically a duplicate definition of
807        // `CanonicalAbiInfo::variant_static`, these should be kept in sync.
808
809        let cases = cases.into_iter();
810        let discrim_size = u32::from(DiscriminantSize::from_count(cases.len()).unwrap());
811        let mut max_size32 = 0;
812        let mut max_align32 = discrim_size;
813        let mut max_size64 = 0;
814        let mut max_align64 = discrim_size;
815        let mut max_case_count = Some(0);
816        for case in cases {
817            if let Some(case) = case {
818                max_size32 = max_size32.max(case.size32);
819                max_align32 = max_align32.max(case.align32);
820                max_size64 = max_size64.max(case.size64);
821                max_align64 = max_align64.max(case.align64);
822                max_case_count = max_flat(max_case_count, case.flat_count);
823            }
824        }
825        CanonicalAbiInfo {
826            size32: align_to(
827                align_to(discrim_size, max_align32) + max_size32,
828                max_align32,
829            ),
830            align32: max_align32,
831            size64: align_to(
832                align_to(discrim_size, max_align64) + max_size64,
833                max_align64,
834            ),
835            align64: max_align64,
836            flat_count: add_flat(max_case_count, Some(1)),
837        }
838    }
839
840    /// Same as `CanonicalAbiInfo::variant` but `const`-safe
841    pub const fn variant_static(cases: &[Option<CanonicalAbiInfo>]) -> CanonicalAbiInfo {
842        // NB: this is basically a duplicate definition of
843        // `CanonicalAbiInfo::variant`, these should be kept in sync.
844
845        let discrim_size = match DiscriminantSize::from_count(cases.len()) {
846            Some(size) => size.byte_size(),
847            None => unreachable!(),
848        };
849        let mut max_size32 = 0;
850        let mut max_align32 = discrim_size;
851        let mut max_size64 = 0;
852        let mut max_align64 = discrim_size;
853        let mut max_case_count = Some(0);
854        let mut i = 0;
855        while i < cases.len() {
856            let case = &cases[i];
857            if let Some(case) = case {
858                max_size32 = max(max_size32, case.size32);
859                max_align32 = max(max_align32, case.align32);
860                max_size64 = max(max_size64, case.size64);
861                max_align64 = max(max_align64, case.align64);
862                max_case_count = max_flat(max_case_count, case.flat_count);
863            }
864            i += 1;
865        }
866        CanonicalAbiInfo {
867            size32: align_to(
868                align_to(discrim_size, max_align32) + max_size32,
869                max_align32,
870            ),
871            align32: max_align32,
872            size64: align_to(
873                align_to(discrim_size, max_align64) + max_size64,
874                max_align64,
875            ),
876            align64: max_align64,
877            flat_count: add_flat(max_case_count, Some(1)),
878        }
879    }
880
881    /// Calculates ABI information for an enum with `cases` cases.
882    pub const fn enum_(cases: usize) -> CanonicalAbiInfo {
883        // NB: this is basically a duplicate definition of
884        // `CanonicalAbiInfo::variant`, these should be kept in sync.
885
886        let discrim_size = match DiscriminantSize::from_count(cases) {
887            Some(size) => size.byte_size(),
888            None => unreachable!(),
889        };
890        CanonicalAbiInfo {
891            size32: discrim_size,
892            align32: discrim_size,
893            size64: discrim_size,
894            align64: discrim_size,
895            flat_count: Some(1),
896        }
897    }
898
899    /// Returns the flat count of this ABI information so long as the count
900    /// doesn't exceed the `max` specified.
901    pub fn flat_count(&self, max: usize) -> Option<usize> {
902        let flat = usize::from(self.flat_count?);
903        if flat > max { None } else { Some(flat) }
904    }
905}
906
907/// ABI information about the representation of a variant.
908#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
909pub struct VariantInfo {
910    /// The size of the discriminant used.
911    #[serde(with = "serde_discrim_size")]
912    pub size: DiscriminantSize,
913    /// The offset of the payload from the start of the variant in 32-bit
914    /// memories.
915    pub payload_offset32: u32,
916    /// The offset of the payload from the start of the variant in 64-bit
917    /// memories.
918    pub payload_offset64: u32,
919}
920
921impl VariantInfo {
922    /// Returns the abi information for a variant represented by the specified
923    /// cases.
924    pub fn new<'a, I>(cases: I) -> (VariantInfo, CanonicalAbiInfo)
925    where
926        I: IntoIterator<Item = Option<&'a CanonicalAbiInfo>>,
927        I::IntoIter: ExactSizeIterator,
928    {
929        let cases = cases.into_iter();
930        let size = DiscriminantSize::from_count(cases.len()).unwrap();
931        let abi = CanonicalAbiInfo::variant(cases);
932        (
933            VariantInfo {
934                size,
935                payload_offset32: align_to(u32::from(size), abi.align32),
936                payload_offset64: align_to(u32::from(size), abi.align64),
937            },
938            abi,
939        )
940    }
941    /// TODO
942    pub const fn new_static(cases: &[Option<CanonicalAbiInfo>]) -> VariantInfo {
943        let size = match DiscriminantSize::from_count(cases.len()) {
944            Some(size) => size,
945            None => unreachable!(),
946        };
947        let abi = CanonicalAbiInfo::variant_static(cases);
948        VariantInfo {
949            size,
950            payload_offset32: align_to(size.byte_size(), abi.align32),
951            payload_offset64: align_to(size.byte_size(), abi.align64),
952        }
953    }
954}
955
956mod serde_discrim_size {
957    use super::DiscriminantSize;
958    use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
959
960    pub fn serialize<S>(disc: &DiscriminantSize, ser: S) -> Result<S::Ok, S::Error>
961    where
962        S: Serializer,
963    {
964        u32::from(*disc).serialize(ser)
965    }
966
967    pub fn deserialize<'de, D>(deser: D) -> Result<DiscriminantSize, D::Error>
968    where
969        D: Deserializer<'de>,
970    {
971        match u32::deserialize(deser)? {
972            1 => Ok(DiscriminantSize::Size1),
973            2 => Ok(DiscriminantSize::Size2),
974            4 => Ok(DiscriminantSize::Size4),
975            _ => Err(D::Error::custom("invalid discriminant size")),
976        }
977    }
978}
979
980/// Shape of a "record" type in interface types.
981///
982/// This is equivalent to a `struct` in Rust.
983#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
984pub struct TypeRecord {
985    /// The fields that are contained within this struct type.
986    pub fields: Box<[RecordField]>,
987    /// Byte information about this type in the canonical ABI.
988    pub abi: CanonicalAbiInfo,
989}
990
991/// One field within a record.
992#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
993pub struct RecordField {
994    /// The name of the field, unique amongst all fields in a record.
995    pub name: String,
996    /// The type that this field contains.
997    pub ty: InterfaceType,
998}
999
1000/// Shape of a "variant" type in interface types.
1001///
1002/// Variants are close to Rust `enum` declarations where a value is one of many
1003/// cases and each case has a unique name and an optional payload associated
1004/// with it.
1005#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug)]
1006pub struct TypeVariant {
1007    /// The list of cases that this variant can take.
1008    pub cases: IndexMap<String, Option<InterfaceType>>,
1009    /// Byte information about this type in the canonical ABI.
1010    pub abi: CanonicalAbiInfo,
1011    /// Byte information about this variant type.
1012    pub info: VariantInfo,
1013}
1014
1015impl Hash for TypeVariant {
1016    fn hash<H: Hasher>(&self, h: &mut H) {
1017        let TypeVariant { cases, abi, info } = self;
1018        cases.len().hash(h);
1019        for pair in cases {
1020            pair.hash(h);
1021        }
1022        abi.hash(h);
1023        info.hash(h);
1024    }
1025}
1026
1027/// Shape of a "tuple" type in interface types.
1028///
1029/// This is largely the same as a tuple in Rust, basically a record with
1030/// unnamed fields.
1031#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1032pub struct TypeTuple {
1033    /// The types that are contained within this tuple.
1034    pub types: Box<[InterfaceType]>,
1035    /// Byte information about this type in the canonical ABI.
1036    pub abi: CanonicalAbiInfo,
1037}
1038
1039/// Shape of a "flags" type in interface types.
1040///
1041/// This can be thought of as a record-of-bools, although the representation is
1042/// more efficient as bitflags.
1043#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug)]
1044pub struct TypeFlags {
1045    /// The names of all flags, all of which are unique.
1046    pub names: IndexSet<String>,
1047    /// Byte information about this type in the canonical ABI.
1048    pub abi: CanonicalAbiInfo,
1049}
1050
1051impl Hash for TypeFlags {
1052    fn hash<H: Hasher>(&self, h: &mut H) {
1053        let TypeFlags { names, abi } = self;
1054        names.len().hash(h);
1055        for name in names {
1056            name.hash(h);
1057        }
1058        abi.hash(h);
1059    }
1060}
1061
1062/// Shape of an "enum" type in interface types, not to be confused with a Rust
1063/// `enum` type.
1064///
1065/// In interface types enums are simply a bag of names, and can be seen as a
1066/// variant where all payloads are `Unit`.
1067#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug)]
1068pub struct TypeEnum {
1069    /// The names of this enum, all of which are unique.
1070    pub names: IndexSet<String>,
1071    /// Byte information about this type in the canonical ABI.
1072    pub abi: CanonicalAbiInfo,
1073    /// Byte information about this variant type.
1074    pub info: VariantInfo,
1075}
1076
1077impl Hash for TypeEnum {
1078    fn hash<H: Hasher>(&self, h: &mut H) {
1079        let TypeEnum { names, abi, info } = self;
1080        names.len().hash(h);
1081        for name in names {
1082            name.hash(h);
1083        }
1084        abi.hash(h);
1085        info.hash(h);
1086    }
1087}
1088
1089/// Shape of an "option" interface type.
1090#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1091pub struct TypeOption {
1092    /// The `T` in `Result<T, E>`
1093    pub ty: InterfaceType,
1094    /// Byte information about this type in the canonical ABI.
1095    pub abi: CanonicalAbiInfo,
1096    /// Byte information about this variant type.
1097    pub info: VariantInfo,
1098}
1099
1100/// Shape of a "result" interface type.
1101#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1102pub struct TypeResult {
1103    /// The `T` in `Result<T, E>`
1104    pub ok: Option<InterfaceType>,
1105    /// The `E` in `Result<T, E>`
1106    pub err: Option<InterfaceType>,
1107    /// Byte information about this type in the canonical ABI.
1108    pub abi: CanonicalAbiInfo,
1109    /// Byte information about this variant type.
1110    pub info: VariantInfo,
1111}
1112
1113/// Shape of a "future" interface type.
1114#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1115pub struct TypeFuture {
1116    /// The `T` in `future<T>`
1117    pub payload: Option<InterfaceType>,
1118}
1119
1120/// Metadata about a future table added to a component.
1121#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1122pub struct TypeFutureTable {
1123    /// The specific future type this table is used for.
1124    pub ty: TypeFutureIndex,
1125    /// The specific component instance this table is used for.
1126    pub instance: RuntimeComponentInstanceIndex,
1127}
1128
1129/// Shape of a "stream" interface type.
1130#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1131pub struct TypeStream {
1132    /// The `T` in `stream<T>`
1133    pub payload: Option<InterfaceType>,
1134}
1135
1136/// Metadata about a stream table added to a component.
1137#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1138pub struct TypeStreamTable {
1139    /// The specific stream type this table is used for.
1140    pub ty: TypeStreamIndex,
1141    /// The specific component instance this table is used for.
1142    pub instance: RuntimeComponentInstanceIndex,
1143}
1144
1145/// Metadata about a error context table added to a component.
1146#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1147pub struct TypeErrorContextTable {
1148    /// The specific component instance this table is used for.
1149    pub instance: RuntimeComponentInstanceIndex,
1150}
1151
1152/// Metadata about a resource table added to a component.
1153#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1154pub enum TypeResourceTable {
1155    /// This resource is for an actual concrete resource which has runtime state
1156    /// associated with it.
1157    ///
1158    /// This is used for any resource which might actually enter a component.
1159    /// For example when a resource is either imported or defined in a component
1160    /// it'll get this case.
1161    Concrete {
1162        /// The original resource that this table contains.
1163        ///
1164        /// This is used when destroying resources within this table since this
1165        /// original definition will know how to execute destructors.
1166        ty: ResourceIndex,
1167
1168        /// The component instance that contains this resource table.
1169        instance: RuntimeComponentInstanceIndex,
1170    },
1171
1172    /// This table does not actually exist at runtime but instead represents
1173    /// type information for an uninstantiable resource. This tracks, for
1174    /// example, resources in component and instance types.
1175    Abstract(AbstractResourceIndex),
1176}
1177
1178impl TypeResourceTable {
1179    /// Asserts that this is `TypeResourceTable::Concrete` and returns the `ty`
1180    /// field.
1181    ///
1182    /// # Panics
1183    ///
1184    /// Panics if this is `TypeResourceTable::Abstract`.
1185    pub fn unwrap_concrete_ty(&self) -> ResourceIndex {
1186        match self {
1187            TypeResourceTable::Concrete { ty, .. } => *ty,
1188            TypeResourceTable::Abstract(_) => panic!("not a concrete resource table"),
1189        }
1190    }
1191
1192    /// Asserts that this is `TypeResourceTable::Concrete` and returns the
1193    /// `instance` field.
1194    ///
1195    /// # Panics
1196    ///
1197    /// Panics if this is `TypeResourceTable::Abstract`.
1198    pub fn unwrap_concrete_instance(&self) -> RuntimeComponentInstanceIndex {
1199        match self {
1200            TypeResourceTable::Concrete { instance, .. } => *instance,
1201            TypeResourceTable::Abstract(_) => panic!("not a concrete resource table"),
1202        }
1203    }
1204}
1205
1206/// Shape of a "list" interface type.
1207#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1208pub struct TypeList {
1209    /// The element type of the list.
1210    pub element: InterfaceType,
1211}
1212
1213/// Shape of a "map" interface type.
1214#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1215pub struct TypeMap {
1216    /// The key type of the map.
1217    pub key: InterfaceType,
1218    /// The value type of the map.
1219    pub value: InterfaceType,
1220    /// Byte information for each map entry represented as `tuple<key, value>`.
1221    pub entry_abi: CanonicalAbiInfo,
1222    /// Offset in bytes from the start of the entry tuple to the value field in
1223    /// memory32.
1224    pub value_offset32: u32,
1225    /// Offset in bytes from the start of the entry tuple to the value field in
1226    /// memory64.
1227    pub value_offset64: u32,
1228}
1229
1230/// Shape of a "fixed size list" interface type.
1231#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1232pub struct TypeFixedLengthList {
1233    /// The element type of the list.
1234    pub element: InterfaceType,
1235    /// The fixed length of the list.
1236    pub size: u32,
1237    /// Byte information about this type in the canonical ABI.
1238    pub abi: CanonicalAbiInfo,
1239}
1240
1241/// Maximum number of flat types, for either params or results.
1242pub const MAX_FLAT_TYPES: usize = if MAX_FLAT_PARAMS > MAX_FLAT_RESULTS {
1243    MAX_FLAT_PARAMS
1244} else {
1245    MAX_FLAT_RESULTS
1246};
1247
1248const fn add_flat(a: Option<u8>, b: Option<u8>) -> Option<u8> {
1249    const MAX: u8 = MAX_FLAT_TYPES as u8;
1250    let sum = match (a, b) {
1251        (Some(a), Some(b)) => match a.checked_add(b) {
1252            Some(c) => c,
1253            None => return None,
1254        },
1255        _ => return None,
1256    };
1257    if sum > MAX { None } else { Some(sum) }
1258}
1259
1260const fn max_flat(a: Option<u8>, b: Option<u8>) -> Option<u8> {
1261    match (a, b) {
1262        (Some(a), Some(b)) => {
1263            if a > b {
1264                Some(a)
1265            } else {
1266                Some(b)
1267            }
1268        }
1269        _ => None,
1270    }
1271}
1272
1273/// Flat representation of a type in just core wasm types.
1274pub struct FlatTypes<'a> {
1275    /// The flat representation of this type in 32-bit memories.
1276    pub memory32: &'a [FlatType],
1277    /// The flat representation of this type in 64-bit memories.
1278    pub memory64: &'a [FlatType],
1279}
1280
1281impl FlatTypes<'_> {
1282    /// Returns the number of flat types used to represent this type.
1283    ///
1284    /// Note that this length is the same regardless to the size of memory.
1285    pub fn len(&self) -> usize {
1286        assert_eq!(self.memory32.len(), self.memory64.len());
1287        self.memory32.len()
1288    }
1289}
1290
1291// Note that this is intentionally duplicated here to keep the size to 1 byte
1292// regardless to changes in the core wasm type system since this will only
1293// ever use integers/floats for the foreseeable future.
1294#[derive(Serialize, Deserialize, Hash, Debug, PartialEq, Eq, Copy, Clone)]
1295#[expect(missing_docs, reason = "self-describing variants")]
1296pub enum FlatType {
1297    I32,
1298    I64,
1299    F32,
1300    F64,
1301}