dusk_wasmtime/runtime/
types.rs

1use anyhow::{bail, Result};
2use std::fmt::{self, Display};
3use wasmtime_environ::{
4    EngineOrModuleTypeIndex, EntityType, Global, Memory, ModuleTypes, Table, TypeTrace,
5    WasmFuncType, WasmHeapType, WasmRefType, WasmValType,
6};
7use wasmtime_runtime::VMSharedTypeIndex;
8
9use crate::{type_registry::RegisteredType, Engine};
10
11pub(crate) mod matching;
12
13// Type Representations
14
15// Type attributes
16
17/// Indicator of whether a global is mutable or not
18#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
19pub enum Mutability {
20    /// The global is constant and its value does not change
21    Const,
22    /// The value of the global can change over time
23    Var,
24}
25
26// Value Types
27
28/// A list of all possible value types in WebAssembly.
29///
30/// # Subtyping and Equality
31///
32/// `ValType` does not implement `Eq`, because reference types have a subtyping
33/// relationship, and so 99.99% of the time you actually want to check whether
34/// one type matches (i.e. is a subtype of) another type. You can use the
35/// [`ValType::matches`] and [`Val::matches_ty`][crate::Val::matches_ty] methods
36/// to perform these types of checks. If, however, you are in that 0.01%
37/// scenario where you need to check precise equality between types, you can use
38/// the [`ValType::eq`] method.
39#[derive(Clone, Hash)]
40pub enum ValType {
41    // NB: the ordering of variants here is intended to match the ordering in
42    // `wasmtime_types::WasmType` to help improve codegen when converting.
43    //
44    /// Signed 32 bit integer.
45    I32,
46    /// Signed 64 bit integer.
47    I64,
48    /// Floating point 32 bit integer.
49    F32,
50    /// Floating point 64 bit integer.
51    F64,
52    /// A 128 bit number.
53    V128,
54    /// An opaque reference to some type on the heap.
55    Ref(RefType),
56}
57
58impl fmt::Debug for ValType {
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60        fmt::Display::fmt(self, f)
61    }
62}
63
64impl Display for ValType {
65    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66        match self {
67            ValType::I32 => write!(f, "i32"),
68            ValType::I64 => write!(f, "i64"),
69            ValType::F32 => write!(f, "f32"),
70            ValType::F64 => write!(f, "f64"),
71            ValType::V128 => write!(f, "v128"),
72            ValType::Ref(r) => Display::fmt(r, f),
73        }
74    }
75}
76
77impl From<RefType> for ValType {
78    #[inline]
79    fn from(r: RefType) -> Self {
80        ValType::Ref(r)
81    }
82}
83
84impl ValType {
85    /// The `externref` type, aka `(ref null extern)`.
86    pub const EXTERNREF: Self = ValType::Ref(RefType::EXTERNREF);
87
88    /// The `funcref` type, aka `(ref null func)`.
89    pub const FUNCREF: Self = ValType::Ref(RefType::FUNCREF);
90
91    /// The `nullfuncref` type, aka `(ref null nofunc)`.
92    pub const NULLFUNCREF: Self = ValType::Ref(RefType::NULLFUNCREF);
93
94    /// The `anyref` type, aka `(ref null any)`.
95    pub const ANYREF: Self = ValType::Ref(RefType::ANYREF);
96
97    /// The `i31ref` type, aka `(ref null i31)`.
98    pub const I31REF: Self = ValType::Ref(RefType::I31REF);
99
100    /// The `nullref` type, aka `(ref null none)`.
101    pub const NULLREF: Self = ValType::Ref(RefType::NULLREF);
102
103    /// Returns true if `ValType` matches any of the numeric types. (e.g. `I32`,
104    /// `I64`, `F32`, `F64`).
105    #[inline]
106    pub fn is_num(&self) -> bool {
107        match self {
108            ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => true,
109            _ => false,
110        }
111    }
112
113    /// Is this the `i32` type?
114    #[inline]
115    pub fn is_i32(&self) -> bool {
116        matches!(self, ValType::I32)
117    }
118
119    /// Is this the `i64` type?
120    #[inline]
121    pub fn is_i64(&self) -> bool {
122        matches!(self, ValType::I64)
123    }
124
125    /// Is this the `f32` type?
126    #[inline]
127    pub fn is_f32(&self) -> bool {
128        matches!(self, ValType::F32)
129    }
130
131    /// Is this the `f64` type?
132    #[inline]
133    pub fn is_f64(&self) -> bool {
134        matches!(self, ValType::F64)
135    }
136
137    /// Is this the `v128` type?
138    #[inline]
139    pub fn is_v128(&self) -> bool {
140        matches!(self, ValType::V128)
141    }
142
143    /// Returns true if `ValType` is any kind of reference type.
144    #[inline]
145    pub fn is_ref(&self) -> bool {
146        matches!(self, ValType::Ref(_))
147    }
148
149    /// Is this the `funcref` (aka `(ref null func)`) type?
150    #[inline]
151    pub fn is_funcref(&self) -> bool {
152        matches!(
153            self,
154            ValType::Ref(RefType {
155                is_nullable: true,
156                heap_type: HeapType::Func
157            })
158        )
159    }
160
161    /// Is this the `externref` (aka `(ref null extern)`) type?
162    #[inline]
163    pub fn is_externref(&self) -> bool {
164        matches!(
165            self,
166            ValType::Ref(RefType {
167                is_nullable: true,
168                heap_type: HeapType::Extern
169            })
170        )
171    }
172
173    /// Is this the `anyref` (aka `(ref null any)`) type?
174    #[inline]
175    pub fn is_anyref(&self) -> bool {
176        matches!(
177            self,
178            ValType::Ref(RefType {
179                is_nullable: true,
180                heap_type: HeapType::Any
181            })
182        )
183    }
184
185    /// Get the underlying reference type, if this value type is a reference
186    /// type.
187    #[inline]
188    pub fn as_ref(&self) -> Option<&RefType> {
189        match self {
190            ValType::Ref(r) => Some(r),
191            _ => None,
192        }
193    }
194
195    /// Get the underlying reference type, panicking if this value type is not a
196    /// reference type.
197    #[inline]
198    pub fn unwrap_ref(&self) -> &RefType {
199        self.as_ref()
200            .expect("ValType::unwrap_ref on a non-reference type")
201    }
202
203    /// Does this value type match the other type?
204    ///
205    /// That is, is this value type a subtype of the other?
206    ///
207    /// # Panics
208    ///
209    /// Panics if either type is associated with a different engine from the
210    /// other.
211    pub fn matches(&self, other: &ValType) -> bool {
212        match (self, other) {
213            (Self::I32, Self::I32) => true,
214            (Self::I64, Self::I64) => true,
215            (Self::F32, Self::F32) => true,
216            (Self::F64, Self::F64) => true,
217            (Self::V128, Self::V128) => true,
218            (Self::Ref(a), Self::Ref(b)) => a.matches(b),
219            (Self::I32, _)
220            | (Self::I64, _)
221            | (Self::F32, _)
222            | (Self::F64, _)
223            | (Self::V128, _)
224            | (Self::Ref(_), _) => false,
225        }
226    }
227
228    /// Is value type `a` precisely equal to value type `b`?
229    ///
230    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
231    /// are not exactly the same value type.
232    ///
233    /// # Panics
234    ///
235    /// Panics if either type is associated with a different engine.
236    pub fn eq(a: &Self, b: &Self) -> bool {
237        a.matches(b) && b.matches(a)
238    }
239
240    pub(crate) fn ensure_matches(&self, engine: &Engine, other: &ValType) -> Result<()> {
241        if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) {
242            bail!("type used with wrong engine");
243        }
244        if self.matches(other) {
245            Ok(())
246        } else {
247            bail!("type mismatch: expected {other}, found {self}")
248        }
249    }
250
251    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
252        match self {
253            Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128 => true,
254            Self::Ref(r) => r.comes_from_same_engine(engine),
255        }
256    }
257
258    pub(crate) fn to_wasm_type(&self) -> WasmValType {
259        match self {
260            Self::I32 => WasmValType::I32,
261            Self::I64 => WasmValType::I64,
262            Self::F32 => WasmValType::F32,
263            Self::F64 => WasmValType::F64,
264            Self::V128 => WasmValType::V128,
265            Self::Ref(r) => WasmValType::Ref(r.to_wasm_type()),
266        }
267    }
268
269    #[inline]
270    pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmValType) -> Self {
271        match ty {
272            WasmValType::I32 => Self::I32,
273            WasmValType::I64 => Self::I64,
274            WasmValType::F32 => Self::F32,
275            WasmValType::F64 => Self::F64,
276            WasmValType::V128 => Self::V128,
277            WasmValType::Ref(r) => Self::Ref(RefType::from_wasm_type(engine, r)),
278        }
279    }
280}
281
282/// Opaque references to data in the Wasm heap or to host data.
283///
284/// # Subtyping and Equality
285///
286/// `RefType` does not implement `Eq`, because reference types have a subtyping
287/// relationship, and so 99.99% of the time you actually want to check whether
288/// one type matches (i.e. is a subtype of) another type. You can use the
289/// [`RefType::matches`] and [`Ref::matches_ty`][crate::Ref::matches_ty] methods
290/// to perform these types of checks. If, however, you are in that 0.01%
291/// scenario where you need to check precise equality between types, you can use
292/// the [`RefType::eq`] method.
293#[derive(Clone, Hash)]
294pub struct RefType {
295    is_nullable: bool,
296    heap_type: HeapType,
297}
298
299impl fmt::Debug for RefType {
300    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
301        Display::fmt(self, f)
302    }
303}
304
305impl fmt::Display for RefType {
306    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
307        write!(f, "(ref ")?;
308        if self.is_nullable() {
309            write!(f, "null ")?;
310        }
311        write!(f, "{})", self.heap_type())
312    }
313}
314
315impl RefType {
316    /// The `externref` type, aka `(ref null extern)`.
317    pub const EXTERNREF: Self = RefType {
318        is_nullable: true,
319        heap_type: HeapType::Extern,
320    };
321
322    /// The `funcref` type, aka `(ref null func)`.
323    pub const FUNCREF: Self = RefType {
324        is_nullable: true,
325        heap_type: HeapType::Func,
326    };
327
328    /// The `nullfuncref` type, aka `(ref null nofunc)`.
329    pub const NULLFUNCREF: Self = RefType {
330        is_nullable: true,
331        heap_type: HeapType::NoFunc,
332    };
333
334    /// The `anyref` type, aka `(ref null any)`.
335    pub const ANYREF: Self = RefType {
336        is_nullable: true,
337        heap_type: HeapType::Any,
338    };
339
340    /// The `i31ref` type, aka `(ref null i31)`.
341    pub const I31REF: Self = RefType {
342        is_nullable: true,
343        heap_type: HeapType::I31,
344    };
345
346    /// The `nullref` type, aka `(ref null none)`.
347    pub const NULLREF: Self = RefType {
348        is_nullable: true,
349        heap_type: HeapType::None,
350    };
351
352    /// Construct a new reference type.
353    pub fn new(is_nullable: bool, heap_type: HeapType) -> RefType {
354        RefType {
355            is_nullable,
356            heap_type,
357        }
358    }
359
360    /// Can this type of reference be null?
361    pub fn is_nullable(&self) -> bool {
362        self.is_nullable
363    }
364
365    /// The heap type that this is a reference to.
366    pub fn heap_type(&self) -> &HeapType {
367        &self.heap_type
368    }
369
370    /// Does this reference type match the other?
371    ///
372    /// That is, is this reference type a subtype of the other?
373    ///
374    /// # Panics
375    ///
376    /// Panics if either type is associated with a different engine from the
377    /// other.
378    pub fn matches(&self, other: &RefType) -> bool {
379        if self.is_nullable() && !other.is_nullable() {
380            return false;
381        }
382        self.heap_type().matches(other.heap_type())
383    }
384
385    /// Is reference type `a` precisely equal to reference type `b`?
386    ///
387    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
388    /// are not exactly the same reference type.
389    ///
390    /// # Panics
391    ///
392    /// Panics if either type is associated with a different engine.
393    pub fn eq(a: &RefType, b: &RefType) -> bool {
394        a.matches(b) && b.matches(a)
395    }
396
397    pub(crate) fn ensure_matches(&self, engine: &Engine, other: &RefType) -> Result<()> {
398        if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) {
399            bail!("type used with wrong engine");
400        }
401        if self.matches(other) {
402            Ok(())
403        } else {
404            bail!("type mismatch: expected {other}, found {self}")
405        }
406    }
407
408    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
409        self.heap_type().comes_from_same_engine(engine)
410    }
411
412    pub(crate) fn to_wasm_type(&self) -> WasmRefType {
413        WasmRefType {
414            nullable: self.is_nullable(),
415            heap_type: self.heap_type().to_wasm_type(),
416        }
417    }
418
419    pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmRefType) -> RefType {
420        RefType {
421            is_nullable: ty.nullable,
422            heap_type: HeapType::from_wasm_type(engine, &ty.heap_type),
423        }
424    }
425
426    pub(crate) fn is_gc_heap_type(&self) -> bool {
427        self.heap_type().is_gc_heap_type()
428    }
429}
430
431/// The heap types that can Wasm can have references to.
432///
433/// # Subtyping and Equality
434///
435/// `HeapType` does not implement `Eq`, because heap types have a subtyping
436/// relationship, and so 99.99% of the time you actually want to check whether
437/// one type matches (i.e. is a subtype of) another type. You can use the
438/// [`HeapType::matches`] method to perform these types of checks. If, however,
439/// you are in that 0.01% scenario where you need to check precise equality
440/// between types, you can use the [`HeapType::eq`] method.
441#[derive(Debug, Clone, Hash)]
442pub enum HeapType {
443    /// The `extern` heap type represents external host data.
444    Extern,
445
446    /// The `func` heap type represents a reference to any kind of function.
447    ///
448    /// This is the top type for the function references type hierarchy, and is
449    /// therefore a supertype of every function reference.
450    Func,
451
452    /// The concrete heap type represents a reference to a function of a
453    /// specific, concrete type.
454    ///
455    /// This is a subtype of `func` and a supertype of `nofunc`.
456    Concrete(FuncType),
457
458    /// The `nofunc` heap type represents the null function reference.
459    ///
460    /// This is the bottom type for the function references type hierarchy, and
461    /// therefore `nofunc` is a subtype of all function reference types.
462    NoFunc,
463
464    /// The abstract `any` heap type represents all internal Wasm data.
465    ///
466    /// This is the top type of the internal type hierarchy, and is therefore a
467    /// supertype of all internal types (such as `i31`, `struct`s, and
468    /// `array`s).
469    Any,
470
471    /// The `i31` heap type represents unboxed 31-bit integers.
472    I31,
473
474    /// The abstract `none` heap type represents the null internal reference.
475    ///
476    /// This is the bottom type for the internal type hierarchy, and therefore
477    /// `none` is a subtype of internal types.
478    None,
479}
480
481impl Display for HeapType {
482    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
483        match self {
484            HeapType::Extern => write!(f, "extern"),
485            HeapType::Func => write!(f, "func"),
486            HeapType::NoFunc => write!(f, "nofunc"),
487            HeapType::Any => write!(f, "any"),
488            HeapType::I31 => write!(f, "i31"),
489            HeapType::None => write!(f, "none"),
490            HeapType::Concrete(ty) => write!(f, "(concrete {:?})", ty.type_index()),
491        }
492    }
493}
494
495impl From<FuncType> for HeapType {
496    #[inline]
497    fn from(f: FuncType) -> Self {
498        HeapType::Concrete(f)
499    }
500}
501
502impl HeapType {
503    /// Is this the abstract `extern` heap type?
504    pub fn is_extern(&self) -> bool {
505        matches!(self, HeapType::Extern)
506    }
507
508    /// Is this the abstract `func` heap type?
509    pub fn is_func(&self) -> bool {
510        matches!(self, HeapType::Func)
511    }
512
513    /// Is this the abstract `nofunc` heap type?
514    pub fn is_no_func(&self) -> bool {
515        matches!(self, HeapType::NoFunc)
516    }
517
518    /// Is this the abstract `any` heap type?
519    pub fn is_any(&self) -> bool {
520        matches!(self, HeapType::Any)
521    }
522
523    /// Is this the abstract `i31` heap type?
524    pub fn is_i31(&self) -> bool {
525        matches!(self, HeapType::I31)
526    }
527
528    /// Is this the abstract `none` heap type?
529    pub fn is_none(&self) -> bool {
530        matches!(self, HeapType::None)
531    }
532
533    /// Is this an abstract type?
534    ///
535    /// Types that are not abstract are concrete, user-defined types.
536    pub fn is_abstract(&self) -> bool {
537        !self.is_concrete()
538    }
539
540    /// Is this a concrete, user-defined heap type?
541    ///
542    /// Types that are not concrete, user-defined types are abstract types.
543    pub fn is_concrete(&self) -> bool {
544        matches!(self, HeapType::Concrete(_))
545    }
546
547    /// Get the underlying concrete, user-defined type, if any.
548    ///
549    /// Returns `None` for abstract types.
550    pub fn as_concrete(&self) -> Option<&FuncType> {
551        match self {
552            HeapType::Concrete(f) => Some(f),
553            _ => None,
554        }
555    }
556
557    /// Get the underlying concrete, user-defined type, panicking if this heap
558    /// type is not concrete.
559    pub fn unwrap_concrete(&self) -> &FuncType {
560        self.as_concrete()
561            .expect("HeapType::unwrap_concrete on non-concrete heap type")
562    }
563
564    /// Get the top type of this heap type's type hierarchy.
565    ///
566    /// The returned heap type is a supertype of all types in this heap type's
567    /// type hierarchy.
568    pub fn top(&self, engine: &Engine) -> HeapType {
569        // The engine isn't used yet, but will be once we support Wasm GC, so
570        // future-proof our API.
571        let _ = engine;
572
573        match self {
574            HeapType::Func | HeapType::Concrete(_) | HeapType::NoFunc => HeapType::Func,
575            HeapType::Extern => HeapType::Extern,
576            HeapType::Any | HeapType::I31 | HeapType::None => HeapType::Any,
577        }
578    }
579
580    /// Does this heap type match the other heap type?
581    ///
582    /// That is, is this heap type a subtype of the other?
583    ///
584    /// # Panics
585    ///
586    /// Panics if either type is associated with a different engine from the
587    /// other.
588    pub fn matches(&self, other: &HeapType) -> bool {
589        match (self, other) {
590            (HeapType::Extern, HeapType::Extern) => true,
591            (HeapType::Extern, _) => false,
592
593            (HeapType::NoFunc, HeapType::NoFunc | HeapType::Concrete(_) | HeapType::Func) => true,
594            (HeapType::NoFunc, _) => false,
595
596            (HeapType::Concrete(_), HeapType::Func) => true,
597            (HeapType::Concrete(a), HeapType::Concrete(b)) => a.matches(b),
598            (HeapType::Concrete(_), _) => false,
599
600            (HeapType::Func, HeapType::Func) => true,
601            (HeapType::Func, _) => false,
602
603            (HeapType::None, HeapType::None | HeapType::I31 | HeapType::Any) => true,
604            (HeapType::None, _) => false,
605
606            (HeapType::I31, HeapType::I31 | HeapType::Any) => true,
607            (HeapType::I31, _) => false,
608
609            (HeapType::Any, HeapType::Any) => true,
610            (HeapType::Any, _) => false,
611        }
612    }
613
614    /// Is heap type `a` precisely equal to heap type `b`?
615    ///
616    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
617    /// are not exactly the same heap type.
618    ///
619    /// # Panics
620    ///
621    /// Panics if either type is associated with a different engine from the
622    /// other.
623    pub fn eq(a: &HeapType, b: &HeapType) -> bool {
624        a.matches(b) && b.matches(a)
625    }
626
627    pub(crate) fn ensure_matches(&self, engine: &Engine, other: &HeapType) -> Result<()> {
628        if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) {
629            bail!("type used with wrong engine");
630        }
631        if self.matches(other) {
632            Ok(())
633        } else {
634            bail!("type mismatch: expected {other}, found {self}");
635        }
636    }
637
638    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
639        match self {
640            HeapType::Extern
641            | HeapType::Func
642            | HeapType::NoFunc
643            | HeapType::Any
644            | HeapType::I31
645            | HeapType::None => true,
646            HeapType::Concrete(ty) => ty.comes_from_same_engine(engine),
647        }
648    }
649
650    pub(crate) fn to_wasm_type(&self) -> WasmHeapType {
651        match self {
652            HeapType::Extern => WasmHeapType::Extern,
653            HeapType::Func => WasmHeapType::Func,
654            HeapType::NoFunc => WasmHeapType::NoFunc,
655            HeapType::Any => WasmHeapType::Any,
656            HeapType::I31 => WasmHeapType::I31,
657            HeapType::None => WasmHeapType::None,
658            HeapType::Concrete(f) => {
659                WasmHeapType::Concrete(EngineOrModuleTypeIndex::Engine(f.type_index().bits()))
660            }
661        }
662    }
663
664    pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmHeapType) -> HeapType {
665        match ty {
666            WasmHeapType::Extern => HeapType::Extern,
667            WasmHeapType::Func => HeapType::Func,
668            WasmHeapType::NoFunc => HeapType::NoFunc,
669            WasmHeapType::Any => HeapType::Any,
670            WasmHeapType::I31 => HeapType::I31,
671            WasmHeapType::None => HeapType::None,
672            WasmHeapType::Concrete(EngineOrModuleTypeIndex::Engine(idx)) => {
673                let idx = VMSharedTypeIndex::new(*idx);
674                HeapType::Concrete(FuncType::from_shared_type_index(engine, idx))
675            }
676            WasmHeapType::Concrete(EngineOrModuleTypeIndex::Module(_)) => {
677                panic!("HeapType::from_wasm_type on non-canonical heap type")
678            }
679        }
680    }
681
682    pub(crate) fn is_gc_heap_type(&self) -> bool {
683        // All `t <: (ref null any)` and `t <: (ref null extern)` that are
684        // not `(ref null? i31)` are GC-managed references.
685        match self {
686            // These types are managed by the GC.
687            HeapType::Extern | HeapType::Any => true,
688
689            // TODO: Once we support concrete struct and array types, we will
690            // need to inspect the payload to determine whether this is a
691            // GC-managed type or not.
692            Self::Concrete(_) => false,
693
694            // These are compatible with GC references, but don't actually point
695            // to GC objecs. It would generally be safe to return `true` here,
696            // but there is no need to.
697            HeapType::I31 => false,
698
699            // These are a subtype of GC-managed types, but are uninhabited, so
700            // can never actually point to a GC object. Again, we could return
701            // `true` here but there is no need.
702            HeapType::None => false,
703
704            // These types are not managed by the GC.
705            HeapType::Func | HeapType::NoFunc => false,
706        }
707    }
708}
709
710// External Types
711
712/// A list of all possible types which can be externally referenced from a
713/// WebAssembly module.
714///
715/// This list can be found in [`ImportType`] or [`ExportType`], so these types
716/// can either be imported or exported.
717#[derive(Debug, Clone)]
718pub enum ExternType {
719    /// This external type is the type of a WebAssembly function.
720    Func(FuncType),
721    /// This external type is the type of a WebAssembly global.
722    Global(GlobalType),
723    /// This external type is the type of a WebAssembly table.
724    Table(TableType),
725    /// This external type is the type of a WebAssembly memory.
726    Memory(MemoryType),
727}
728
729macro_rules! extern_type_accessors {
730    ($(($variant:ident($ty:ty) $get:ident $unwrap:ident))*) => ($(
731        /// Attempt to return the underlying type of this external type,
732        /// returning `None` if it is a different type.
733        pub fn $get(&self) -> Option<&$ty> {
734            if let ExternType::$variant(e) = self {
735                Some(e)
736            } else {
737                None
738            }
739        }
740
741        /// Returns the underlying descriptor of this [`ExternType`], panicking
742        /// if it is a different type.
743        ///
744        /// # Panics
745        ///
746        /// Panics if `self` is not of the right type.
747        pub fn $unwrap(&self) -> &$ty {
748            self.$get().expect(concat!("expected ", stringify!($ty)))
749        }
750    )*)
751}
752
753impl ExternType {
754    extern_type_accessors! {
755        (Func(FuncType) func unwrap_func)
756        (Global(GlobalType) global unwrap_global)
757        (Table(TableType) table unwrap_table)
758        (Memory(MemoryType) memory unwrap_memory)
759    }
760
761    pub(crate) fn from_wasmtime(
762        engine: &Engine,
763        types: &ModuleTypes,
764        ty: &EntityType,
765    ) -> ExternType {
766        match ty {
767            EntityType::Function(idx) => match idx {
768                EngineOrModuleTypeIndex::Engine(e) => {
769                    FuncType::from_shared_type_index(engine, VMSharedTypeIndex::new(*e)).into()
770                }
771                EngineOrModuleTypeIndex::Module(m) => {
772                    FuncType::from_wasm_func_type(engine, types[*m].clone()).into()
773                }
774            },
775            EntityType::Global(ty) => GlobalType::from_wasmtime_global(engine, ty).into(),
776            EntityType::Memory(ty) => MemoryType::from_wasmtime_memory(ty).into(),
777            EntityType::Table(ty) => TableType::from_wasmtime_table(engine, ty).into(),
778            EntityType::Tag(_) => unimplemented!("wasm tag support"),
779        }
780    }
781}
782
783impl From<FuncType> for ExternType {
784    fn from(ty: FuncType) -> ExternType {
785        ExternType::Func(ty)
786    }
787}
788
789impl From<GlobalType> for ExternType {
790    fn from(ty: GlobalType) -> ExternType {
791        ExternType::Global(ty)
792    }
793}
794
795impl From<MemoryType> for ExternType {
796    fn from(ty: MemoryType) -> ExternType {
797        ExternType::Memory(ty)
798    }
799}
800
801impl From<TableType> for ExternType {
802    fn from(ty: TableType) -> ExternType {
803        ExternType::Table(ty)
804    }
805}
806
807/// The type of a WebAssembly function.
808///
809/// WebAssembly functions can have 0 or more parameters and results.
810///
811/// # Subtyping and Equality
812///
813/// `FuncType` does not implement `Eq`, because reference types have a subtyping
814/// relationship, and so 99.99% of the time you actually want to check whether
815/// one type matches (i.e. is a subtype of) another type. You can use the
816/// [`FuncType::matches`] and [`Func::matches_ty`][crate::Func::matches_ty]
817/// methods to perform these types of checks. If, however, you are in that 0.01%
818/// scenario where you need to check precise equality between types, you can use
819/// the [`FuncType::eq`] method.
820#[derive(Debug, Clone, Hash)]
821pub struct FuncType {
822    registered_type: RegisteredType,
823}
824
825impl Display for FuncType {
826    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
827        write!(f, "(type (func")?;
828        if self.params().len() > 0 {
829            write!(f, " (param")?;
830            for p in self.params() {
831                write!(f, " {p}")?;
832            }
833            write!(f, ")")?;
834        }
835        if self.results().len() > 0 {
836            write!(f, " (result")?;
837            for r in self.results() {
838                write!(f, " {r}")?;
839            }
840            write!(f, ")")?;
841        }
842        write!(f, "))")
843    }
844}
845
846impl FuncType {
847    /// Creates a new function descriptor from the given parameters and results.
848    ///
849    /// The function descriptor returned will represent a function which takes
850    /// `params` as arguments and returns `results` when it is finished.
851    pub fn new(
852        engine: &Engine,
853        params: impl IntoIterator<Item = ValType>,
854        results: impl IntoIterator<Item = ValType>,
855    ) -> FuncType {
856        // Keep any of our parameters' and results' `RegisteredType`s alive
857        // across `Self::from_wasm_func_type`. If one of our given `ValType`s is
858        // the only thing keeping a type in the registry, we don't want to
859        // unregister it when we convert the `ValType` into a `WasmValType` just
860        // before we register our new `WasmFuncType` that will reference it.
861        let mut registrations = vec![];
862
863        let mut to_wasm_type = |ty: ValType| {
864            if let Some(r) = ty.as_ref() {
865                if let Some(c) = r.heap_type().as_concrete() {
866                    registrations.push(c.registered_type.clone());
867                }
868            }
869            ty.to_wasm_type()
870        };
871
872        Self::from_wasm_func_type(
873            engine,
874            WasmFuncType::new(
875                params.into_iter().map(&mut to_wasm_type).collect(),
876                results.into_iter().map(&mut to_wasm_type).collect(),
877            ),
878        )
879    }
880
881    /// Get the engine that this function type is associated with.
882    pub fn engine(&self) -> &Engine {
883        self.registered_type.engine()
884    }
885
886    /// Get the `i`th parameter type.
887    ///
888    /// Returns `None` if `i` is out of bounds.
889    pub fn param(&self, i: usize) -> Option<ValType> {
890        let engine = self.engine();
891        self.registered_type
892            .params()
893            .get(i)
894            .map(|ty| ValType::from_wasm_type(engine, ty))
895    }
896
897    /// Returns the list of parameter types for this function.
898    #[inline]
899    pub fn params(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
900        let engine = self.engine();
901        self.registered_type
902            .params()
903            .iter()
904            .map(|ty| ValType::from_wasm_type(engine, ty))
905    }
906
907    /// Get the `i`th result type.
908    ///
909    /// Returns `None` if `i` is out of bounds.
910    pub fn result(&self, i: usize) -> Option<ValType> {
911        let engine = self.engine();
912        self.registered_type
913            .returns()
914            .get(i)
915            .map(|ty| ValType::from_wasm_type(engine, ty))
916    }
917
918    /// Returns the list of result types for this function.
919    #[inline]
920    pub fn results(&self) -> impl ExactSizeIterator<Item = ValType> + '_ {
921        let engine = self.engine();
922        self.registered_type
923            .returns()
924            .iter()
925            .map(|ty| ValType::from_wasm_type(engine, ty))
926    }
927
928    /// Does this function type match the other function type?
929    ///
930    /// That is, is this function type a subtype of the other function type?
931    ///
932    /// # Panics
933    ///
934    /// Panics if either type is associated with a different engine from the
935    /// other.
936    pub fn matches(&self, other: &FuncType) -> bool {
937        assert!(self.comes_from_same_engine(other.engine()));
938
939        // Avoid matching on structure for subtyping checks when we have
940        // precisely the same type.
941        if self.type_index() == other.type_index() {
942            return true;
943        }
944
945        self.params().len() == other.params().len()
946            && self.results().len() == other.results().len()
947            // Params are contravariant and results are covariant. For more
948            // details and a refresher on variance, read
949            // https://github.com/bytecodealliance/wasm-tools/blob/f1d89a4/crates/wasmparser/src/readers/core/types/matches.rs#L137-L174
950            && self
951                .params()
952                .zip(other.params())
953                .all(|(a, b)| b.matches(&a))
954            && self
955                .results()
956                .zip(other.results())
957                .all(|(a, b)| a.matches(&b))
958    }
959
960    /// Is function type `a` precisely equal to function type `b`?
961    ///
962    /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they
963    /// are not exactly the same function type.
964    ///
965    /// # Panics
966    ///
967    /// Panics if either type is associated with a different engine from the
968    /// other.
969    pub fn eq(a: &FuncType, b: &FuncType) -> bool {
970        assert!(a.comes_from_same_engine(b.engine()));
971        a.type_index() == b.type_index()
972    }
973
974    pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool {
975        Engine::same(self.registered_type.engine(), engine)
976    }
977
978    pub(crate) fn type_index(&self) -> VMSharedTypeIndex {
979        self.registered_type.index()
980    }
981
982    pub(crate) fn as_wasm_func_type(&self) -> &WasmFuncType {
983        &self.registered_type
984    }
985
986    pub(crate) fn into_registered_type(self) -> RegisteredType {
987        self.registered_type
988    }
989
990    /// Construct a `FuncType` from a `WasmFuncType`.
991    ///
992    /// This method should only be used when something has already registered --
993    /// and is *keeping registered* -- any other concrete Wasm types referenced
994    /// by the given `WasmFuncType`.
995    ///
996    /// For example, this method may be called to convert a function type from
997    /// within a Wasm module's `ModuleTypes` since the Wasm module itself is
998    /// holding a strong reference to all of its types, including any `(ref null
999    /// <index>)` types used in the function's parameters and results.
1000    pub(crate) fn from_wasm_func_type(engine: &Engine, ty: WasmFuncType) -> FuncType {
1001        let ty = RegisteredType::new(engine, ty);
1002        Self {
1003            registered_type: ty,
1004        }
1005    }
1006
1007    pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> FuncType {
1008        let ty = RegisteredType::root(engine, index).expect(
1009            "VMSharedTypeIndex is not registered in the Engine! Wrong \
1010             engine? Didn't root the index somewhere?",
1011        );
1012        Self {
1013            registered_type: ty,
1014        }
1015    }
1016}
1017
1018// Global Types
1019
1020/// A WebAssembly global descriptor.
1021///
1022/// This type describes an instance of a global in a WebAssembly module. Globals
1023/// are local to an [`Instance`](crate::Instance) and are either immutable or
1024/// mutable.
1025#[derive(Debug, Clone, Hash)]
1026pub struct GlobalType {
1027    content: ValType,
1028    mutability: Mutability,
1029}
1030
1031impl GlobalType {
1032    /// Creates a new global descriptor of the specified `content` type and
1033    /// whether or not it's mutable.
1034    pub fn new(content: ValType, mutability: Mutability) -> GlobalType {
1035        GlobalType {
1036            content,
1037            mutability,
1038        }
1039    }
1040
1041    /// Returns the value type of this global descriptor.
1042    pub fn content(&self) -> &ValType {
1043        &self.content
1044    }
1045
1046    /// Returns whether or not this global is mutable.
1047    pub fn mutability(&self) -> Mutability {
1048        self.mutability
1049    }
1050
1051    pub(crate) fn to_wasm_type(&self) -> Global {
1052        let wasm_ty = self.content().to_wasm_type();
1053        let mutability = matches!(self.mutability(), Mutability::Var);
1054        Global {
1055            wasm_ty,
1056            mutability,
1057        }
1058    }
1059
1060    /// Returns `None` if the wasmtime global has a type that we can't
1061    /// represent, but that should only very rarely happen and indicate a bug.
1062    pub(crate) fn from_wasmtime_global(engine: &Engine, global: &Global) -> GlobalType {
1063        let ty = ValType::from_wasm_type(engine, &global.wasm_ty);
1064        let mutability = if global.mutability {
1065            Mutability::Var
1066        } else {
1067            Mutability::Const
1068        };
1069        GlobalType::new(ty, mutability)
1070    }
1071}
1072
1073// Table Types
1074
1075/// A descriptor for a table in a WebAssembly module.
1076///
1077/// Tables are contiguous chunks of a specific element, typically a `funcref` or
1078/// an `externref`. The most common use for tables is a function table through
1079/// which `call_indirect` can invoke other functions.
1080#[derive(Debug, Clone, Hash)]
1081pub struct TableType {
1082    // Keep a `wasmtime::RefType` so that `TableType::element` doesn't need to
1083    // take an `&Engine`.
1084    element: RefType,
1085    ty: Table,
1086}
1087
1088impl TableType {
1089    /// Creates a new table descriptor which will contain the specified
1090    /// `element` and have the `limits` applied to its length.
1091    pub fn new(element: RefType, min: u32, max: Option<u32>) -> TableType {
1092        let wasm_ty = element.to_wasm_type();
1093
1094        if cfg!(debug_assertions) {
1095            wasm_ty
1096                .trace(&mut |idx| match idx {
1097                    EngineOrModuleTypeIndex::Engine(_) => Ok(()),
1098                    EngineOrModuleTypeIndex::Module(module_idx) => Err(format!(
1099                        "found module-level canonicalized type index: {module_idx:?}"
1100                    )),
1101                })
1102                .expect("element type should be engine-level canonicalized");
1103        }
1104
1105        TableType {
1106            element,
1107            ty: Table {
1108                wasm_ty,
1109                minimum: min,
1110                maximum: max,
1111            },
1112        }
1113    }
1114
1115    /// Returns the element value type of this table.
1116    pub fn element(&self) -> &RefType {
1117        &self.element
1118    }
1119
1120    /// Returns minimum number of elements this table must have
1121    pub fn minimum(&self) -> u32 {
1122        self.ty.minimum
1123    }
1124
1125    /// Returns the optionally-specified maximum number of elements this table
1126    /// can have.
1127    ///
1128    /// If this returns `None` then the table is not limited in size.
1129    pub fn maximum(&self) -> Option<u32> {
1130        self.ty.maximum
1131    }
1132
1133    pub(crate) fn from_wasmtime_table(engine: &Engine, table: &Table) -> TableType {
1134        let element = RefType::from_wasm_type(engine, &table.wasm_ty);
1135        TableType {
1136            element,
1137            ty: table.clone(),
1138        }
1139    }
1140
1141    pub(crate) fn wasmtime_table(&self) -> &Table {
1142        &self.ty
1143    }
1144}
1145
1146// Memory Types
1147
1148/// A descriptor for a WebAssembly memory type.
1149///
1150/// Memories are described in units of pages (64KB) and represent contiguous
1151/// chunks of addressable memory.
1152#[derive(Debug, Clone, Hash, Eq, PartialEq)]
1153pub struct MemoryType {
1154    ty: Memory,
1155}
1156
1157impl MemoryType {
1158    /// Creates a new descriptor for a 32-bit WebAssembly memory given the
1159    /// specified limits of the memory.
1160    ///
1161    /// The `minimum` and `maximum`  values here are specified in units of
1162    /// WebAssembly pages, which are 64k.
1163    pub fn new(minimum: u32, maximum: Option<u32>) -> MemoryType {
1164        MemoryType {
1165            ty: Memory {
1166                memory64: false,
1167                shared: false,
1168                minimum: minimum.into(),
1169                maximum: maximum.map(|i| i.into()),
1170            },
1171        }
1172    }
1173
1174    /// Creates a new descriptor for a 64-bit WebAssembly memory given the
1175    /// specified limits of the memory.
1176    ///
1177    /// The `minimum` and `maximum`  values here are specified in units of
1178    /// WebAssembly pages, which are 64k.
1179    ///
1180    /// Note that 64-bit memories are part of the memory64 proposal for
1181    /// WebAssembly which is not standardized yet.
1182    pub fn new64(minimum: u64, maximum: Option<u64>) -> MemoryType {
1183        MemoryType {
1184            ty: Memory {
1185                memory64: true,
1186                shared: false,
1187                minimum,
1188                maximum,
1189            },
1190        }
1191    }
1192
1193    /// Creates a new descriptor for shared WebAssembly memory given the
1194    /// specified limits of the memory.
1195    ///
1196    /// The `minimum` and `maximum`  values here are specified in units of
1197    /// WebAssembly pages, which are 64k.
1198    ///
1199    /// Note that shared memories are part of the threads proposal for
1200    /// WebAssembly which is not standardized yet.
1201    pub fn shared(minimum: u32, maximum: u32) -> MemoryType {
1202        MemoryType {
1203            ty: Memory {
1204                memory64: false,
1205                shared: true,
1206                minimum: minimum.into(),
1207                maximum: Some(maximum.into()),
1208            },
1209        }
1210    }
1211
1212    /// Returns whether this is a 64-bit memory or not.
1213    ///
1214    /// Note that 64-bit memories are part of the memory64 proposal for
1215    /// WebAssembly which is not standardized yet.
1216    pub fn is_64(&self) -> bool {
1217        self.ty.memory64
1218    }
1219
1220    /// Returns whether this is a shared memory or not.
1221    ///
1222    /// Note that shared memories are part of the threads proposal for
1223    /// WebAssembly which is not standardized yet.
1224    pub fn is_shared(&self) -> bool {
1225        self.ty.shared
1226    }
1227
1228    /// Returns minimum number of WebAssembly pages this memory must have.
1229    ///
1230    /// Note that the return value, while a `u64`, will always fit into a `u32`
1231    /// for 32-bit memories.
1232    pub fn minimum(&self) -> u64 {
1233        self.ty.minimum
1234    }
1235
1236    /// Returns the optionally-specified maximum number of pages this memory
1237    /// can have.
1238    ///
1239    /// If this returns `None` then the memory is not limited in size.
1240    ///
1241    /// Note that the return value, while a `u64`, will always fit into a `u32`
1242    /// for 32-bit memories.
1243    pub fn maximum(&self) -> Option<u64> {
1244        self.ty.maximum
1245    }
1246
1247    pub(crate) fn from_wasmtime_memory(memory: &Memory) -> MemoryType {
1248        MemoryType { ty: memory.clone() }
1249    }
1250
1251    pub(crate) fn wasmtime_memory(&self) -> &Memory {
1252        &self.ty
1253    }
1254}
1255
1256// Import Types
1257
1258/// A descriptor for an imported value into a wasm module.
1259///
1260/// This type is primarily accessed from the
1261/// [`Module::imports`](crate::Module::imports) API. Each [`ImportType`]
1262/// describes an import into the wasm module with the module/name that it's
1263/// imported from as well as the type of item that's being imported.
1264#[derive(Clone)]
1265pub struct ImportType<'module> {
1266    /// The module of the import.
1267    module: &'module str,
1268
1269    /// The field of the import.
1270    name: &'module str,
1271
1272    /// The type of the import.
1273    ty: EntityType,
1274    types: &'module ModuleTypes,
1275    engine: &'module Engine,
1276}
1277
1278impl<'module> ImportType<'module> {
1279    /// Creates a new import descriptor which comes from `module` and `name` and
1280    /// is of type `ty`.
1281    pub(crate) fn new(
1282        module: &'module str,
1283        name: &'module str,
1284        ty: EntityType,
1285        types: &'module ModuleTypes,
1286        engine: &'module Engine,
1287    ) -> ImportType<'module> {
1288        ImportType {
1289            module,
1290            name,
1291            ty,
1292            types,
1293            engine,
1294        }
1295    }
1296
1297    /// Returns the module name that this import is expected to come from.
1298    pub fn module(&self) -> &'module str {
1299        self.module
1300    }
1301
1302    /// Returns the field name of the module that this import is expected to
1303    /// come from.
1304    pub fn name(&self) -> &'module str {
1305        self.name
1306    }
1307
1308    /// Returns the expected type of this import.
1309    pub fn ty(&self) -> ExternType {
1310        ExternType::from_wasmtime(self.engine, self.types, &self.ty)
1311    }
1312}
1313
1314impl<'module> fmt::Debug for ImportType<'module> {
1315    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1316        f.debug_struct("ImportType")
1317            .field("module", &self.module())
1318            .field("name", &self.name())
1319            .field("ty", &self.ty())
1320            .finish()
1321    }
1322}
1323
1324// Export Types
1325
1326/// A descriptor for an exported WebAssembly value.
1327///
1328/// This type is primarily accessed from the
1329/// [`Module::exports`](crate::Module::exports) accessor and describes what
1330/// names are exported from a wasm module and the type of the item that is
1331/// exported.
1332#[derive(Clone)]
1333pub struct ExportType<'module> {
1334    /// The name of the export.
1335    name: &'module str,
1336
1337    /// The type of the export.
1338    ty: EntityType,
1339    types: &'module ModuleTypes,
1340    engine: &'module Engine,
1341}
1342
1343impl<'module> ExportType<'module> {
1344    /// Creates a new export which is exported with the given `name` and has the
1345    /// given `ty`.
1346    pub(crate) fn new(
1347        name: &'module str,
1348        ty: EntityType,
1349        types: &'module ModuleTypes,
1350        engine: &'module Engine,
1351    ) -> ExportType<'module> {
1352        ExportType {
1353            name,
1354            ty,
1355            types,
1356            engine,
1357        }
1358    }
1359
1360    /// Returns the name by which this export is known.
1361    pub fn name(&self) -> &'module str {
1362        self.name
1363    }
1364
1365    /// Returns the type of this export.
1366    pub fn ty(&self) -> ExternType {
1367        ExternType::from_wasmtime(self.engine, self.types, &self.ty)
1368    }
1369}
1370
1371impl<'module> fmt::Debug for ExportType<'module> {
1372    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1373        f.debug_struct("ExportType")
1374            .field("name", &self.name().to_owned())
1375            .field("ty", &self.ty())
1376            .finish()
1377    }
1378}