wasmtime/runtime/
types.rs

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