wasmtime/runtime/
types.rs

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