wasmtime/runtime/
types.rs

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