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