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