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