Skip to main content

wasmtime/runtime/component/
types.rs

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