wasmtime/runtime/component/
types.rs

1//! This module defines the `Type` type, representing the dynamic form of a component interface type.
2
3use crate::component::matching::InstanceType;
4use crate::{Engine, ExternType, FuncType};
5use alloc::sync::Arc;
6use core::fmt;
7use core::ops::Deref;
8use wasmtime_environ::PrimaryMap;
9use wasmtime_environ::component::{
10    ComponentTypes, Export, InterfaceType, ResourceIndex, TypeComponentIndex,
11    TypeComponentInstanceIndex, TypeDef, TypeEnumIndex, TypeFlagsIndex, TypeFuncIndex,
12    TypeFutureIndex, TypeFutureTableIndex, TypeListIndex, TypeModuleIndex, TypeOptionIndex,
13    TypeRecordIndex, TypeResourceTable, TypeResourceTableIndex, TypeResultIndex, TypeStreamIndex,
14    TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex,
15};
16
17pub use crate::component::resources::ResourceType;
18
19/// An owned and `'static` handle for type information in a component.
20///
21/// The components here are:
22///
23/// * `index` - a `TypeFooIndex` defined in the `wasmtime_environ` crate. This
24///   then points into the next field of...
25///
26/// * `types` - this is an allocation originally created from compilation and is
27///   stored in a compiled `Component`. This contains all types necessary and
28///   information about recursive structures and all other type information
29///   within the component. The above `index` points into this structure.
30///
31/// * `resources` - this is used to "close the loop" and represent a concrete
32///   instance type rather than an abstract component type. Instantiating a
33///   component with different resources produces different instance types but
34///   the same underlying component type, so this field serves the purpose to
35///   distinguish instance types from one another. This is runtime state created
36///   during instantiation and threaded through here.
37#[derive(Clone)]
38struct Handle<T> {
39    index: T,
40    types: Arc<ComponentTypes>,
41    resources: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
42}
43
44impl<T> Handle<T> {
45    fn new(index: T, ty: &InstanceType<'_>) -> Handle<T> {
46        Handle {
47            index,
48            types: ty.types.clone(),
49            resources: ty.resources.clone(),
50        }
51    }
52
53    fn instance(&self) -> InstanceType<'_> {
54        InstanceType {
55            types: &self.types,
56            resources: &self.resources,
57        }
58    }
59
60    fn equivalent<'a>(
61        &'a self,
62        other: &'a Self,
63        type_check: fn(&TypeChecker<'a>, T, T) -> bool,
64    ) -> bool
65    where
66        T: PartialEq + Copy,
67    {
68        (self.index == other.index
69            && Arc::ptr_eq(&self.types, &other.types)
70            && Arc::ptr_eq(&self.resources, &other.resources))
71            || type_check(
72                &TypeChecker {
73                    a_types: &self.types,
74                    b_types: &other.types,
75                    a_resource: &self.resources,
76                    b_resource: &other.resources,
77                },
78                self.index,
79                other.index,
80            )
81    }
82}
83
84impl<T: fmt::Debug> fmt::Debug for Handle<T> {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86        f.debug_struct("Handle")
87            .field("index", &self.index)
88            .finish()
89    }
90}
91
92/// Type checker between two `Handle`s
93struct TypeChecker<'a> {
94    a_types: &'a ComponentTypes,
95    a_resource: &'a PrimaryMap<ResourceIndex, ResourceType>,
96    b_types: &'a ComponentTypes,
97    b_resource: &'a PrimaryMap<ResourceIndex, ResourceType>,
98}
99
100impl TypeChecker<'_> {
101    fn interface_types_equal(&self, a: InterfaceType, b: InterfaceType) -> bool {
102        match (a, b) {
103            (InterfaceType::Own(o1), InterfaceType::Own(o2)) => self.resources_equal(o1, o2),
104            (InterfaceType::Own(_), _) => false,
105            (InterfaceType::Borrow(b1), InterfaceType::Borrow(b2)) => self.resources_equal(b1, b2),
106            (InterfaceType::Borrow(_), _) => false,
107            (InterfaceType::List(l1), InterfaceType::List(l2)) => self.lists_equal(l1, l2),
108            (InterfaceType::List(_), _) => false,
109            (InterfaceType::Record(r1), InterfaceType::Record(r2)) => self.records_equal(r1, r2),
110            (InterfaceType::Record(_), _) => false,
111            (InterfaceType::Variant(v1), InterfaceType::Variant(v2)) => self.variants_equal(v1, v2),
112            (InterfaceType::Variant(_), _) => false,
113            (InterfaceType::Result(r1), InterfaceType::Result(r2)) => self.results_equal(r1, r2),
114            (InterfaceType::Result(_), _) => false,
115            (InterfaceType::Option(o1), InterfaceType::Option(o2)) => self.options_equal(o1, o2),
116            (InterfaceType::Option(_), _) => false,
117            (InterfaceType::Enum(e1), InterfaceType::Enum(e2)) => self.enums_equal(e1, e2),
118            (InterfaceType::Enum(_), _) => false,
119            (InterfaceType::Tuple(t1), InterfaceType::Tuple(t2)) => self.tuples_equal(t1, t2),
120            (InterfaceType::Tuple(_), _) => false,
121            (InterfaceType::Flags(f1), InterfaceType::Flags(f2)) => self.flags_equal(f1, f2),
122            (InterfaceType::Flags(_), _) => false,
123            (InterfaceType::Bool, InterfaceType::Bool) => true,
124            (InterfaceType::Bool, _) => false,
125            (InterfaceType::U8, InterfaceType::U8) => true,
126            (InterfaceType::U8, _) => false,
127            (InterfaceType::U16, InterfaceType::U16) => true,
128            (InterfaceType::U16, _) => false,
129            (InterfaceType::U32, InterfaceType::U32) => true,
130            (InterfaceType::U32, _) => false,
131            (InterfaceType::U64, InterfaceType::U64) => true,
132            (InterfaceType::U64, _) => false,
133            (InterfaceType::S8, InterfaceType::S8) => true,
134            (InterfaceType::S8, _) => false,
135            (InterfaceType::S16, InterfaceType::S16) => true,
136            (InterfaceType::S16, _) => false,
137            (InterfaceType::S32, InterfaceType::S32) => true,
138            (InterfaceType::S32, _) => false,
139            (InterfaceType::S64, InterfaceType::S64) => true,
140            (InterfaceType::S64, _) => false,
141            (InterfaceType::Float32, InterfaceType::Float32) => true,
142            (InterfaceType::Float32, _) => false,
143            (InterfaceType::Float64, InterfaceType::Float64) => true,
144            (InterfaceType::Float64, _) => false,
145            (InterfaceType::String, InterfaceType::String) => true,
146            (InterfaceType::String, _) => false,
147            (InterfaceType::Char, InterfaceType::Char) => true,
148            (InterfaceType::Char, _) => false,
149            (InterfaceType::Future(t1), InterfaceType::Future(t2)) => {
150                self.future_table_types_equal(t1, t2)
151            }
152            (InterfaceType::Future(_), _) => false,
153            (InterfaceType::Stream(t1), InterfaceType::Stream(t2)) => {
154                self.stream_table_types_equal(t1, t2)
155            }
156            (InterfaceType::Stream(_), _) => false,
157            (InterfaceType::ErrorContext(_), InterfaceType::ErrorContext(_)) => true,
158            (InterfaceType::ErrorContext(_), _) => false,
159        }
160    }
161
162    fn lists_equal(&self, l1: TypeListIndex, l2: TypeListIndex) -> bool {
163        let a = &self.a_types[l1];
164        let b = &self.b_types[l2];
165        self.interface_types_equal(a.element, b.element)
166    }
167
168    fn resources_equal(&self, o1: TypeResourceTableIndex, o2: TypeResourceTableIndex) -> bool {
169        match (&self.a_types[o1], &self.b_types[o2]) {
170            // Concrete resource types are the same if they map back to the
171            // exact same `ResourceType` at runtime, so look them up in resource
172            // type tables and compare the types themselves.
173            (
174                TypeResourceTable::Concrete { ty: a, .. },
175                TypeResourceTable::Concrete { ty: b, .. },
176            ) => self.a_resource[*a] == self.b_resource[*b],
177            (TypeResourceTable::Concrete { .. }, _) => false,
178
179            // Abstract resource types are only the same if they have the same
180            // index and come from the exact same component.
181            (TypeResourceTable::Abstract(a), TypeResourceTable::Abstract(b)) => {
182                core::ptr::eq(self.a_types, self.b_types) && a == b
183            }
184            (TypeResourceTable::Abstract(_), _) => false,
185        }
186    }
187
188    fn records_equal(&self, r1: TypeRecordIndex, r2: TypeRecordIndex) -> bool {
189        let a = &self.a_types[r1];
190        let b = &self.b_types[r2];
191        if a.fields.len() != b.fields.len() {
192            return false;
193        }
194        a.fields
195            .iter()
196            .zip(b.fields.iter())
197            .all(|(a_field, b_field)| {
198                a_field.name == b_field.name && self.interface_types_equal(a_field.ty, b_field.ty)
199            })
200    }
201
202    fn variants_equal(&self, v1: TypeVariantIndex, v2: TypeVariantIndex) -> bool {
203        let a = &self.a_types[v1];
204        let b = &self.b_types[v2];
205        if a.cases.len() != b.cases.len() {
206            return false;
207        }
208        a.cases
209            .iter()
210            .zip(b.cases.iter())
211            .all(|((a_name, a_ty), (b_name, b_ty))| {
212                if a_name != b_name {
213                    return false;
214                }
215                match (a_ty, b_ty) {
216                    (Some(a_case_ty), Some(b_case_ty)) => {
217                        self.interface_types_equal(*a_case_ty, *b_case_ty)
218                    }
219                    (None, None) => true,
220                    _ => false,
221                }
222            })
223    }
224
225    fn results_equal(&self, r1: TypeResultIndex, r2: TypeResultIndex) -> bool {
226        let a = &self.a_types[r1];
227        let b = &self.b_types[r2];
228        let oks = match (a.ok, b.ok) {
229            (Some(ok1), Some(ok2)) => self.interface_types_equal(ok1, ok2),
230            (None, None) => true,
231            _ => false,
232        };
233        if !oks {
234            return false;
235        }
236        match (a.err, b.err) {
237            (Some(err1), Some(err2)) => self.interface_types_equal(err1, err2),
238            (None, None) => true,
239            _ => false,
240        }
241    }
242
243    fn options_equal(&self, o1: TypeOptionIndex, o2: TypeOptionIndex) -> bool {
244        let a = &self.a_types[o1];
245        let b = &self.b_types[o2];
246        self.interface_types_equal(a.ty, b.ty)
247    }
248
249    fn enums_equal(&self, e1: TypeEnumIndex, e2: TypeEnumIndex) -> bool {
250        let a = &self.a_types[e1];
251        let b = &self.b_types[e2];
252        a.names == b.names
253    }
254
255    fn tuples_equal(&self, t1: TypeTupleIndex, t2: TypeTupleIndex) -> bool {
256        let a = &self.a_types[t1];
257        let b = &self.b_types[t2];
258        if a.types.len() != b.types.len() {
259            return false;
260        }
261        a.types
262            .iter()
263            .zip(b.types.iter())
264            .all(|(&a, &b)| self.interface_types_equal(a, b))
265    }
266
267    fn flags_equal(&self, f1: TypeFlagsIndex, f2: TypeFlagsIndex) -> bool {
268        let a = &self.a_types[f1];
269        let b = &self.b_types[f2];
270        a.names == b.names
271    }
272
273    fn future_table_types_equal(&self, t1: TypeFutureTableIndex, t2: TypeFutureTableIndex) -> bool {
274        self.futures_equal(self.a_types[t1].ty, self.b_types[t2].ty)
275    }
276
277    fn futures_equal(&self, t1: TypeFutureIndex, t2: TypeFutureIndex) -> bool {
278        let a = &self.a_types[t1];
279        let b = &self.b_types[t2];
280        match (a.payload, b.payload) {
281            (Some(t1), Some(t2)) => self.interface_types_equal(t1, t2),
282            (None, None) => true,
283            _ => false,
284        }
285    }
286
287    fn stream_table_types_equal(&self, t1: TypeStreamTableIndex, t2: TypeStreamTableIndex) -> bool {
288        self.streams_equal(self.a_types[t1].ty, self.b_types[t2].ty)
289    }
290
291    fn streams_equal(&self, t1: TypeStreamIndex, t2: TypeStreamIndex) -> bool {
292        let a = &self.a_types[t1];
293        let b = &self.b_types[t2];
294        match (a.payload, b.payload) {
295            (Some(t1), Some(t2)) => self.interface_types_equal(t1, t2),
296            (None, None) => true,
297            _ => false,
298        }
299    }
300}
301
302/// A `list` interface type
303#[derive(Clone, Debug)]
304pub struct List(Handle<TypeListIndex>);
305
306impl PartialEq for List {
307    fn eq(&self, other: &Self) -> bool {
308        self.0.equivalent(&other.0, TypeChecker::lists_equal)
309    }
310}
311
312impl Eq for List {}
313
314impl List {
315    pub(crate) fn from(index: TypeListIndex, ty: &InstanceType<'_>) -> Self {
316        List(Handle::new(index, ty))
317    }
318
319    /// Retrieve the element type of this `list`.
320    pub fn ty(&self) -> Type {
321        Type::from(&self.0.types[self.0.index].element, &self.0.instance())
322    }
323}
324
325/// A field declaration belonging to a `record`
326#[derive(Debug)]
327pub struct Field<'a> {
328    /// The name of the field
329    pub name: &'a str,
330    /// The type of the field
331    pub ty: Type,
332}
333
334/// A `record` interface type
335#[derive(Clone, Debug)]
336pub struct Record(Handle<TypeRecordIndex>);
337
338impl Record {
339    pub(crate) fn from(index: TypeRecordIndex, ty: &InstanceType<'_>) -> Self {
340        Record(Handle::new(index, ty))
341    }
342
343    /// Retrieve the fields of this `record` in declaration order.
344    pub fn fields(&self) -> impl ExactSizeIterator<Item = Field<'_>> {
345        self.0.types[self.0.index].fields.iter().map(|field| Field {
346            name: &field.name,
347            ty: Type::from(&field.ty, &self.0.instance()),
348        })
349    }
350}
351
352impl PartialEq for Record {
353    fn eq(&self, other: &Self) -> bool {
354        self.0.equivalent(&other.0, TypeChecker::records_equal)
355    }
356}
357
358impl Eq for Record {}
359
360/// A `tuple` interface type
361#[derive(Clone, Debug)]
362pub struct Tuple(Handle<TypeTupleIndex>);
363
364impl Tuple {
365    pub(crate) fn from(index: TypeTupleIndex, ty: &InstanceType<'_>) -> Self {
366        Tuple(Handle::new(index, ty))
367    }
368
369    /// Retrieve the types of the fields of this `tuple` in declaration order.
370    pub fn types(&self) -> impl ExactSizeIterator<Item = Type> + '_ {
371        self.0.types[self.0.index]
372            .types
373            .iter()
374            .map(|ty| Type::from(ty, &self.0.instance()))
375    }
376}
377
378impl PartialEq for Tuple {
379    fn eq(&self, other: &Self) -> bool {
380        self.0.equivalent(&other.0, TypeChecker::tuples_equal)
381    }
382}
383
384impl Eq for Tuple {}
385
386/// A case declaration belonging to a `variant`
387pub struct Case<'a> {
388    /// The name of the case
389    pub name: &'a str,
390    /// The optional payload type of the case
391    pub ty: Option<Type>,
392}
393
394/// A `variant` interface type
395#[derive(Clone, Debug)]
396pub struct Variant(Handle<TypeVariantIndex>);
397
398impl Variant {
399    pub(crate) fn from(index: TypeVariantIndex, ty: &InstanceType<'_>) -> Self {
400        Variant(Handle::new(index, ty))
401    }
402
403    /// Retrieve the cases of this `variant` in declaration order.
404    pub fn cases(&self) -> impl ExactSizeIterator<Item = Case<'_>> {
405        self.0.types[self.0.index]
406            .cases
407            .iter()
408            .map(|(name, ty)| Case {
409                name,
410                ty: ty.as_ref().map(|ty| Type::from(ty, &self.0.instance())),
411            })
412    }
413}
414
415impl PartialEq for Variant {
416    fn eq(&self, other: &Self) -> bool {
417        self.0.equivalent(&other.0, TypeChecker::variants_equal)
418    }
419}
420
421impl Eq for Variant {}
422
423/// An `enum` interface type
424#[derive(Clone, Debug)]
425pub struct Enum(Handle<TypeEnumIndex>);
426
427impl Enum {
428    pub(crate) fn from(index: TypeEnumIndex, ty: &InstanceType<'_>) -> Self {
429        Enum(Handle::new(index, ty))
430    }
431
432    /// Retrieve the names of the cases of this `enum` in declaration order.
433    pub fn names(&self) -> impl ExactSizeIterator<Item = &str> {
434        self.0.types[self.0.index]
435            .names
436            .iter()
437            .map(|name| name.deref())
438    }
439}
440
441impl PartialEq for Enum {
442    fn eq(&self, other: &Self) -> bool {
443        self.0.equivalent(&other.0, TypeChecker::enums_equal)
444    }
445}
446
447impl Eq for Enum {}
448
449/// An `option` interface type
450#[derive(Clone, Debug)]
451pub struct OptionType(Handle<TypeOptionIndex>);
452
453impl OptionType {
454    pub(crate) fn from(index: TypeOptionIndex, ty: &InstanceType<'_>) -> Self {
455        OptionType(Handle::new(index, ty))
456    }
457
458    /// Retrieve the type parameter for this `option`.
459    pub fn ty(&self) -> Type {
460        Type::from(&self.0.types[self.0.index].ty, &self.0.instance())
461    }
462}
463
464impl PartialEq for OptionType {
465    fn eq(&self, other: &Self) -> bool {
466        self.0.equivalent(&other.0, TypeChecker::options_equal)
467    }
468}
469
470impl Eq for OptionType {}
471
472/// A `result` interface type
473#[derive(Clone, Debug)]
474pub struct ResultType(Handle<TypeResultIndex>);
475
476impl ResultType {
477    pub(crate) fn from(index: TypeResultIndex, ty: &InstanceType<'_>) -> Self {
478        ResultType(Handle::new(index, ty))
479    }
480
481    /// Retrieve the `ok` type parameter for this `result`.
482    pub fn ok(&self) -> Option<Type> {
483        Some(Type::from(
484            self.0.types[self.0.index].ok.as_ref()?,
485            &self.0.instance(),
486        ))
487    }
488
489    /// Retrieve the `err` type parameter for this `result`.
490    pub fn err(&self) -> Option<Type> {
491        Some(Type::from(
492            self.0.types[self.0.index].err.as_ref()?,
493            &self.0.instance(),
494        ))
495    }
496}
497
498impl PartialEq for ResultType {
499    fn eq(&self, other: &Self) -> bool {
500        self.0.equivalent(&other.0, TypeChecker::results_equal)
501    }
502}
503
504impl Eq for ResultType {}
505
506/// A `flags` interface type
507#[derive(Clone, Debug)]
508pub struct Flags(Handle<TypeFlagsIndex>);
509
510impl Flags {
511    pub(crate) fn from(index: TypeFlagsIndex, ty: &InstanceType<'_>) -> Self {
512        Flags(Handle::new(index, ty))
513    }
514
515    /// Retrieve the names of the flags of this `flags` type in declaration order.
516    pub fn names(&self) -> impl ExactSizeIterator<Item = &str> {
517        self.0.types[self.0.index]
518            .names
519            .iter()
520            .map(|name| name.deref())
521    }
522}
523
524impl PartialEq for Flags {
525    fn eq(&self, other: &Self) -> bool {
526        self.0.equivalent(&other.0, TypeChecker::flags_equal)
527    }
528}
529
530impl Eq for Flags {}
531
532/// An `future` interface type
533#[derive(Clone, Debug)]
534pub struct FutureType(Handle<TypeFutureIndex>);
535
536impl FutureType {
537    pub(crate) fn from(index: TypeFutureIndex, ty: &InstanceType<'_>) -> Self {
538        FutureType(Handle::new(index, ty))
539    }
540
541    /// Retrieve the type parameter for this `future`.
542    pub fn ty(&self) -> Option<Type> {
543        Some(Type::from(
544            self.0.types[self.0.index].payload.as_ref()?,
545            &self.0.instance(),
546        ))
547    }
548}
549
550impl PartialEq for FutureType {
551    fn eq(&self, other: &Self) -> bool {
552        self.0.equivalent(&other.0, TypeChecker::futures_equal)
553    }
554}
555
556impl Eq for FutureType {}
557
558/// An `stream` interface type
559#[derive(Clone, Debug)]
560pub struct StreamType(Handle<TypeStreamIndex>);
561
562impl StreamType {
563    pub(crate) fn from(index: TypeStreamIndex, ty: &InstanceType<'_>) -> Self {
564        StreamType(Handle::new(index, ty))
565    }
566
567    /// Retrieve the type parameter for this `stream`.
568    pub fn ty(&self) -> Option<Type> {
569        Some(Type::from(
570            self.0.types[self.0.index].payload.as_ref()?,
571            &self.0.instance(),
572        ))
573    }
574}
575
576impl PartialEq for StreamType {
577    fn eq(&self, other: &Self) -> bool {
578        self.0.equivalent(&other.0, TypeChecker::streams_equal)
579    }
580}
581
582impl Eq for StreamType {}
583
584/// Represents a component model interface type
585#[derive(Clone, PartialEq, Eq, Debug)]
586#[expect(missing_docs, reason = "self-describing variants")]
587pub enum Type {
588    Bool,
589    S8,
590    U8,
591    S16,
592    U16,
593    S32,
594    U32,
595    S64,
596    U64,
597    Float32,
598    Float64,
599    Char,
600    String,
601    List(List),
602    Record(Record),
603    Tuple(Tuple),
604    Variant(Variant),
605    Enum(Enum),
606    Option(OptionType),
607    Result(ResultType),
608    Flags(Flags),
609    Own(ResourceType),
610    Borrow(ResourceType),
611    Future(FutureType),
612    Stream(StreamType),
613    ErrorContext,
614}
615
616impl Type {
617    /// Retrieve the inner [`List`] of a [`Type::List`].
618    ///
619    /// # Panics
620    ///
621    /// This will panic if `self` is not a [`Type::List`].
622    pub fn unwrap_list(&self) -> &List {
623        if let Type::List(handle) = self {
624            &handle
625        } else {
626            panic!("attempted to unwrap a {} as a list", self.desc())
627        }
628    }
629
630    /// Retrieve the inner [`Record`] of a [`Type::Record`].
631    ///
632    /// # Panics
633    ///
634    /// This will panic if `self` is not a [`Type::Record`].
635    pub fn unwrap_record(&self) -> &Record {
636        if let Type::Record(handle) = self {
637            &handle
638        } else {
639            panic!("attempted to unwrap a {} as a record", self.desc())
640        }
641    }
642
643    /// Retrieve the inner [`Tuple`] of a [`Type::Tuple`].
644    ///
645    /// # Panics
646    ///
647    /// This will panic if `self` is not a [`Type::Tuple`].
648    pub fn unwrap_tuple(&self) -> &Tuple {
649        if let Type::Tuple(handle) = self {
650            &handle
651        } else {
652            panic!("attempted to unwrap a {} as a tuple", self.desc())
653        }
654    }
655
656    /// Retrieve the inner [`Variant`] of a [`Type::Variant`].
657    ///
658    /// # Panics
659    ///
660    /// This will panic if `self` is not a [`Type::Variant`].
661    pub fn unwrap_variant(&self) -> &Variant {
662        if let Type::Variant(handle) = self {
663            &handle
664        } else {
665            panic!("attempted to unwrap a {} as a variant", self.desc())
666        }
667    }
668
669    /// Retrieve the inner [`Enum`] of a [`Type::Enum`].
670    ///
671    /// # Panics
672    ///
673    /// This will panic if `self` is not a [`Type::Enum`].
674    pub fn unwrap_enum(&self) -> &Enum {
675        if let Type::Enum(handle) = self {
676            &handle
677        } else {
678            panic!("attempted to unwrap a {} as a enum", self.desc())
679        }
680    }
681
682    /// Retrieve the inner [`OptionType`] of a [`Type::Option`].
683    ///
684    /// # Panics
685    ///
686    /// This will panic if `self` is not a [`Type::Option`].
687    pub fn unwrap_option(&self) -> &OptionType {
688        if let Type::Option(handle) = self {
689            &handle
690        } else {
691            panic!("attempted to unwrap a {} as a option", self.desc())
692        }
693    }
694
695    /// Retrieve the inner [`ResultType`] of a [`Type::Result`].
696    ///
697    /// # Panics
698    ///
699    /// This will panic if `self` is not a [`Type::Result`].
700    pub fn unwrap_result(&self) -> &ResultType {
701        if let Type::Result(handle) = self {
702            &handle
703        } else {
704            panic!("attempted to unwrap a {} as a result", self.desc())
705        }
706    }
707
708    /// Retrieve the inner [`Flags`] of a [`Type::Flags`].
709    ///
710    /// # Panics
711    ///
712    /// This will panic if `self` is not a [`Type::Flags`].
713    pub fn unwrap_flags(&self) -> &Flags {
714        if let Type::Flags(handle) = self {
715            &handle
716        } else {
717            panic!("attempted to unwrap a {} as a flags", self.desc())
718        }
719    }
720
721    /// Retrieve the inner [`ResourceType`] of a [`Type::Own`].
722    ///
723    /// # Panics
724    ///
725    /// This will panic if `self` is not a [`Type::Own`].
726    pub fn unwrap_own(&self) -> &ResourceType {
727        match self {
728            Type::Own(ty) => ty,
729            _ => panic!("attempted to unwrap a {} as a own", self.desc()),
730        }
731    }
732
733    /// Retrieve the inner [`ResourceType`] of a [`Type::Borrow`].
734    ///
735    /// # Panics
736    ///
737    /// This will panic if `self` is not a [`Type::Borrow`].
738    pub fn unwrap_borrow(&self) -> &ResourceType {
739        match self {
740            Type::Borrow(ty) => ty,
741            _ => panic!("attempted to unwrap a {} as a own", self.desc()),
742        }
743    }
744
745    /// Convert the specified `InterfaceType` to a `Type`.
746    pub(crate) fn from(ty: &InterfaceType, instance: &InstanceType<'_>) -> Self {
747        match ty {
748            InterfaceType::Bool => Type::Bool,
749            InterfaceType::S8 => Type::S8,
750            InterfaceType::U8 => Type::U8,
751            InterfaceType::S16 => Type::S16,
752            InterfaceType::U16 => Type::U16,
753            InterfaceType::S32 => Type::S32,
754            InterfaceType::U32 => Type::U32,
755            InterfaceType::S64 => Type::S64,
756            InterfaceType::U64 => Type::U64,
757            InterfaceType::Float32 => Type::Float32,
758            InterfaceType::Float64 => Type::Float64,
759            InterfaceType::Char => Type::Char,
760            InterfaceType::String => Type::String,
761            InterfaceType::List(index) => Type::List(List::from(*index, instance)),
762            InterfaceType::Record(index) => Type::Record(Record::from(*index, instance)),
763            InterfaceType::Tuple(index) => Type::Tuple(Tuple::from(*index, instance)),
764            InterfaceType::Variant(index) => Type::Variant(Variant::from(*index, instance)),
765            InterfaceType::Enum(index) => Type::Enum(Enum::from(*index, instance)),
766            InterfaceType::Option(index) => Type::Option(OptionType::from(*index, instance)),
767            InterfaceType::Result(index) => Type::Result(ResultType::from(*index, instance)),
768            InterfaceType::Flags(index) => Type::Flags(Flags::from(*index, instance)),
769            InterfaceType::Own(index) => Type::Own(instance.resource_type(*index)),
770            InterfaceType::Borrow(index) => Type::Borrow(instance.resource_type(*index)),
771            InterfaceType::Future(index) => Type::Future(instance.future_type(*index)),
772            InterfaceType::Stream(index) => Type::Stream(instance.stream_type(*index)),
773            InterfaceType::ErrorContext(_) => Type::ErrorContext,
774        }
775    }
776
777    fn desc(&self) -> &'static str {
778        match self {
779            Type::Bool => "bool",
780            Type::S8 => "s8",
781            Type::U8 => "u8",
782            Type::S16 => "s16",
783            Type::U16 => "u16",
784            Type::S32 => "s32",
785            Type::U32 => "u32",
786            Type::S64 => "s64",
787            Type::U64 => "u64",
788            Type::Float32 => "float32",
789            Type::Float64 => "float64",
790            Type::Char => "char",
791            Type::String => "string",
792            Type::List(_) => "list",
793            Type::Record(_) => "record",
794            Type::Tuple(_) => "tuple",
795            Type::Variant(_) => "variant",
796            Type::Enum(_) => "enum",
797            Type::Option(_) => "option",
798            Type::Result(_) => "result",
799            Type::Flags(_) => "flags",
800            Type::Own(_) => "own",
801            Type::Borrow(_) => "borrow",
802            Type::Future(_) => "future",
803            Type::Stream(_) => "stream",
804            Type::ErrorContext => "error-context",
805        }
806    }
807}
808
809/// Component function type
810#[derive(Clone, Debug)]
811pub struct ComponentFunc(Handle<TypeFuncIndex>);
812
813impl ComponentFunc {
814    pub(crate) fn from(index: TypeFuncIndex, ty: &InstanceType<'_>) -> Self {
815        Self(Handle::new(index, ty))
816    }
817
818    /// Returns whether this is an async function
819    pub fn async_(&self) -> bool {
820        self.0.types[self.0.index].async_
821    }
822
823    /// Iterates over types of function parameters and names.
824    pub fn params(&self) -> impl ExactSizeIterator<Item = (&str, Type)> + '_ {
825        let ty = &self.0.types[self.0.index];
826        self.0.types[ty.params]
827            .types
828            .iter()
829            .zip(&ty.param_names)
830            .map(|(ty, name)| (name.as_str(), Type::from(ty, &self.0.instance())))
831    }
832
833    /// Iterates over types of function results
834    pub fn results(&self) -> impl ExactSizeIterator<Item = Type> + '_ {
835        let results = self.0.types[self.0.index].results;
836        self.0.types[results]
837            .types
838            .iter()
839            .map(|ty| Type::from(ty, &self.0.instance()))
840    }
841
842    #[doc(hidden)]
843    pub fn typecheck<Params, Return>(&self, cx: &InstanceType) -> anyhow::Result<()>
844    where
845        Params: crate::component::ComponentNamedList + crate::component::Lower,
846        Return: crate::component::ComponentNamedList + crate::component::Lift,
847    {
848        let ty = &self.0.types[self.0.index];
849        Params::typecheck(&InterfaceType::Tuple(ty.params), cx)?;
850        Return::typecheck(&InterfaceType::Tuple(ty.results), cx)?;
851        Ok(())
852    }
853}
854
855/// Core module type
856#[derive(Clone, Debug)]
857pub struct Module(Handle<TypeModuleIndex>);
858
859impl Module {
860    pub(crate) fn from(index: TypeModuleIndex, ty: &InstanceType<'_>) -> Self {
861        Self(Handle::new(index, ty))
862    }
863
864    /// Iterates over imports of the module
865    pub fn imports<'a>(
866        &'a self,
867        engine: &'a Engine,
868    ) -> impl ExactSizeIterator<Item = ((&'a str, &'a str), ExternType)> + 'a {
869        self.0.types[self.0.index]
870            .imports
871            .iter()
872            .map(|((namespace, name), ty)| {
873                (
874                    (namespace.as_str(), name.as_str()),
875                    ExternType::from_wasmtime(engine, self.0.types.module_types(), ty),
876                )
877            })
878    }
879
880    /// Iterates over exports of the module
881    pub fn exports<'a>(
882        &'a self,
883        engine: &'a Engine,
884    ) -> impl ExactSizeIterator<Item = (&'a str, ExternType)> + 'a {
885        self.0.types[self.0.index].exports.iter().map(|(name, ty)| {
886            (
887                name.as_str(),
888                ExternType::from_wasmtime(engine, self.0.types.module_types(), ty),
889            )
890        })
891    }
892}
893
894/// Component type
895#[derive(Clone, Debug)]
896pub struct Component(Handle<TypeComponentIndex>);
897
898impl Component {
899    pub(crate) fn from(index: TypeComponentIndex, ty: &InstanceType<'_>) -> Self {
900        Self(Handle::new(index, ty))
901    }
902
903    /// Returns import associated with `name`, if such exists in the component
904    pub fn get_import(&self, engine: &Engine, name: &str) -> Option<ComponentItem> {
905        self.0.types[self.0.index]
906            .imports
907            .get(name)
908            .map(|ty| ComponentItem::from(engine, ty, &self.0.instance()))
909    }
910
911    /// Iterates over imports of the component
912    pub fn imports<'a>(
913        &'a self,
914        engine: &'a Engine,
915    ) -> impl ExactSizeIterator<Item = (&'a str, ComponentItem)> + 'a {
916        self.0.types[self.0.index].imports.iter().map(|(name, ty)| {
917            (
918                name.as_str(),
919                ComponentItem::from(engine, ty, &self.0.instance()),
920            )
921        })
922    }
923
924    /// Returns export associated with `name`, if such exists in the component
925    pub fn get_export(&self, engine: &Engine, name: &str) -> Option<ComponentItem> {
926        self.0.types[self.0.index]
927            .exports
928            .get(name)
929            .map(|ty| ComponentItem::from(engine, ty, &self.0.instance()))
930    }
931
932    /// Iterates over exports of the component
933    pub fn exports<'a>(
934        &'a self,
935        engine: &'a Engine,
936    ) -> impl ExactSizeIterator<Item = (&'a str, ComponentItem)> + 'a {
937        self.0.types[self.0.index].exports.iter().map(|(name, ty)| {
938            (
939                name.as_str(),
940                ComponentItem::from(engine, ty, &self.0.instance()),
941            )
942        })
943    }
944
945    #[doc(hidden)]
946    pub fn instance_type(&self) -> InstanceType<'_> {
947        InstanceType {
948            types: &self.0.types,
949            resources: &self.0.resources,
950        }
951    }
952}
953
954/// Component instance type
955#[derive(Clone, Debug)]
956pub struct ComponentInstance(Handle<TypeComponentInstanceIndex>);
957
958impl ComponentInstance {
959    pub(crate) fn from(index: TypeComponentInstanceIndex, ty: &InstanceType<'_>) -> Self {
960        Self(Handle::new(index, ty))
961    }
962
963    /// Returns export associated with `name`, if such exists in the component instance
964    pub fn get_export(&self, engine: &Engine, name: &str) -> Option<ComponentItem> {
965        self.0.types[self.0.index]
966            .exports
967            .get(name)
968            .map(|ty| ComponentItem::from(engine, ty, &self.0.instance()))
969    }
970
971    /// Iterates over exports of the component instance
972    pub fn exports<'a>(
973        &'a self,
974        engine: &'a Engine,
975    ) -> impl ExactSizeIterator<Item = (&'a str, ComponentItem)> {
976        self.0.types[self.0.index].exports.iter().map(|(name, ty)| {
977            (
978                name.as_str(),
979                ComponentItem::from(engine, ty, &self.0.instance()),
980            )
981        })
982    }
983}
984
985/// Type of an item contained within the component
986#[derive(Clone, Debug)]
987pub enum ComponentItem {
988    /// Component function item
989    ComponentFunc(ComponentFunc),
990    /// Core function item
991    CoreFunc(FuncType),
992    /// Core module item
993    Module(Module),
994    /// Component item
995    Component(Component),
996    /// Component instance item
997    ComponentInstance(ComponentInstance),
998    /// Interface type item
999    Type(Type),
1000    /// Resource item
1001    Resource(ResourceType),
1002}
1003
1004impl ComponentItem {
1005    pub(crate) fn from(engine: &Engine, def: &TypeDef, ty: &InstanceType<'_>) -> Self {
1006        match def {
1007            TypeDef::Component(idx) => Self::Component(Component::from(*idx, ty)),
1008            TypeDef::ComponentInstance(idx) => {
1009                Self::ComponentInstance(ComponentInstance::from(*idx, ty))
1010            }
1011            TypeDef::ComponentFunc(idx) => Self::ComponentFunc(ComponentFunc::from(*idx, ty)),
1012            TypeDef::Interface(iface_ty) => Self::Type(Type::from(iface_ty, ty)),
1013            TypeDef::Module(idx) => Self::Module(Module::from(*idx, ty)),
1014            TypeDef::CoreFunc(idx) => {
1015                let subty = &ty.types[*idx];
1016                Self::CoreFunc(FuncType::from_wasm_func_type(
1017                    engine,
1018                    subty.is_final,
1019                    subty.supertype,
1020                    subty.unwrap_func().clone(),
1021                ))
1022            }
1023            TypeDef::Resource(idx) => match ty.types[*idx] {
1024                TypeResourceTable::Concrete {
1025                    ty: resource_index, ..
1026                } => {
1027                    let ty = match ty.resources.get(resource_index) {
1028                        // This resource type was substituted by a linker for
1029                        // example so it's replaced here.
1030                        Some(ty) => *ty,
1031
1032                        // This resource type was not substituted.
1033                        None => ResourceType::uninstantiated(&ty.types, resource_index),
1034                    };
1035                    Self::Resource(ty)
1036                }
1037                TypeResourceTable::Abstract(resource_index) => {
1038                    Self::Resource(ResourceType::abstract_(&ty.types, resource_index))
1039                }
1040            },
1041        }
1042    }
1043    pub(crate) fn from_export(engine: &Engine, export: &Export, ty: &InstanceType<'_>) -> Self {
1044        match export {
1045            Export::Instance { ty: idx, .. } => {
1046                Self::ComponentInstance(ComponentInstance::from(*idx, ty))
1047            }
1048            Export::LiftedFunction { ty: idx, .. } => {
1049                Self::ComponentFunc(ComponentFunc::from(*idx, ty))
1050            }
1051            Export::ModuleStatic { ty: idx, .. } | Export::ModuleImport { ty: idx, .. } => {
1052                Self::Module(Module::from(*idx, ty))
1053            }
1054            Export::Type(idx) => Self::from(engine, idx, ty),
1055        }
1056    }
1057}