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