1#[cfg(feature = "component-model-async")]
4use crate::component::ComponentType;
5use crate::component::matching::InstanceType;
6use crate::{Engine, ExternType, FuncType, prelude::*};
7use alloc::sync::Arc;
8use core::fmt;
9use core::ops::Deref;
10use wasmtime_environ::component::{
11 ComponentTypes, Export, InterfaceType, ResourceIndex, TypeComponentIndex,
12 TypeComponentInstanceIndex, TypeDef, TypeEnumIndex, TypeFlagsIndex, TypeFuncIndex,
13 TypeFutureIndex, TypeFutureTableIndex, TypeListIndex, TypeMapIndex, TypeModuleIndex,
14 TypeOptionIndex, TypeRecordIndex, TypeResourceTable, TypeResourceTableIndex, TypeResultIndex,
15 TypeStreamIndex, TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex,
16};
17use wasmtime_environ::{PanicOnOom as _, PrimaryMap};
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::Map(m1), InterfaceType::Map(m2)) => self.maps_equal(m1, m2),
112 (InterfaceType::Map(_), _) => false,
113 (InterfaceType::Record(r1), InterfaceType::Record(r2)) => self.records_equal(r1, r2),
114 (InterfaceType::Record(_), _) => false,
115 (InterfaceType::Variant(v1), InterfaceType::Variant(v2)) => self.variants_equal(v1, v2),
116 (InterfaceType::Variant(_), _) => false,
117 (InterfaceType::Result(r1), InterfaceType::Result(r2)) => self.results_equal(r1, r2),
118 (InterfaceType::Result(_), _) => false,
119 (InterfaceType::Option(o1), InterfaceType::Option(o2)) => self.options_equal(o1, o2),
120 (InterfaceType::Option(_), _) => false,
121 (InterfaceType::Enum(e1), InterfaceType::Enum(e2)) => self.enums_equal(e1, e2),
122 (InterfaceType::Enum(_), _) => false,
123 (InterfaceType::Tuple(t1), InterfaceType::Tuple(t2)) => self.tuples_equal(t1, t2),
124 (InterfaceType::Tuple(_), _) => false,
125 (InterfaceType::Flags(f1), InterfaceType::Flags(f2)) => self.flags_equal(f1, f2),
126 (InterfaceType::Flags(_), _) => false,
127 (InterfaceType::Bool, InterfaceType::Bool) => true,
128 (InterfaceType::Bool, _) => false,
129 (InterfaceType::U8, InterfaceType::U8) => true,
130 (InterfaceType::U8, _) => false,
131 (InterfaceType::U16, InterfaceType::U16) => true,
132 (InterfaceType::U16, _) => false,
133 (InterfaceType::U32, InterfaceType::U32) => true,
134 (InterfaceType::U32, _) => false,
135 (InterfaceType::U64, InterfaceType::U64) => true,
136 (InterfaceType::U64, _) => false,
137 (InterfaceType::S8, InterfaceType::S8) => true,
138 (InterfaceType::S8, _) => false,
139 (InterfaceType::S16, InterfaceType::S16) => true,
140 (InterfaceType::S16, _) => false,
141 (InterfaceType::S32, InterfaceType::S32) => true,
142 (InterfaceType::S32, _) => false,
143 (InterfaceType::S64, InterfaceType::S64) => true,
144 (InterfaceType::S64, _) => false,
145 (InterfaceType::Float32, InterfaceType::Float32) => true,
146 (InterfaceType::Float32, _) => false,
147 (InterfaceType::Float64, InterfaceType::Float64) => true,
148 (InterfaceType::Float64, _) => false,
149 (InterfaceType::String, InterfaceType::String) => true,
150 (InterfaceType::String, _) => false,
151 (InterfaceType::Char, InterfaceType::Char) => true,
152 (InterfaceType::Char, _) => false,
153 (InterfaceType::Future(t1), InterfaceType::Future(t2)) => {
154 self.future_table_types_equal(t1, t2)
155 }
156 (InterfaceType::Future(_), _) => false,
157 (InterfaceType::Stream(t1), InterfaceType::Stream(t2)) => {
158 self.stream_table_types_equal(t1, t2)
159 }
160 (InterfaceType::Stream(_), _) => false,
161 (InterfaceType::ErrorContext(_), InterfaceType::ErrorContext(_)) => true,
162 (InterfaceType::ErrorContext(_), _) => false,
163 (InterfaceType::FixedLengthList(_), _) => todo!(), }
165 }
166
167 fn lists_equal(&self, l1: TypeListIndex, l2: TypeListIndex) -> bool {
168 let a = &self.a_types[l1];
169 let b = &self.b_types[l2];
170 self.interface_types_equal(a.element, b.element)
171 }
172
173 fn maps_equal(&self, m1: TypeMapIndex, m2: TypeMapIndex) -> bool {
174 let a = &self.a_types[m1];
175 let b = &self.b_types[m2];
176 self.interface_types_equal(a.key, b.key) && self.interface_types_equal(a.value, b.value)
177 }
178
179 fn resources_equal(&self, o1: TypeResourceTableIndex, o2: TypeResourceTableIndex) -> bool {
180 match (&self.a_types[o1], &self.b_types[o2]) {
181 (
185 TypeResourceTable::Concrete { ty: a, .. },
186 TypeResourceTable::Concrete { ty: b, .. },
187 ) => self.a_resource[*a] == self.b_resource[*b],
188 (TypeResourceTable::Concrete { .. }, _) => false,
189
190 (TypeResourceTable::Abstract(a), TypeResourceTable::Abstract(b)) => {
193 core::ptr::eq(self.a_types, self.b_types) && a == b
194 }
195 (TypeResourceTable::Abstract(_), _) => false,
196 }
197 }
198
199 fn records_equal(&self, r1: TypeRecordIndex, r2: TypeRecordIndex) -> bool {
200 let a = &self.a_types[r1];
201 let b = &self.b_types[r2];
202 if a.fields.len() != b.fields.len() {
203 return false;
204 }
205 a.fields
206 .iter()
207 .zip(b.fields.iter())
208 .all(|(a_field, b_field)| {
209 a_field.name == b_field.name && self.interface_types_equal(a_field.ty, b_field.ty)
210 })
211 }
212
213 fn variants_equal(&self, v1: TypeVariantIndex, v2: TypeVariantIndex) -> bool {
214 let a = &self.a_types[v1];
215 let b = &self.b_types[v2];
216 if a.cases.len() != b.cases.len() {
217 return false;
218 }
219 a.cases
220 .iter()
221 .zip(b.cases.iter())
222 .all(|((a_name, a_ty), (b_name, b_ty))| {
223 if a_name != b_name {
224 return false;
225 }
226 match (a_ty, b_ty) {
227 (Some(a_case_ty), Some(b_case_ty)) => {
228 self.interface_types_equal(*a_case_ty, *b_case_ty)
229 }
230 (None, None) => true,
231 _ => false,
232 }
233 })
234 }
235
236 fn results_equal(&self, r1: TypeResultIndex, r2: TypeResultIndex) -> bool {
237 let a = &self.a_types[r1];
238 let b = &self.b_types[r2];
239 let oks = match (a.ok, b.ok) {
240 (Some(ok1), Some(ok2)) => self.interface_types_equal(ok1, ok2),
241 (None, None) => true,
242 _ => false,
243 };
244 if !oks {
245 return false;
246 }
247 match (a.err, b.err) {
248 (Some(err1), Some(err2)) => self.interface_types_equal(err1, err2),
249 (None, None) => true,
250 _ => false,
251 }
252 }
253
254 fn options_equal(&self, o1: TypeOptionIndex, o2: TypeOptionIndex) -> bool {
255 let a = &self.a_types[o1];
256 let b = &self.b_types[o2];
257 self.interface_types_equal(a.ty, b.ty)
258 }
259
260 fn enums_equal(&self, e1: TypeEnumIndex, e2: TypeEnumIndex) -> bool {
261 let a = &self.a_types[e1];
262 let b = &self.b_types[e2];
263 a.names == b.names
264 }
265
266 fn tuples_equal(&self, t1: TypeTupleIndex, t2: TypeTupleIndex) -> bool {
267 let a = &self.a_types[t1];
268 let b = &self.b_types[t2];
269 if a.types.len() != b.types.len() {
270 return false;
271 }
272 a.types
273 .iter()
274 .zip(b.types.iter())
275 .all(|(&a, &b)| self.interface_types_equal(a, b))
276 }
277
278 fn flags_equal(&self, f1: TypeFlagsIndex, f2: TypeFlagsIndex) -> bool {
279 let a = &self.a_types[f1];
280 let b = &self.b_types[f2];
281 a.names == b.names
282 }
283
284 fn future_table_types_equal(&self, t1: TypeFutureTableIndex, t2: TypeFutureTableIndex) -> bool {
285 self.futures_equal(self.a_types[t1].ty, self.b_types[t2].ty)
286 }
287
288 fn futures_equal(&self, t1: TypeFutureIndex, t2: TypeFutureIndex) -> bool {
289 let a = &self.a_types[t1];
290 let b = &self.b_types[t2];
291 match (a.payload, b.payload) {
292 (Some(t1), Some(t2)) => self.interface_types_equal(t1, t2),
293 (None, None) => true,
294 _ => false,
295 }
296 }
297
298 fn stream_table_types_equal(&self, t1: TypeStreamTableIndex, t2: TypeStreamTableIndex) -> bool {
299 self.streams_equal(self.a_types[t1].ty, self.b_types[t2].ty)
300 }
301
302 fn streams_equal(&self, t1: TypeStreamIndex, t2: TypeStreamIndex) -> bool {
303 let a = &self.a_types[t1];
304 let b = &self.b_types[t2];
305 match (a.payload, b.payload) {
306 (Some(t1), Some(t2)) => self.interface_types_equal(t1, t2),
307 (None, None) => true,
308 _ => false,
309 }
310 }
311}
312
313#[derive(Clone, Debug)]
315pub struct List(Handle<TypeListIndex>);
316
317impl PartialEq for List {
318 fn eq(&self, other: &Self) -> bool {
319 self.0.equivalent(&other.0, TypeChecker::lists_equal)
320 }
321}
322
323impl Eq for List {}
324
325impl List {
326 pub(crate) fn from(index: TypeListIndex, ty: &InstanceType<'_>) -> Self {
327 List(Handle::new(index, ty))
328 }
329
330 pub fn ty(&self) -> Type {
332 Type::from(&self.0.types[self.0.index].element, &self.0.instance())
333 }
334}
335
336#[derive(Clone, Debug)]
338pub struct Map(Handle<TypeMapIndex>);
339
340impl PartialEq for Map {
341 fn eq(&self, other: &Self) -> bool {
342 self.0.equivalent(&other.0, TypeChecker::maps_equal)
343 }
344}
345
346impl Eq for Map {}
347
348impl Map {
349 pub(crate) fn from(index: TypeMapIndex, ty: &InstanceType<'_>) -> Self {
350 Map(Handle::new(index, ty))
351 }
352
353 pub fn key(&self) -> Type {
355 Type::from(&self.0.types[self.0.index].key, &self.0.instance())
356 }
357
358 pub fn value(&self) -> Type {
360 Type::from(&self.0.types[self.0.index].value, &self.0.instance())
361 }
362}
363
364#[derive(Debug)]
366pub struct Field<'a> {
367 pub name: &'a str,
369 pub ty: Type,
371}
372
373#[derive(Clone, Debug)]
375pub struct Record(Handle<TypeRecordIndex>);
376
377impl Record {
378 pub(crate) fn from(index: TypeRecordIndex, ty: &InstanceType<'_>) -> Self {
379 Record(Handle::new(index, ty))
380 }
381
382 pub fn fields(&self) -> impl ExactSizeIterator<Item = Field<'_>> {
384 self.0.types[self.0.index].fields.iter().map(|field| Field {
385 name: &field.name,
386 ty: Type::from(&field.ty, &self.0.instance()),
387 })
388 }
389}
390
391impl PartialEq for Record {
392 fn eq(&self, other: &Self) -> bool {
393 self.0.equivalent(&other.0, TypeChecker::records_equal)
394 }
395}
396
397impl Eq for Record {}
398
399#[derive(Clone, Debug)]
401pub struct Tuple(Handle<TypeTupleIndex>);
402
403impl Tuple {
404 pub(crate) fn from(index: TypeTupleIndex, ty: &InstanceType<'_>) -> Self {
405 Tuple(Handle::new(index, ty))
406 }
407
408 pub fn types(&self) -> impl ExactSizeIterator<Item = Type> + '_ {
410 self.0.types[self.0.index]
411 .types
412 .iter()
413 .map(|ty| Type::from(ty, &self.0.instance()))
414 }
415}
416
417impl PartialEq for Tuple {
418 fn eq(&self, other: &Self) -> bool {
419 self.0.equivalent(&other.0, TypeChecker::tuples_equal)
420 }
421}
422
423impl Eq for Tuple {}
424
425pub struct Case<'a> {
427 pub name: &'a str,
429 pub ty: Option<Type>,
431}
432
433#[derive(Clone, Debug)]
435pub struct Variant(Handle<TypeVariantIndex>);
436
437impl Variant {
438 pub(crate) fn from(index: TypeVariantIndex, ty: &InstanceType<'_>) -> Self {
439 Variant(Handle::new(index, ty))
440 }
441
442 pub fn cases(&self) -> impl ExactSizeIterator<Item = Case<'_>> {
444 self.0.types[self.0.index]
445 .cases
446 .iter()
447 .map(|(name, ty)| Case {
448 name,
449 ty: ty.as_ref().map(|ty| Type::from(ty, &self.0.instance())),
450 })
451 }
452}
453
454impl PartialEq for Variant {
455 fn eq(&self, other: &Self) -> bool {
456 self.0.equivalent(&other.0, TypeChecker::variants_equal)
457 }
458}
459
460impl Eq for Variant {}
461
462#[derive(Clone, Debug)]
464pub struct Enum(Handle<TypeEnumIndex>);
465
466impl Enum {
467 pub(crate) fn from(index: TypeEnumIndex, ty: &InstanceType<'_>) -> Self {
468 Enum(Handle::new(index, ty))
469 }
470
471 pub fn names(&self) -> impl ExactSizeIterator<Item = &str> {
473 self.0.types[self.0.index]
474 .names
475 .iter()
476 .map(|name| name.deref())
477 }
478}
479
480impl PartialEq for Enum {
481 fn eq(&self, other: &Self) -> bool {
482 self.0.equivalent(&other.0, TypeChecker::enums_equal)
483 }
484}
485
486impl Eq for Enum {}
487
488#[derive(Clone, Debug)]
490pub struct OptionType(Handle<TypeOptionIndex>);
491
492impl OptionType {
493 pub(crate) fn from(index: TypeOptionIndex, ty: &InstanceType<'_>) -> Self {
494 OptionType(Handle::new(index, ty))
495 }
496
497 pub fn ty(&self) -> Type {
499 Type::from(&self.0.types[self.0.index].ty, &self.0.instance())
500 }
501}
502
503impl PartialEq for OptionType {
504 fn eq(&self, other: &Self) -> bool {
505 self.0.equivalent(&other.0, TypeChecker::options_equal)
506 }
507}
508
509impl Eq for OptionType {}
510
511#[derive(Clone, Debug)]
513pub struct ResultType(Handle<TypeResultIndex>);
514
515impl ResultType {
516 pub(crate) fn from(index: TypeResultIndex, ty: &InstanceType<'_>) -> Self {
517 ResultType(Handle::new(index, ty))
518 }
519
520 pub fn ok(&self) -> Option<Type> {
522 Some(Type::from(
523 self.0.types[self.0.index].ok.as_ref()?,
524 &self.0.instance(),
525 ))
526 }
527
528 pub fn err(&self) -> Option<Type> {
530 Some(Type::from(
531 self.0.types[self.0.index].err.as_ref()?,
532 &self.0.instance(),
533 ))
534 }
535}
536
537impl PartialEq for ResultType {
538 fn eq(&self, other: &Self) -> bool {
539 self.0.equivalent(&other.0, TypeChecker::results_equal)
540 }
541}
542
543impl Eq for ResultType {}
544
545#[derive(Clone, Debug)]
547pub struct Flags(Handle<TypeFlagsIndex>);
548
549impl Flags {
550 pub(crate) fn from(index: TypeFlagsIndex, ty: &InstanceType<'_>) -> Self {
551 Flags(Handle::new(index, ty))
552 }
553
554 pub fn names(&self) -> impl ExactSizeIterator<Item = &str> {
556 self.0.types[self.0.index]
557 .names
558 .iter()
559 .map(|name| name.deref())
560 }
561}
562
563impl PartialEq for Flags {
564 fn eq(&self, other: &Self) -> bool {
565 self.0.equivalent(&other.0, TypeChecker::flags_equal)
566 }
567}
568
569impl Eq for Flags {}
570
571#[cfg(feature = "component-model-async")]
572pub(crate) fn typecheck_payload<T>(
573 payload: Option<&InterfaceType>,
574 types: &InstanceType<'_>,
575) -> crate::Result<()>
576where
577 T: ComponentType,
578{
579 match payload {
580 Some(a) => T::typecheck(a, types),
581 None => {
582 if T::IS_RUST_UNIT_TYPE {
583 Ok(())
584 } else {
585 crate::bail!("future payload types differ")
586 }
587 }
588 }
589}
590
591#[derive(Clone, Debug)]
593pub struct FutureType(Handle<TypeFutureIndex>);
594
595impl FutureType {
596 pub(crate) fn from(index: TypeFutureIndex, ty: &InstanceType<'_>) -> Self {
597 FutureType(Handle::new(index, ty))
598 }
599
600 pub fn ty(&self) -> Option<Type> {
602 Some(Type::from(
603 self.0.types[self.0.index].payload.as_ref()?,
604 &self.0.instance(),
605 ))
606 }
607
608 #[cfg(feature = "component-model-async")]
609 pub(crate) fn equivalent_payload_guest(
610 &self,
611 ty: &InstanceType<'_>,
612 payload: Option<&InterfaceType>,
613 ) -> bool {
614 let my_payload = self.0.types[self.0.index].payload.as_ref();
615 match (my_payload, payload) {
616 (Some(a), Some(b)) => TypeChecker {
617 a_types: &self.0.types,
618 a_resource: &self.0.resources,
619 b_types: ty.types,
620 b_resource: ty.resources,
621 }
622 .interface_types_equal(*a, *b),
623 (None, None) => true,
624 (Some(_), None) | (None, Some(_)) => false,
625 }
626 }
627
628 #[cfg(feature = "component-model-async")]
629 pub(crate) fn equivalent_payload_host<T>(&self) -> crate::Result<()>
630 where
631 T: ComponentType,
632 {
633 typecheck_payload::<T>(
634 self.0.types[self.0.index].payload.as_ref(),
635 &self.0.instance(),
636 )
637 }
638}
639
640impl PartialEq for FutureType {
641 fn eq(&self, other: &Self) -> bool {
642 self.0.equivalent(&other.0, TypeChecker::futures_equal)
643 }
644}
645
646impl Eq for FutureType {}
647
648#[derive(Clone, Debug)]
650pub struct StreamType(Handle<TypeStreamIndex>);
651
652impl StreamType {
653 pub(crate) fn from(index: TypeStreamIndex, ty: &InstanceType<'_>) -> Self {
654 StreamType(Handle::new(index, ty))
655 }
656
657 pub fn ty(&self) -> Option<Type> {
659 Some(Type::from(
660 self.0.types[self.0.index].payload.as_ref()?,
661 &self.0.instance(),
662 ))
663 }
664
665 #[cfg(feature = "component-model-async")]
666 pub(crate) fn equivalent_payload_guest(
667 &self,
668 ty: &InstanceType<'_>,
669 payload: Option<&InterfaceType>,
670 ) -> bool {
671 let my_payload = self.0.types[self.0.index].payload.as_ref();
672 match (my_payload, payload) {
673 (Some(a), Some(b)) => TypeChecker {
674 a_types: &self.0.types,
675 a_resource: &self.0.resources,
676 b_types: ty.types,
677 b_resource: ty.resources,
678 }
679 .interface_types_equal(*a, *b),
680 (None, None) => true,
681 (Some(_), None) | (None, Some(_)) => false,
682 }
683 }
684
685 #[cfg(feature = "component-model-async")]
686 pub(crate) fn equivalent_payload_host<T>(&self) -> crate::Result<()>
687 where
688 T: ComponentType,
689 {
690 typecheck_payload::<T>(
691 self.0.types[self.0.index].payload.as_ref(),
692 &self.0.instance(),
693 )
694 }
695}
696
697impl PartialEq for StreamType {
698 fn eq(&self, other: &Self) -> bool {
699 self.0.equivalent(&other.0, TypeChecker::streams_equal)
700 }
701}
702
703impl Eq for StreamType {}
704
705#[derive(Clone, PartialEq, Eq, Debug)]
707#[expect(missing_docs, reason = "self-describing variants")]
708pub enum Type {
709 Bool,
710 S8,
711 U8,
712 S16,
713 U16,
714 S32,
715 U32,
716 S64,
717 U64,
718 Float32,
719 Float64,
720 Char,
721 String,
722 List(List),
723 Map(Map),
724 Record(Record),
725 Tuple(Tuple),
726 Variant(Variant),
727 Enum(Enum),
728 Option(OptionType),
729 Result(ResultType),
730 Flags(Flags),
731 Own(ResourceType),
732 Borrow(ResourceType),
733 Future(FutureType),
734 Stream(StreamType),
735 ErrorContext,
736}
737
738impl Type {
739 pub fn unwrap_list(&self) -> &List {
745 if let Type::List(handle) = self {
746 &handle
747 } else {
748 panic!("attempted to unwrap a {} as a list", self.desc())
749 }
750 }
751
752 pub fn unwrap_record(&self) -> &Record {
758 if let Type::Record(handle) = self {
759 &handle
760 } else {
761 panic!("attempted to unwrap a {} as a record", self.desc())
762 }
763 }
764
765 pub fn unwrap_tuple(&self) -> &Tuple {
771 if let Type::Tuple(handle) = self {
772 &handle
773 } else {
774 panic!("attempted to unwrap a {} as a tuple", self.desc())
775 }
776 }
777
778 pub fn unwrap_variant(&self) -> &Variant {
784 if let Type::Variant(handle) = self {
785 &handle
786 } else {
787 panic!("attempted to unwrap a {} as a variant", self.desc())
788 }
789 }
790
791 pub fn unwrap_enum(&self) -> &Enum {
797 if let Type::Enum(handle) = self {
798 &handle
799 } else {
800 panic!("attempted to unwrap a {} as a enum", self.desc())
801 }
802 }
803
804 pub fn unwrap_option(&self) -> &OptionType {
810 if let Type::Option(handle) = self {
811 &handle
812 } else {
813 panic!("attempted to unwrap a {} as a option", self.desc())
814 }
815 }
816
817 pub fn unwrap_result(&self) -> &ResultType {
823 if let Type::Result(handle) = self {
824 &handle
825 } else {
826 panic!("attempted to unwrap a {} as a result", self.desc())
827 }
828 }
829
830 pub fn unwrap_flags(&self) -> &Flags {
836 if let Type::Flags(handle) = self {
837 &handle
838 } else {
839 panic!("attempted to unwrap a {} as a flags", self.desc())
840 }
841 }
842
843 pub fn unwrap_own(&self) -> &ResourceType {
849 match self {
850 Type::Own(ty) => ty,
851 _ => panic!("attempted to unwrap a {} as a own", self.desc()),
852 }
853 }
854
855 pub fn unwrap_borrow(&self) -> &ResourceType {
861 match self {
862 Type::Borrow(ty) => ty,
863 _ => panic!("attempted to unwrap a {} as a own", self.desc()),
864 }
865 }
866
867 pub(crate) fn from(ty: &InterfaceType, instance: &InstanceType<'_>) -> Self {
869 match ty {
870 InterfaceType::Bool => Type::Bool,
871 InterfaceType::S8 => Type::S8,
872 InterfaceType::U8 => Type::U8,
873 InterfaceType::S16 => Type::S16,
874 InterfaceType::U16 => Type::U16,
875 InterfaceType::S32 => Type::S32,
876 InterfaceType::U32 => Type::U32,
877 InterfaceType::S64 => Type::S64,
878 InterfaceType::U64 => Type::U64,
879 InterfaceType::Float32 => Type::Float32,
880 InterfaceType::Float64 => Type::Float64,
881 InterfaceType::Char => Type::Char,
882 InterfaceType::String => Type::String,
883 InterfaceType::List(index) => Type::List(List::from(*index, instance)),
884 InterfaceType::Map(index) => Type::Map(Map::from(*index, instance)),
885 InterfaceType::Record(index) => Type::Record(Record::from(*index, instance)),
886 InterfaceType::Tuple(index) => Type::Tuple(Tuple::from(*index, instance)),
887 InterfaceType::Variant(index) => Type::Variant(Variant::from(*index, instance)),
888 InterfaceType::Enum(index) => Type::Enum(Enum::from(*index, instance)),
889 InterfaceType::Option(index) => Type::Option(OptionType::from(*index, instance)),
890 InterfaceType::Result(index) => Type::Result(ResultType::from(*index, instance)),
891 InterfaceType::Flags(index) => Type::Flags(Flags::from(*index, instance)),
892 InterfaceType::Own(index) => Type::Own(instance.resource_type(*index)),
893 InterfaceType::Borrow(index) => Type::Borrow(instance.resource_type(*index)),
894 InterfaceType::Future(index) => Type::Future(instance.future_type(*index)),
895 InterfaceType::Stream(index) => Type::Stream(instance.stream_type(*index)),
896 InterfaceType::ErrorContext(_) => Type::ErrorContext,
897 InterfaceType::FixedLengthList(_) => todo!(), }
899 }
900
901 fn desc(&self) -> &'static str {
902 match self {
903 Type::Bool => "bool",
904 Type::S8 => "s8",
905 Type::U8 => "u8",
906 Type::S16 => "s16",
907 Type::U16 => "u16",
908 Type::S32 => "s32",
909 Type::U32 => "u32",
910 Type::S64 => "s64",
911 Type::U64 => "u64",
912 Type::Float32 => "float32",
913 Type::Float64 => "float64",
914 Type::Char => "char",
915 Type::String => "string",
916 Type::List(_) => "list",
917 Type::Map(_) => "map",
918 Type::Record(_) => "record",
919 Type::Tuple(_) => "tuple",
920 Type::Variant(_) => "variant",
921 Type::Enum(_) => "enum",
922 Type::Option(_) => "option",
923 Type::Result(_) => "result",
924 Type::Flags(_) => "flags",
925 Type::Own(_) => "own",
926 Type::Borrow(_) => "borrow",
927 Type::Future(_) => "future",
928 Type::Stream(_) => "stream",
929 Type::ErrorContext => "error-context",
930 }
931 }
932}
933
934#[derive(Clone, Debug)]
936pub struct ComponentFunc(Handle<TypeFuncIndex>);
937
938impl ComponentFunc {
939 pub(crate) fn from(index: TypeFuncIndex, ty: &InstanceType<'_>) -> Self {
940 Self(Handle::new(index, ty))
941 }
942
943 pub fn async_(&self) -> bool {
945 self.0.types[self.0.index].async_
946 }
947
948 pub fn params(&self) -> impl ExactSizeIterator<Item = (&str, Type)> + '_ {
950 let ty = &self.0.types[self.0.index];
951 self.0.types[ty.params]
952 .types
953 .iter()
954 .zip(&ty.param_names)
955 .map(|(ty, name)| (name.as_str(), Type::from(ty, &self.0.instance())))
956 }
957
958 pub fn results(&self) -> impl ExactSizeIterator<Item = Type> + '_ {
960 let results = self.0.types[self.0.index].results;
961 self.0.types[results]
962 .types
963 .iter()
964 .map(|ty| Type::from(ty, &self.0.instance()))
965 }
966
967 #[doc(hidden)]
968 pub fn typecheck<Params, Return>(&self, cx: &InstanceType) -> crate::Result<()>
969 where
970 Params: crate::component::ComponentNamedList + crate::component::Lower,
971 Return: crate::component::ComponentNamedList + crate::component::Lift,
972 {
973 let ty = &self.0.types[self.0.index];
974 Params::typecheck(&InterfaceType::Tuple(ty.params), cx)?;
975 Return::typecheck(&InterfaceType::Tuple(ty.results), cx)?;
976 Ok(())
977 }
978}
979
980#[derive(Clone, Debug)]
982pub struct Module(Handle<TypeModuleIndex>);
983
984impl Module {
985 pub(crate) fn from(index: TypeModuleIndex, ty: &InstanceType<'_>) -> Self {
986 Self(Handle::new(index, ty))
987 }
988
989 pub fn imports<'a>(
991 &'a self,
992 engine: &'a Engine,
993 ) -> impl ExactSizeIterator<Item = ((&'a str, &'a str), ExternType)> + 'a {
994 self.0.types[self.0.index]
995 .imports
996 .iter()
997 .map(|((namespace, name), ty)| {
998 (
999 (namespace.as_str(), name.as_str()),
1000 ExternType::from_wasmtime(engine, self.0.types.module_types(), ty),
1001 )
1002 })
1003 }
1004
1005 pub fn exports<'a>(
1007 &'a self,
1008 engine: &'a Engine,
1009 ) -> impl ExactSizeIterator<Item = (&'a str, ExternType)> + 'a {
1010 self.0.types[self.0.index].exports.iter().map(|(name, ty)| {
1011 (
1012 name.as_str(),
1013 ExternType::from_wasmtime(engine, self.0.types.module_types(), ty),
1014 )
1015 })
1016 }
1017}
1018
1019#[derive(Clone, Debug)]
1021pub struct Component(Handle<TypeComponentIndex>);
1022
1023impl Component {
1024 pub(crate) fn from(index: TypeComponentIndex, ty: &InstanceType<'_>) -> Self {
1025 Self(Handle::new(index, ty))
1026 }
1027
1028 pub fn get_import(&self, engine: &Engine, name: &str) -> Option<ComponentItem> {
1030 self.0.types[self.0.index]
1031 .imports
1032 .get(name)
1033 .map(|ty| ComponentItem::from(engine, ty, &self.0.instance()))
1034 }
1035
1036 pub fn imports<'a>(
1038 &'a self,
1039 engine: &'a Engine,
1040 ) -> impl ExactSizeIterator<Item = (&'a str, ComponentItem)> + 'a {
1041 self.0.types[self.0.index].imports.iter().map(|(name, ty)| {
1042 (
1043 name.as_str(),
1044 ComponentItem::from(engine, ty, &self.0.instance()),
1045 )
1046 })
1047 }
1048
1049 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 pub fn exports<'a>(
1059 &'a self,
1060 engine: &'a Engine,
1061 ) -> impl ExactSizeIterator<Item = (&'a str, ComponentItem)> + 'a {
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 #[doc(hidden)]
1071 pub fn instance_type(&self) -> InstanceType<'_> {
1072 InstanceType {
1073 types: &self.0.types,
1074 resources: &self.0.resources,
1075 }
1076 }
1077}
1078
1079#[derive(Clone, Debug)]
1081pub struct ComponentInstance(Handle<TypeComponentInstanceIndex>);
1082
1083impl ComponentInstance {
1084 pub(crate) fn from(index: TypeComponentInstanceIndex, ty: &InstanceType<'_>) -> Self {
1085 Self(Handle::new(index, ty))
1086 }
1087
1088 pub fn get_export(&self, engine: &Engine, name: &str) -> Option<ComponentItem> {
1090 self.0.types[self.0.index]
1091 .exports
1092 .get(name)
1093 .map(|ty| ComponentItem::from(engine, ty, &self.0.instance()))
1094 }
1095
1096 pub fn exports<'a>(
1098 &'a self,
1099 engine: &'a Engine,
1100 ) -> impl ExactSizeIterator<Item = (&'a str, ComponentItem)> {
1101 self.0.types[self.0.index].exports.iter().map(|(name, ty)| {
1102 (
1103 name.as_str(),
1104 ComponentItem::from(engine, ty, &self.0.instance()),
1105 )
1106 })
1107 }
1108}
1109
1110#[derive(Clone, Debug)]
1112pub enum ComponentItem {
1113 ComponentFunc(ComponentFunc),
1115 CoreFunc(FuncType),
1117 Module(Module),
1119 Component(Component),
1121 ComponentInstance(ComponentInstance),
1123 Type(Type),
1125 Resource(ResourceType),
1127}
1128
1129impl ComponentItem {
1130 pub(crate) fn from(engine: &Engine, def: &TypeDef, ty: &InstanceType<'_>) -> Self {
1131 match def {
1132 TypeDef::Component(idx) => Self::Component(Component::from(*idx, ty)),
1133 TypeDef::ComponentInstance(idx) => {
1134 Self::ComponentInstance(ComponentInstance::from(*idx, ty))
1135 }
1136 TypeDef::ComponentFunc(idx) => Self::ComponentFunc(ComponentFunc::from(*idx, ty)),
1137 TypeDef::Interface(iface_ty) => Self::Type(Type::from(iface_ty, ty)),
1138 TypeDef::Module(idx) => Self::Module(Module::from(*idx, ty)),
1139 TypeDef::CoreFunc(idx) => {
1140 let subty = &ty.types[*idx];
1141 Self::CoreFunc(
1142 FuncType::from_wasm_func_type(
1143 engine,
1144 subty.is_final,
1145 subty.supertype,
1146 subty.unwrap_func().try_clone().panic_on_oom(),
1147 )
1148 .panic_on_oom(),
1149 )
1150 }
1151 TypeDef::Resource(idx) => match ty.types[*idx] {
1152 TypeResourceTable::Concrete {
1153 ty: resource_index, ..
1154 } => {
1155 let ty = match ty.resources.get(resource_index) {
1156 Some(ty) => *ty,
1159
1160 None => ResourceType::uninstantiated(&ty.types, resource_index),
1162 };
1163 Self::Resource(ty)
1164 }
1165 TypeResourceTable::Abstract(resource_index) => {
1166 Self::Resource(ResourceType::abstract_(&ty.types, resource_index))
1167 }
1168 },
1169 }
1170 }
1171 pub(crate) fn from_export(engine: &Engine, export: &Export, ty: &InstanceType<'_>) -> Self {
1172 match export {
1173 Export::Instance { ty: idx, .. } => {
1174 Self::ComponentInstance(ComponentInstance::from(*idx, ty))
1175 }
1176 Export::LiftedFunction { ty: idx, .. } => {
1177 Self::ComponentFunc(ComponentFunc::from(*idx, ty))
1178 }
1179 Export::ModuleStatic { ty: idx, .. } | Export::ModuleImport { ty: idx, .. } => {
1180 Self::Module(Module::from(*idx, ty))
1181 }
1182 Export::Type(idx) => Self::from(engine, idx, ty),
1183 }
1184 }
1185}