Skip to main content

wasmtime/runtime/
types.rs

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