1#[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#[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
94struct 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 (
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 (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#[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 pub fn ty(&self) -> Type {
323 Type::from(&self.0.types[self.0.index].element, &self.0.instance())
324 }
325}
326
327#[derive(Debug)]
329pub struct Field<'a> {
330 pub name: &'a str,
332 pub ty: Type,
334}
335
336#[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 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#[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 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
388pub struct Case<'a> {
390 pub name: &'a str,
392 pub ty: Option<Type>,
394}
395
396#[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 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#[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 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#[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 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#[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 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 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#[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 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#[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 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#[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 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#[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 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 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 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 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 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 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 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 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 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 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 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#[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 pub fn async_(&self) -> bool {
904 self.0.types[self.0.index].async_
905 }
906
907 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 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#[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 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 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#[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 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 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 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 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#[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 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 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#[derive(Clone, Debug)]
1071pub enum ComponentItem {
1072 ComponentFunc(ComponentFunc),
1074 CoreFunc(FuncType),
1076 Module(Module),
1078 Component(Component),
1080 ComponentInstance(ComponentInstance),
1082 Type(Type),
1084 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 Some(ty) => *ty,
1115
1116 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}