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