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