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