Skip to main content

wasmtime/runtime/
types.rs

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