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/// Types of imports and exports in the component model.
453///
454/// These types are what's available for import and export in components. Note
455/// that all indirect indices contained here are intended to be looked up
456/// through a sibling `ComponentTypes` structure.
457#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
458pub enum TypeDef {
459    /// A component and its type.
460    Component(TypeComponentIndex),
461    /// An instance of a component.
462    ComponentInstance(TypeComponentInstanceIndex),
463    /// A component function, not to be confused with a core wasm function.
464    ComponentFunc(TypeFuncIndex),
465    /// An type in an interface.
466    Interface(InterfaceType),
467    /// A core wasm module and its type.
468    Module(TypeModuleIndex),
469    /// A core wasm function using only core wasm types.
470    CoreFunc(ModuleInternedTypeIndex),
471    /// A resource type which operates on the specified resource table.
472    ///
473    /// Note that different resource tables may point to the same underlying
474    /// actual resource type, but that's a private detail.
475    Resource(TypeResourceTableIndex),
476}
477
478impl TypeDef {
479    /// A human readable description of what kind of type definition this is.
480    pub fn desc(&self) -> &str {
481        match self {
482            TypeDef::Component(_) => "component",
483            TypeDef::ComponentInstance(_) => "instance",
484            TypeDef::ComponentFunc(_) => "function",
485            TypeDef::Interface(_) => "type",
486            TypeDef::Module(_) => "core module",
487            TypeDef::CoreFunc(_) => "core function",
488            TypeDef::Resource(_) => "resource",
489        }
490    }
491}
492
493// NB: Note that maps below are stored as an `IndexMap` now but the order
494// typically does not matter. As a minor implementation detail we want the
495// serialization of this type to always be deterministic and using `IndexMap`
496// gets us that over using a `HashMap` for example.
497
498/// The type of a module in the component model.
499///
500/// Note that this is not to be confused with `TypeComponent` below. This is
501/// intended only for core wasm modules, not for components.
502#[derive(Serialize, Deserialize, Default)]
503pub struct TypeModule {
504    /// The values that this module imports.
505    ///
506    /// Note that the value of this map is a core wasm `EntityType`, not a
507    /// component model `TypeRef`. Additionally note that this reflects the
508    /// two-level namespace of core WebAssembly, but unlike core wasm all import
509    /// names are required to be unique to describe a module in the component
510    /// model.
511    pub imports: IndexMap<(String, String), EntityType>,
512
513    /// The values that this module exports.
514    ///
515    /// Note that the value of this map is the core wasm `EntityType` to
516    /// represent that core wasm items are being exported.
517    pub exports: IndexMap<String, EntityType>,
518}
519
520impl TypeTrace for TypeModule {
521    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
522    where
523        F: FnMut(crate::EngineOrModuleTypeIndex) -> Result<(), E>,
524    {
525        for ty in self.imports.values() {
526            ty.trace(func)?;
527        }
528        for ty in self.exports.values() {
529            ty.trace(func)?;
530        }
531        Ok(())
532    }
533
534    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
535    where
536        F: FnMut(&mut crate::EngineOrModuleTypeIndex) -> Result<(), E>,
537    {
538        for ty in self.imports.values_mut() {
539            ty.trace_mut(func)?;
540        }
541        for ty in self.exports.values_mut() {
542            ty.trace_mut(func)?;
543        }
544        Ok(())
545    }
546}
547
548/// The type of a component in the component model.
549#[derive(Serialize, Deserialize, Default)]
550pub struct TypeComponent {
551    /// The named values that this component imports.
552    pub imports: IndexMap<String, TypeDef>,
553    /// The named values that this component exports.
554    pub exports: IndexMap<String, TypeDef>,
555}
556
557/// The type of a component instance in the component model, or an instantiated
558/// component.
559///
560/// Component instances only have exports of types in the component model.
561#[derive(Serialize, Deserialize, Default)]
562pub struct TypeComponentInstance {
563    /// The list of exports that this component has along with their types.
564    pub exports: IndexMap<String, TypeDef>,
565}
566
567/// A component function type in the component model.
568#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
569pub struct TypeFunc {
570    /// Whether or not this is an async function.
571    pub async_: bool,
572    /// Names of parameters.
573    pub param_names: Vec<String>,
574    /// Parameters to the function represented as a tuple.
575    pub params: TypeTupleIndex,
576    /// Results of the function represented as a tuple.
577    pub results: TypeTupleIndex,
578}
579
580/// All possible interface types that values can have.
581///
582/// This list represents an exhaustive listing of interface types and the
583/// shapes that they can take. Note that this enum is considered an "index" of
584/// forms where for non-primitive types a `ComponentTypes` structure is used to
585/// lookup further information based on the index found here.
586#[derive(Serialize, Deserialize, Copy, Clone, Hash, Eq, PartialEq, Debug)]
587#[expect(missing_docs, reason = "self-describing variants")]
588pub enum InterfaceType {
589    Bool,
590    S8,
591    U8,
592    S16,
593    U16,
594    S32,
595    U32,
596    S64,
597    U64,
598    Float32,
599    Float64,
600    Char,
601    String,
602    Record(TypeRecordIndex),
603    Variant(TypeVariantIndex),
604    List(TypeListIndex),
605    Tuple(TypeTupleIndex),
606    Map(TypeMapIndex),
607    Flags(TypeFlagsIndex),
608    Enum(TypeEnumIndex),
609    Option(TypeOptionIndex),
610    Result(TypeResultIndex),
611    Own(TypeResourceTableIndex),
612    Borrow(TypeResourceTableIndex),
613    Future(TypeFutureTableIndex),
614    Stream(TypeStreamTableIndex),
615    ErrorContext(TypeComponentLocalErrorContextTableIndex),
616    FixedLengthList(TypeFixedLengthListIndex),
617}
618
619/// Bye information about a type in the canonical ABI, with metadata for both
620/// memory32 and memory64-based types.
621#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
622pub struct CanonicalAbiInfo {
623    /// The byte-size of this type in a 32-bit memory.
624    pub size32: u32,
625    /// The byte-alignment of this type in a 32-bit memory.
626    pub align32: u32,
627    /// The byte-size of this type in a 64-bit memory.
628    pub size64: u32,
629    /// The byte-alignment of this type in a 64-bit memory.
630    pub align64: u32,
631    /// The number of types it takes to represents this type in the "flat"
632    /// representation of the canonical abi where everything is passed as
633    /// immediate arguments or results.
634    ///
635    /// If this is `None` then this type is not representable in the flat ABI
636    /// because it is too large.
637    pub flat_count: Option<u8>,
638}
639
640impl Default for CanonicalAbiInfo {
641    fn default() -> CanonicalAbiInfo {
642        CanonicalAbiInfo {
643            size32: 0,
644            align32: 1,
645            size64: 0,
646            align64: 1,
647            flat_count: Some(0),
648        }
649    }
650}
651
652const fn align_to(a: u32, b: u32) -> u32 {
653    assert!(b.is_power_of_two());
654    (a + (b - 1)) & !(b - 1)
655}
656
657const fn max(a: u32, b: u32) -> u32 {
658    if a > b { a } else { b }
659}
660
661impl CanonicalAbiInfo {
662    /// ABI information for zero-sized types.
663    pub const ZERO: CanonicalAbiInfo = CanonicalAbiInfo {
664        size32: 0,
665        align32: 1,
666        size64: 0,
667        align64: 1,
668        flat_count: Some(0),
669    };
670
671    /// ABI information for one-byte scalars.
672    pub const SCALAR1: CanonicalAbiInfo = CanonicalAbiInfo::scalar(1);
673    /// ABI information for two-byte scalars.
674    pub const SCALAR2: CanonicalAbiInfo = CanonicalAbiInfo::scalar(2);
675    /// ABI information for four-byte scalars.
676    pub const SCALAR4: CanonicalAbiInfo = CanonicalAbiInfo::scalar(4);
677    /// ABI information for eight-byte scalars.
678    pub const SCALAR8: CanonicalAbiInfo = CanonicalAbiInfo::scalar(8);
679
680    const fn scalar(size: u32) -> CanonicalAbiInfo {
681        CanonicalAbiInfo {
682            size32: size,
683            align32: size,
684            size64: size,
685            align64: size,
686            flat_count: Some(1),
687        }
688    }
689
690    /// ABI information for lists/strings which are "pointer pairs"
691    pub const POINTER_PAIR: CanonicalAbiInfo = CanonicalAbiInfo {
692        size32: 8,
693        align32: 4,
694        size64: 16,
695        align64: 8,
696        flat_count: Some(2),
697    };
698
699    /// Returns the abi for a record represented by the specified fields.
700    pub fn record<'a>(fields: impl Iterator<Item = &'a CanonicalAbiInfo>) -> CanonicalAbiInfo {
701        // NB: this is basically a duplicate copy of
702        // `CanonicalAbiInfo::record_static` and the two should be kept in sync.
703
704        let mut ret = CanonicalAbiInfo::default();
705        for field in fields {
706            ret.size32 = align_to(ret.size32, field.align32) + field.size32;
707            ret.align32 = ret.align32.max(field.align32);
708            ret.size64 = align_to(ret.size64, field.align64) + field.size64;
709            ret.align64 = ret.align64.max(field.align64);
710            ret.flat_count = add_flat(ret.flat_count, field.flat_count);
711        }
712        ret.size32 = align_to(ret.size32, ret.align32);
713        ret.size64 = align_to(ret.size64, ret.align64);
714        return ret;
715    }
716
717    /// Same as `CanonicalAbiInfo::record` but in a `const`-friendly context.
718    pub const fn record_static(fields: &[CanonicalAbiInfo]) -> CanonicalAbiInfo {
719        // NB: this is basically a duplicate copy of `CanonicalAbiInfo::record`
720        // and the two should be kept in sync.
721
722        let mut ret = CanonicalAbiInfo::ZERO;
723        let mut i = 0;
724        while i < fields.len() {
725            let field = &fields[i];
726            ret.size32 = align_to(ret.size32, field.align32) + field.size32;
727            ret.align32 = max(ret.align32, field.align32);
728            ret.size64 = align_to(ret.size64, field.align64) + field.size64;
729            ret.align64 = max(ret.align64, field.align64);
730            ret.flat_count = add_flat(ret.flat_count, field.flat_count);
731            i += 1;
732        }
733        ret.size32 = align_to(ret.size32, ret.align32);
734        ret.size64 = align_to(ret.size64, ret.align64);
735        return ret;
736    }
737
738    /// Returns the delta from the current value of `offset` to align properly
739    /// and read the next record field of type `abi` for 32-bit memories.
740    pub fn next_field32(&self, offset: &mut u32) -> u32 {
741        *offset = align_to(*offset, self.align32) + self.size32;
742        *offset - self.size32
743    }
744
745    /// Same as `next_field32`, but bumps a usize pointer
746    pub fn next_field32_size(&self, offset: &mut usize) -> usize {
747        let cur = u32::try_from(*offset).unwrap();
748        let cur = align_to(cur, self.align32) + self.size32;
749        *offset = usize::try_from(cur).unwrap();
750        usize::try_from(cur - self.size32).unwrap()
751    }
752
753    /// Returns the delta from the current value of `offset` to align properly
754    /// and read the next record field of type `abi` for 64-bit memories.
755    pub fn next_field64(&self, offset: &mut u32) -> u32 {
756        *offset = align_to(*offset, self.align64) + self.size64;
757        *offset - self.size64
758    }
759
760    /// Same as `next_field64`, but bumps a usize pointer
761    pub fn next_field64_size(&self, offset: &mut usize) -> usize {
762        let cur = u32::try_from(*offset).unwrap();
763        let cur = align_to(cur, self.align64) + self.size64;
764        *offset = usize::try_from(cur).unwrap();
765        usize::try_from(cur - self.size64).unwrap()
766    }
767
768    /// Returns ABI information for a structure which contains `count` flags.
769    pub const fn flags(count: usize) -> CanonicalAbiInfo {
770        let (size, align, flat_count) = match FlagsSize::from_count(count) {
771            FlagsSize::Size0 => (0, 1, 0),
772            FlagsSize::Size1 => (1, 1, 1),
773            FlagsSize::Size2 => (2, 2, 1),
774            FlagsSize::Size4Plus(n) => ((n as u32) * 4, 4, n),
775        };
776        CanonicalAbiInfo {
777            size32: size,
778            align32: align,
779            size64: size,
780            align64: align,
781            flat_count: Some(flat_count),
782        }
783    }
784
785    fn variant<'a, I>(cases: I) -> CanonicalAbiInfo
786    where
787        I: IntoIterator<Item = Option<&'a CanonicalAbiInfo>>,
788        I::IntoIter: ExactSizeIterator,
789    {
790        // NB: this is basically a duplicate definition of
791        // `CanonicalAbiInfo::variant_static`, these should be kept in sync.
792
793        let cases = cases.into_iter();
794        let discrim_size = u32::from(DiscriminantSize::from_count(cases.len()).unwrap());
795        let mut max_size32 = 0;
796        let mut max_align32 = discrim_size;
797        let mut max_size64 = 0;
798        let mut max_align64 = discrim_size;
799        let mut max_case_count = Some(0);
800        for case in cases {
801            if let Some(case) = case {
802                max_size32 = max_size32.max(case.size32);
803                max_align32 = max_align32.max(case.align32);
804                max_size64 = max_size64.max(case.size64);
805                max_align64 = max_align64.max(case.align64);
806                max_case_count = max_flat(max_case_count, case.flat_count);
807            }
808        }
809        CanonicalAbiInfo {
810            size32: align_to(
811                align_to(discrim_size, max_align32) + max_size32,
812                max_align32,
813            ),
814            align32: max_align32,
815            size64: align_to(
816                align_to(discrim_size, max_align64) + max_size64,
817                max_align64,
818            ),
819            align64: max_align64,
820            flat_count: add_flat(max_case_count, Some(1)),
821        }
822    }
823
824    /// Same as `CanonicalAbiInfo::variant` but `const`-safe
825    pub const fn variant_static(cases: &[Option<CanonicalAbiInfo>]) -> CanonicalAbiInfo {
826        // NB: this is basically a duplicate definition of
827        // `CanonicalAbiInfo::variant`, these should be kept in sync.
828
829        let discrim_size = match DiscriminantSize::from_count(cases.len()) {
830            Some(size) => size.byte_size(),
831            None => unreachable!(),
832        };
833        let mut max_size32 = 0;
834        let mut max_align32 = discrim_size;
835        let mut max_size64 = 0;
836        let mut max_align64 = discrim_size;
837        let mut max_case_count = Some(0);
838        let mut i = 0;
839        while i < cases.len() {
840            let case = &cases[i];
841            if let Some(case) = case {
842                max_size32 = max(max_size32, case.size32);
843                max_align32 = max(max_align32, case.align32);
844                max_size64 = max(max_size64, case.size64);
845                max_align64 = max(max_align64, case.align64);
846                max_case_count = max_flat(max_case_count, case.flat_count);
847            }
848            i += 1;
849        }
850        CanonicalAbiInfo {
851            size32: align_to(
852                align_to(discrim_size, max_align32) + max_size32,
853                max_align32,
854            ),
855            align32: max_align32,
856            size64: align_to(
857                align_to(discrim_size, max_align64) + max_size64,
858                max_align64,
859            ),
860            align64: max_align64,
861            flat_count: add_flat(max_case_count, Some(1)),
862        }
863    }
864
865    /// Calculates ABI information for an enum with `cases` cases.
866    pub const fn enum_(cases: usize) -> CanonicalAbiInfo {
867        // NB: this is basically a duplicate definition of
868        // `CanonicalAbiInfo::variant`, these should be kept in sync.
869
870        let discrim_size = match DiscriminantSize::from_count(cases) {
871            Some(size) => size.byte_size(),
872            None => unreachable!(),
873        };
874        CanonicalAbiInfo {
875            size32: discrim_size,
876            align32: discrim_size,
877            size64: discrim_size,
878            align64: discrim_size,
879            flat_count: Some(1),
880        }
881    }
882
883    /// Returns the flat count of this ABI information so long as the count
884    /// doesn't exceed the `max` specified.
885    pub fn flat_count(&self, max: usize) -> Option<usize> {
886        let flat = usize::from(self.flat_count?);
887        if flat > max { None } else { Some(flat) }
888    }
889}
890
891/// ABI information about the representation of a variant.
892#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
893pub struct VariantInfo {
894    /// The size of the discriminant used.
895    #[serde(with = "serde_discrim_size")]
896    pub size: DiscriminantSize,
897    /// The offset of the payload from the start of the variant in 32-bit
898    /// memories.
899    pub payload_offset32: u32,
900    /// The offset of the payload from the start of the variant in 64-bit
901    /// memories.
902    pub payload_offset64: u32,
903}
904
905impl VariantInfo {
906    /// Returns the abi information for a variant represented by the specified
907    /// cases.
908    pub fn new<'a, I>(cases: I) -> (VariantInfo, CanonicalAbiInfo)
909    where
910        I: IntoIterator<Item = Option<&'a CanonicalAbiInfo>>,
911        I::IntoIter: ExactSizeIterator,
912    {
913        let cases = cases.into_iter();
914        let size = DiscriminantSize::from_count(cases.len()).unwrap();
915        let abi = CanonicalAbiInfo::variant(cases);
916        (
917            VariantInfo {
918                size,
919                payload_offset32: align_to(u32::from(size), abi.align32),
920                payload_offset64: align_to(u32::from(size), abi.align64),
921            },
922            abi,
923        )
924    }
925    /// TODO
926    pub const fn new_static(cases: &[Option<CanonicalAbiInfo>]) -> VariantInfo {
927        let size = match DiscriminantSize::from_count(cases.len()) {
928            Some(size) => size,
929            None => unreachable!(),
930        };
931        let abi = CanonicalAbiInfo::variant_static(cases);
932        VariantInfo {
933            size,
934            payload_offset32: align_to(size.byte_size(), abi.align32),
935            payload_offset64: align_to(size.byte_size(), abi.align64),
936        }
937    }
938}
939
940mod serde_discrim_size {
941    use super::DiscriminantSize;
942    use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
943
944    pub fn serialize<S>(disc: &DiscriminantSize, ser: S) -> Result<S::Ok, S::Error>
945    where
946        S: Serializer,
947    {
948        u32::from(*disc).serialize(ser)
949    }
950
951    pub fn deserialize<'de, D>(deser: D) -> Result<DiscriminantSize, D::Error>
952    where
953        D: Deserializer<'de>,
954    {
955        match u32::deserialize(deser)? {
956            1 => Ok(DiscriminantSize::Size1),
957            2 => Ok(DiscriminantSize::Size2),
958            4 => Ok(DiscriminantSize::Size4),
959            _ => Err(D::Error::custom("invalid discriminant size")),
960        }
961    }
962}
963
964/// Shape of a "record" type in interface types.
965///
966/// This is equivalent to a `struct` in Rust.
967#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
968pub struct TypeRecord {
969    /// The fields that are contained within this struct type.
970    pub fields: Box<[RecordField]>,
971    /// Byte information about this type in the canonical ABI.
972    pub abi: CanonicalAbiInfo,
973}
974
975/// One field within a record.
976#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
977pub struct RecordField {
978    /// The name of the field, unique amongst all fields in a record.
979    pub name: String,
980    /// The type that this field contains.
981    pub ty: InterfaceType,
982}
983
984/// Shape of a "variant" type in interface types.
985///
986/// Variants are close to Rust `enum` declarations where a value is one of many
987/// cases and each case has a unique name and an optional payload associated
988/// with it.
989#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug)]
990pub struct TypeVariant {
991    /// The list of cases that this variant can take.
992    pub cases: IndexMap<String, Option<InterfaceType>>,
993    /// Byte information about this type in the canonical ABI.
994    pub abi: CanonicalAbiInfo,
995    /// Byte information about this variant type.
996    pub info: VariantInfo,
997}
998
999impl Hash for TypeVariant {
1000    fn hash<H: Hasher>(&self, h: &mut H) {
1001        let TypeVariant { cases, abi, info } = self;
1002        cases.len().hash(h);
1003        for pair in cases {
1004            pair.hash(h);
1005        }
1006        abi.hash(h);
1007        info.hash(h);
1008    }
1009}
1010
1011/// Shape of a "tuple" type in interface types.
1012///
1013/// This is largely the same as a tuple in Rust, basically a record with
1014/// unnamed fields.
1015#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1016pub struct TypeTuple {
1017    /// The types that are contained within this tuple.
1018    pub types: Box<[InterfaceType]>,
1019    /// Byte information about this type in the canonical ABI.
1020    pub abi: CanonicalAbiInfo,
1021}
1022
1023/// Shape of a "flags" type in interface types.
1024///
1025/// This can be thought of as a record-of-bools, although the representation is
1026/// more efficient as bitflags.
1027#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug)]
1028pub struct TypeFlags {
1029    /// The names of all flags, all of which are unique.
1030    pub names: IndexSet<String>,
1031    /// Byte information about this type in the canonical ABI.
1032    pub abi: CanonicalAbiInfo,
1033}
1034
1035impl Hash for TypeFlags {
1036    fn hash<H: Hasher>(&self, h: &mut H) {
1037        let TypeFlags { names, abi } = self;
1038        names.len().hash(h);
1039        for name in names {
1040            name.hash(h);
1041        }
1042        abi.hash(h);
1043    }
1044}
1045
1046/// Shape of an "enum" type in interface types, not to be confused with a Rust
1047/// `enum` type.
1048///
1049/// In interface types enums are simply a bag of names, and can be seen as a
1050/// variant where all payloads are `Unit`.
1051#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug)]
1052pub struct TypeEnum {
1053    /// The names of this enum, all of which are unique.
1054    pub names: IndexSet<String>,
1055    /// Byte information about this type in the canonical ABI.
1056    pub abi: CanonicalAbiInfo,
1057    /// Byte information about this variant type.
1058    pub info: VariantInfo,
1059}
1060
1061impl Hash for TypeEnum {
1062    fn hash<H: Hasher>(&self, h: &mut H) {
1063        let TypeEnum { names, abi, info } = self;
1064        names.len().hash(h);
1065        for name in names {
1066            name.hash(h);
1067        }
1068        abi.hash(h);
1069        info.hash(h);
1070    }
1071}
1072
1073/// Shape of an "option" interface type.
1074#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1075pub struct TypeOption {
1076    /// The `T` in `Result<T, E>`
1077    pub ty: InterfaceType,
1078    /// Byte information about this type in the canonical ABI.
1079    pub abi: CanonicalAbiInfo,
1080    /// Byte information about this variant type.
1081    pub info: VariantInfo,
1082}
1083
1084/// Shape of a "result" interface type.
1085#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1086pub struct TypeResult {
1087    /// The `T` in `Result<T, E>`
1088    pub ok: Option<InterfaceType>,
1089    /// The `E` in `Result<T, E>`
1090    pub err: Option<InterfaceType>,
1091    /// Byte information about this type in the canonical ABI.
1092    pub abi: CanonicalAbiInfo,
1093    /// Byte information about this variant type.
1094    pub info: VariantInfo,
1095}
1096
1097/// Shape of a "future" interface type.
1098#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1099pub struct TypeFuture {
1100    /// The `T` in `future<T>`
1101    pub payload: Option<InterfaceType>,
1102}
1103
1104/// Metadata about a future table added to a component.
1105#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1106pub struct TypeFutureTable {
1107    /// The specific future type this table is used for.
1108    pub ty: TypeFutureIndex,
1109    /// The specific component instance this table is used for.
1110    pub instance: RuntimeComponentInstanceIndex,
1111}
1112
1113/// Shape of a "stream" interface type.
1114#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1115pub struct TypeStream {
1116    /// The `T` in `stream<T>`
1117    pub payload: Option<InterfaceType>,
1118}
1119
1120/// Metadata about a stream table added to a component.
1121#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1122pub struct TypeStreamTable {
1123    /// The specific stream type this table is used for.
1124    pub ty: TypeStreamIndex,
1125    /// The specific component instance this table is used for.
1126    pub instance: RuntimeComponentInstanceIndex,
1127}
1128
1129/// Metadata about a error context table added to a component.
1130#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1131pub struct TypeErrorContextTable {
1132    /// The specific component instance this table is used for.
1133    pub instance: RuntimeComponentInstanceIndex,
1134}
1135
1136/// Metadata about a resource table added to a component.
1137#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1138pub enum TypeResourceTable {
1139    /// This resource is for an actual concrete resource which has runtime state
1140    /// associated with it.
1141    ///
1142    /// This is used for any resource which might actually enter a component.
1143    /// For example when a resource is either imported or defined in a component
1144    /// it'll get this case.
1145    Concrete {
1146        /// The original resource that this table contains.
1147        ///
1148        /// This is used when destroying resources within this table since this
1149        /// original definition will know how to execute destructors.
1150        ty: ResourceIndex,
1151
1152        /// The component instance that contains this resource table.
1153        instance: RuntimeComponentInstanceIndex,
1154    },
1155
1156    /// This table does not actually exist at runtime but instead represents
1157    /// type information for an uninstantiable resource. This tracks, for
1158    /// example, resources in component and instance types.
1159    Abstract(AbstractResourceIndex),
1160}
1161
1162impl TypeResourceTable {
1163    /// Asserts that this is `TypeResourceTable::Concrete` and returns the `ty`
1164    /// field.
1165    ///
1166    /// # Panics
1167    ///
1168    /// Panics if this is `TypeResourceTable::Abstract`.
1169    pub fn unwrap_concrete_ty(&self) -> ResourceIndex {
1170        match self {
1171            TypeResourceTable::Concrete { ty, .. } => *ty,
1172            TypeResourceTable::Abstract(_) => panic!("not a concrete resource table"),
1173        }
1174    }
1175
1176    /// Asserts that this is `TypeResourceTable::Concrete` and returns the
1177    /// `instance` field.
1178    ///
1179    /// # Panics
1180    ///
1181    /// Panics if this is `TypeResourceTable::Abstract`.
1182    pub fn unwrap_concrete_instance(&self) -> RuntimeComponentInstanceIndex {
1183        match self {
1184            TypeResourceTable::Concrete { instance, .. } => *instance,
1185            TypeResourceTable::Abstract(_) => panic!("not a concrete resource table"),
1186        }
1187    }
1188}
1189
1190/// Shape of a "list" interface type.
1191#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1192pub struct TypeList {
1193    /// The element type of the list.
1194    pub element: InterfaceType,
1195}
1196
1197/// Shape of a "map" interface type.
1198#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1199pub struct TypeMap {
1200    /// The key type of the map.
1201    pub key: InterfaceType,
1202    /// The value type of the map.
1203    pub value: InterfaceType,
1204    /// Byte information for each map entry represented as `tuple<key, value>`.
1205    pub entry_abi: CanonicalAbiInfo,
1206    /// Offset in bytes from the start of the entry tuple to the value field in
1207    /// memory32.
1208    pub value_offset32: u32,
1209    /// Offset in bytes from the start of the entry tuple to the value field in
1210    /// memory64.
1211    pub value_offset64: u32,
1212}
1213
1214/// Shape of a "fixed size list" interface type.
1215#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1216pub struct TypeFixedLengthList {
1217    /// The element type of the list.
1218    pub element: InterfaceType,
1219    /// The fixed length of the list.
1220    pub size: u32,
1221    /// Byte information about this type in the canonical ABI.
1222    pub abi: CanonicalAbiInfo,
1223}
1224
1225/// Maximum number of flat types, for either params or results.
1226pub const MAX_FLAT_TYPES: usize = if MAX_FLAT_PARAMS > MAX_FLAT_RESULTS {
1227    MAX_FLAT_PARAMS
1228} else {
1229    MAX_FLAT_RESULTS
1230};
1231
1232const fn add_flat(a: Option<u8>, b: Option<u8>) -> Option<u8> {
1233    const MAX: u8 = MAX_FLAT_TYPES as u8;
1234    let sum = match (a, b) {
1235        (Some(a), Some(b)) => match a.checked_add(b) {
1236            Some(c) => c,
1237            None => return None,
1238        },
1239        _ => return None,
1240    };
1241    if sum > MAX { None } else { Some(sum) }
1242}
1243
1244const fn max_flat(a: Option<u8>, b: Option<u8>) -> Option<u8> {
1245    match (a, b) {
1246        (Some(a), Some(b)) => {
1247            if a > b {
1248                Some(a)
1249            } else {
1250                Some(b)
1251            }
1252        }
1253        _ => None,
1254    }
1255}
1256
1257/// Flat representation of a type in just core wasm types.
1258pub struct FlatTypes<'a> {
1259    /// The flat representation of this type in 32-bit memories.
1260    pub memory32: &'a [FlatType],
1261    /// The flat representation of this type in 64-bit memories.
1262    pub memory64: &'a [FlatType],
1263}
1264
1265impl FlatTypes<'_> {
1266    /// Returns the number of flat types used to represent this type.
1267    ///
1268    /// Note that this length is the same regardless to the size of memory.
1269    pub fn len(&self) -> usize {
1270        assert_eq!(self.memory32.len(), self.memory64.len());
1271        self.memory32.len()
1272    }
1273}
1274
1275// Note that this is intentionally duplicated here to keep the size to 1 byte
1276// regardless to changes in the core wasm type system since this will only
1277// ever use integers/floats for the foreseeable future.
1278#[derive(Serialize, Deserialize, Hash, Debug, PartialEq, Eq, Copy, Clone)]
1279#[expect(missing_docs, reason = "self-describing variants")]
1280pub enum FlatType {
1281    I32,
1282    I64,
1283    F32,
1284    F64,
1285}