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    /// Iterates over types of function parameters and names.
819    pub fn params(&self) -> impl ExactSizeIterator<Item = (&str, Type)> + '_ {
820        let ty = &self.0.types[self.0.index];
821        self.0.types[ty.params]
822            .types
823            .iter()
824            .zip(&ty.param_names)
825            .map(|(ty, name)| (name.as_str(), Type::from(ty, &self.0.instance())))
826    }
827
828    /// Iterates over types of function results
829    pub fn results(&self) -> impl ExactSizeIterator<Item = Type> + '_ {
830        let results = self.0.types[self.0.index].results;
831        self.0.types[results]
832            .types
833            .iter()
834            .map(|ty| Type::from(ty, &self.0.instance()))
835    }
836
837    #[doc(hidden)]
838    pub fn typecheck<Params, Return>(&self, cx: &InstanceType) -> anyhow::Result<()>
839    where
840        Params: crate::component::ComponentNamedList + crate::component::Lower,
841        Return: crate::component::ComponentNamedList + crate::component::Lift,
842    {
843        let ty = &self.0.types[self.0.index];
844        Params::typecheck(&InterfaceType::Tuple(ty.params), cx)?;
845        Return::typecheck(&InterfaceType::Tuple(ty.results), cx)?;
846        Ok(())
847    }
848}
849
850/// Core module type
851#[derive(Clone, Debug)]
852pub struct Module(Handle<TypeModuleIndex>);
853
854impl Module {
855    pub(crate) fn from(index: TypeModuleIndex, ty: &InstanceType<'_>) -> Self {
856        Self(Handle::new(index, ty))
857    }
858
859    /// Iterates over imports of the module
860    pub fn imports<'a>(
861        &'a self,
862        engine: &'a Engine,
863    ) -> impl ExactSizeIterator<Item = ((&'a str, &'a str), ExternType)> + 'a {
864        self.0.types[self.0.index]
865            .imports
866            .iter()
867            .map(|((namespace, name), ty)| {
868                (
869                    (namespace.as_str(), name.as_str()),
870                    ExternType::from_wasmtime(engine, self.0.types.module_types(), ty),
871                )
872            })
873    }
874
875    /// Iterates over exports of the module
876    pub fn exports<'a>(
877        &'a self,
878        engine: &'a Engine,
879    ) -> impl ExactSizeIterator<Item = (&'a str, ExternType)> + 'a {
880        self.0.types[self.0.index].exports.iter().map(|(name, ty)| {
881            (
882                name.as_str(),
883                ExternType::from_wasmtime(engine, self.0.types.module_types(), ty),
884            )
885        })
886    }
887}
888
889/// Component type
890#[derive(Clone, Debug)]
891pub struct Component(Handle<TypeComponentIndex>);
892
893impl Component {
894    pub(crate) fn from(index: TypeComponentIndex, ty: &InstanceType<'_>) -> Self {
895        Self(Handle::new(index, ty))
896    }
897
898    /// Returns import associated with `name`, if such exists in the component
899    pub fn get_import(&self, engine: &Engine, name: &str) -> Option<ComponentItem> {
900        self.0.types[self.0.index]
901            .imports
902            .get(name)
903            .map(|ty| ComponentItem::from(engine, ty, &self.0.instance()))
904    }
905
906    /// Iterates over imports of the component
907    pub fn imports<'a>(
908        &'a self,
909        engine: &'a Engine,
910    ) -> impl ExactSizeIterator<Item = (&'a str, ComponentItem)> + 'a {
911        self.0.types[self.0.index].imports.iter().map(|(name, ty)| {
912            (
913                name.as_str(),
914                ComponentItem::from(engine, ty, &self.0.instance()),
915            )
916        })
917    }
918
919    /// Returns export associated with `name`, if such exists in the component
920    pub fn get_export(&self, engine: &Engine, name: &str) -> Option<ComponentItem> {
921        self.0.types[self.0.index]
922            .exports
923            .get(name)
924            .map(|ty| ComponentItem::from(engine, ty, &self.0.instance()))
925    }
926
927    /// Iterates over exports of the component
928    pub fn exports<'a>(
929        &'a self,
930        engine: &'a Engine,
931    ) -> impl ExactSizeIterator<Item = (&'a str, ComponentItem)> + 'a {
932        self.0.types[self.0.index].exports.iter().map(|(name, ty)| {
933            (
934                name.as_str(),
935                ComponentItem::from(engine, ty, &self.0.instance()),
936            )
937        })
938    }
939
940    #[doc(hidden)]
941    pub fn instance_type(&self) -> InstanceType<'_> {
942        InstanceType {
943            types: &self.0.types,
944            resources: &self.0.resources,
945        }
946    }
947}
948
949/// Component instance type
950#[derive(Clone, Debug)]
951pub struct ComponentInstance(Handle<TypeComponentInstanceIndex>);
952
953impl ComponentInstance {
954    pub(crate) fn from(index: TypeComponentInstanceIndex, ty: &InstanceType<'_>) -> Self {
955        Self(Handle::new(index, ty))
956    }
957
958    /// Returns export associated with `name`, if such exists in the component instance
959    pub fn get_export(&self, engine: &Engine, name: &str) -> Option<ComponentItem> {
960        self.0.types[self.0.index]
961            .exports
962            .get(name)
963            .map(|ty| ComponentItem::from(engine, ty, &self.0.instance()))
964    }
965
966    /// Iterates over exports of the component instance
967    pub fn exports<'a>(
968        &'a self,
969        engine: &'a Engine,
970    ) -> impl ExactSizeIterator<Item = (&'a str, ComponentItem)> {
971        self.0.types[self.0.index].exports.iter().map(|(name, ty)| {
972            (
973                name.as_str(),
974                ComponentItem::from(engine, ty, &self.0.instance()),
975            )
976        })
977    }
978}
979
980/// Type of an item contained within the component
981#[derive(Clone, Debug)]
982pub enum ComponentItem {
983    /// Component function item
984    ComponentFunc(ComponentFunc),
985    /// Core function item
986    CoreFunc(FuncType),
987    /// Core module item
988    Module(Module),
989    /// Component item
990    Component(Component),
991    /// Component instance item
992    ComponentInstance(ComponentInstance),
993    /// Interface type item
994    Type(Type),
995    /// Resource item
996    Resource(ResourceType),
997}
998
999impl ComponentItem {
1000    pub(crate) fn from(engine: &Engine, def: &TypeDef, ty: &InstanceType<'_>) -> Self {
1001        match def {
1002            TypeDef::Component(idx) => Self::Component(Component::from(*idx, ty)),
1003            TypeDef::ComponentInstance(idx) => {
1004                Self::ComponentInstance(ComponentInstance::from(*idx, ty))
1005            }
1006            TypeDef::ComponentFunc(idx) => Self::ComponentFunc(ComponentFunc::from(*idx, ty)),
1007            TypeDef::Interface(iface_ty) => Self::Type(Type::from(iface_ty, ty)),
1008            TypeDef::Module(idx) => Self::Module(Module::from(*idx, ty)),
1009            TypeDef::CoreFunc(idx) => {
1010                let subty = &ty.types[*idx];
1011                Self::CoreFunc(FuncType::from_wasm_func_type(
1012                    engine,
1013                    subty.is_final,
1014                    subty.supertype,
1015                    subty.unwrap_func().clone(),
1016                ))
1017            }
1018            TypeDef::Resource(idx) => match ty.types[*idx] {
1019                TypeResourceTable::Concrete {
1020                    ty: resource_index, ..
1021                } => {
1022                    let ty = match ty.resources.get(resource_index) {
1023                        // This resource type was substituted by a linker for
1024                        // example so it's replaced here.
1025                        Some(ty) => *ty,
1026
1027                        // This resource type was not substituted.
1028                        None => ResourceType::uninstantiated(&ty.types, resource_index),
1029                    };
1030                    Self::Resource(ty)
1031                }
1032                TypeResourceTable::Abstract(resource_index) => {
1033                    Self::Resource(ResourceType::abstract_(&ty.types, resource_index))
1034                }
1035            },
1036        }
1037    }
1038    pub(crate) fn from_export(engine: &Engine, export: &Export, ty: &InstanceType<'_>) -> Self {
1039        match export {
1040            Export::Instance { ty: idx, .. } => {
1041                Self::ComponentInstance(ComponentInstance::from(*idx, ty))
1042            }
1043            Export::LiftedFunction { ty: idx, .. } => {
1044                Self::ComponentFunc(ComponentFunc::from(*idx, ty))
1045            }
1046            Export::ModuleStatic { ty: idx, .. } | Export::ModuleImport { ty: idx, .. } => {
1047                Self::Module(Module::from(*idx, ty))
1048            }
1049            Export::Type(idx) => Self::from(engine, idx, ty),
1050        }
1051    }
1052}