Skip to main content

wasmtime/runtime/
types.rs

1use crate::error::OutOfMemory;
2use crate::prelude::*;
3use crate::runtime::externals::Global as RuntimeGlobal;
4use crate::runtime::externals::Table as RuntimeTable;
5use crate::runtime::externals::Tag as RuntimeTag;
6use crate::{AsContextMut, Extern, Func, Val};
7use crate::{Engine, type_registry::RegisteredType};
8use core::fmt::{self, Display, Write};
9use wasmtime_environ::WasmExnType;
10use wasmtime_environ::{
11    EngineOrModuleTypeIndex, EntityType, Global, IndexType, Limits, Memory, ModuleTypes,
12    PanicOnOom as _, Table, Tag, TypeTrace, VMSharedTypeIndex, WasmArrayType,
13    WasmCompositeInnerType, WasmCompositeType, WasmFieldType, WasmFuncType, WasmHeapType,
14    WasmRefType, WasmStorageType, WasmStructType, WasmSubType, WasmValType,
15};
16
17pub(crate) mod matching;
18
19// Type Representations
20
21// Type attributes
22
23/// Indicator of whether a global value, struct's field, or array type's
24/// elements are mutable or not.
25#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
26pub enum Mutability {
27    /// The global value, struct field, or array elements are constant and the
28    /// value does not change.
29    Const,
30    /// The value of the global, struct field, or array elements can change over
31    /// time.
32    Var,
33}
34
35impl Mutability {
36    /// Is this constant?
37    #[inline]
38    pub fn is_const(&self) -> bool {
39        *self == Self::Const
40    }
41
42    /// Is this variable?
43    #[inline]
44    pub fn is_var(&self) -> bool {
45        *self == Self::Var
46    }
47}
48
49/// Indicator of whether a type is final or not.
50///
51/// Final types may not be the supertype of other types.
52#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
53pub enum Finality {
54    /// The associated type is final.
55    Final,
56    /// The associated type is not final.
57    NonFinal,
58}
59
60impl Finality {
61    /// Is this final?
62    #[inline]
63    pub fn is_final(&self) -> bool {
64        *self == Self::Final
65    }
66
67    /// Is this non-final?
68    #[inline]
69    pub fn is_non_final(&self) -> bool {
70        *self == Self::NonFinal
71    }
72}
73
74// Value Types
75
76/// A list of all possible value types in WebAssembly.
77///
78/// # Subtyping and Equality
79///
80/// `ValType` does not implement `Eq`, because reference types have a subtyping
81/// relationship, and so 99.99% of the time you actually want to check whether
82/// one type matches (i.e. is a subtype of) another type. You can use the
83/// [`ValType::matches`] and [`Val::matches_ty`][crate::Val::matches_ty] methods
84/// to perform these types of checks. If, however, you are in that 0.01%
85/// scenario where you need to check precise equality between types, you can use
86/// the [`ValType::eq`] method.
87#[derive(Clone, Hash)]
88pub enum ValType {
89    // NB: the ordering of variants here is intended to match the ordering in
90    // `wasmtime_environ::WasmType` to help improve codegen when converting.
91    //
92    /// Signed 32 bit integer.
93    I32,
94    /// Signed 64 bit integer.
95    I64,
96    /// Floating point 32 bit integer.
97    F32,
98    /// Floating point 64 bit integer.
99    F64,
100    /// A 128 bit number.
101    V128,
102    /// An opaque reference to some type on the heap.
103    Ref(RefType),
104}
105
106impl fmt::Debug for ValType {
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        fmt::Display::fmt(self, f)
109    }
110}
111
112impl Display for ValType {
113    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114        match self {
115            ValType::I32 => write!(f, "i32"),
116            ValType::I64 => write!(f, "i64"),
117            ValType::F32 => write!(f, "f32"),
118            ValType::F64 => write!(f, "f64"),
119            ValType::V128 => write!(f, "v128"),
120            ValType::Ref(r) => Display::fmt(r, f),
121        }
122    }
123}
124
125impl From<RefType> for ValType {
126    #[inline]
127    fn from(r: RefType) -> Self {
128        ValType::Ref(r)
129    }
130}
131
132impl ValType {
133    /// The `externref` type, aka `(ref null extern)`.
134    pub const EXTERNREF: Self = ValType::Ref(RefType::EXTERNREF);
135
136    /// The `nullexternref` type, aka `(ref null noextern)`.
137    pub const NULLEXTERNREF: Self = ValType::Ref(RefType::NULLEXTERNREF);
138
139    /// The `funcref` type, aka `(ref null func)`.
140    pub const FUNCREF: Self = ValType::Ref(RefType::FUNCREF);
141
142    /// The `nullfuncref` type, aka `(ref null nofunc)`.
143    pub const NULLFUNCREF: Self = ValType::Ref(RefType::NULLFUNCREF);
144
145    /// The `anyref` type, aka `(ref null any)`.
146    pub const ANYREF: Self = ValType::Ref(RefType::ANYREF);
147
148    /// The `eqref` type, aka `(ref null eq)`.
149    pub const EQREF: Self = ValType::Ref(RefType::EQREF);
150
151    /// The `i31ref` type, aka `(ref null i31)`.
152    pub const I31REF: Self = ValType::Ref(RefType::I31REF);
153
154    /// The `arrayref` type, aka `(ref null array)`.
155    pub const ARRAYREF: Self = ValType::Ref(RefType::ARRAYREF);
156
157    /// The `structref` type, aka `(ref null struct)`.
158    pub const STRUCTREF: Self = ValType::Ref(RefType::STRUCTREF);
159
160    /// The `nullref` type, aka `(ref null none)`.
161    pub const NULLREF: Self = ValType::Ref(RefType::NULLREF);
162
163    /// The `contref` type, aka `(ref null cont)`.
164    pub const CONTREF: Self = ValType::Ref(RefType::CONTREF);
165
166    /// The `nullcontref` type, aka. `(ref null nocont)`.
167    pub const NULLCONTREF: Self = ValType::Ref(RefType::NULLCONTREF);
168
169    /// The `exnref` type, aka `(ref null exn)`.
170    pub const EXNREF: Self = ValType::Ref(RefType::EXNREF);
171
172    /// The `nullexnref` type, aka `(ref null noexn)`.
173    pub const NULLEXNREF: Self = ValType::Ref(RefType::NULLEXNREF);
174
175    /// Returns true if `ValType` matches any of the numeric types. (e.g. `I32`,
176    /// `I64`, `F32`, `F64`).
177    #[inline]
178    pub fn is_num(&self) -> bool {
179        match self {
180            ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => true,
181            _ => false,
182        }
183    }
184
185    /// Is this the `i32` type?
186    #[inline]
187    pub fn is_i32(&self) -> bool {
188        matches!(self, ValType::I32)
189    }
190
191    /// Is this the `i64` type?
192    #[inline]
193    pub fn is_i64(&self) -> bool {
194        matches!(self, ValType::I64)
195    }
196
197    /// Is this the `f32` type?
198    #[inline]
199    pub fn is_f32(&self) -> bool {
200        matches!(self, ValType::F32)
201    }
202
203    /// Is this the `f64` type?
204    #[inline]
205    pub fn is_f64(&self) -> bool {
206        matches!(self, ValType::F64)
207    }
208
209    /// Is this the `v128` type?
210    #[inline]
211    pub fn is_v128(&self) -> bool {
212        matches!(self, ValType::V128)
213    }
214
215    /// Returns true if `ValType` is any kind of reference type.
216    #[inline]
217    pub fn is_ref(&self) -> bool {
218        matches!(self, ValType::Ref(_))
219    }
220
221    /// Is this the `funcref` (aka `(ref null func)`) type?
222    #[inline]
223    pub fn is_funcref(&self) -> bool {
224        matches!(
225            self,
226            ValType::Ref(RefType {
227                is_nullable: true,
228                heap_type: HeapType::Func
229            })
230        )
231    }
232
233    /// Is this the `externref` (aka `(ref null extern)`) type?
234    #[inline]
235    pub fn is_externref(&self) -> bool {
236        matches!(
237            self,
238            ValType::Ref(RefType {
239                is_nullable: true,
240                heap_type: HeapType::Extern
241            })
242        )
243    }
244
245    /// Is this the `anyref` (aka `(ref null any)`) type?
246    #[inline]
247    pub fn is_anyref(&self) -> bool {
248        matches!(
249            self,
250            ValType::Ref(RefType {
251                is_nullable: true,
252                heap_type: HeapType::Any
253            })
254        )
255    }
256
257    /// Is this the `contref` (aka `(ref null cont)`) type?
258    #[inline]
259    pub fn is_contref(&self) -> bool {
260        matches!(
261            self,
262            ValType::Ref(RefType {
263                is_nullable: true,
264                heap_type: HeapType::Cont
265            })
266        )
267    }
268
269    /// Get the underlying reference type, if this value type is a reference
270    /// type.
271    #[inline]
272    pub fn as_ref(&self) -> Option<&RefType> {
273        match self {
274            ValType::Ref(r) => Some(r),
275            _ => None,
276        }
277    }
278
279    /// Get the underlying reference type, panicking if this value type is not a
280    /// reference type.
281    #[inline]
282    pub fn unwrap_ref(&self) -> &RefType {
283        self.as_ref()
284            .expect("ValType::unwrap_ref on a non-reference type")
285    }
286
287    /// Does this value type match the other type?
288    ///
289    /// That is, is this value type a subtype of the other?
290    ///
291    /// # Panics
292    ///
293    /// Panics if either type is associated with a different engine from the
294    /// other.
295    pub fn matches(&self, other: &ValType) -> bool {
296        match (self, other) {
297            (Self::I32, Self::I32) => true,
298            (Self::I64, Self::I64) => true,
299            (Self::F32, Self::F32) => true,
300            (Self::F64, Self::F64) => true,
301            (Self::V128, Self::V128) => true,
302            (Self::Ref(a), Self::Ref(b)) => a.matches(b),
303            (Self::I32, _)
304            | (Self::I64, _)
305            | (Self::F32, _)
306            | (Self::F64, _)
307            | (Self::V128, _)
308            | (Self::Ref(_), _) => false,
309        }
310    }
311
312    /// Is value type `a` precisely equal to value type `b`?
313    ///
314    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
315    /// are not exactly the same value type.
316    ///
317    /// # Panics
318    ///
319    /// Panics if either type is associated with a different engine.
320    pub fn eq(a: &Self, b: &Self) -> bool {
321        a.matches(b) && b.matches(a)
322    }
323
324    /// Is this a `VMGcRef` type that is not i31 and is not an uninhabited
325    /// bottom type?
326    #[inline]
327    pub(crate) fn is_vmgcref_type_and_points_to_object(&self) -> bool {
328        match self {
329            ValType::Ref(r) => r.is_vmgcref_type_and_points_to_object(),
330            ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => false,
331        }
332    }
333
334    pub(crate) fn ensure_matches(&self, engine: &Engine, other: &ValType) -> Result<()> {
335        if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) {
336            bail!("type used with wrong engine");
337        }
338        if self.matches(other) {
339            Ok(())
340        } else {
341            bail!("type mismatch: expected {other}, found {self}")
342        }
343    }
344
345    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
346        match self {
347            Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128 => true,
348            Self::Ref(r) => r.comes_from_same_engine(engine),
349        }
350    }
351
352    pub(crate) fn to_wasm_type(&self) -> WasmValType {
353        match self {
354            Self::I32 => WasmValType::I32,
355            Self::I64 => WasmValType::I64,
356            Self::F32 => WasmValType::F32,
357            Self::F64 => WasmValType::F64,
358            Self::V128 => WasmValType::V128,
359            Self::Ref(r) => WasmValType::Ref(r.to_wasm_type()),
360        }
361    }
362
363    #[inline]
364    pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmValType) -> Self {
365        match ty {
366            WasmValType::I32 => Self::I32,
367            WasmValType::I64 => Self::I64,
368            WasmValType::F32 => Self::F32,
369            WasmValType::F64 => Self::F64,
370            WasmValType::V128 => Self::V128,
371            WasmValType::Ref(r) => Self::Ref(RefType::from_wasm_type(engine, r)),
372        }
373    }
374    /// Construct a default value. Returns None for non-nullable Ref types, which have no default.
375    pub fn default_value(&self) -> Option<Val> {
376        match self {
377            ValType::I32 => Some(Val::I32(0)),
378            ValType::I64 => Some(Val::I64(0)),
379            ValType::F32 => Some(Val::F32(0)),
380            ValType::F64 => Some(Val::F64(0)),
381            ValType::V128 => Some(Val::V128(0.into())),
382            ValType::Ref(r) => {
383                if r.is_nullable() {
384                    Some(Val::null_ref(r.heap_type()))
385                } else {
386                    None
387                }
388            }
389        }
390    }
391
392    pub(crate) fn into_registered_type(self) -> Option<RegisteredType> {
393        match self {
394            ValType::Ref(ty) => ty.into_registered_type(),
395            _ => None,
396        }
397    }
398}
399
400/// Opaque references to data in the Wasm heap or to host data.
401///
402/// # Subtyping and Equality
403///
404/// `RefType` does not implement `Eq`, because reference types have a subtyping
405/// relationship, and so 99.99% of the time you actually want to check whether
406/// one type matches (i.e. is a subtype of) another type. You can use the
407/// [`RefType::matches`] and [`Ref::matches_ty`][crate::Ref::matches_ty] methods
408/// to perform these types of checks. If, however, you are in that 0.01%
409/// scenario where you need to check precise equality between types, you can use
410/// the [`RefType::eq`] method.
411#[derive(Clone, Hash)]
412pub struct RefType {
413    is_nullable: bool,
414    heap_type: HeapType,
415}
416
417impl fmt::Debug for RefType {
418    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419        Display::fmt(self, f)
420    }
421}
422
423impl fmt::Display for RefType {
424    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
425        write!(f, "(ref ")?;
426        if self.is_nullable() {
427            write!(f, "null ")?;
428        }
429        write!(f, "{})", self.heap_type())
430    }
431}
432
433impl RefType {
434    /// The `externref` type, aka `(ref null extern)`.
435    pub const EXTERNREF: Self = RefType {
436        is_nullable: true,
437        heap_type: HeapType::Extern,
438    };
439
440    /// The `nullexternref` type, aka `(ref null noextern)`.
441    pub const NULLEXTERNREF: Self = RefType {
442        is_nullable: true,
443        heap_type: HeapType::NoExtern,
444    };
445
446    /// The `funcref` type, aka `(ref null func)`.
447    pub const FUNCREF: Self = RefType {
448        is_nullable: true,
449        heap_type: HeapType::Func,
450    };
451
452    /// The `nullfuncref` type, aka `(ref null nofunc)`.
453    pub const NULLFUNCREF: Self = RefType {
454        is_nullable: true,
455        heap_type: HeapType::NoFunc,
456    };
457
458    /// The `anyref` type, aka `(ref null any)`.
459    pub const ANYREF: Self = RefType {
460        is_nullable: true,
461        heap_type: HeapType::Any,
462    };
463
464    /// The `eqref` type, aka `(ref null eq)`.
465    pub const EQREF: Self = RefType {
466        is_nullable: true,
467        heap_type: HeapType::Eq,
468    };
469
470    /// The `i31ref` type, aka `(ref null i31)`.
471    pub const I31REF: Self = RefType {
472        is_nullable: true,
473        heap_type: HeapType::I31,
474    };
475
476    /// The `arrayref` type, aka `(ref null array)`.
477    pub const ARRAYREF: Self = RefType {
478        is_nullable: true,
479        heap_type: HeapType::Array,
480    };
481
482    /// The `structref` type, aka `(ref null struct)`.
483    pub const STRUCTREF: Self = RefType {
484        is_nullable: true,
485        heap_type: HeapType::Struct,
486    };
487
488    /// The `nullref` type, aka `(ref null none)`.
489    pub const NULLREF: Self = RefType {
490        is_nullable: true,
491        heap_type: HeapType::None,
492    };
493
494    /// The `contref` type, aka `(ref null cont)`.
495    pub const CONTREF: Self = RefType {
496        is_nullable: true,
497        heap_type: HeapType::Cont,
498    };
499
500    /// The `nullcontref` type, aka `(ref null nocont)`.
501    pub const NULLCONTREF: Self = RefType {
502        is_nullable: true,
503        heap_type: HeapType::NoCont,
504    };
505
506    /// The `exnref` type, aka `(ref null exn)`.
507    pub const EXNREF: Self = RefType {
508        is_nullable: true,
509        heap_type: HeapType::Exn,
510    };
511
512    /// The `nullexnref` type, aka `(ref null noexn)`.
513    pub const NULLEXNREF: Self = RefType {
514        is_nullable: true,
515        heap_type: HeapType::NoExn,
516    };
517
518    /// Construct a new reference type.
519    pub fn new(is_nullable: bool, heap_type: HeapType) -> RefType {
520        RefType {
521            is_nullable,
522            heap_type,
523        }
524    }
525
526    /// Can this type of reference be null?
527    pub fn is_nullable(&self) -> bool {
528        self.is_nullable
529    }
530
531    /// The heap type that this is a reference to.
532    #[inline]
533    pub fn heap_type(&self) -> &HeapType {
534        &self.heap_type
535    }
536
537    /// Does this reference type match the other?
538    ///
539    /// That is, is this reference type a subtype of the other?
540    ///
541    /// # Panics
542    ///
543    /// Panics if either type is associated with a different engine from the
544    /// other.
545    pub fn matches(&self, other: &RefType) -> bool {
546        if self.is_nullable() && !other.is_nullable() {
547            return false;
548        }
549        self.heap_type().matches(other.heap_type())
550    }
551
552    /// Is reference type `a` precisely equal to reference type `b`?
553    ///
554    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
555    /// are not exactly the same reference type.
556    ///
557    /// # Panics
558    ///
559    /// Panics if either type is associated with a different engine.
560    pub fn eq(a: &RefType, b: &RefType) -> bool {
561        a.matches(b) && b.matches(a)
562    }
563
564    pub(crate) fn ensure_matches(&self, engine: &Engine, other: &RefType) -> Result<()> {
565        if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) {
566            bail!("type used with wrong engine");
567        }
568        if self.matches(other) {
569            Ok(())
570        } else {
571            bail!("type mismatch: expected {other}, found {self}")
572        }
573    }
574
575    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
576        self.heap_type().comes_from_same_engine(engine)
577    }
578
579    pub(crate) fn to_wasm_type(&self) -> WasmRefType {
580        WasmRefType {
581            nullable: self.is_nullable(),
582            heap_type: self.heap_type().to_wasm_type(),
583        }
584    }
585
586    pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmRefType) -> RefType {
587        RefType {
588            is_nullable: ty.nullable,
589            heap_type: HeapType::from_wasm_type(engine, &ty.heap_type),
590        }
591    }
592
593    pub(crate) fn is_vmgcref_type_and_points_to_object(&self) -> bool {
594        self.heap_type().is_vmgcref_type_and_points_to_object()
595    }
596
597    pub(crate) fn into_registered_type(self) -> Option<RegisteredType> {
598        self.heap_type.into_registered_type()
599    }
600}
601
602/// The heap types that can Wasm can have references to.
603///
604/// # Subtyping Hierarchy
605///
606/// Wasm has three different heap type hierarchies:
607///
608/// 1. Function types
609/// 2. External types
610/// 3. Internal (struct and array) types
611/// 4. Exception types
612///
613/// Each hierarchy has a top type (the common supertype of which everything else
614/// in its hierarchy is a subtype of) and a bottom type (the common subtype of
615/// which everything else in its hierarchy is supertype of).
616///
617/// ## Function Types Hierarchy
618///
619/// The top of the function types hierarchy is `func`; the bottom is
620/// `nofunc`. In between are all the concrete function types.
621///
622/// ```text
623///                          func
624///                       /  /  \  \
625///      ,----------------  /    \  -------------------------.
626///     /                  /      \                           \
627///    |              ,----        -----------.                |
628///    |              |                       |                |
629///    |              |                       |                |
630/// (func)    (func (param i32))    (func (param i32 i32))    ...
631///    |              |                       |                |
632///    |              |                       |                |
633///    |              `---.        ,----------'                |
634///     \                  \      /                           /
635///      `---------------.  \    /  ,------------------------'
636///                       \  \  /  /
637///                         nofunc
638/// ```
639///
640/// Additionally, some concrete function types are sub- or supertypes of other
641/// concrete function types, if that was declared in their definition. For
642/// simplicity, this isn't depicted in the diagram above.
643///
644/// ## External
645///
646/// The top of the external types hierarchy is `extern`; the bottom is
647/// `noextern`. There are no concrete types in this hierarchy.
648///
649/// ```text
650///  extern
651///    |
652/// noextern
653/// ```
654///
655/// ## Internal
656///
657/// The top of the internal types hierarchy is `any`; the bottom is `none`. The
658/// `eq` type is the common supertype of all types that can be compared for
659/// equality. The `struct` and `array` types are the common supertypes of all
660/// concrete struct and array types respectively. The `i31` type represents
661/// unboxed 31-bit integers.
662///
663/// ```text
664///                                   any
665///                                  / | \
666///    ,----------------------------'  |  `--------------------------.
667///   /                                |                              \
668///  |                        .--------'                               |
669///  |                        |                                        |
670///  |                      struct                                   array
671///  |                     /  |   \                                 /  |   \
672/// i31             ,-----'   |    '-----.                   ,-----'   |    `-----.
673///  |             /          |           \                 /          |           \
674///  |            |           |            |               |           |            |
675///  |        (struct)    (struct i32)    ...        (array i32)    (array i64)    ...
676///  |            |           |            |               |           |            |
677///  |             \          |           /                 \          |           /
678///   \             `-----.   |    ,-----'                   `-----.   |    ,-----'
679///    \                   \  |   /                                 \  |   /
680///     \                   \ |  /                                   \ |  /
681///      \                   \| /                                     \| /
682///       \                   |/                                       |/
683///        \                  |                                        |
684///         \                 |                                       /
685///          \                '--------.                             /
686///           \                        |                            /
687///            `--------------------.  |   ,-----------------------'
688///                                  \ |  /
689///                                   none
690/// ```
691///
692/// Additionally, concrete struct and array types can be subtypes of other
693/// concrete struct and array types respectively, if that was declared in their
694/// definitions. Once again, this is omitted from the above diagram for
695/// simplicity.
696///
697/// ## Exceptions
698///
699/// The top of the exception types hierarchy is `exn`; the bottom is
700/// `noexn`. At the WebAssembly level, there are no concrete types in
701/// this hierarchy. However, internally we do reify a heap type for
702/// each tag, similar to how continuation objects work.
703///
704/// ```text
705///   exn
706///  / | \
707/// (exn $t) ...
708///  \ | /
709/// noexn
710/// ```
711///
712/// # Subtyping and Equality
713///
714/// `HeapType` does not implement `Eq`, because heap types have a subtyping
715/// relationship, and so 99.99% of the time you actually want to check whether
716/// one type matches (i.e. is a subtype of) another type. You can use the
717/// [`HeapType::matches`] method to perform these types of checks. If, however,
718/// you are in that 0.01% scenario where you need to check precise equality
719/// between types, you can use the [`HeapType::eq`] method.
720#[derive(Debug, Clone, Hash)]
721pub enum HeapType {
722    /// The abstract `extern` heap type represents external host data.
723    ///
724    /// This is the top type for the external type hierarchy, and therefore is
725    /// the common supertype of all external reference types.
726    Extern,
727
728    /// The abstract `noextern` heap type represents the null external
729    /// reference.
730    ///
731    /// This is the bottom type for the external type hierarchy, and therefore
732    /// is the common subtype of all external reference types.
733    NoExtern,
734
735    /// The abstract `func` heap type represents a reference to any kind of
736    /// function.
737    ///
738    /// This is the top type for the function references type hierarchy, and is
739    /// therefore a supertype of every function reference.
740    Func,
741
742    /// A reference to a function of a specific, concrete type.
743    ///
744    /// These are subtypes of `func` and supertypes of `nofunc`.
745    ConcreteFunc(FuncType),
746
747    /// The abstract `nofunc` heap type represents the null function reference.
748    ///
749    /// This is the bottom type for the function references type hierarchy, and
750    /// therefore `nofunc` is a subtype of all function reference types.
751    NoFunc,
752
753    /// The abstract `any` heap type represents all internal Wasm data.
754    ///
755    /// This is the top type of the internal type hierarchy, and is therefore a
756    /// supertype of all internal types (such as `eq`, `i31`, `struct`s, and
757    /// `array`s).
758    Any,
759
760    /// The abstract `eq` heap type represenets all internal Wasm references
761    /// that can be compared for equality.
762    ///
763    /// This is a subtype of `any` and a supertype of `i31`, `array`, `struct`,
764    /// and `none` heap types.
765    Eq,
766
767    /// The `i31` heap type represents unboxed 31-bit integers.
768    ///
769    /// This is a subtype of `any` and `eq`, and a supertype of `none`.
770    I31,
771
772    /// The abstract `array` heap type represents a reference to any kind of
773    /// array.
774    ///
775    /// This is a subtype of `any` and `eq`, and a supertype of all concrete
776    /// array types, as well as a supertype of the abstract `none` heap type.
777    Array,
778
779    /// A reference to an array of a specific, concrete type.
780    ///
781    /// These are subtypes of the `array` heap type (therefore also a subtype of
782    /// `any` and `eq`) and supertypes of the `none` heap type.
783    ConcreteArray(ArrayType),
784
785    /// The abstract `struct` heap type represents a reference to any kind of
786    /// struct.
787    ///
788    /// This is a subtype of `any` and `eq`, and a supertype of all concrete
789    /// struct types, as well as a supertype of the abstract `none` heap type.
790    Struct,
791
792    /// A reference to an struct of a specific, concrete type.
793    ///
794    /// These are subtypes of the `struct` heap type (therefore also a subtype
795    /// of `any` and `eq`) and supertypes of the `none` heap type.
796    ConcreteStruct(StructType),
797
798    /// The abstract `exn` heap type represents a reference to any
799    /// kind of exception.
800    ///
801    /// This is a supertype of the internal concrete exception heap
802    /// types and the `noexn` heap type.
803    Exn,
804
805    /// A concrete exception object with a specific tag.
806    ///
807    /// These are internal, not exposed at the Wasm level, but useful
808    /// in our implementation and host API. These are subtypes of
809    /// `exn` and supertypes of `noexn`.
810    ConcreteExn(ExnType),
811
812    /// A reference to a continuation of a specific, concrete type.
813    ///
814    /// These are subtypes of `cont` and supertypes of `nocont`.
815    ConcreteCont(ContType),
816
817    /// The `cont` heap type represents a reference to any kind of continuation.
818    ///
819    /// This is the top type for the continuation objects type hierarchy, and is
820    /// therefore a supertype of every continuation object.
821    Cont,
822
823    /// The `nocont` heap type represents the null continuation object.
824    ///
825    /// This is the bottom type for the continuation objects type hierarchy, and
826    /// therefore `nocont` is a subtype of all continuation object types.
827    NoCont,
828
829    /// The abstract `none` heap type represents the null internal reference.
830    ///
831    /// This is the bottom type for the internal type hierarchy, and therefore
832    /// `none` is a subtype of internal types.
833    None,
834
835    /// The `noexn` heap type represents the null exception object.
836    ///
837    /// This is the bottom type for the exception objects type hierarchy.
838    NoExn,
839}
840
841/// A top heap type.
842#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
843pub enum HeapTopType {
844    /// The common supertype of all external references.
845    Extern,
846    /// The common supertype of all internal references.
847    Any,
848    /// The common supertype of all function references.
849    Func,
850    /// The common supertype of all exception references.
851    Exn,
852    /// The common supertype of all continuation references.
853    Cont,
854}
855
856/// A bottom heap type.
857#[derive(Debug, Clone, Copy, Eq, PartialEq)]
858pub enum HeapBottomType {
859    /// The common subtype of all external references.
860    NoExtern,
861    /// The common subtype of all internal references.
862    None,
863    /// The common subtype of all function references.
864    NoFunc,
865    /// The common subtype of all exception references.
866    NoExn,
867    /// The common subtype of all continuation references.
868    NoCont,
869}
870
871impl From<HeapTopType> for HeapType {
872    fn from(value: HeapTopType) -> Self {
873        match value {
874            HeapTopType::Extern => Self::Extern,
875            HeapTopType::Any => Self::Any,
876            HeapTopType::Func => Self::Func,
877            HeapTopType::Exn => Self::Exn,
878            HeapTopType::Cont => Self::Cont,
879        }
880    }
881}
882
883impl From<HeapBottomType> for HeapType {
884    fn from(value: HeapBottomType) -> Self {
885        match value {
886            HeapBottomType::NoExtern => Self::NoExtern,
887            HeapBottomType::None => Self::None,
888            HeapBottomType::NoFunc => Self::NoFunc,
889            HeapBottomType::NoExn => Self::NoExn,
890            HeapBottomType::NoCont => Self::NoCont,
891        }
892    }
893}
894
895impl Display for HeapType {
896    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
897        match self {
898            HeapType::Extern => write!(f, "extern"),
899            HeapType::NoExtern => write!(f, "noextern"),
900            HeapType::Func => write!(f, "func"),
901            HeapType::NoFunc => write!(f, "nofunc"),
902            HeapType::Any => write!(f, "any"),
903            HeapType::Eq => write!(f, "eq"),
904            HeapType::I31 => write!(f, "i31"),
905            HeapType::Array => write!(f, "array"),
906            HeapType::Struct => write!(f, "struct"),
907            HeapType::None => write!(f, "none"),
908            HeapType::ConcreteFunc(ty) => write!(f, "(concrete func {:?})", ty.type_index()),
909            HeapType::ConcreteArray(ty) => write!(f, "(concrete array {:?})", ty.type_index()),
910            HeapType::ConcreteStruct(ty) => write!(f, "(concrete struct {:?})", ty.type_index()),
911            HeapType::ConcreteCont(ty) => write!(f, "(concrete cont {:?})", ty.type_index()),
912            HeapType::ConcreteExn(ty) => write!(f, "(concrete exn {:?})", ty.type_index()),
913            HeapType::Cont => write!(f, "cont"),
914            HeapType::NoCont => write!(f, "nocont"),
915            HeapType::Exn => write!(f, "exn"),
916            HeapType::NoExn => write!(f, "noexn"),
917        }
918    }
919}
920
921impl From<FuncType> for HeapType {
922    #[inline]
923    fn from(f: FuncType) -> Self {
924        HeapType::ConcreteFunc(f)
925    }
926}
927
928impl From<ArrayType> for HeapType {
929    #[inline]
930    fn from(a: ArrayType) -> Self {
931        HeapType::ConcreteArray(a)
932    }
933}
934
935impl From<StructType> for HeapType {
936    #[inline]
937    fn from(s: StructType) -> Self {
938        HeapType::ConcreteStruct(s)
939    }
940}
941
942impl From<ContType> for HeapType {
943    #[inline]
944    fn from(f: ContType) -> Self {
945        HeapType::ConcreteCont(f)
946    }
947}
948
949impl From<ExnType> for HeapType {
950    #[inline]
951    fn from(e: ExnType) -> Self {
952        HeapType::ConcreteExn(e)
953    }
954}
955
956impl HeapType {
957    /// Is this the abstract `extern` heap type?
958    pub fn is_extern(&self) -> bool {
959        matches!(self, HeapType::Extern)
960    }
961
962    /// Is this the abstract `func` heap type?
963    pub fn is_func(&self) -> bool {
964        matches!(self, HeapType::Func)
965    }
966
967    /// Is this the abstract `nofunc` heap type?
968    pub fn is_no_func(&self) -> bool {
969        matches!(self, HeapType::NoFunc)
970    }
971
972    /// Is this the abstract `any` heap type?
973    pub fn is_any(&self) -> bool {
974        matches!(self, HeapType::Any)
975    }
976
977    /// Is this the abstract `i31` heap type?
978    pub fn is_i31(&self) -> bool {
979        matches!(self, HeapType::I31)
980    }
981
982    /// Is this the abstract `none` heap type?
983    pub fn is_none(&self) -> bool {
984        matches!(self, HeapType::None)
985    }
986
987    /// Is this the abstract `cont` heap type?
988    pub fn is_cont(&self) -> bool {
989        matches!(self, HeapType::Cont)
990    }
991
992    /// Is this the abstract `exn` heap type?
993    pub fn is_exn(&self) -> bool {
994        matches!(self, HeapType::Exn)
995    }
996
997    /// Is this the abstract `noexn` heap type?
998    pub fn is_no_exn(&self) -> bool {
999        matches!(self, HeapType::NoExn)
1000    }
1001
1002    /// Is this an abstract type?
1003    ///
1004    /// Types that are not abstract are concrete, user-defined types.
1005    pub fn is_abstract(&self) -> bool {
1006        !self.is_concrete()
1007    }
1008
1009    /// Is this a concrete, user-defined heap type?
1010    ///
1011    /// Types that are not concrete, user-defined types are abstract types.
1012    #[inline]
1013    pub fn is_concrete(&self) -> bool {
1014        matches!(
1015            self,
1016            HeapType::ConcreteFunc(_)
1017                | HeapType::ConcreteArray(_)
1018                | HeapType::ConcreteStruct(_)
1019                | HeapType::ConcreteCont(_)
1020                | HeapType::ConcreteExn(_)
1021        )
1022    }
1023
1024    /// Is this a concrete, user-defined function type?
1025    pub fn is_concrete_func(&self) -> bool {
1026        matches!(self, HeapType::ConcreteFunc(_))
1027    }
1028
1029    /// Get the underlying concrete, user-defined function type, if any.
1030    ///
1031    /// Returns `None` if this is not a concrete function type.
1032    pub fn as_concrete_func(&self) -> Option<&FuncType> {
1033        match self {
1034            HeapType::ConcreteFunc(f) => Some(f),
1035            _ => None,
1036        }
1037    }
1038
1039    /// Get the underlying concrete, user-defined type, panicking if this is not
1040    /// a concrete function type.
1041    pub fn unwrap_concrete_func(&self) -> &FuncType {
1042        self.as_concrete_func().unwrap()
1043    }
1044
1045    /// Is this a concrete, user-defined array type?
1046    pub fn is_concrete_array(&self) -> bool {
1047        matches!(self, HeapType::ConcreteArray(_))
1048    }
1049
1050    /// Get the underlying concrete, user-defined array type, if any.
1051    ///
1052    /// Returns `None` for if this is not a concrete array type.
1053    pub fn as_concrete_array(&self) -> Option<&ArrayType> {
1054        match self {
1055            HeapType::ConcreteArray(f) => Some(f),
1056            _ => None,
1057        }
1058    }
1059
1060    /// Get the underlying concrete, user-defined type, panicking if this is not
1061    /// a concrete array type.
1062    pub fn unwrap_concrete_array(&self) -> &ArrayType {
1063        self.as_concrete_array().unwrap()
1064    }
1065
1066    /// Is this a concrete, user-defined continuation type?
1067    pub fn is_concrete_cont(&self) -> bool {
1068        matches!(self, HeapType::ConcreteCont(_))
1069    }
1070
1071    /// Get the underlying concrete, user-defined continuation type, if any.
1072    ///
1073    /// Returns `None` if this is not a concrete continuation type.
1074    pub fn as_concrete_cont(&self) -> Option<&ContType> {
1075        match self {
1076            HeapType::ConcreteCont(f) => Some(f),
1077            _ => None,
1078        }
1079    }
1080
1081    /// Is this a concrete, user-defined struct type?
1082    pub fn is_concrete_struct(&self) -> bool {
1083        matches!(self, HeapType::ConcreteStruct(_))
1084    }
1085
1086    /// Get the underlying concrete, user-defined struct type, if any.
1087    ///
1088    /// Returns `None` for if this is not a concrete struct type.
1089    pub fn as_concrete_struct(&self) -> Option<&StructType> {
1090        match self {
1091            HeapType::ConcreteStruct(f) => Some(f),
1092            _ => None,
1093        }
1094    }
1095
1096    /// Get the underlying concrete, user-defined type, panicking if this is not
1097    /// a concrete continuation type.
1098    pub fn unwrap_concrete_cont(&self) -> &ContType {
1099        self.as_concrete_cont().unwrap()
1100    }
1101
1102    /// Get the underlying concrete, user-defined type, panicking if this is not
1103    /// a concrete struct type.
1104    pub fn unwrap_concrete_struct(&self) -> &StructType {
1105        self.as_concrete_struct().unwrap()
1106    }
1107
1108    /// Is this a concrete, user-defined exception type?
1109    pub fn is_concrete_exn(&self) -> bool {
1110        matches!(self, HeapType::ConcreteExn(_))
1111    }
1112
1113    /// Get the underlying concrete, user-defined exception type, if any.
1114    ///
1115    /// Returns `None` if this is not a concrete exception type.
1116    pub fn as_concrete_exn(&self) -> Option<&ExnType> {
1117        match self {
1118            HeapType::ConcreteExn(e) => Some(e),
1119            _ => None,
1120        }
1121    }
1122
1123    /// Get the top type of this heap type's type hierarchy.
1124    ///
1125    /// The returned type represents a supertype of all types in this heap
1126    /// type's type hierarchy.
1127    #[inline]
1128    pub fn top(&self) -> HeapTopType {
1129        match self {
1130            HeapType::Func | HeapType::ConcreteFunc(_) | HeapType::NoFunc => HeapTopType::Func,
1131
1132            HeapType::Extern | HeapType::NoExtern => HeapTopType::Extern,
1133
1134            HeapType::Any
1135            | HeapType::Eq
1136            | HeapType::I31
1137            | HeapType::Array
1138            | HeapType::ConcreteArray(_)
1139            | HeapType::Struct
1140            | HeapType::ConcreteStruct(_)
1141            | HeapType::None => HeapTopType::Any,
1142
1143            HeapType::Cont | HeapType::ConcreteCont(_) | HeapType::NoCont => HeapTopType::Cont,
1144
1145            HeapType::Exn | HeapType::ConcreteExn(_) | HeapType::NoExn => HeapTopType::Exn,
1146        }
1147    }
1148
1149    /// Is this the top type within its type hierarchy?
1150    #[inline]
1151    pub fn is_top(&self) -> bool {
1152        match self {
1153            HeapType::Any | HeapType::Extern | HeapType::Func | HeapType::Cont | HeapType::Exn => {
1154                true
1155            }
1156            _ => false,
1157        }
1158    }
1159
1160    /// Get the bottom type of this heap type's type hierarchy.
1161    ///
1162    /// The returned type represents a subtype of all types in this heap type's
1163    /// type hierarchy.
1164    #[inline]
1165    pub fn bottom(&self) -> HeapBottomType {
1166        match self {
1167            HeapType::Extern | HeapType::NoExtern => HeapBottomType::NoExtern,
1168
1169            HeapType::Func | HeapType::ConcreteFunc(_) | HeapType::NoFunc => HeapBottomType::NoFunc,
1170
1171            HeapType::Any
1172            | HeapType::Eq
1173            | HeapType::I31
1174            | HeapType::Array
1175            | HeapType::ConcreteArray(_)
1176            | HeapType::Struct
1177            | HeapType::ConcreteStruct(_)
1178            | HeapType::None => HeapBottomType::None,
1179
1180            HeapType::Cont | HeapType::ConcreteCont(_) | HeapType::NoCont => HeapBottomType::NoCont,
1181
1182            HeapType::Exn | HeapType::ConcreteExn(_) | HeapType::NoExn => HeapBottomType::NoExn,
1183        }
1184    }
1185
1186    /// Is this the bottom type within its type hierarchy?
1187    #[inline]
1188    pub fn is_bottom(&self) -> bool {
1189        match self {
1190            HeapType::None
1191            | HeapType::NoExtern
1192            | HeapType::NoFunc
1193            | HeapType::NoCont
1194            | HeapType::NoExn => true,
1195            _ => false,
1196        }
1197    }
1198
1199    /// Does this heap type match the other heap type?
1200    ///
1201    /// That is, is this heap type a subtype of the other?
1202    ///
1203    /// # Panics
1204    ///
1205    /// Panics if either type is associated with a different engine from the
1206    /// other.
1207    pub fn matches(&self, other: &HeapType) -> bool {
1208        match (self, other) {
1209            (HeapType::Extern, HeapType::Extern) => true,
1210            (HeapType::Extern, _) => false,
1211
1212            (HeapType::NoExtern, HeapType::NoExtern | HeapType::Extern) => true,
1213            (HeapType::NoExtern, _) => false,
1214
1215            (HeapType::NoFunc, HeapType::NoFunc | HeapType::ConcreteFunc(_) | HeapType::Func) => {
1216                true
1217            }
1218            (HeapType::NoFunc, _) => false,
1219
1220            (HeapType::ConcreteFunc(_), HeapType::Func) => true,
1221            (HeapType::ConcreteFunc(a), HeapType::ConcreteFunc(b)) => {
1222                assert!(a.comes_from_same_engine(b.engine()));
1223                a.engine()
1224                    .signatures()
1225                    .is_subtype(a.type_index(), b.type_index())
1226            }
1227            (HeapType::ConcreteFunc(_), _) => false,
1228
1229            (HeapType::Func, HeapType::Func) => true,
1230            (HeapType::Func, _) => false,
1231
1232            (HeapType::Cont, HeapType::Cont) => true,
1233            (HeapType::Cont, _) => false,
1234
1235            (HeapType::NoCont, HeapType::NoCont | HeapType::ConcreteCont(_) | HeapType::Cont) => {
1236                true
1237            }
1238            (HeapType::NoCont, _) => false,
1239
1240            (HeapType::ConcreteCont(_), HeapType::Cont) => true,
1241            (HeapType::ConcreteCont(a), HeapType::ConcreteCont(b)) => a.matches(b),
1242            (HeapType::ConcreteCont(_), _) => false,
1243
1244            (
1245                HeapType::None,
1246                HeapType::None
1247                | HeapType::ConcreteArray(_)
1248                | HeapType::Array
1249                | HeapType::ConcreteStruct(_)
1250                | HeapType::Struct
1251                | HeapType::I31
1252                | HeapType::Eq
1253                | HeapType::Any,
1254            ) => true,
1255            (HeapType::None, _) => false,
1256
1257            (HeapType::ConcreteArray(_), HeapType::Array | HeapType::Eq | HeapType::Any) => true,
1258            (HeapType::ConcreteArray(a), HeapType::ConcreteArray(b)) => {
1259                assert!(a.comes_from_same_engine(b.engine()));
1260                a.engine()
1261                    .signatures()
1262                    .is_subtype(a.type_index(), b.type_index())
1263            }
1264            (HeapType::ConcreteArray(_), _) => false,
1265
1266            (HeapType::Array, HeapType::Array | HeapType::Eq | HeapType::Any) => true,
1267            (HeapType::Array, _) => false,
1268
1269            (HeapType::ConcreteStruct(_), HeapType::Struct | HeapType::Eq | HeapType::Any) => true,
1270            (HeapType::ConcreteStruct(a), HeapType::ConcreteStruct(b)) => {
1271                assert!(a.comes_from_same_engine(b.engine()));
1272                a.engine()
1273                    .signatures()
1274                    .is_subtype(a.type_index(), b.type_index())
1275            }
1276            (HeapType::ConcreteStruct(_), _) => false,
1277
1278            (HeapType::Struct, HeapType::Struct | HeapType::Eq | HeapType::Any) => true,
1279            (HeapType::Struct, _) => false,
1280
1281            (HeapType::I31, HeapType::I31 | HeapType::Eq | HeapType::Any) => true,
1282            (HeapType::I31, _) => false,
1283
1284            (HeapType::Eq, HeapType::Eq | HeapType::Any) => true,
1285            (HeapType::Eq, _) => false,
1286
1287            (HeapType::Any, HeapType::Any) => true,
1288            (HeapType::Any, _) => false,
1289
1290            (HeapType::NoExn, HeapType::Exn | HeapType::ConcreteExn(_) | HeapType::NoExn) => true,
1291            (HeapType::NoExn, _) => false,
1292
1293            (HeapType::ConcreteExn(_), HeapType::Exn) => true,
1294            (HeapType::ConcreteExn(a), HeapType::ConcreteExn(b)) => a.matches(b),
1295            (HeapType::ConcreteExn(_), _) => false,
1296
1297            (HeapType::Exn, HeapType::Exn) => true,
1298            (HeapType::Exn, _) => false,
1299        }
1300    }
1301
1302    /// Is heap type `a` precisely equal to heap type `b`?
1303    ///
1304    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
1305    /// are not exactly the same heap type.
1306    ///
1307    /// # Panics
1308    ///
1309    /// Panics if either type is associated with a different engine from the
1310    /// other.
1311    pub fn eq(a: &HeapType, b: &HeapType) -> bool {
1312        a.matches(b) && b.matches(a)
1313    }
1314
1315    pub(crate) fn ensure_matches(&self, engine: &Engine, other: &HeapType) -> Result<()> {
1316        if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) {
1317            bail!("type used with wrong engine");
1318        }
1319        if self.matches(other) {
1320            Ok(())
1321        } else {
1322            bail!("type mismatch: expected {other}, found {self}");
1323        }
1324    }
1325
1326    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
1327        match self {
1328            HeapType::Extern
1329            | HeapType::NoExtern
1330            | HeapType::Func
1331            | HeapType::NoFunc
1332            | HeapType::Any
1333            | HeapType::Eq
1334            | HeapType::I31
1335            | HeapType::Array
1336            | HeapType::Struct
1337            | HeapType::Cont
1338            | HeapType::NoCont
1339            | HeapType::Exn
1340            | HeapType::NoExn
1341            | HeapType::None => true,
1342            HeapType::ConcreteFunc(ty) => ty.comes_from_same_engine(engine),
1343            HeapType::ConcreteArray(ty) => ty.comes_from_same_engine(engine),
1344            HeapType::ConcreteStruct(ty) => ty.comes_from_same_engine(engine),
1345            HeapType::ConcreteCont(ty) => ty.comes_from_same_engine(engine),
1346            HeapType::ConcreteExn(ty) => ty.comes_from_same_engine(engine),
1347        }
1348    }
1349
1350    pub(crate) fn to_wasm_type(&self) -> WasmHeapType {
1351        match self {
1352            HeapType::Extern => WasmHeapType::Extern,
1353            HeapType::NoExtern => WasmHeapType::NoExtern,
1354            HeapType::Func => WasmHeapType::Func,
1355            HeapType::NoFunc => WasmHeapType::NoFunc,
1356            HeapType::Any => WasmHeapType::Any,
1357            HeapType::Eq => WasmHeapType::Eq,
1358            HeapType::I31 => WasmHeapType::I31,
1359            HeapType::Array => WasmHeapType::Array,
1360            HeapType::Struct => WasmHeapType::Struct,
1361            HeapType::None => WasmHeapType::None,
1362            HeapType::ConcreteFunc(f) => {
1363                WasmHeapType::ConcreteFunc(EngineOrModuleTypeIndex::Engine(f.type_index()))
1364            }
1365            HeapType::ConcreteArray(a) => {
1366                WasmHeapType::ConcreteArray(EngineOrModuleTypeIndex::Engine(a.type_index()))
1367            }
1368            HeapType::ConcreteStruct(a) => {
1369                WasmHeapType::ConcreteStruct(EngineOrModuleTypeIndex::Engine(a.type_index()))
1370            }
1371            HeapType::Cont => WasmHeapType::Cont,
1372            HeapType::NoCont => WasmHeapType::NoCont,
1373            HeapType::ConcreteCont(c) => {
1374                WasmHeapType::ConcreteCont(EngineOrModuleTypeIndex::Engine(c.type_index()))
1375            }
1376            HeapType::Exn => WasmHeapType::Exn,
1377            HeapType::NoExn => WasmHeapType::NoExn,
1378            HeapType::ConcreteExn(e) => {
1379                WasmHeapType::ConcreteExn(EngineOrModuleTypeIndex::Engine(e.type_index()))
1380            }
1381        }
1382    }
1383
1384    pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmHeapType) -> HeapType {
1385        match ty {
1386            WasmHeapType::Extern => HeapType::Extern,
1387            WasmHeapType::NoExtern => HeapType::NoExtern,
1388            WasmHeapType::Func => HeapType::Func,
1389            WasmHeapType::NoFunc => HeapType::NoFunc,
1390            WasmHeapType::Any => HeapType::Any,
1391            WasmHeapType::Eq => HeapType::Eq,
1392            WasmHeapType::I31 => HeapType::I31,
1393            WasmHeapType::Array => HeapType::Array,
1394            WasmHeapType::Struct => HeapType::Struct,
1395            WasmHeapType::None => HeapType::None,
1396            WasmHeapType::ConcreteFunc(EngineOrModuleTypeIndex::Engine(idx)) => {
1397                HeapType::ConcreteFunc(FuncType::from_shared_type_index(engine, *idx).unwrap())
1398            }
1399            WasmHeapType::ConcreteArray(EngineOrModuleTypeIndex::Engine(idx)) => {
1400                HeapType::ConcreteArray(ArrayType::from_shared_type_index(engine, *idx).unwrap())
1401            }
1402            WasmHeapType::ConcreteStruct(EngineOrModuleTypeIndex::Engine(idx)) => {
1403                HeapType::ConcreteStruct(StructType::from_shared_type_index(engine, *idx).unwrap())
1404            }
1405
1406            WasmHeapType::ConcreteFunc(EngineOrModuleTypeIndex::Module(_))
1407            | WasmHeapType::ConcreteFunc(EngineOrModuleTypeIndex::RecGroup(_))
1408            | WasmHeapType::ConcreteArray(EngineOrModuleTypeIndex::Module(_))
1409            | WasmHeapType::ConcreteArray(EngineOrModuleTypeIndex::RecGroup(_))
1410            | WasmHeapType::ConcreteStruct(EngineOrModuleTypeIndex::Module(_))
1411            | WasmHeapType::ConcreteStruct(EngineOrModuleTypeIndex::RecGroup(_))
1412            | WasmHeapType::ConcreteCont(EngineOrModuleTypeIndex::Module(_))
1413            | WasmHeapType::ConcreteCont(EngineOrModuleTypeIndex::RecGroup(_))
1414            | WasmHeapType::ConcreteExn(EngineOrModuleTypeIndex::Module(_))
1415            | WasmHeapType::ConcreteExn(EngineOrModuleTypeIndex::RecGroup(_)) => {
1416                panic!("HeapType::from_wasm_type on non-canonicalized-for-runtime-usage heap type")
1417            }
1418            WasmHeapType::Cont => HeapType::Cont,
1419            WasmHeapType::NoCont => HeapType::NoCont,
1420            WasmHeapType::ConcreteCont(EngineOrModuleTypeIndex::Engine(idx)) => {
1421                HeapType::ConcreteCont(ContType::from_shared_type_index(engine, *idx).unwrap())
1422            }
1423            WasmHeapType::Exn => HeapType::Exn,
1424            WasmHeapType::NoExn => HeapType::NoExn,
1425            WasmHeapType::ConcreteExn(EngineOrModuleTypeIndex::Engine(idx)) => {
1426                HeapType::ConcreteExn(ExnType::from_shared_type_index(engine, *idx).unwrap())
1427            }
1428        }
1429    }
1430
1431    pub(crate) fn as_registered_type(&self) -> Option<&RegisteredType> {
1432        match self {
1433            HeapType::ConcreteCont(c) => Some(&c.registered_type),
1434            HeapType::ConcreteFunc(f) => Some(&f.registered_type),
1435            HeapType::ConcreteArray(a) => Some(&a.registered_type),
1436            HeapType::ConcreteStruct(a) => Some(&a.registered_type),
1437            HeapType::ConcreteExn(e) => Some(&e.registered_type),
1438
1439            HeapType::Extern
1440            | HeapType::NoExtern
1441            | HeapType::Func
1442            | HeapType::NoFunc
1443            | HeapType::Any
1444            | HeapType::Eq
1445            | HeapType::I31
1446            | HeapType::Array
1447            | HeapType::Struct
1448            | HeapType::Cont
1449            | HeapType::NoCont
1450            | HeapType::Exn
1451            | HeapType::NoExn
1452            | HeapType::None => None,
1453        }
1454    }
1455
1456    #[inline]
1457    pub(crate) fn is_vmgcref_type(&self) -> bool {
1458        match self.top() {
1459            HeapTopType::Any | HeapTopType::Extern | HeapTopType::Exn => true,
1460            HeapTopType::Func | HeapTopType::Cont => false,
1461        }
1462    }
1463
1464    /// Is this a `VMGcRef` type that is not i31 and is not an uninhabited
1465    /// bottom type?
1466    #[inline]
1467    pub(crate) fn is_vmgcref_type_and_points_to_object(&self) -> bool {
1468        self.is_vmgcref_type()
1469            && !matches!(
1470                self,
1471                HeapType::I31 | HeapType::NoExtern | HeapType::NoFunc | HeapType::None
1472            )
1473    }
1474
1475    pub(crate) fn into_registered_type(self) -> Option<RegisteredType> {
1476        use HeapType::*;
1477        match self {
1478            ConcreteFunc(ty) => Some(ty.registered_type),
1479            ConcreteArray(ty) => Some(ty.registered_type),
1480            ConcreteStruct(ty) => Some(ty.registered_type),
1481            ConcreteCont(ty) => Some(ty.registered_type),
1482            ConcreteExn(ty) => Some(ty.registered_type),
1483            Extern | NoExtern | Func | NoFunc | Any | Eq | I31 | Array | Struct | Cont | NoCont
1484            | Exn | NoExn | None => Option::None,
1485        }
1486    }
1487}
1488
1489// External Types
1490
1491/// A list of all possible types which can be externally referenced from a
1492/// WebAssembly module.
1493///
1494/// This list can be found in [`ImportType`] or [`ExportType`], so these types
1495/// can either be imported or exported.
1496#[derive(Debug, Clone)]
1497pub enum ExternType {
1498    /// This external type is the type of a WebAssembly function.
1499    Func(FuncType),
1500    /// This external type is the type of a WebAssembly global.
1501    Global(GlobalType),
1502    /// This external type is the type of a WebAssembly table.
1503    Table(TableType),
1504    /// This external type is the type of a WebAssembly memory.
1505    Memory(MemoryType),
1506    /// This external type is the type of a WebAssembly tag.
1507    Tag(TagType),
1508}
1509
1510macro_rules! extern_type_accessors {
1511    ($(($variant:ident($ty:ty) $get:ident $unwrap:ident))*) => ($(
1512        /// Attempt to return the underlying type of this external type,
1513        /// returning `None` if it is a different type.
1514        pub fn $get(&self) -> Option<&$ty> {
1515            if let ExternType::$variant(e) = self {
1516                Some(e)
1517            } else {
1518                None
1519            }
1520        }
1521
1522        /// Returns the underlying descriptor of this [`ExternType`], panicking
1523        /// if it is a different type.
1524        ///
1525        /// # Panics
1526        ///
1527        /// Panics if `self` is not of the right type.
1528        pub fn $unwrap(&self) -> &$ty {
1529            self.$get().expect(concat!("expected ", stringify!($ty)))
1530        }
1531    )*)
1532}
1533
1534impl ExternType {
1535    extern_type_accessors! {
1536        (Func(FuncType) func unwrap_func)
1537        (Global(GlobalType) global unwrap_global)
1538        (Table(TableType) table unwrap_table)
1539        (Memory(MemoryType) memory unwrap_memory)
1540        (Tag(TagType) tag unwrap_tag)
1541    }
1542
1543    pub(crate) fn from_wasmtime(
1544        engine: &Engine,
1545        types: &ModuleTypes,
1546        ty: &EntityType,
1547    ) -> ExternType {
1548        match ty {
1549            EntityType::Function(idx) => match idx {
1550                EngineOrModuleTypeIndex::Engine(e) => {
1551                    FuncType::from_shared_type_index(engine, *e).unwrap().into()
1552                }
1553                EngineOrModuleTypeIndex::Module(m) => {
1554                    let subty = &types[*m];
1555                    debug_assert!(subty.is_canonicalized_for_runtime_usage());
1556                    // subty.canonicalize_for_runtime_usage(&mut |idx| {
1557                    //     signatures.shared_type(idx).unwrap()
1558                    // });
1559                    FuncType::from_wasm_func_type(
1560                        engine,
1561                        subty.is_final,
1562                        subty.supertype,
1563                        subty.unwrap_func().clone_panic_on_oom(),
1564                    )
1565                    .panic_on_oom()
1566                    .into()
1567                }
1568                EngineOrModuleTypeIndex::RecGroup(_) => unreachable!(),
1569            },
1570            EntityType::Global(ty) => GlobalType::from_wasmtime_global(engine, ty).into(),
1571            EntityType::Memory(ty) => MemoryType::from_wasmtime_memory(ty).into(),
1572            EntityType::Table(ty) => TableType::from_wasmtime_table(engine, ty).into(),
1573            EntityType::Tag(ty) => TagType::from_wasmtime_tag(engine, ty).into(),
1574        }
1575    }
1576    /// Construct a default value, if possible, for the underlying type.
1577    pub fn default_value(&self, store: impl AsContextMut) -> Result<Extern> {
1578        match self {
1579            ExternType::Func(func_ty) => func_ty.default_value(store).map(Extern::Func),
1580            ExternType::Global(global_ty) => global_ty.default_value(store).map(Extern::Global),
1581            ExternType::Table(table_ty) => table_ty.default_value(store).map(Extern::Table),
1582            ExternType::Memory(mem_ty) => mem_ty.default_value(store),
1583            ExternType::Tag(tag_ty) => tag_ty.default_value(store).map(Extern::Tag),
1584        }
1585    }
1586}
1587
1588impl From<FuncType> for ExternType {
1589    fn from(ty: FuncType) -> ExternType {
1590        ExternType::Func(ty)
1591    }
1592}
1593
1594impl From<GlobalType> for ExternType {
1595    fn from(ty: GlobalType) -> ExternType {
1596        ExternType::Global(ty)
1597    }
1598}
1599
1600impl From<MemoryType> for ExternType {
1601    fn from(ty: MemoryType) -> ExternType {
1602        ExternType::Memory(ty)
1603    }
1604}
1605
1606impl From<TableType> for ExternType {
1607    fn from(ty: TableType) -> ExternType {
1608        ExternType::Table(ty)
1609    }
1610}
1611
1612impl From<TagType> for ExternType {
1613    fn from(ty: TagType) -> ExternType {
1614        ExternType::Tag(ty)
1615    }
1616}
1617
1618/// The storage type of a `struct` field or `array` element.
1619///
1620/// This is either a packed 8- or -16 bit integer, or else it is some unpacked
1621/// Wasm value type.
1622#[derive(Debug, Clone, Hash)]
1623pub enum StorageType {
1624    /// `i8`, an 8-bit integer.
1625    I8,
1626    /// `i16`, a 16-bit integer.
1627    I16,
1628    /// A value type.
1629    ValType(ValType),
1630}
1631
1632impl fmt::Display for StorageType {
1633    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1634        match self {
1635            StorageType::I8 => write!(f, "i8"),
1636            StorageType::I16 => write!(f, "i16"),
1637            StorageType::ValType(ty) => fmt::Display::fmt(ty, f),
1638        }
1639    }
1640}
1641
1642impl From<ValType> for StorageType {
1643    #[inline]
1644    fn from(v: ValType) -> Self {
1645        StorageType::ValType(v)
1646    }
1647}
1648
1649impl From<RefType> for StorageType {
1650    #[inline]
1651    fn from(r: RefType) -> Self {
1652        StorageType::ValType(r.into())
1653    }
1654}
1655
1656impl StorageType {
1657    /// Is this an `i8`?
1658    #[inline]
1659    pub fn is_i8(&self) -> bool {
1660        matches!(self, Self::I8)
1661    }
1662
1663    /// Is this an `i16`?
1664    #[inline]
1665    pub fn is_i16(&self) -> bool {
1666        matches!(self, Self::I16)
1667    }
1668
1669    /// Is this a Wasm value type?
1670    #[inline]
1671    pub fn is_val_type(&self) -> bool {
1672        matches!(self, Self::I16)
1673    }
1674
1675    /// Get this storage type's underlying value type, if any.
1676    ///
1677    /// Returns `None` if this storage type is not a value type.
1678    #[inline]
1679    pub fn as_val_type(&self) -> Option<&ValType> {
1680        match self {
1681            Self::ValType(v) => Some(v),
1682            _ => None,
1683        }
1684    }
1685
1686    /// Get this storage type's underlying value type, panicking if it is not a
1687    /// value type.
1688    pub fn unwrap_val_type(&self) -> &ValType {
1689        self.as_val_type().unwrap()
1690    }
1691
1692    /// Unpack this (possibly packed) storage type into a full `ValType`.
1693    ///
1694    /// If this is a `StorageType::ValType`, then the inner `ValType` is
1695    /// returned as-is.
1696    ///
1697    /// If this is a packed `StorageType::I8` or `StorageType::I16, then a
1698    /// `ValType::I32` is returned.
1699    pub fn unpack(&self) -> &ValType {
1700        match self {
1701            StorageType::I8 | StorageType::I16 => &ValType::I32,
1702            StorageType::ValType(ty) => ty,
1703        }
1704    }
1705
1706    /// Does this field type match the other field type?
1707    ///
1708    /// That is, is this field type a subtype of the other field type?
1709    ///
1710    /// # Panics
1711    ///
1712    /// Panics if either type is associated with a different engine from the
1713    /// other.
1714    pub fn matches(&self, other: &Self) -> bool {
1715        match (self, other) {
1716            (StorageType::I8, StorageType::I8) => true,
1717            (StorageType::I8, _) => false,
1718            (StorageType::I16, StorageType::I16) => true,
1719            (StorageType::I16, _) => false,
1720            (StorageType::ValType(a), StorageType::ValType(b)) => a.matches(b),
1721            (StorageType::ValType(_), _) => false,
1722        }
1723    }
1724
1725    /// Is field type `a` precisely equal to field type `b`?
1726    ///
1727    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
1728    /// are not exactly the same field type.
1729    ///
1730    /// # Panics
1731    ///
1732    /// Panics if either type is associated with a different engine from the
1733    /// other.
1734    pub fn eq(a: &Self, b: &Self) -> bool {
1735        match (a, b) {
1736            (StorageType::I8, StorageType::I8) => true,
1737            (StorageType::I8, _) => false,
1738            (StorageType::I16, StorageType::I16) => true,
1739            (StorageType::I16, _) => false,
1740            (StorageType::ValType(a), StorageType::ValType(b)) => ValType::eq(a, b),
1741            (StorageType::ValType(_), _) => false,
1742        }
1743    }
1744
1745    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
1746        match self {
1747            StorageType::I8 | StorageType::I16 => true,
1748            StorageType::ValType(v) => v.comes_from_same_engine(engine),
1749        }
1750    }
1751
1752    pub(crate) fn from_wasm_storage_type(engine: &Engine, ty: &WasmStorageType) -> Self {
1753        match ty {
1754            WasmStorageType::I8 => Self::I8,
1755            WasmStorageType::I16 => Self::I16,
1756            WasmStorageType::Val(v) => ValType::from_wasm_type(engine, &v).into(),
1757        }
1758    }
1759
1760    pub(crate) fn to_wasm_storage_type(&self) -> WasmStorageType {
1761        match self {
1762            Self::I8 => WasmStorageType::I8,
1763            Self::I16 => WasmStorageType::I16,
1764            Self::ValType(v) => WasmStorageType::Val(v.to_wasm_type()),
1765        }
1766    }
1767}
1768
1769/// The type of a `struct` field or an `array`'s elements.
1770///
1771/// This is a pair of both the field's storage type and its mutability
1772/// (i.e. whether the field can be updated or not).
1773#[derive(Clone, Hash)]
1774pub struct FieldType {
1775    mutability: Mutability,
1776    element_type: StorageType,
1777}
1778
1779impl fmt::Display for FieldType {
1780    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1781        if self.mutability.is_var() {
1782            write!(f, "(mut {})", self.element_type)
1783        } else {
1784            fmt::Display::fmt(&self.element_type, f)
1785        }
1786    }
1787}
1788
1789impl FieldType {
1790    /// Construct a new field type from the given parts.
1791    #[inline]
1792    pub fn new(mutability: Mutability, element_type: StorageType) -> Self {
1793        Self {
1794            mutability,
1795            element_type,
1796        }
1797    }
1798
1799    /// Get whether or not this field type is mutable.
1800    #[inline]
1801    pub fn mutability(&self) -> Mutability {
1802        self.mutability
1803    }
1804
1805    /// Get this field type's storage type.
1806    #[inline]
1807    pub fn element_type(&self) -> &StorageType {
1808        &self.element_type
1809    }
1810
1811    /// Does this field type match the other field type?
1812    ///
1813    /// That is, is this field type a subtype of the other field type?
1814    ///
1815    /// # Panics
1816    ///
1817    /// Panics if either type is associated with a different engine from the
1818    /// other.
1819    pub fn matches(&self, other: &Self) -> bool {
1820        // Our storage type must match `other`'s storage type and either
1821        //
1822        // 1. Both field types are immutable, or
1823        //
1824        // 2. Both field types are mutable and `other`'s storage type must match
1825        //    ours, i.e. the storage types are exactly the same.
1826        use Mutability as M;
1827        match (self.mutability, other.mutability) {
1828            // Case 1
1829            (M::Const, M::Const) => self.element_type.matches(&other.element_type),
1830            // Case 2
1831            (M::Var, M::Var) => StorageType::eq(&self.element_type, &other.element_type),
1832            // Does not match.
1833            _ => false,
1834        }
1835    }
1836
1837    /// Is field type `a` precisely equal to field type `b`?
1838    ///
1839    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
1840    /// are not exactly the same field type.
1841    ///
1842    /// # Panics
1843    ///
1844    /// Panics if either type is associated with a different engine from the
1845    /// other.
1846    pub fn eq(a: &Self, b: &Self) -> bool {
1847        a.matches(b) && b.matches(a)
1848    }
1849
1850    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
1851        self.element_type.comes_from_same_engine(engine)
1852    }
1853
1854    pub(crate) fn from_wasm_field_type(engine: &Engine, ty: &WasmFieldType) -> Self {
1855        Self {
1856            mutability: if ty.mutable {
1857                Mutability::Var
1858            } else {
1859                Mutability::Const
1860            },
1861            element_type: StorageType::from_wasm_storage_type(engine, &ty.element_type),
1862        }
1863    }
1864
1865    pub(crate) fn to_wasm_field_type(&self) -> WasmFieldType {
1866        WasmFieldType {
1867            element_type: self.element_type.to_wasm_storage_type(),
1868            mutable: matches!(self.mutability, Mutability::Var),
1869        }
1870    }
1871}
1872
1873/// The type of a WebAssembly struct.
1874///
1875/// WebAssembly structs are a static, fixed-length, ordered sequence of
1876/// fields. Fields are named by index, not an identifier. Each field is mutable
1877/// or constant and stores unpacked [`Val`][crate::Val]s or packed 8-/16-bit
1878/// integers.
1879///
1880/// # Subtyping and Equality
1881///
1882/// `StructType` does not implement `Eq`, because reference types have a
1883/// subtyping relationship, and so 99.99% of the time you actually want to check
1884/// whether one type matches (i.e. is a subtype of) another type. You can use
1885/// the [`StructType::matches`] method to perform these types of checks. If,
1886/// however, you are in that 0.01% scenario where you need to check precise
1887/// equality between types, you can use the [`StructType::eq`] method.
1888//
1889// TODO: Once we have struct values, update above docs with a reference to the
1890// future `Struct::matches_ty` method
1891#[derive(Debug, Clone, Hash)]
1892pub struct StructType {
1893    registered_type: RegisteredType,
1894}
1895
1896impl fmt::Display for StructType {
1897    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1898        write!(f, "(struct")?;
1899        for field in self.fields() {
1900            write!(f, " (field {field})")?;
1901        }
1902        write!(f, ")")?;
1903        Ok(())
1904    }
1905}
1906
1907impl StructType {
1908    /// Construct a new `StructType` with the given field types.
1909    ///
1910    /// This `StructType` will be final and without a supertype.
1911    ///
1912    /// The result will be associated with the given engine, and attempts to use
1913    /// it with other engines will panic (for example, checking whether it is a
1914    /// subtype of another struct type that is associated with a different
1915    /// engine).
1916    ///
1917    /// Returns an error if the number of fields exceeds the implementation
1918    /// limit.
1919    ///
1920    /// # Panics
1921    ///
1922    /// Panics if any given field type is not associated with the given engine.
1923    pub fn new(engine: &Engine, fields: impl IntoIterator<Item = FieldType>) -> Result<Self> {
1924        Self::with_finality_and_supertype(engine, Finality::Final, None, fields)
1925    }
1926
1927    /// Construct a new `StructType` with the given finality, supertype, and
1928    /// fields.
1929    ///
1930    /// The result will be associated with the given engine, and attempts to use
1931    /// it with other engines will panic (for example, checking whether it is a
1932    /// subtype of another struct type that is associated with a different
1933    /// engine).
1934    ///
1935    /// Returns an error if the number of fields exceeds the implementation
1936    /// limit, if the supertype is final, or if this type does not match the
1937    /// supertype.
1938    ///
1939    /// # Panics
1940    ///
1941    /// Panics if any given field type is not associated with the given engine.
1942    pub fn with_finality_and_supertype(
1943        engine: &Engine,
1944        finality: Finality,
1945        supertype: Option<&Self>,
1946        fields: impl IntoIterator<Item = FieldType>,
1947    ) -> Result<Self> {
1948        let fields = fields.into_iter();
1949
1950        let mut wasmtime_fields = Vec::with_capacity({
1951            let size_hint = fields.size_hint();
1952            let cap = size_hint.1.unwrap_or(size_hint.0);
1953            // Only reserve space if we have a supertype, as that is the only time
1954            // that this vec is used.
1955            supertype.is_some() as usize * cap
1956        });
1957
1958        // Same as in `FuncType::new`: we must prevent any `RegisteredType`s
1959        // from being reclaimed while constructing this struct type.
1960        let mut registrations = smallvec::SmallVec::<[_; 4]>::new();
1961
1962        let fields: Box<[WasmFieldType]> = fields
1963            .map(|ty: FieldType| -> Result<_, Error> {
1964                assert!(ty.comes_from_same_engine(engine));
1965
1966                if supertype.is_some() {
1967                    wasmtime_fields.push(ty.clone());
1968                }
1969
1970                if let Some(r) = ty.element_type.as_val_type().and_then(|v| v.as_ref()) {
1971                    if let Some(r) = r.heap_type().as_registered_type() {
1972                        registrations.push(r.clone());
1973                    }
1974                }
1975
1976                Ok(ty.to_wasm_field_type())
1977            })
1978            .try_collect()?;
1979
1980        if let Some(supertype) = supertype {
1981            ensure!(
1982                supertype.finality().is_non_final(),
1983                "cannot create a subtype of a final supertype"
1984            );
1985            ensure!(
1986                Self::fields_match(wasmtime_fields.into_iter(), supertype.fields()),
1987                "struct fields must match their supertype's fields"
1988            );
1989        }
1990
1991        Self::from_wasm_struct_type(
1992            engine,
1993            finality.is_final(),
1994            false,
1995            supertype.map(|ty| ty.type_index().into()),
1996            WasmStructType { fields },
1997        )
1998    }
1999
2000    /// Get the engine that this struct type is associated with.
2001    pub fn engine(&self) -> &Engine {
2002        self.registered_type.engine()
2003    }
2004
2005    /// Get the finality of this struct type.
2006    pub fn finality(&self) -> Finality {
2007        match self.registered_type.is_final {
2008            true => Finality::Final,
2009            false => Finality::NonFinal,
2010        }
2011    }
2012
2013    /// Get the supertype of this struct type, if any.
2014    pub fn supertype(&self) -> Option<Self> {
2015        self.registered_type.supertype.map(|ty| {
2016            Self::from_shared_type_index(self.engine(), ty.unwrap_engine_type_index()).unwrap()
2017        })
2018    }
2019
2020    /// Get the `i`th field type.
2021    ///
2022    /// Returns `None` if `i` is out of bounds.
2023    pub fn field(&self, i: usize) -> Option<FieldType> {
2024        let engine = self.engine();
2025        self.as_wasm_struct_type()
2026            .fields
2027            .get(i)
2028            .map(|ty| FieldType::from_wasm_field_type(engine, ty))
2029    }
2030
2031    /// Returns the list of field types for this function.
2032    #[inline]
2033    pub fn fields(&self) -> impl ExactSizeIterator<Item = FieldType> + '_ {
2034        let engine = self.engine();
2035        self.as_wasm_struct_type()
2036            .fields
2037            .iter()
2038            .map(|ty| FieldType::from_wasm_field_type(engine, ty))
2039    }
2040
2041    /// Does this struct type match the other struct type?
2042    ///
2043    /// That is, is this function type a subtype of the other struct type?
2044    ///
2045    /// # Panics
2046    ///
2047    /// Panics if either type is associated with a different engine from the
2048    /// other.
2049    pub fn matches(&self, other: &StructType) -> bool {
2050        assert!(self.comes_from_same_engine(other.engine()));
2051
2052        self.engine()
2053            .signatures()
2054            .is_subtype(self.type_index(), other.type_index())
2055    }
2056
2057    fn fields_match(
2058        a: impl ExactSizeIterator<Item = FieldType>,
2059        b: impl ExactSizeIterator<Item = FieldType>,
2060    ) -> bool {
2061        a.len() >= b.len() && a.zip(b).all(|(a, b)| a.matches(&b))
2062    }
2063
2064    /// Is struct type `a` precisely equal to struct type `b`?
2065    ///
2066    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
2067    /// are not exactly the same struct type.
2068    ///
2069    /// # Panics
2070    ///
2071    /// Panics if either type is associated with a different engine from the
2072    /// other.
2073    pub fn eq(a: &StructType, b: &StructType) -> bool {
2074        assert!(a.comes_from_same_engine(b.engine()));
2075        a.type_index() == b.type_index()
2076    }
2077
2078    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
2079        Engine::same(self.registered_type().engine(), engine)
2080    }
2081
2082    pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
2083        self.registered_type().index()
2084    }
2085
2086    pub(crate) fn as_wasm_struct_type(&self) -> &WasmStructType {
2087        self.registered_type().unwrap_struct()
2088    }
2089
2090    pub(crate) fn registered_type(&self) -> &RegisteredType {
2091        &self.registered_type
2092    }
2093
2094    /// Construct a `StructType` from a `WasmStructType`.
2095    ///
2096    /// This method should only be used when something has already registered --
2097    /// and is *keeping registered* -- any other concrete Wasm types referenced
2098    /// by the given `WasmStructType`.
2099    ///
2100    /// For example, this method may be called to convert an struct type from
2101    /// within a Wasm module's `ModuleTypes` since the Wasm module itself is
2102    /// holding a strong reference to all of its types, including any `(ref null
2103    /// <index>)` types used as the element type for this struct type.
2104    pub(crate) fn from_wasm_struct_type(
2105        engine: &Engine,
2106        is_final: bool,
2107        is_shared: bool,
2108        supertype: Option<EngineOrModuleTypeIndex>,
2109        ty: WasmStructType,
2110    ) -> Result<StructType> {
2111        const MAX_FIELDS: usize = 10_000;
2112        let fields_len = ty.fields.len();
2113        ensure!(
2114            fields_len <= MAX_FIELDS,
2115            "attempted to define a struct type with {fields_len} fields, but \
2116             that is more than the maximum supported number of fields \
2117             ({MAX_FIELDS})",
2118        );
2119
2120        let ty = RegisteredType::new(
2121            engine,
2122            WasmSubType {
2123                is_final,
2124                supertype,
2125                composite_type: WasmCompositeType {
2126                    shared: is_shared,
2127                    inner: WasmCompositeInnerType::Struct(ty),
2128                },
2129            },
2130        )?;
2131        Ok(Self {
2132            registered_type: ty,
2133        })
2134    }
2135
2136    /// Get the type registered for `index`.
2137    ///
2138    /// Returns `None` if `index` does not name a registered type of this
2139    /// shape, since indices may come from the untrusted GC heap.
2140    pub(crate) fn from_shared_type_index(
2141        engine: &Engine,
2142        index: VMSharedTypeIndex,
2143    ) -> Option<StructType> {
2144        let ty = RegisteredType::try_root(engine, index)?;
2145        if !ty.is_struct() {
2146            return None;
2147        }
2148        Some(Self::from_registered_type(ty))
2149    }
2150
2151    pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self {
2152        debug_assert!(registered_type.is_struct());
2153        Self { registered_type }
2154    }
2155}
2156
2157/// The type of a WebAssembly array.
2158///
2159/// WebAssembly arrays are dynamically-sized, but not resizable. They contain
2160/// either unpacked [`Val`][crate::Val]s or packed 8-/16-bit integers.
2161///
2162/// # Subtyping and Equality
2163///
2164/// `ArrayType` does not implement `Eq`, because reference types have a
2165/// subtyping relationship, and so 99.99% of the time you actually want to check
2166/// whether one type matches (i.e. is a subtype of) another type. You can use
2167/// the [`ArrayType::matches`] method to perform these types of checks. If,
2168/// however, you are in that 0.01% scenario where you need to check precise
2169/// equality between types, you can use the [`ArrayType::eq`] method.
2170//
2171// TODO: Once we have array values, update above docs with a reference to the
2172// future `Array::matches_ty` method
2173#[derive(Debug, Clone, Hash)]
2174pub struct ArrayType {
2175    registered_type: RegisteredType,
2176}
2177
2178impl fmt::Display for ArrayType {
2179    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2180        let field_ty = self.field_type();
2181        write!(f, "(array (field {field_ty}))")?;
2182        Ok(())
2183    }
2184}
2185
2186impl ArrayType {
2187    /// Construct a new `ArrayType` with the given field type's mutability and
2188    /// storage type.
2189    ///
2190    /// The new `ArrayType` will be final and without a supertype.
2191    ///
2192    /// The result will be associated with the given engine, and attempts to use
2193    /// it with other engines will panic (for example, checking whether it is a
2194    /// subtype of another array type that is associated with a different
2195    /// engine).
2196    ///
2197    /// # Panics
2198    ///
2199    /// Panics if the given field type is not associated with the given engine.
2200    pub fn new(engine: &Engine, field_type: FieldType) -> Self {
2201        Self::with_finality_and_supertype(engine, Finality::Final, None, field_type)
2202            .expect("cannot fail without a supertype")
2203    }
2204
2205    /// Construct a new `StructType` with the given finality, supertype, and
2206    /// fields.
2207    ///
2208    /// The result will be associated with the given engine, and attempts to use
2209    /// it with other engines will panic (for example, checking whether it is a
2210    /// subtype of another struct type that is associated with a different
2211    /// engine).
2212    ///
2213    /// Returns an error if the supertype is final, or if this type does not
2214    /// match the supertype.
2215    ///
2216    /// # Panics
2217    ///
2218    /// Panics if the given field type is not associated with the given engine.
2219    pub fn with_finality_and_supertype(
2220        engine: &Engine,
2221        finality: Finality,
2222        supertype: Option<&Self>,
2223        field_type: FieldType,
2224    ) -> Result<Self> {
2225        if let Some(supertype) = supertype {
2226            assert!(supertype.comes_from_same_engine(engine));
2227            ensure!(
2228                supertype.finality().is_non_final(),
2229                "cannot create a subtype of a final supertype"
2230            );
2231            ensure!(
2232                field_type.matches(&supertype.field_type()),
2233                "array field type must match its supertype's field type"
2234            );
2235        }
2236
2237        // Same as in `FuncType::new`: we must prevent any `RegisteredType` in
2238        // `field_type` from being reclaimed while constructing this array type.
2239        let _registration = field_type
2240            .element_type
2241            .as_val_type()
2242            .and_then(|v| v.as_ref())
2243            .and_then(|r| r.heap_type().as_registered_type());
2244
2245        assert!(field_type.comes_from_same_engine(engine));
2246        let wasm_ty = WasmArrayType(field_type.to_wasm_field_type());
2247
2248        Ok(Self::from_wasm_array_type(
2249            engine,
2250            finality.is_final(),
2251            supertype.map(|ty| ty.type_index().into()),
2252            wasm_ty,
2253        )?)
2254    }
2255
2256    /// Get the engine that this array type is associated with.
2257    pub fn engine(&self) -> &Engine {
2258        self.registered_type.engine()
2259    }
2260
2261    /// Get the finality of this array type.
2262    pub fn finality(&self) -> Finality {
2263        match self.registered_type.is_final {
2264            true => Finality::Final,
2265            false => Finality::NonFinal,
2266        }
2267    }
2268
2269    /// Get the supertype of this array type, if any.
2270    pub fn supertype(&self) -> Option<Self> {
2271        self.registered_type.supertype.map(|ty| {
2272            Self::from_shared_type_index(self.engine(), ty.unwrap_engine_type_index()).unwrap()
2273        })
2274    }
2275
2276    /// Get this array's underlying field type.
2277    ///
2278    /// The field type contains information about both this array type's
2279    /// mutability and the storage type used for its elements.
2280    pub fn field_type(&self) -> FieldType {
2281        FieldType::from_wasm_field_type(self.engine(), &self.as_wasm_array_type().0)
2282    }
2283
2284    /// Get this array type's mutability and whether its instances' elements can
2285    /// be updated or not.
2286    ///
2287    /// This is a convenience method providing a short-hand for
2288    /// `my_array_type.field_type().mutability()`.
2289    pub fn mutability(&self) -> Mutability {
2290        if self.as_wasm_array_type().0.mutable {
2291            Mutability::Var
2292        } else {
2293            Mutability::Const
2294        }
2295    }
2296
2297    /// Get the storage type used for this array type's elements.
2298    ///
2299    /// This is a convenience method providing a short-hand for
2300    /// `my_array_type.field_type().element_type()`.
2301    pub fn element_type(&self) -> StorageType {
2302        StorageType::from_wasm_storage_type(
2303            self.engine(),
2304            &self.registered_type.unwrap_array().0.element_type,
2305        )
2306    }
2307
2308    /// Does this array type match the other array type?
2309    ///
2310    /// That is, is this function type a subtype of the other array type?
2311    ///
2312    /// # Panics
2313    ///
2314    /// Panics if either type is associated with a different engine from the
2315    /// other.
2316    pub fn matches(&self, other: &ArrayType) -> bool {
2317        assert!(self.comes_from_same_engine(other.engine()));
2318
2319        self.engine()
2320            .signatures()
2321            .is_subtype(self.type_index(), other.type_index())
2322    }
2323
2324    /// Is array type `a` precisely equal to array type `b`?
2325    ///
2326    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
2327    /// are not exactly the same array type.
2328    ///
2329    /// # Panics
2330    ///
2331    /// Panics if either type is associated with a different engine from the
2332    /// other.
2333    pub fn eq(a: &ArrayType, b: &ArrayType) -> bool {
2334        assert!(a.comes_from_same_engine(b.engine()));
2335        a.type_index() == b.type_index()
2336    }
2337
2338    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
2339        Engine::same(self.registered_type.engine(), engine)
2340    }
2341
2342    #[cfg(feature = "gc")]
2343    pub(crate) fn registered_type(&self) -> &RegisteredType {
2344        &self.registered_type
2345    }
2346
2347    pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
2348        self.registered_type.index()
2349    }
2350
2351    pub(crate) fn as_wasm_array_type(&self) -> &WasmArrayType {
2352        self.registered_type.unwrap_array()
2353    }
2354
2355    /// Construct a `ArrayType` from a `WasmArrayType`.
2356    ///
2357    /// This method should only be used when something has already registered --
2358    /// and is *keeping registered* -- any other concrete Wasm types referenced
2359    /// by the given `WasmArrayType`.
2360    ///
2361    /// For example, this method may be called to convert an array type from
2362    /// within a Wasm module's `ModuleTypes` since the Wasm module itself is
2363    /// holding a strong reference to all of its types, including any `(ref null
2364    /// <index>)` types used as the element type for this array type.
2365    pub(crate) fn from_wasm_array_type(
2366        engine: &Engine,
2367        is_final: bool,
2368        supertype: Option<EngineOrModuleTypeIndex>,
2369        ty: WasmArrayType,
2370    ) -> Result<ArrayType> {
2371        let ty = RegisteredType::new(
2372            engine,
2373            WasmSubType {
2374                is_final,
2375                supertype,
2376                composite_type: WasmCompositeType {
2377                    shared: false,
2378                    inner: WasmCompositeInnerType::Array(ty),
2379                },
2380            },
2381        )?;
2382        Ok(Self {
2383            registered_type: ty,
2384        })
2385    }
2386
2387    /// Get the type registered for `index`.
2388    ///
2389    /// Returns `None` if `index` does not name a registered type of this
2390    /// shape, since indices may come from the untrusted GC heap.
2391    pub(crate) fn from_shared_type_index(
2392        engine: &Engine,
2393        index: VMSharedTypeIndex,
2394    ) -> Option<ArrayType> {
2395        let ty = RegisteredType::try_root(engine, index)?;
2396        if !ty.is_array() {
2397            return None;
2398        }
2399        Some(Self::from_registered_type(ty))
2400    }
2401
2402    pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self {
2403        debug_assert!(registered_type.is_array());
2404        Self { registered_type }
2405    }
2406}
2407
2408/// The type of a WebAssembly function.
2409///
2410/// WebAssembly functions can have 0 or more parameters and results.
2411///
2412/// # Subtyping and Equality
2413///
2414/// `FuncType` does not implement `Eq`, because reference types have a subtyping
2415/// relationship, and so 99.99% of the time you actually want to check whether
2416/// one type matches (i.e. is a subtype of) another type. You can use the
2417/// [`FuncType::matches`] and [`Func::matches_ty`][crate::Func::matches_ty]
2418/// methods to perform these types of checks. If, however, you are in that 0.01%
2419/// scenario where you need to check precise equality between types, you can use
2420/// the [`FuncType::eq`] method.
2421#[derive(Debug, Clone, Hash)]
2422pub struct FuncType {
2423    registered_type: RegisteredType,
2424}
2425
2426impl Display for FuncType {
2427    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2428        write!(f, "(type (func")?;
2429        if self.params().len() > 0 {
2430            write!(f, " (param")?;
2431            for p in self.params() {
2432                write!(f, " {p}")?;
2433            }
2434            write!(f, ")")?;
2435        }
2436        if self.results().len() > 0 {
2437            write!(f, " (result")?;
2438            for r in self.results() {
2439                write!(f, " {r}")?;
2440            }
2441            write!(f, ")")?;
2442        }
2443        write!(f, "))")
2444    }
2445}
2446
2447impl FuncType {
2448    /// Creates a new function type from the given parameters and results.
2449    ///
2450    /// The function type returned will represent a function which takes
2451    /// `params` as arguments and returns `results` when it is finished.
2452    ///
2453    /// The resulting function type will be final and without a supertype.
2454    ///
2455    /// # Panics
2456    ///
2457    /// Panics if any parameter or value type is not associated with the given
2458    /// engine.
2459    pub fn new(
2460        engine: &Engine,
2461        params: impl IntoIterator<Item = ValType>,
2462        results: impl IntoIterator<Item = ValType>,
2463    ) -> FuncType {
2464        Self::with_finality_and_supertype(engine, Finality::Final, None, params, results)
2465            .expect("cannot fail without a supertype")
2466    }
2467
2468    /// Like [`FuncType::new`] but returns an
2469    /// [`OutOfMemory`][crate::error::OutOfMemory] error on allocation failure.
2470    ///
2471    /// # Errors
2472    ///
2473    /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
2474    /// memory allocation fails. See the `OutOfMemory` type's documentation for
2475    /// details on Wasmtime's out-of-memory handling.
2476    pub fn try_new(
2477        engine: &Engine,
2478        params: impl IntoIterator<Item = ValType>,
2479        results: impl IntoIterator<Item = ValType>,
2480    ) -> Result<FuncType, OutOfMemory> {
2481        Self::with_finality_and_supertype(engine, Finality::Final, None, params, results).map_err(
2482            |e| {
2483                e.downcast::<OutOfMemory>()
2484                    .expect("cannot fail without a supertype, other than OOM")
2485            },
2486        )
2487    }
2488
2489    /// Create a new function type with the given finality, supertype, parameter
2490    /// types, and result types.
2491    ///
2492    /// Returns an error if the supertype is final, or if this function type
2493    /// does not match the supertype.
2494    ///
2495    /// # Panics
2496    ///
2497    /// Panics if any parameter or value type is not associated with the given
2498    /// engine.
2499    pub fn with_finality_and_supertype(
2500        engine: &Engine,
2501        finality: Finality,
2502        supertype: Option<&Self>,
2503        params: impl IntoIterator<Item = ValType>,
2504        results: impl IntoIterator<Item = ValType>,
2505    ) -> Result<Self> {
2506        let params = params.into_iter();
2507        let results = results.into_iter();
2508
2509        let mut wasmtime_params = TryVec::with_capacity({
2510            let size_hint = params.size_hint();
2511            let cap = size_hint.1.unwrap_or(size_hint.0);
2512            // Only reserve space if we have a supertype, as that is the only time
2513            // that this vec is used.
2514            supertype.is_some() as usize * cap
2515        })?;
2516
2517        let mut wasmtime_results = TryVec::with_capacity({
2518            let size_hint = results.size_hint();
2519            let cap = size_hint.1.unwrap_or(size_hint.0);
2520            // Same as above.
2521            supertype.is_some() as usize * cap
2522        })?;
2523
2524        // Keep any of our parameters' and results' `RegisteredType`s alive
2525        // across `Self::from_wasm_func_type`. If one of our given `ValType`s is
2526        // the only thing keeping a type in the registry, we don't want to
2527        // unregister it when we convert the `ValType` into a `WasmValType` just
2528        // before we register our new `WasmFuncType` that will reference it.
2529        let mut registrations = TryVec::new();
2530
2531        let mut to_wasm_type =
2532            |ty: ValType, vec: &mut TryVec<_>| -> Result<WasmValType, OutOfMemory> {
2533                assert!(ty.comes_from_same_engine(engine));
2534
2535                if supertype.is_some() {
2536                    vec.push(ty.clone())?;
2537                }
2538
2539                if let Some(r) = ty.as_ref() {
2540                    if let Some(r) = r.heap_type().as_registered_type() {
2541                        registrations.push(r.clone())?;
2542                    }
2543                }
2544
2545                Ok(ty.to_wasm_type())
2546            };
2547
2548        let params: Box<[_]> = params
2549            .map(|p| to_wasm_type(p, &mut wasmtime_params))
2550            .try_collect()?;
2551        let results: Box<[_]> = results
2552            .map(|p| to_wasm_type(p, &mut wasmtime_results))
2553            .try_collect()?;
2554        let wasm_func_ty = WasmFuncType::new(params, results)?;
2555
2556        if let Some(supertype) = supertype {
2557            assert!(supertype.comes_from_same_engine(engine));
2558            ensure!(
2559                supertype.finality().is_non_final(),
2560                "cannot create a subtype of a final supertype"
2561            );
2562            ensure!(
2563                Self::matches_impl(
2564                    wasmtime_params.iter().cloned(),
2565                    supertype.params(),
2566                    wasmtime_results.iter().cloned(),
2567                    supertype.results()
2568                ),
2569                "function type must match its supertype: found (func{params}{results}), expected \
2570                 {supertype}",
2571                params = if wasmtime_params.is_empty() {
2572                    String::new()
2573                } else {
2574                    let mut s = format!(" (params");
2575                    for p in &wasmtime_params {
2576                        write!(&mut s, " {p}").unwrap();
2577                    }
2578                    s.push(')');
2579                    s
2580                },
2581                results = if wasmtime_results.is_empty() {
2582                    String::new()
2583                } else {
2584                    let mut s = format!(" (results");
2585                    for r in &wasmtime_results {
2586                        write!(&mut s, " {r}").unwrap();
2587                    }
2588                    s.push(')');
2589                    s
2590                },
2591            );
2592        }
2593
2594        Ok(Self::from_wasm_func_type(
2595            engine,
2596            finality.is_final(),
2597            supertype.map(|ty| ty.type_index().into()),
2598            wasm_func_ty,
2599        )?)
2600    }
2601
2602    /// Get the engine that this function type is associated with.
2603    pub fn engine(&self) -> &Engine {
2604        self.registered_type.engine()
2605    }
2606
2607    /// Get the finality of this function type.
2608    pub fn finality(&self) -> Finality {
2609        match self.registered_type.is_final {
2610            true => Finality::Final,
2611            false => Finality::NonFinal,
2612        }
2613    }
2614
2615    /// Get the supertype of this function type, if any.
2616    pub fn supertype(&self) -> Option<Self> {
2617        self.registered_type.supertype.map(|ty| {
2618            Self::from_shared_type_index(self.engine(), ty.unwrap_engine_type_index()).unwrap()
2619        })
2620    }
2621
2622    /// Get the `i`th parameter type.
2623    ///
2624    /// Returns `None` if `i` is out of bounds.
2625    pub fn param(&self, i: usize) -> Option<ValType> {
2626        let engine = self.engine();
2627        self.registered_type
2628            .unwrap_func()
2629            .params()
2630            .get(i)
2631            .map(|ty| ValType::from_wasm_type(engine, ty))
2632    }
2633
2634    /// Returns the list of parameter types for this function.
2635    #[inline]
2636    pub fn params(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
2637        let engine = self.engine();
2638        self.registered_type
2639            .unwrap_func()
2640            .params()
2641            .iter()
2642            .map(|ty| ValType::from_wasm_type(engine, ty))
2643    }
2644
2645    /// Get the `i`th result type.
2646    ///
2647    /// Returns `None` if `i` is out of bounds.
2648    pub fn result(&self, i: usize) -> Option<ValType> {
2649        let engine = self.engine();
2650        self.registered_type
2651            .unwrap_func()
2652            .results()
2653            .get(i)
2654            .map(|ty| ValType::from_wasm_type(engine, ty))
2655    }
2656
2657    /// Returns the list of result types for this function.
2658    #[inline]
2659    pub fn results(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
2660        let engine = self.engine();
2661        self.registered_type
2662            .unwrap_func()
2663            .results()
2664            .iter()
2665            .map(|ty| ValType::from_wasm_type(engine, ty))
2666    }
2667
2668    /// Does this function type match the other function type?
2669    ///
2670    /// That is, is this function type a subtype of the other function type?
2671    ///
2672    /// # Panics
2673    ///
2674    /// Panics if either type is associated with a different engine from the
2675    /// other.
2676    pub fn matches(&self, other: &FuncType) -> bool {
2677        assert!(self.comes_from_same_engine(other.engine()));
2678
2679        // Avoid matching on structure for subtyping checks when we have
2680        // precisely the same type.
2681        if self.type_index() == other.type_index() {
2682            return true;
2683        }
2684
2685        Self::matches_impl(
2686            self.params(),
2687            other.params(),
2688            self.results(),
2689            other.results(),
2690        )
2691    }
2692
2693    fn matches_impl(
2694        a_params: impl ExactSizeIterator<Item = ValType>,
2695        b_params: impl ExactSizeIterator<Item = ValType>,
2696        a_results: impl ExactSizeIterator<Item = ValType>,
2697        b_results: impl ExactSizeIterator<Item = ValType>,
2698    ) -> bool {
2699        a_params.len() == b_params.len()
2700            && a_results.len() == b_results.len()
2701            // Params are contravariant and results are covariant. For more
2702            // details and a refresher on variance, read
2703            // https://github.com/bytecodealliance/wasm-tools/blob/f1d89a4/crates/wasmparser/src/readers/core/types/matches.rs#L137-L174
2704            && a_params
2705                .zip(b_params)
2706                .all(|(a, b)| b.matches(&a))
2707            && a_results
2708                .zip(b_results)
2709                .all(|(a, b)| a.matches(&b))
2710    }
2711
2712    /// Is function type `a` precisely equal to function type `b`?
2713    ///
2714    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
2715    /// are not exactly the same function type.
2716    ///
2717    /// # Panics
2718    ///
2719    /// Panics if either type is associated with a different engine from the
2720    /// other.
2721    pub fn eq(a: &FuncType, b: &FuncType) -> bool {
2722        assert!(a.comes_from_same_engine(b.engine()));
2723        a.type_index() == b.type_index()
2724    }
2725
2726    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
2727        Engine::same(self.registered_type.engine(), engine)
2728    }
2729
2730    pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
2731        self.registered_type.index()
2732    }
2733
2734    pub(crate) fn into_registered_type(self) -> RegisteredType {
2735        self.registered_type
2736    }
2737
2738    /// Construct a `FuncType` from a `WasmFuncType`.
2739    ///
2740    /// This method should only be used when something has already registered --
2741    /// and is *keeping registered* -- any other concrete Wasm types referenced
2742    /// by the given `WasmFuncType`.
2743    ///
2744    /// For example, this method may be called to convert a function type from
2745    /// within a Wasm module's `ModuleTypes` since the Wasm module itself is
2746    /// holding a strong reference to all of its types, including any `(ref null
2747    /// <index>)` types used in the function's parameters and results.
2748    pub(crate) fn from_wasm_func_type(
2749        engine: &Engine,
2750        is_final: bool,
2751        supertype: Option<EngineOrModuleTypeIndex>,
2752        ty: WasmFuncType,
2753    ) -> Result<FuncType, OutOfMemory> {
2754        let ty = RegisteredType::new(
2755            engine,
2756            WasmSubType {
2757                is_final,
2758                supertype,
2759                composite_type: WasmCompositeType {
2760                    shared: false,
2761                    inner: WasmCompositeInnerType::Func(ty),
2762                },
2763            },
2764        )?;
2765        Ok(Self {
2766            registered_type: ty,
2767        })
2768    }
2769
2770    /// Get the type registered for `index`.
2771    ///
2772    /// Returns `None` if `index` does not name a registered type of this
2773    /// shape, since indices may come from the untrusted GC heap.
2774    pub(crate) fn from_shared_type_index(
2775        engine: &Engine,
2776        index: VMSharedTypeIndex,
2777    ) -> Option<FuncType> {
2778        let ty = RegisteredType::try_root(engine, index)?;
2779        if !ty.is_func() {
2780            return None;
2781        }
2782        Some(Self::from_registered_type(ty))
2783    }
2784
2785    pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self {
2786        debug_assert!(registered_type.is_func());
2787        Self { registered_type }
2788    }
2789    /// Construct a func which returns results of default value, if each result type has a default value.
2790    pub fn default_value(&self, mut store: impl AsContextMut) -> Result<Func> {
2791        let mut dummy_results = TryVec::new();
2792        for ty in self.results() {
2793            let val = ty
2794                .default_value()
2795                .ok_or_else(|| format_err!("function results do not have a default value"))?;
2796            dummy_results.push(val)?;
2797        }
2798        Func::try_new(&mut store, self.clone(), move |_, _, results| {
2799            for (slot, dummy) in results.iter_mut().zip(dummy_results.iter()) {
2800                *slot = *dummy;
2801            }
2802            Ok(())
2803        })
2804    }
2805}
2806
2807// Continuation types
2808/// A WebAssembly continuation descriptor.
2809#[derive(Debug, Clone, Hash)]
2810pub struct ContType {
2811    registered_type: RegisteredType,
2812}
2813
2814impl ContType {
2815    /// Get the engine that this function type is associated with.
2816    pub fn engine(&self) -> &Engine {
2817        self.registered_type.engine()
2818    }
2819
2820    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
2821        Engine::same(self.registered_type.engine(), engine)
2822    }
2823
2824    pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
2825        self.registered_type.index()
2826    }
2827
2828    /// Does this continuation type match the other continuation type?
2829    ///
2830    /// That is, is this continuation type a subtype of the other continuation type?
2831    ///
2832    /// # Panics
2833    ///
2834    /// Panics if either type is associated with a different engine from the
2835    /// other.
2836    pub fn matches(&self, other: &ContType) -> bool {
2837        assert!(self.comes_from_same_engine(other.engine()));
2838
2839        // Avoid matching on structure for subtyping checks when we have
2840        // precisely the same type.
2841        // TODO(dhil): Implement subtype check later.
2842        self.type_index() == other.type_index()
2843    }
2844
2845    /// Get the type registered for `index`.
2846    ///
2847    /// Returns `None` if `index` does not name a registered type of this
2848    /// shape, since indices may come from the untrusted GC heap.
2849    pub(crate) fn from_shared_type_index(
2850        engine: &Engine,
2851        index: VMSharedTypeIndex,
2852    ) -> Option<ContType> {
2853        let ty = RegisteredType::try_root(engine, index)?;
2854        if !ty.is_cont() {
2855            return None;
2856        }
2857        Some(Self {
2858            registered_type: ty,
2859        })
2860    }
2861}
2862
2863// Exception types
2864
2865/// A WebAssembly exception-object signature type.
2866///
2867/// This type captures the *signature* of an exception object. Note
2868/// that the WebAssembly standard does not define concrete types in
2869/// the heap-type lattice between `exn` (any exception object -- the
2870/// top type) and `noexn` (the uninhabited bottom type). Wasmtime
2871/// defines concrete types based on the *signature* -- that is, the
2872/// function type that describes the signature of the exception
2873/// payload values -- rather than the tag. The tag is a per-instance
2874/// nominal entity (similar to a memory or a table) and is associated
2875/// only with particular exception *objects*.
2876#[derive(Debug, Clone, Hash)]
2877pub struct ExnType {
2878    func_ty: FuncType,
2879    registered_type: RegisteredType,
2880}
2881
2882impl fmt::Display for ExnType {
2883    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2884        write!(f, "(exn {}", self.func_ty)?;
2885        for field in self.fields() {
2886            write!(f, " (field {field})")?;
2887        }
2888        write!(f, ")")?;
2889        Ok(())
2890    }
2891}
2892
2893impl ExnType {
2894    /// Create a new `ExnType`.
2895    ///
2896    /// This function creates a new exception object type with the
2897    /// given signature, i.e., list of payload value types. This
2898    /// signature implies a tag type, and when instantiated at
2899    /// runtime, it must be associated with a tag of that type.
2900    pub fn new(engine: &Engine, fields: impl IntoIterator<Item = ValType>) -> Result<ExnType> {
2901        let fields: TryVec<_> = fields.into_iter().try_collect()?;
2902
2903        // First, construct/intern a FuncType: we need this to exist
2904        // so we can hand out a TagType, and it also roots any nested registrations.
2905        let func_ty = FuncType::try_new(engine, fields.iter().cloned(), [])?;
2906
2907        Self::_new(engine, fields, func_ty)
2908    }
2909
2910    /// Create a new `ExnType` from an existing `TagType`.
2911    ///
2912    /// This function creates a new exception object type with the
2913    /// signature represented by the tag. The signature must have no
2914    /// result values, i.e., must be of the form `(T1, T2, ...) ->
2915    /// ()`.
2916    pub fn from_tag_type(tag: &TagType) -> Result<ExnType> {
2917        let func_ty = tag.ty();
2918
2919        // Check that the tag's signature type has no results.
2920        ensure!(
2921            func_ty.results().len() == 0,
2922            "Cannot create an exception type from a tag type with results in the signature"
2923        );
2924
2925        Self::_new(tag.ty.engine(), func_ty.params(), func_ty.clone())
2926    }
2927
2928    fn _new(
2929        engine: &Engine,
2930        fields: impl IntoIterator<Item = ValType>,
2931        func_ty: FuncType,
2932    ) -> Result<ExnType> {
2933        ensure!(
2934            engine.gc_runtime().is_some(),
2935            "cannot define `ExnType`s without a GC runtime enabled"
2936        );
2937
2938        let mut wasm_fields = TryVec::new();
2939        for ty in fields.into_iter() {
2940            assert!(ty.comes_from_same_engine(engine));
2941            wasm_fields.push(WasmFieldType {
2942                element_type: WasmStorageType::Val(ty.to_wasm_type()),
2943                mutable: false,
2944            })?;
2945        }
2946
2947        let ty = RegisteredType::new(
2948            engine,
2949            WasmSubType {
2950                is_final: true,
2951                supertype: None,
2952                composite_type: WasmCompositeType {
2953                    shared: false,
2954                    inner: WasmCompositeInnerType::Exn(WasmExnType {
2955                        func_ty: EngineOrModuleTypeIndex::Engine(func_ty.type_index()),
2956                        fields: wasm_fields.into_boxed_slice()?,
2957                    }),
2958                },
2959            },
2960        )?;
2961
2962        Ok(ExnType {
2963            func_ty,
2964            registered_type: ty,
2965        })
2966    }
2967
2968    /// Get the tag type that this exception type is associated with.
2969    pub fn tag_type(&self) -> TagType {
2970        TagType {
2971            ty: self.func_ty.clone(),
2972        }
2973    }
2974
2975    /// Get the `i`th field type.
2976    ///
2977    /// Returns `None` if `i` is out of bounds.
2978    pub fn field(&self, i: usize) -> Option<FieldType> {
2979        let engine = self.engine();
2980        self.as_wasm_exn_type()
2981            .fields
2982            .get(i)
2983            .map(|ty| FieldType::from_wasm_field_type(engine, ty))
2984    }
2985
2986    /// Returns the list of field types for this function.
2987    #[inline]
2988    pub fn fields(&self) -> impl ExactSizeIterator<Item = FieldType> + '_ {
2989        let engine = self.engine();
2990        self.as_wasm_exn_type()
2991            .fields
2992            .iter()
2993            .map(|ty| FieldType::from_wasm_field_type(engine, ty))
2994    }
2995
2996    /// Get the engine that this exception type is associated with.
2997    pub fn engine(&self) -> &Engine {
2998        self.registered_type.engine()
2999    }
3000
3001    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
3002        Engine::same(self.registered_type.engine(), engine)
3003    }
3004
3005    pub(crate) fn as_wasm_exn_type(&self) -> &WasmExnType {
3006        self.registered_type().unwrap_exn()
3007    }
3008
3009    pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
3010        self.registered_type.index()
3011    }
3012
3013    /// Does this exception type match the other exception type?
3014    ///
3015    /// That is, is this exception type a subtype of the other exception type?
3016    ///
3017    /// # Panics
3018    ///
3019    /// Panics if either type is associated with a different engine from the
3020    /// other.
3021    pub fn matches(&self, other: &ExnType) -> bool {
3022        assert!(self.comes_from_same_engine(other.engine()));
3023
3024        // We have no concrete-exception-type subtyping; concrete
3025        // exception types are only (mutually, trivially) subtypes if
3026        // they are exactly equal.
3027        self.type_index() == other.type_index()
3028    }
3029
3030    pub(crate) fn registered_type(&self) -> &RegisteredType {
3031        &self.registered_type
3032    }
3033
3034    /// Get the type registered for `index`.
3035    ///
3036    /// Returns `None` if `index` does not name a registered type of this
3037    /// shape, since indices may come from the untrusted GC heap.
3038    pub(crate) fn from_shared_type_index(
3039        engine: &Engine,
3040        index: VMSharedTypeIndex,
3041    ) -> Option<ExnType> {
3042        let ty = RegisteredType::try_root(engine, index)?;
3043        if !ty.is_exn() {
3044            return None;
3045        }
3046        let func_ty = FuncType::from_shared_type_index(
3047            engine,
3048            ty.unwrap_exn().func_ty.as_engine_type_index()?,
3049        )?;
3050        Some(Self {
3051            func_ty,
3052            registered_type: ty,
3053        })
3054    }
3055}
3056
3057// Global Types
3058
3059/// A WebAssembly global descriptor.
3060///
3061/// This type describes an instance of a global in a WebAssembly module. Globals
3062/// are local to an [`Instance`](crate::Instance) and are either immutable or
3063/// mutable.
3064#[derive(Debug, Clone, Hash)]
3065pub struct GlobalType {
3066    content: ValType,
3067    mutability: Mutability,
3068}
3069
3070impl GlobalType {
3071    /// Creates a new global descriptor of the specified `content` type and
3072    /// whether or not it's mutable.
3073    pub fn new(content: ValType, mutability: Mutability) -> GlobalType {
3074        GlobalType {
3075            content,
3076            mutability,
3077        }
3078    }
3079
3080    /// Returns the value type of this global descriptor.
3081    pub fn content(&self) -> &ValType {
3082        &self.content
3083    }
3084
3085    /// Returns whether or not this global is mutable.
3086    pub fn mutability(&self) -> Mutability {
3087        self.mutability
3088    }
3089
3090    /// Returns `None` if the wasmtime global has a type that we can't
3091    /// represent, but that should only very rarely happen and indicate a bug.
3092    pub(crate) fn from_wasmtime_global(engine: &Engine, global: &Global) -> GlobalType {
3093        let ty = ValType::from_wasm_type(engine, &global.wasm_ty);
3094        let mutability = if global.mutability {
3095            Mutability::Var
3096        } else {
3097            Mutability::Const
3098        };
3099        GlobalType::new(ty, mutability)
3100    }
3101    /// Construct a new global import with this type’s default value.
3102    ///
3103    /// This creates a host `Global` in the given store initialized to the
3104    /// type’s zero/null default (e.g. `0` for numeric globals, `null_ref` for refs).
3105    pub fn default_value(&self, store: impl AsContextMut) -> Result<RuntimeGlobal> {
3106        let val = self
3107            .content()
3108            .default_value()
3109            .ok_or_else(|| format_err!("global type has no default value"))?;
3110        RuntimeGlobal::new(store, self.clone(), val)
3111    }
3112
3113    pub(crate) fn into_registered_type(self) -> Option<RegisteredType> {
3114        self.content.into_registered_type()
3115    }
3116}
3117
3118// Tag Types
3119
3120/// A descriptor for a tag in a WebAssembly module.
3121///
3122/// Note that tags are local to an [`Instance`](crate::Instance),
3123/// i.e., are a runtime entity. However, a tag is associated with a
3124/// function type, and so has a kind of static type. This descriptor
3125/// is a thin wrapper around a `FuncType` representing the function
3126/// type of a tag.
3127#[derive(Debug, Clone, Hash)]
3128pub struct TagType {
3129    ty: FuncType,
3130}
3131
3132impl TagType {
3133    /// Creates a new global descriptor of the specified type.
3134    pub fn new(ty: FuncType) -> TagType {
3135        TagType { ty }
3136    }
3137
3138    /// Returns the underlying function type of this tag descriptor.
3139    pub fn ty(&self) -> &FuncType {
3140        &self.ty
3141    }
3142
3143    pub(crate) fn from_wasmtime_tag(engine: &Engine, tag: &Tag) -> TagType {
3144        let ty = FuncType::from_shared_type_index(engine, tag.signature.unwrap_engine_type_index())
3145            .unwrap();
3146        TagType { ty }
3147    }
3148
3149    /// Construct a new default tag with this type.
3150    ///
3151    /// This creates a host `Tag` in the given store. Tag instances
3152    /// have no content other than their type, so this "default" value
3153    /// is identical to ordinary host tag allocation.
3154    pub fn default_value(&self, store: impl AsContextMut) -> Result<RuntimeTag> {
3155        RuntimeTag::new(store, self)
3156    }
3157}
3158
3159// Table Types
3160
3161/// A descriptor for a table in a WebAssembly module.
3162///
3163/// Tables are contiguous chunks of a specific element, typically a `funcref` or
3164/// an `externref`. The most common use for tables is a function table through
3165/// which `call_indirect` can invoke other functions.
3166#[derive(Debug, Clone, Hash)]
3167pub struct TableType {
3168    // Keep a `wasmtime::RefType` so that `TableType::element` doesn't need to
3169    // take an `&Engine`.
3170    element: RefType,
3171    ty: Table,
3172}
3173
3174impl TableType {
3175    /// Creates a new table descriptor which will contain the specified
3176    /// `element` and have the `limits` applied to its length.
3177    ///
3178    /// # Errors
3179    ///
3180    /// Returns an error if the minimum is greater than the maximum.
3181    pub fn new(element: RefType, min: u32, max: Option<u32>) -> Result<TableType> {
3182        if let Some(max) = max
3183            && max < min
3184        {
3185            bail!("table's maximum size cannot be smaller than its minimum size");
3186        }
3187        let ref_type = element.to_wasm_type();
3188
3189        debug_assert!(
3190            ref_type.is_canonicalized_for_runtime_usage(),
3191            "should be canonicalized for runtime usage: {ref_type:?}"
3192        );
3193
3194        let limits = Limits {
3195            min: u64::from(min),
3196            max: max.map(|x| u64::from(x)),
3197        };
3198
3199        Ok(TableType {
3200            element,
3201            ty: Table {
3202                idx_type: IndexType::I32,
3203                limits,
3204                ref_type,
3205            },
3206        })
3207    }
3208
3209    /// Crates a new descriptor for a 64-bit table.
3210    ///
3211    /// Note that 64-bit tables are part of the memory64 proposal for
3212    /// WebAssembly which is not standardized yet.
3213    ///
3214    /// # Errors
3215    ///
3216    /// Returns an error if the minimum is greater than the maximum.
3217    pub fn new64(element: RefType, min: u64, max: Option<u64>) -> Result<TableType> {
3218        if let Some(max) = max
3219            && max < min
3220        {
3221            bail!("table's maximum size cannot be smaller than its minimum size");
3222        }
3223        let ref_type = element.to_wasm_type();
3224
3225        debug_assert!(
3226            ref_type.is_canonicalized_for_runtime_usage(),
3227            "should be canonicalized for runtime usage: {ref_type:?}"
3228        );
3229
3230        Ok(TableType {
3231            element,
3232            ty: Table {
3233                ref_type,
3234                idx_type: IndexType::I64,
3235                limits: Limits { min, max },
3236            },
3237        })
3238    }
3239
3240    /// Returns whether or not this table is a 64-bit table.
3241    ///
3242    /// Note that 64-bit tables are part of the memory64 proposal for
3243    /// WebAssembly which is not standardized yet.
3244    pub fn is_64(&self) -> bool {
3245        matches!(self.ty.idx_type, IndexType::I64)
3246    }
3247
3248    /// Returns the element value type of this table.
3249    pub fn element(&self) -> &RefType {
3250        &self.element
3251    }
3252
3253    /// Returns minimum number of elements this table must have
3254    pub fn minimum(&self) -> u64 {
3255        self.ty.limits.min
3256    }
3257
3258    /// Returns the optionally-specified maximum number of elements this table
3259    /// can have.
3260    ///
3261    /// If this returns `None` then the table is not limited in size.
3262    pub fn maximum(&self) -> Option<u64> {
3263        self.ty.limits.max
3264    }
3265
3266    pub(crate) fn from_wasmtime_table(engine: &Engine, table: &Table) -> TableType {
3267        let element = RefType::from_wasm_type(engine, &table.ref_type);
3268        TableType {
3269            element,
3270            ty: *table,
3271        }
3272    }
3273
3274    pub(crate) fn wasmtime_table(&self) -> &Table {
3275        &self.ty
3276    }
3277    /// Construct a new table import whose entries are filled with this type’s default.
3278    ///
3279    /// Creates a host `Table` in the store with its initial size and element
3280    /// type’s default (e.g. `null_ref` for nullable refs).
3281    pub fn default_value(&self, store: impl AsContextMut) -> Result<RuntimeTable> {
3282        let val: ValType = self.element().clone().into();
3283        let init_val = val
3284            .default_value()
3285            .context("table element type does not have a default value")?
3286            .ref_()
3287            .unwrap();
3288        RuntimeTable::new(store, self.clone(), init_val)
3289    }
3290}
3291
3292// Memory Types
3293
3294/// A builder for [`MemoryType`][crate::MemoryType]s.
3295///
3296/// A new builder can be constructed via its `Default` implementation.
3297///
3298/// When you're done configuring, get the underlying
3299/// [`MemoryType`][crate::MemoryType] by calling the
3300/// [`build`][crate::MemoryTypeBuilder::build] method.
3301///
3302/// # Example
3303///
3304/// ```
3305/// # fn foo() -> wasmtime::Result<()> {
3306/// use wasmtime::MemoryTypeBuilder;
3307///
3308/// let memory_type = MemoryTypeBuilder::new()
3309///     // Set the minimum size, in pages.
3310///     .min(4096)
3311///     // Set the maximum size, in pages.
3312///     .max(Some(4096))
3313///     // Set the page size to 1 byte (aka 2**0).
3314///     .page_size_log2(0)
3315///     // Get the underlying memory type.
3316///     .build()?;
3317/// #   Ok(())
3318/// # }
3319/// ```
3320pub struct MemoryTypeBuilder {
3321    ty: Memory,
3322}
3323
3324impl Default for MemoryTypeBuilder {
3325    fn default() -> Self {
3326        MemoryTypeBuilder {
3327            ty: Memory {
3328                idx_type: IndexType::I32,
3329                limits: Limits { min: 0, max: None },
3330                shared: false,
3331                page_size_log2: Memory::DEFAULT_PAGE_SIZE_LOG2,
3332            },
3333        }
3334    }
3335}
3336
3337impl MemoryTypeBuilder {
3338    /// Create a new builder for a [`MemoryType`] with the default settings.
3339    ///
3340    /// By default memory types have the following properties:
3341    ///
3342    /// * The minimum memory size is 0 pages.
3343    /// * The maximum memory size is unspecified.
3344    /// * Memories use 32-bit indexes.
3345    /// * The page size is 64KiB.
3346    ///
3347    /// Each option can be configured through the methods on the returned
3348    /// builder.
3349    pub fn new() -> MemoryTypeBuilder {
3350        MemoryTypeBuilder::default()
3351    }
3352
3353    fn validate(&self) -> Result<()> {
3354        if self
3355            .ty
3356            .limits
3357            .max
3358            .map_or(false, |max| max < self.ty.limits.min)
3359        {
3360            bail!("maximum page size cannot be smaller than the minimum page size");
3361        }
3362
3363        match self.ty.page_size_log2 {
3364            0 | Memory::DEFAULT_PAGE_SIZE_LOG2 => {}
3365            x => bail!(
3366                "page size must be 2**16 or 2**0, but was given 2**{x}; note \
3367                 that future Wasm extensions might allow any power of two page \
3368                 size, but only 2**16 and 2**0 are currently valid",
3369            ),
3370        }
3371
3372        if self.ty.shared && self.ty.limits.max.is_none() {
3373            bail!("shared memories must have a maximum size");
3374        }
3375
3376        let absolute_max = self.ty.max_size_based_on_index_type();
3377        let min = self
3378            .ty
3379            .minimum_byte_size()
3380            .context("memory's minimum byte size must fit in a u64")?;
3381        if min > absolute_max {
3382            bail!("minimum size is too large for this memory type's index type");
3383        }
3384        if self
3385            .ty
3386            .maximum_byte_size()
3387            .map_or(false, |max| max > absolute_max)
3388        {
3389            bail!("maximum size is too large for this memory type's index type");
3390        }
3391
3392        Ok(())
3393    }
3394
3395    /// Set the minimum size, in units of pages, for the memory type being
3396    /// built.
3397    ///
3398    /// The default minimum is `0`.
3399    pub fn min(&mut self, minimum: u64) -> &mut Self {
3400        self.ty.limits.min = minimum;
3401        self
3402    }
3403
3404    /// Set the maximum size, in units of pages, for the memory type being
3405    /// built.
3406    ///
3407    /// The default maximum is `None`.
3408    pub fn max(&mut self, maximum: Option<u64>) -> &mut Self {
3409        self.ty.limits.max = maximum;
3410        self
3411    }
3412
3413    /// Set whether this is a 64-bit memory or not.
3414    ///
3415    /// If a memory is not a 64-bit memory, then it is a 32-bit memory.
3416    ///
3417    /// The default is `false`, aka 32-bit memories.
3418    ///
3419    /// Note that 64-bit memories are part of [the memory64
3420    /// proposal](https://github.com/WebAssembly/memory64) for WebAssembly which
3421    /// is not fully standardized yet.
3422    pub fn memory64(&mut self, memory64: bool) -> &mut Self {
3423        self.ty.idx_type = match memory64 {
3424            true => IndexType::I64,
3425            false => IndexType::I32,
3426        };
3427        self
3428    }
3429
3430    /// Set the sharedness for the memory type being built.
3431    ///
3432    /// The default is `false`, aka unshared.
3433    ///
3434    /// Note that shared memories are part of [the threads
3435    /// proposal](https://github.com/WebAssembly/threads) for WebAssembly which
3436    /// is not fully standardized yet.
3437    pub fn shared(&mut self, shared: bool) -> &mut Self {
3438        self.ty.shared = shared;
3439        self
3440    }
3441
3442    /// Set the log base 2 of the page size, in bytes, for the memory type being
3443    /// built.
3444    ///
3445    /// The default value is `16`, which results in the default Wasm page size
3446    /// of 64KiB (aka 2<sup>16</sup> or 65536).
3447    ///
3448    /// Other than `16`, the only valid value is `0`, which results in a page
3449    /// size of one byte (aka 2<sup>0</sup>). Single-byte page sizes can be used
3450    /// to get fine-grained control over a Wasm memory's resource consumption
3451    /// and run Wasm in embedded environments with less than 64KiB of RAM, for
3452    /// example.
3453    ///
3454    /// Future extensions to the core WebAssembly language might relax these
3455    /// constraints and introduce more valid page sizes, such as any power of
3456    /// two between 1 and 65536 inclusive.
3457    ///
3458    /// Note that non-default page sizes are part of [the custom-page-sizes
3459    /// proposal](https://github.com/WebAssembly/custom-page-sizes) for
3460    /// WebAssembly which is not fully standardized yet.
3461    pub fn page_size_log2(&mut self, page_size_log2: u8) -> &mut Self {
3462        self.ty.page_size_log2 = page_size_log2;
3463        self
3464    }
3465
3466    /// Get the underlying memory type that this builder has been building.
3467    ///
3468    /// # Errors
3469    ///
3470    /// Returns an error if the configured memory type is invalid, for example
3471    /// if the maximum size is smaller than the minimum size.
3472    pub fn build(&self) -> Result<MemoryType> {
3473        self.validate()?;
3474        Ok(MemoryType { ty: self.ty })
3475    }
3476}
3477
3478/// A descriptor for a WebAssembly memory type.
3479///
3480/// Memories are described in units of pages (64KB) and represent contiguous
3481/// chunks of addressable memory.
3482#[derive(Debug, Clone, Hash, Eq, PartialEq)]
3483pub struct MemoryType {
3484    ty: Memory,
3485}
3486
3487impl MemoryType {
3488    /// Creates a new descriptor for a 32-bit WebAssembly memory given the
3489    /// specified limits of the memory.
3490    ///
3491    /// The `minimum` and `maximum` values here are specified in units of
3492    /// WebAssembly pages, which are 64KiB by default. Use
3493    /// [`MemoryTypeBuilder`][crate::MemoryTypeBuilder] if you want a
3494    /// non-default page size.
3495    ///
3496    /// # Errors
3497    ///
3498    /// Returns an error if the minimum is greater than the maximum or if the
3499    /// minimum or maximum number of pages can result in a byte size that is
3500    /// not addressable with a 32-bit integer.
3501    pub fn new(minimum: u32, maximum: Option<u32>) -> Result<MemoryType> {
3502        MemoryTypeBuilder::default()
3503            .min(minimum.into())
3504            .max(maximum.map(Into::into))
3505            .build()
3506    }
3507
3508    /// Creates a new descriptor for a 64-bit WebAssembly memory given the
3509    /// specified limits of the memory.
3510    ///
3511    /// The `minimum` and `maximum` values here are specified in units of
3512    /// WebAssembly pages, which are 64KiB by default. Use
3513    /// [`MemoryTypeBuilder`][crate::MemoryTypeBuilder] if you want a
3514    /// non-default page size.
3515    ///
3516    /// Note that 64-bit memories are part of [the memory64
3517    /// proposal](https://github.com/WebAssembly/memory64) for WebAssembly which
3518    /// is not fully standardized yet.
3519    ///
3520    /// # Errors
3521    ///
3522    /// Returns an error if the minimum is greater than the maximum or if the
3523    /// minimum or maximum number of pages can result in a byte size that is
3524    /// not addressable with a 64-bit integer.
3525    pub fn new64(minimum: u64, maximum: Option<u64>) -> Result<MemoryType> {
3526        MemoryTypeBuilder::default()
3527            .memory64(true)
3528            .min(minimum)
3529            .max(maximum)
3530            .build()
3531    }
3532
3533    /// Creates a new descriptor for shared WebAssembly memory given the
3534    /// specified limits of the memory.
3535    ///
3536    /// The `minimum` and `maximum` values here are specified in units of
3537    /// WebAssembly pages, which are 64KiB by default. Use
3538    /// [`MemoryTypeBuilder`][crate::MemoryTypeBuilder] if you want a
3539    /// non-default page size.
3540    ///
3541    /// Note that shared memories are part of [the threads
3542    /// proposal](https://github.com/WebAssembly/threads) for WebAssembly which
3543    /// is not fully standardized yet.
3544    ///
3545    /// # Errors
3546    ///
3547    /// Returns an error if the minimum is greater than the maximum or if the
3548    /// minimum or maximum number of pages can result in a byte size that is
3549    /// not addressable with a 32-bit integer.
3550    pub fn shared(minimum: u32, maximum: u32) -> Result<MemoryType> {
3551        MemoryTypeBuilder::default()
3552            .shared(true)
3553            .min(minimum.into())
3554            .max(Some(maximum.into()))
3555            .build()
3556    }
3557
3558    /// Creates a new [`MemoryTypeBuilder`] to configure all the various knobs
3559    /// of the final memory type being created.
3560    ///
3561    /// This is a convenience function for [`MemoryTypeBuilder::new`].
3562    pub fn builder() -> MemoryTypeBuilder {
3563        MemoryTypeBuilder::new()
3564    }
3565
3566    /// Returns whether this is a 64-bit memory or not.
3567    ///
3568    /// Note that 64-bit memories are part of the memory64 proposal for
3569    /// WebAssembly which is not standardized yet.
3570    pub fn is_64(&self) -> bool {
3571        matches!(self.ty.idx_type, IndexType::I64)
3572    }
3573
3574    /// Returns whether this is a shared memory or not.
3575    ///
3576    /// Note that shared memories are part of the threads proposal for
3577    /// WebAssembly which is not standardized yet.
3578    pub fn is_shared(&self) -> bool {
3579        self.ty.shared
3580    }
3581
3582    /// Returns minimum number of WebAssembly pages this memory must have.
3583    ///
3584    /// Note that the return value, while a `u64`, will always fit into a `u32`
3585    /// for 32-bit memories.
3586    pub fn minimum(&self) -> u64 {
3587        self.ty.limits.min
3588    }
3589
3590    /// Returns the optionally-specified maximum number of pages this memory
3591    /// can have.
3592    ///
3593    /// If this returns `None` then the memory is not limited in size.
3594    ///
3595    /// Note that the return value, while a `u64`, will always fit into a `u32`
3596    /// for 32-bit memories.
3597    pub fn maximum(&self) -> Option<u64> {
3598        self.ty.limits.max
3599    }
3600
3601    /// This memory's page size, in bytes.
3602    pub fn page_size(&self) -> u64 {
3603        self.ty.page_size()
3604    }
3605
3606    /// The log2 of this memory's page size, in bytes.
3607    pub fn page_size_log2(&self) -> u8 {
3608        self.ty.page_size_log2
3609    }
3610
3611    pub(crate) fn from_wasmtime_memory(memory: &Memory) -> MemoryType {
3612        MemoryType { ty: *memory }
3613    }
3614
3615    pub(crate) fn wasmtime_memory(&self) -> &Memory {
3616        &self.ty
3617    }
3618    /// Construct a new memory import initialized to this memory type’s default
3619    /// state.
3620    ///
3621    /// Returns a host `Memory` or `SharedMemory` depending on if this is a
3622    /// shared memory type or not. The memory's type will have the same type as
3623    /// `self` and the initial contents of the memory, if any, will be all zero.
3624    pub fn default_value(&self, store: impl AsContextMut) -> Result<Extern> {
3625        Ok(if self.is_shared() {
3626            #[cfg(feature = "threads")]
3627            {
3628                let store = store.as_context();
3629                Extern::SharedMemory(crate::SharedMemory::new(store.engine(), self.clone())?)
3630            }
3631            #[cfg(not(feature = "threads"))]
3632            {
3633                bail!("creation of shared memories disabled at compile time")
3634            }
3635        } else {
3636            Extern::Memory(crate::Memory::new(store, self.clone())?)
3637        })
3638    }
3639}
3640
3641// Import Types
3642
3643/// A descriptor for an imported value into a wasm module.
3644///
3645/// This type is primarily accessed from the
3646/// [`Module::imports`](crate::Module::imports) API. Each [`ImportType`]
3647/// describes an import into the wasm module with the module/name that it's
3648/// imported from as well as the type of item that's being imported.
3649#[derive(Clone)]
3650pub struct ImportType<'module> {
3651    /// The module of the import.
3652    module: &'module str,
3653
3654    /// The field of the import.
3655    name: &'module str,
3656
3657    /// The type of the import.
3658    ty: EntityType,
3659    types: &'module ModuleTypes,
3660    engine: &'module Engine,
3661}
3662
3663impl<'module> ImportType<'module> {
3664    /// Creates a new import descriptor which comes from `module` and `name` and
3665    /// is of type `ty`.
3666    pub(crate) fn new(
3667        module: &'module str,
3668        name: &'module str,
3669        ty: EntityType,
3670        types: &'module ModuleTypes,
3671        engine: &'module Engine,
3672    ) -> ImportType<'module> {
3673        assert!(ty.is_canonicalized_for_runtime_usage());
3674        ImportType {
3675            module,
3676            name,
3677            ty,
3678            types,
3679            engine,
3680        }
3681    }
3682
3683    /// Returns the module name that this import is expected to come from.
3684    pub fn module(&self) -> &'module str {
3685        self.module
3686    }
3687
3688    /// Returns the field name of the module that this import is expected to
3689    /// come from.
3690    pub fn name(&self) -> &'module str {
3691        self.name
3692    }
3693
3694    /// Returns the expected type of this import.
3695    pub fn ty(&self) -> ExternType {
3696        ExternType::from_wasmtime(self.engine, self.types, &self.ty)
3697    }
3698}
3699
3700impl<'module> fmt::Debug for ImportType<'module> {
3701    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3702        f.debug_struct("ImportType")
3703            .field("module", &self.module())
3704            .field("name", &self.name())
3705            .field("ty", &self.ty())
3706            .finish()
3707    }
3708}
3709
3710// Export Types
3711
3712/// A descriptor for an exported WebAssembly value.
3713///
3714/// This type is primarily accessed from the
3715/// [`Module::exports`](crate::Module::exports) accessor and describes what
3716/// names are exported from a wasm module and the type of the item that is
3717/// exported.
3718#[derive(Clone)]
3719pub struct ExportType<'module> {
3720    /// The name of the export.
3721    name: &'module str,
3722
3723    /// The type of the export.
3724    ty: EntityType,
3725    types: &'module ModuleTypes,
3726    engine: &'module Engine,
3727}
3728
3729impl<'module> ExportType<'module> {
3730    /// Creates a new export which is exported with the given `name` and has the
3731    /// given `ty`.
3732    pub(crate) fn new(
3733        name: &'module str,
3734        ty: EntityType,
3735        types: &'module ModuleTypes,
3736        engine: &'module Engine,
3737    ) -> ExportType<'module> {
3738        ExportType {
3739            name,
3740            ty,
3741            types,
3742            engine,
3743        }
3744    }
3745
3746    /// Returns the name by which this export is known.
3747    pub fn name(&self) -> &'module str {
3748        self.name
3749    }
3750
3751    /// Returns the type of this export.
3752    pub fn ty(&self) -> ExternType {
3753        ExternType::from_wasmtime(self.engine, self.types, &self.ty)
3754    }
3755}
3756
3757impl<'module> fmt::Debug for ExportType<'module> {
3758    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3759        f.debug_struct("ExportType")
3760            .field("name", &self.name().to_owned())
3761            .field("ty", &self.ty())
3762            .finish()
3763    }
3764}