1#[cfg(feature = "component-model-async")]
4use crate::component::ComponentType;
5use crate::component::matching::InstanceType;
6use crate::component::{ResourceAny, Val};
7use crate::{AsContextMut, Engine, ExternType, FuncType, StoreContextMut, prelude::*};
8use alloc::sync::Arc;
9use core::fmt;
10use core::ops::Deref;
11use wasmtime_environ::PanicOnOom as _;
12use wasmtime_environ::component::{
13 ComponentTypes, Export, InterfaceType, ResourceIndex, TypeComponentIndex,
14 TypeComponentInstanceIndex, TypeDef, TypeEnumIndex, TypeFixedLengthListIndex, TypeFlagsIndex,
15 TypeFuncIndex, TypeFutureIndex, TypeFutureTableIndex, TypeListIndex, TypeMapIndex,
16 TypeModuleIndex, TypeOptionIndex, TypeRecordIndex, TypeResourceTable, TypeResourceTableIndex,
17 TypeResultIndex, TypeStreamIndex, TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex,
18 alternate_lookup_key,
19};
20
21pub use crate::component::resources::ResourceType;
22
23#[derive(Clone)]
43struct Handle<T> {
44 index: T,
45 types: Arc<ComponentTypes>,
46 resources: Option<Arc<TryPrimaryMap<ResourceIndex, ResourceType>>>,
47}
48
49impl<T> Handle<T> {
50 fn new(index: T, ty: &InstanceType<'_>) -> Handle<T> {
51 Handle {
52 index,
53 types: ty.types.clone(),
54 resources: ty.resources.cloned(),
55 }
56 }
57
58 fn instance(&self) -> InstanceType<'_> {
59 InstanceType {
60 types: &self.types,
61 resources: self.resources.as_ref(),
62 }
63 }
64
65 fn equivalent<'a>(
66 &'a self,
67 other: &'a Self,
68 type_check: fn(&TypeChecker<'a>, T, T) -> bool,
69 ) -> bool
70 where
71 T: PartialEq + Copy,
72 {
73 (self.index == other.index
74 && Arc::ptr_eq(&self.types, &other.types)
75 && match (&self.resources, &other.resources) {
76 (Some(a), Some(b)) => Arc::ptr_eq(a, b),
77 (None, None) => true,
78 _ => false,
79 })
80 || type_check(
81 &TypeChecker {
82 a_types: &self.types,
83 b_types: &other.types,
84 a_resource: self.resources.as_deref(),
85 b_resource: other.resources.as_deref(),
86 },
87 self.index,
88 other.index,
89 )
90 }
91}
92
93impl<T: fmt::Debug> fmt::Debug for Handle<T> {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 f.debug_struct("Handle")
96 .field("index", &self.index)
97 .finish()
98 }
99}
100
101struct TypeChecker<'a> {
103 a_types: &'a ComponentTypes,
104 a_resource: Option<&'a TryPrimaryMap<ResourceIndex, ResourceType>>,
105 b_types: &'a ComponentTypes,
106 b_resource: Option<&'a TryPrimaryMap<ResourceIndex, ResourceType>>,
107}
108
109impl TypeChecker<'_> {
110 fn interface_types_equal(&self, a: InterfaceType, b: InterfaceType) -> bool {
111 match (a, b) {
112 (InterfaceType::Own(o1), InterfaceType::Own(o2)) => self.resources_equal(o1, o2),
113 (InterfaceType::Own(_), _) => false,
114 (InterfaceType::Borrow(b1), InterfaceType::Borrow(b2)) => self.resources_equal(b1, b2),
115 (InterfaceType::Borrow(_), _) => false,
116 (InterfaceType::List(l1), InterfaceType::List(l2)) => self.lists_equal(l1, l2),
117 (InterfaceType::List(_), _) => false,
118 (InterfaceType::Map(m1), InterfaceType::Map(m2)) => self.maps_equal(m1, m2),
119 (InterfaceType::Map(_), _) => false,
120 (InterfaceType::Record(r1), InterfaceType::Record(r2)) => self.records_equal(r1, r2),
121 (InterfaceType::Record(_), _) => false,
122 (InterfaceType::Variant(v1), InterfaceType::Variant(v2)) => self.variants_equal(v1, v2),
123 (InterfaceType::Variant(_), _) => false,
124 (InterfaceType::Result(r1), InterfaceType::Result(r2)) => self.results_equal(r1, r2),
125 (InterfaceType::Result(_), _) => false,
126 (InterfaceType::Option(o1), InterfaceType::Option(o2)) => self.options_equal(o1, o2),
127 (InterfaceType::Option(_), _) => false,
128 (InterfaceType::Enum(e1), InterfaceType::Enum(e2)) => self.enums_equal(e1, e2),
129 (InterfaceType::Enum(_), _) => false,
130 (InterfaceType::Tuple(t1), InterfaceType::Tuple(t2)) => self.tuples_equal(t1, t2),
131 (InterfaceType::Tuple(_), _) => false,
132 (InterfaceType::Flags(f1), InterfaceType::Flags(f2)) => self.flags_equal(f1, f2),
133 (InterfaceType::Flags(_), _) => false,
134 (InterfaceType::Bool, InterfaceType::Bool) => true,
135 (InterfaceType::Bool, _) => false,
136 (InterfaceType::U8, InterfaceType::U8) => true,
137 (InterfaceType::U8, _) => false,
138 (InterfaceType::U16, InterfaceType::U16) => true,
139 (InterfaceType::U16, _) => false,
140 (InterfaceType::U32, InterfaceType::U32) => true,
141 (InterfaceType::U32, _) => false,
142 (InterfaceType::U64, InterfaceType::U64) => true,
143 (InterfaceType::U64, _) => false,
144 (InterfaceType::S8, InterfaceType::S8) => true,
145 (InterfaceType::S8, _) => false,
146 (InterfaceType::S16, InterfaceType::S16) => true,
147 (InterfaceType::S16, _) => false,
148 (InterfaceType::S32, InterfaceType::S32) => true,
149 (InterfaceType::S32, _) => false,
150 (InterfaceType::S64, InterfaceType::S64) => true,
151 (InterfaceType::S64, _) => false,
152 (InterfaceType::Float32, InterfaceType::Float32) => true,
153 (InterfaceType::Float32, _) => false,
154 (InterfaceType::Float64, InterfaceType::Float64) => true,
155 (InterfaceType::Float64, _) => false,
156 (InterfaceType::String, InterfaceType::String) => true,
157 (InterfaceType::String, _) => false,
158 (InterfaceType::Char, InterfaceType::Char) => true,
159 (InterfaceType::Char, _) => false,
160 (InterfaceType::Future(t1), InterfaceType::Future(t2)) => {
161 self.future_table_types_equal(t1, t2)
162 }
163 (InterfaceType::Future(_), _) => false,
164 (InterfaceType::Stream(t1), InterfaceType::Stream(t2)) => {
165 self.stream_table_types_equal(t1, t2)
166 }
167 (InterfaceType::Stream(_), _) => false,
168 (InterfaceType::ErrorContext(_), InterfaceType::ErrorContext(_)) => true,
169 (InterfaceType::ErrorContext(_), _) => false,
170 (InterfaceType::FixedLengthList(t1), InterfaceType::FixedLengthList(t2)) => {
171 self.fixed_length_lists_equal(t1, t2)
172 }
173 (InterfaceType::FixedLengthList(_), _) => false,
174 }
175 }
176
177 fn lists_equal(&self, l1: TypeListIndex, l2: TypeListIndex) -> bool {
178 let a = &self.a_types[l1];
179 let b = &self.b_types[l2];
180 self.interface_types_equal(a.element, b.element)
181 }
182
183 fn maps_equal(&self, m1: TypeMapIndex, m2: TypeMapIndex) -> bool {
184 let a = &self.a_types[m1];
185 let b = &self.b_types[m2];
186 self.interface_types_equal(a.key, b.key) && self.interface_types_equal(a.value, b.value)
187 }
188
189 fn fixed_length_lists_equal(
190 &self,
191 l1: wasmtime_environ::component::TypeFixedLengthListIndex,
192 l2: wasmtime_environ::component::TypeFixedLengthListIndex,
193 ) -> bool {
194 let a = &self.a_types[l1];
195 let b = &self.b_types[l2];
196 if a.size != b.size {
197 return false;
198 }
199 self.interface_types_equal(a.element, b.element)
200 }
201
202 fn resources_equal(&self, o1: TypeResourceTableIndex, o2: TypeResourceTableIndex) -> bool {
203 match (&self.a_types[o1], &self.b_types[o2]) {
204 (
208 TypeResourceTable::Concrete { ty: a, .. },
209 TypeResourceTable::Concrete { ty: b, .. },
210 ) => self.a_resource.unwrap()[*a] == self.b_resource.unwrap()[*b],
211 (TypeResourceTable::Concrete { .. }, _) => false,
212
213 (TypeResourceTable::Abstract(a), TypeResourceTable::Abstract(b)) => {
216 core::ptr::eq(self.a_types, self.b_types) && a == b
217 }
218 (TypeResourceTable::Abstract(_), _) => false,
219 }
220 }
221
222 fn records_equal(&self, r1: TypeRecordIndex, r2: TypeRecordIndex) -> bool {
223 let a = &self.a_types[r1];
224 let b = &self.b_types[r2];
225 if a.fields.len() != b.fields.len() {
226 return false;
227 }
228 a.fields
229 .iter()
230 .zip(b.fields.iter())
231 .all(|(a_field, b_field)| {
232 a_field.name == b_field.name && self.interface_types_equal(a_field.ty, b_field.ty)
233 })
234 }
235
236 fn variants_equal(&self, v1: TypeVariantIndex, v2: TypeVariantIndex) -> bool {
237 let a = &self.a_types[v1];
238 let b = &self.b_types[v2];
239 if a.cases.len() != b.cases.len() {
240 return false;
241 }
242 a.cases
243 .iter()
244 .zip(b.cases.iter())
245 .all(|((a_name, a_ty), (b_name, b_ty))| {
246 if a_name != b_name {
247 return false;
248 }
249 match (a_ty, b_ty) {
250 (Some(a_case_ty), Some(b_case_ty)) => {
251 self.interface_types_equal(*a_case_ty, *b_case_ty)
252 }
253 (None, None) => true,
254 _ => false,
255 }
256 })
257 }
258
259 fn results_equal(&self, r1: TypeResultIndex, r2: TypeResultIndex) -> bool {
260 let a = &self.a_types[r1];
261 let b = &self.b_types[r2];
262 let oks = match (a.ok, b.ok) {
263 (Some(ok1), Some(ok2)) => self.interface_types_equal(ok1, ok2),
264 (None, None) => true,
265 _ => false,
266 };
267 if !oks {
268 return false;
269 }
270 match (a.err, b.err) {
271 (Some(err1), Some(err2)) => self.interface_types_equal(err1, err2),
272 (None, None) => true,
273 _ => false,
274 }
275 }
276
277 fn options_equal(&self, o1: TypeOptionIndex, o2: TypeOptionIndex) -> bool {
278 let a = &self.a_types[o1];
279 let b = &self.b_types[o2];
280 self.interface_types_equal(a.ty, b.ty)
281 }
282
283 fn enums_equal(&self, e1: TypeEnumIndex, e2: TypeEnumIndex) -> bool {
284 let a = &self.a_types[e1];
285 let b = &self.b_types[e2];
286 a.names == b.names
287 }
288
289 fn tuples_equal(&self, t1: TypeTupleIndex, t2: TypeTupleIndex) -> bool {
290 let a = &self.a_types[t1];
291 let b = &self.b_types[t2];
292 if a.types.len() != b.types.len() {
293 return false;
294 }
295 a.types
296 .iter()
297 .zip(b.types.iter())
298 .all(|(&a, &b)| self.interface_types_equal(a, b))
299 }
300
301 fn flags_equal(&self, f1: TypeFlagsIndex, f2: TypeFlagsIndex) -> bool {
302 let a = &self.a_types[f1];
303 let b = &self.b_types[f2];
304 a.names == b.names
305 }
306
307 fn future_table_types_equal(&self, t1: TypeFutureTableIndex, t2: TypeFutureTableIndex) -> bool {
308 self.futures_equal(self.a_types[t1].ty, self.b_types[t2].ty)
309 }
310
311 fn futures_equal(&self, t1: TypeFutureIndex, t2: TypeFutureIndex) -> bool {
312 let a = &self.a_types[t1];
313 let b = &self.b_types[t2];
314 match (a.payload, b.payload) {
315 (Some(t1), Some(t2)) => self.interface_types_equal(t1, t2),
316 (None, None) => true,
317 _ => false,
318 }
319 }
320
321 fn stream_table_types_equal(&self, t1: TypeStreamTableIndex, t2: TypeStreamTableIndex) -> bool {
322 self.streams_equal(self.a_types[t1].ty, self.b_types[t2].ty)
323 }
324
325 fn streams_equal(&self, t1: TypeStreamIndex, t2: TypeStreamIndex) -> bool {
326 let a = &self.a_types[t1];
327 let b = &self.b_types[t2];
328 match (a.payload, b.payload) {
329 (Some(t1), Some(t2)) => self.interface_types_equal(t1, t2),
330 (None, None) => true,
331 _ => false,
332 }
333 }
334}
335
336#[derive(Clone, Debug)]
338pub struct List(Handle<TypeListIndex>);
339
340impl PartialEq for List {
341 fn eq(&self, other: &Self) -> bool {
342 self.0.equivalent(&other.0, TypeChecker::lists_equal)
343 }
344}
345
346impl Eq for List {}
347
348impl List {
349 pub(crate) fn from(index: TypeListIndex, ty: &InstanceType<'_>) -> Self {
350 List(Handle::new(index, ty))
351 }
352
353 pub fn ty(&self) -> Type {
355 Type::from(&self.0.types[self.0.index].element, &self.0.instance())
356 }
357}
358
359#[derive(Clone, Debug)]
361pub struct Map(Handle<TypeMapIndex>);
362
363impl PartialEq for Map {
364 fn eq(&self, other: &Self) -> bool {
365 self.0.equivalent(&other.0, TypeChecker::maps_equal)
366 }
367}
368
369impl Eq for Map {}
370
371impl Map {
372 pub(crate) fn from(index: TypeMapIndex, ty: &InstanceType<'_>) -> Self {
373 Map(Handle::new(index, ty))
374 }
375
376 pub fn key(&self) -> Type {
378 Type::from(&self.0.types[self.0.index].key, &self.0.instance())
379 }
380
381 pub fn value(&self) -> Type {
383 Type::from(&self.0.types[self.0.index].value, &self.0.instance())
384 }
385}
386#[derive(Clone, Debug)]
388pub struct FixedLengthList(Handle<TypeFixedLengthListIndex>);
389
390impl PartialEq for FixedLengthList {
391 fn eq(&self, other: &Self) -> bool {
392 self.0
393 .equivalent(&other.0, TypeChecker::fixed_length_lists_equal)
394 }
395}
396
397impl Eq for FixedLengthList {}
398
399impl FixedLengthList {
400 pub(crate) fn from(index: TypeFixedLengthListIndex, ty: &InstanceType<'_>) -> Self {
401 FixedLengthList(Handle::new(index, ty))
402 }
403
404 pub fn ty(&self) -> Type {
406 Type::from(&self.0.types[self.0.index].element, &self.0.instance())
407 }
408
409 pub fn len(&self) -> u32 {
411 self.0.types[self.0.index].size
412 }
413}
414
415#[derive(Debug)]
417pub struct Field<'a> {
418 pub name: &'a str,
420 pub ty: Type,
422}
423
424#[derive(Clone, Debug)]
426pub struct Record(Handle<TypeRecordIndex>);
427
428impl Record {
429 pub(crate) fn from(index: TypeRecordIndex, ty: &InstanceType<'_>) -> Self {
430 Record(Handle::new(index, ty))
431 }
432
433 pub fn fields(&self) -> impl ExactSizeIterator<Item = Field<'_>> {
435 self.0.types[self.0.index].fields.iter().map(|field| Field {
436 name: &field.name,
437 ty: Type::from(&field.ty, &self.0.instance()),
438 })
439 }
440}
441
442impl PartialEq for Record {
443 fn eq(&self, other: &Self) -> bool {
444 self.0.equivalent(&other.0, TypeChecker::records_equal)
445 }
446}
447
448impl Eq for Record {}
449
450#[derive(Clone, Debug)]
452pub struct Tuple(Handle<TypeTupleIndex>);
453
454impl Tuple {
455 pub(crate) fn from(index: TypeTupleIndex, ty: &InstanceType<'_>) -> Self {
456 Tuple(Handle::new(index, ty))
457 }
458
459 pub fn types(&self) -> impl ExactSizeIterator<Item = Type> + '_ {
461 self.0.types[self.0.index]
462 .types
463 .iter()
464 .map(|ty| Type::from(ty, &self.0.instance()))
465 }
466}
467
468impl PartialEq for Tuple {
469 fn eq(&self, other: &Self) -> bool {
470 self.0.equivalent(&other.0, TypeChecker::tuples_equal)
471 }
472}
473
474impl Eq for Tuple {}
475
476pub struct Case<'a> {
478 pub name: &'a str,
480 pub ty: Option<Type>,
482}
483
484#[derive(Clone, Debug)]
486pub struct Variant(Handle<TypeVariantIndex>);
487
488impl Variant {
489 pub(crate) fn from(index: TypeVariantIndex, ty: &InstanceType<'_>) -> Self {
490 Variant(Handle::new(index, ty))
491 }
492
493 pub fn cases(&self) -> impl ExactSizeIterator<Item = Case<'_>> {
495 self.0.types[self.0.index]
496 .cases
497 .iter()
498 .map(|(name, ty)| Case {
499 name,
500 ty: ty.as_ref().map(|ty| Type::from(ty, &self.0.instance())),
501 })
502 }
503}
504
505impl PartialEq for Variant {
506 fn eq(&self, other: &Self) -> bool {
507 self.0.equivalent(&other.0, TypeChecker::variants_equal)
508 }
509}
510
511impl Eq for Variant {}
512
513#[derive(Clone, Debug)]
515pub struct Enum(Handle<TypeEnumIndex>);
516
517impl Enum {
518 pub(crate) fn from(index: TypeEnumIndex, ty: &InstanceType<'_>) -> Self {
519 Enum(Handle::new(index, ty))
520 }
521
522 pub fn names(&self) -> impl ExactSizeIterator<Item = &str> {
524 self.0.types[self.0.index]
525 .names
526 .iter()
527 .map(|name| name.deref())
528 }
529}
530
531impl PartialEq for Enum {
532 fn eq(&self, other: &Self) -> bool {
533 self.0.equivalent(&other.0, TypeChecker::enums_equal)
534 }
535}
536
537impl Eq for Enum {}
538
539#[derive(Clone, Debug)]
541pub struct OptionType(Handle<TypeOptionIndex>);
542
543impl OptionType {
544 pub(crate) fn from(index: TypeOptionIndex, ty: &InstanceType<'_>) -> Self {
545 OptionType(Handle::new(index, ty))
546 }
547
548 pub fn ty(&self) -> Type {
550 Type::from(&self.0.types[self.0.index].ty, &self.0.instance())
551 }
552}
553
554impl PartialEq for OptionType {
555 fn eq(&self, other: &Self) -> bool {
556 self.0.equivalent(&other.0, TypeChecker::options_equal)
557 }
558}
559
560impl Eq for OptionType {}
561
562#[derive(Clone, Debug)]
564pub struct ResultType(Handle<TypeResultIndex>);
565
566impl ResultType {
567 pub(crate) fn from(index: TypeResultIndex, ty: &InstanceType<'_>) -> Self {
568 ResultType(Handle::new(index, ty))
569 }
570
571 pub fn ok(&self) -> Option<Type> {
573 Some(Type::from(
574 self.0.types[self.0.index].ok.as_ref()?,
575 &self.0.instance(),
576 ))
577 }
578
579 pub fn err(&self) -> Option<Type> {
581 Some(Type::from(
582 self.0.types[self.0.index].err.as_ref()?,
583 &self.0.instance(),
584 ))
585 }
586}
587
588impl PartialEq for ResultType {
589 fn eq(&self, other: &Self) -> bool {
590 self.0.equivalent(&other.0, TypeChecker::results_equal)
591 }
592}
593
594impl Eq for ResultType {}
595
596#[derive(Clone, Debug)]
598pub struct Flags(Handle<TypeFlagsIndex>);
599
600impl Flags {
601 pub(crate) fn from(index: TypeFlagsIndex, ty: &InstanceType<'_>) -> Self {
602 Flags(Handle::new(index, ty))
603 }
604
605 pub fn names(&self) -> impl ExactSizeIterator<Item = &str> {
607 self.0.types[self.0.index]
608 .names
609 .iter()
610 .map(|name| name.deref())
611 }
612}
613
614impl PartialEq for Flags {
615 fn eq(&self, other: &Self) -> bool {
616 self.0.equivalent(&other.0, TypeChecker::flags_equal)
617 }
618}
619
620impl Eq for Flags {}
621
622#[cfg(feature = "component-model-async")]
623pub(crate) fn typecheck_payload<T>(
624 payload: Option<&InterfaceType>,
625 types: &InstanceType<'_>,
626) -> crate::Result<()>
627where
628 T: ComponentType,
629{
630 match payload {
631 Some(a) => T::typecheck(a, types),
632 None => {
633 if T::IS_RUST_UNIT_TYPE {
634 Ok(())
635 } else {
636 crate::bail!("future payload types differ")
637 }
638 }
639 }
640}
641
642#[derive(Clone, Debug)]
644pub struct FutureType(Handle<TypeFutureIndex>);
645
646impl FutureType {
647 pub(crate) fn from(index: TypeFutureIndex, ty: &InstanceType<'_>) -> Self {
648 FutureType(Handle::new(index, ty))
649 }
650
651 pub fn ty(&self) -> Option<Type> {
653 Some(Type::from(
654 self.0.types[self.0.index].payload.as_ref()?,
655 &self.0.instance(),
656 ))
657 }
658
659 #[cfg(feature = "component-model-async")]
660 pub(crate) fn equivalent_payload_guest(
661 &self,
662 ty: &InstanceType<'_>,
663 payload: Option<&InterfaceType>,
664 ) -> bool {
665 let my_payload = self.0.types[self.0.index].payload.as_ref();
666 match (my_payload, payload) {
667 (Some(a), Some(b)) => TypeChecker {
668 a_types: &self.0.types,
669 a_resource: self.0.resources.as_deref(),
670 b_types: ty.types,
671 b_resource: ty.resources.map(|p| &**p),
672 }
673 .interface_types_equal(*a, *b),
674 (None, None) => true,
675 (Some(_), None) | (None, Some(_)) => false,
676 }
677 }
678
679 #[cfg(feature = "component-model-async")]
680 pub(crate) fn equivalent_payload_host<T>(&self) -> crate::Result<()>
681 where
682 T: ComponentType,
683 {
684 typecheck_payload::<T>(
685 self.0.types[self.0.index].payload.as_ref(),
686 &self.0.instance(),
687 )
688 }
689}
690
691impl PartialEq for FutureType {
692 fn eq(&self, other: &Self) -> bool {
693 self.0.equivalent(&other.0, TypeChecker::futures_equal)
694 }
695}
696
697impl Eq for FutureType {}
698
699#[derive(Clone, Debug)]
701pub struct StreamType(Handle<TypeStreamIndex>);
702
703impl StreamType {
704 pub(crate) fn from(index: TypeStreamIndex, ty: &InstanceType<'_>) -> Self {
705 StreamType(Handle::new(index, ty))
706 }
707
708 pub fn ty(&self) -> Option<Type> {
710 Some(Type::from(
711 self.0.types[self.0.index].payload.as_ref()?,
712 &self.0.instance(),
713 ))
714 }
715
716 #[cfg(feature = "component-model-async")]
717 pub(crate) fn equivalent_payload_guest(
718 &self,
719 ty: &InstanceType<'_>,
720 payload: Option<&InterfaceType>,
721 ) -> bool {
722 let my_payload = self.0.types[self.0.index].payload.as_ref();
723 match (my_payload, payload) {
724 (Some(a), Some(b)) => TypeChecker {
725 a_types: &self.0.types,
726 a_resource: self.0.resources.as_deref(),
727 b_types: ty.types,
728 b_resource: ty.resources.map(|p| &**p),
729 }
730 .interface_types_equal(*a, *b),
731 (None, None) => true,
732 (Some(_), None) | (None, Some(_)) => false,
733 }
734 }
735
736 #[cfg(feature = "component-model-async")]
737 pub(crate) fn equivalent_payload_host<T>(&self) -> crate::Result<()>
738 where
739 T: ComponentType,
740 {
741 typecheck_payload::<T>(
742 self.0.types[self.0.index].payload.as_ref(),
743 &self.0.instance(),
744 )
745 }
746}
747
748impl PartialEq for StreamType {
749 fn eq(&self, other: &Self) -> bool {
750 self.0.equivalent(&other.0, TypeChecker::streams_equal)
751 }
752}
753
754impl Eq for StreamType {}
755
756#[derive(Clone, PartialEq, Eq, Debug)]
758#[expect(missing_docs, reason = "self-describing variants")]
759pub enum Type {
760 Bool,
761 S8,
762 U8,
763 S16,
764 U16,
765 S32,
766 U32,
767 S64,
768 U64,
769 Float32,
770 Float64,
771 Char,
772 String,
773 List(List),
774 Map(Map),
775 Record(Record),
776 Tuple(Tuple),
777 Variant(Variant),
778 Enum(Enum),
779 Option(OptionType),
780 Result(ResultType),
781 Flags(Flags),
782 Own(ResourceType),
783 Borrow(ResourceType),
784 Future(FutureType),
785 Stream(StreamType),
786 ErrorContext,
787 FixedLengthList(FixedLengthList),
788}
789
790impl Type {
791 pub fn unwrap_list(&self) -> &List {
797 if let Type::List(handle) = self {
798 &handle
799 } else {
800 panic!("attempted to unwrap a {} as a list", self.desc())
801 }
802 }
803
804 pub fn unwrap_map(&self) -> &Map {
810 if let Type::Map(handle) = self {
811 &handle
812 } else {
813 panic!("attempted to unwrap a {} as a map", self.desc())
814 }
815 }
816
817 pub fn unwrap_record(&self) -> &Record {
823 if let Type::Record(handle) = self {
824 &handle
825 } else {
826 panic!("attempted to unwrap a {} as a record", self.desc())
827 }
828 }
829
830 pub fn unwrap_tuple(&self) -> &Tuple {
836 if let Type::Tuple(handle) = self {
837 &handle
838 } else {
839 panic!("attempted to unwrap a {} as a tuple", self.desc())
840 }
841 }
842
843 pub fn unwrap_variant(&self) -> &Variant {
849 if let Type::Variant(handle) = self {
850 &handle
851 } else {
852 panic!("attempted to unwrap a {} as a variant", self.desc())
853 }
854 }
855
856 pub fn unwrap_enum(&self) -> &Enum {
862 if let Type::Enum(handle) = self {
863 &handle
864 } else {
865 panic!("attempted to unwrap a {} as a enum", self.desc())
866 }
867 }
868
869 pub fn unwrap_option(&self) -> &OptionType {
875 if let Type::Option(handle) = self {
876 &handle
877 } else {
878 panic!("attempted to unwrap a {} as a option", self.desc())
879 }
880 }
881
882 pub fn unwrap_result(&self) -> &ResultType {
888 if let Type::Result(handle) = self {
889 &handle
890 } else {
891 panic!("attempted to unwrap a {} as a result", self.desc())
892 }
893 }
894
895 pub fn unwrap_flags(&self) -> &Flags {
901 if let Type::Flags(handle) = self {
902 &handle
903 } else {
904 panic!("attempted to unwrap a {} as a flags", self.desc())
905 }
906 }
907
908 pub fn unwrap_own(&self) -> &ResourceType {
914 match self {
915 Type::Own(ty) => ty,
916 _ => panic!("attempted to unwrap a {} as a own", self.desc()),
917 }
918 }
919
920 pub fn unwrap_borrow(&self) -> &ResourceType {
926 match self {
927 Type::Borrow(ty) => ty,
928 _ => panic!("attempted to unwrap a {} as a own", self.desc()),
929 }
930 }
931
932 pub(crate) fn from(ty: &InterfaceType, instance: &InstanceType<'_>) -> Self {
934 match ty {
935 InterfaceType::Bool => Type::Bool,
936 InterfaceType::S8 => Type::S8,
937 InterfaceType::U8 => Type::U8,
938 InterfaceType::S16 => Type::S16,
939 InterfaceType::U16 => Type::U16,
940 InterfaceType::S32 => Type::S32,
941 InterfaceType::U32 => Type::U32,
942 InterfaceType::S64 => Type::S64,
943 InterfaceType::U64 => Type::U64,
944 InterfaceType::Float32 => Type::Float32,
945 InterfaceType::Float64 => Type::Float64,
946 InterfaceType::Char => Type::Char,
947 InterfaceType::String => Type::String,
948 InterfaceType::List(index) => Type::List(List::from(*index, instance)),
949 InterfaceType::Map(index) => Type::Map(Map::from(*index, instance)),
950 InterfaceType::Record(index) => Type::Record(Record::from(*index, instance)),
951 InterfaceType::Tuple(index) => Type::Tuple(Tuple::from(*index, instance)),
952 InterfaceType::Variant(index) => Type::Variant(Variant::from(*index, instance)),
953 InterfaceType::Enum(index) => Type::Enum(Enum::from(*index, instance)),
954 InterfaceType::Option(index) => Type::Option(OptionType::from(*index, instance)),
955 InterfaceType::Result(index) => Type::Result(ResultType::from(*index, instance)),
956 InterfaceType::Flags(index) => Type::Flags(Flags::from(*index, instance)),
957 InterfaceType::Own(index) => Type::Own(instance.resource_type(*index)),
958 InterfaceType::Borrow(index) => Type::Borrow(instance.resource_type(*index)),
959 InterfaceType::Future(index) => Type::Future(instance.future_type(*index)),
960 InterfaceType::Stream(index) => Type::Stream(instance.stream_type(*index)),
961 InterfaceType::ErrorContext(_) => Type::ErrorContext,
962 InterfaceType::FixedLengthList(index) => {
963 Type::FixedLengthList(FixedLengthList::from(*index, instance))
964 }
965 }
966 }
967
968 pub fn default_value(&self, mut store: impl AsContextMut) -> Result<Val> {
996 self.default_value_impl(store.as_context_mut())
997 }
998
999 fn default_value_impl<T>(&self, mut store: StoreContextMut<'_, T>) -> Result<Val> {
1001 Ok(match self {
1002 Type::Bool => Val::Bool(false),
1003 Type::S8 => Val::S8(0),
1004 Type::U8 => Val::U8(0),
1005 Type::S16 => Val::S16(0),
1006 Type::U16 => Val::U16(0),
1007 Type::S32 => Val::S32(0),
1008 Type::U32 => Val::U32(0),
1009 Type::S64 => Val::S64(0),
1010 Type::U64 => Val::U64(0),
1011 Type::Float32 => Val::Float32(0.0),
1012 Type::Float64 => Val::Float64(0.0),
1013 Type::Char => Val::Char('\0'),
1014 Type::String => Val::String(String::new()),
1015
1016 Type::List(_) => Val::List(Vec::new()),
1018 Type::Map(_) => Val::Map(Vec::new()),
1019 Type::Option(_) => Val::Option(None),
1020 Type::Flags(_) => Val::Flags(Vec::new()),
1021
1022 Type::Enum(e) => {
1023 let name = e.names().next().ok_or_else(|| {
1024 format_err!("no default value exists for an `enum` with no cases")
1025 })?;
1026 Val::Enum(name.to_string())
1027 }
1028
1029 Type::Record(record) => {
1030 let mut fields = TryVec::with_capacity(record.fields().len())?;
1031 for field in record.fields() {
1032 let val = field.ty.default_value_impl(store.as_context_mut())?;
1033 fields.push((field.name.to_string(), val))?;
1034 }
1035 Val::Record(fields.into())
1036 }
1037
1038 Type::Tuple(tuple) => {
1039 let mut vals = TryVec::with_capacity(tuple.types().len())?;
1040 for ty in tuple.types() {
1041 vals.push(ty.default_value_impl(store.as_context_mut())?)?;
1042 }
1043 Val::Tuple(vals.into())
1044 }
1045
1046 Type::Variant(variant) => {
1047 let case = variant.cases().next().ok_or_else(|| {
1048 format_err!("no default value exists for a `variant` with no cases")
1049 })?;
1050 let payload = match &case.ty {
1051 Some(ty) => Some(Box::new(ty.default_value_impl(store.as_context_mut())?)),
1052 None => None,
1053 };
1054 Val::Variant(case.name.to_string(), payload)
1055 }
1056
1057 Type::Result(result) => Val::Result(Ok(match result.ok() {
1058 Some(ty) => Some(Box::new(ty.default_value_impl(store.as_context_mut())?)),
1059 None => None,
1060 })),
1061
1062 Type::FixedLengthList(list) => {
1063 let element = list.ty().default_value_impl(store.as_context_mut())?;
1065 let len = usize::try_from(list.len())?;
1066 let mut vals = TryVec::with_capacity(len)?;
1067 for _ in 0..len {
1068 vals.push(element.clone())?;
1069 }
1070 Val::FixedLengthList(vals.into())
1071 }
1072
1073 Type::Own(ty) | Type::Borrow(ty) => {
1077 Val::Resource(ResourceAny::new_own_dynamic(*ty, 0, &mut store)?)
1078 }
1079
1080 Type::Future(_) | Type::Stream(_) | Type::ErrorContext => {
1081 bail!("no default value exists for type `{}`", self.desc())
1082 }
1083 })
1084 }
1085
1086 fn desc(&self) -> &'static str {
1087 match self {
1088 Type::Bool => "bool",
1089 Type::S8 => "s8",
1090 Type::U8 => "u8",
1091 Type::S16 => "s16",
1092 Type::U16 => "u16",
1093 Type::S32 => "s32",
1094 Type::U32 => "u32",
1095 Type::S64 => "s64",
1096 Type::U64 => "u64",
1097 Type::Float32 => "float32",
1098 Type::Float64 => "float64",
1099 Type::Char => "char",
1100 Type::String => "string",
1101 Type::List(_) => "list",
1102 Type::Map(_) => "map",
1103 Type::Record(_) => "record",
1104 Type::Tuple(_) => "tuple",
1105 Type::Variant(_) => "variant",
1106 Type::Enum(_) => "enum",
1107 Type::Option(_) => "option",
1108 Type::Result(_) => "result",
1109 Type::Flags(_) => "flags",
1110 Type::Own(_) => "own",
1111 Type::Borrow(_) => "borrow",
1112 Type::Future(_) => "future",
1113 Type::Stream(_) => "stream",
1114 Type::ErrorContext => "error-context",
1115 Type::FixedLengthList(_) => "list<_, N>",
1116 }
1117 }
1118}
1119
1120#[derive(Clone, Debug)]
1122pub struct ComponentFunc(Handle<TypeFuncIndex>);
1123
1124impl ComponentFunc {
1125 pub(crate) fn from(index: TypeFuncIndex, ty: &InstanceType<'_>) -> Self {
1126 Self(Handle::new(index, ty))
1127 }
1128
1129 pub fn async_(&self) -> bool {
1131 self.0.types[self.0.index].async_
1132 }
1133
1134 pub fn params(&self) -> impl ExactSizeIterator<Item = (&str, Type)> + '_ {
1136 let ty = &self.0.types[self.0.index];
1137 self.0.types[ty.params]
1138 .types
1139 .iter()
1140 .zip(&ty.param_names)
1141 .map(|(ty, name)| (name.as_str(), Type::from(ty, &self.0.instance())))
1142 }
1143
1144 pub fn results(&self) -> impl ExactSizeIterator<Item = Type> + '_ {
1146 let results = self.0.types[self.0.index].results;
1147 self.0.types[results]
1148 .types
1149 .iter()
1150 .map(|ty| Type::from(ty, &self.0.instance()))
1151 }
1152
1153 #[doc(hidden)]
1154 pub fn typecheck<Params, Return>(&self, cx: &InstanceType) -> crate::Result<()>
1155 where
1156 Params: crate::component::ComponentNamedList + crate::component::Lower,
1157 Return: crate::component::ComponentNamedList + crate::component::Lift,
1158 {
1159 let ty = &self.0.types[self.0.index];
1160 Params::typecheck(&InterfaceType::Tuple(ty.params), cx)?;
1161 Return::typecheck(&InterfaceType::Tuple(ty.results), cx)?;
1162 Ok(())
1163 }
1164}
1165
1166#[derive(Clone, Debug)]
1168pub struct Module(Handle<TypeModuleIndex>);
1169
1170impl Module {
1171 pub(crate) fn from(index: TypeModuleIndex, ty: &InstanceType<'_>) -> Self {
1172 Self(Handle::new(index, ty))
1173 }
1174
1175 pub fn imports<'a>(
1177 &'a self,
1178 engine: &'a Engine,
1179 ) -> impl ExactSizeIterator<Item = ((&'a str, &'a str), ExternType)> + 'a {
1180 self.0.types[self.0.index]
1181 .imports
1182 .iter()
1183 .map(|((namespace, name), ty)| {
1184 (
1185 (namespace.as_str(), name.as_str()),
1186 ExternType::from_wasmtime(engine, self.0.types.module_types(), ty),
1187 )
1188 })
1189 }
1190
1191 pub fn exports<'a>(
1193 &'a self,
1194 engine: &'a Engine,
1195 ) -> impl ExactSizeIterator<Item = (&'a str, ExternType)> + 'a {
1196 self.0.types[self.0.index].exports.iter().map(|(name, ty)| {
1197 (
1198 name.as_str(),
1199 ExternType::from_wasmtime(engine, self.0.types.module_types(), ty),
1200 )
1201 })
1202 }
1203}
1204
1205#[derive(Clone, Debug)]
1207pub struct Component(Handle<TypeComponentIndex>);
1208
1209impl Component {
1210 pub(crate) fn from(index: TypeComponentIndex, ty: &InstanceType<'_>) -> Self {
1211 Self(Handle::new(index, ty))
1212 }
1213
1214 pub fn get_import<'a>(&'a self, engine: &'a Engine, name: &str) -> Option<ComponentExtern<'a>> {
1216 self.0.types[self.0.index]
1217 .imports
1218 .get(name)
1219 .map(|e| ComponentExtern::new(engine, &self.0.instance(), e))
1220 }
1221
1222 pub fn imports<'a>(
1224 &'a self,
1225 engine: &'a Engine,
1226 ) -> impl ExactSizeIterator<Item = (&'a str, ComponentExtern<'a>)> + 'a {
1227 self.0.types[self.0.index].imports.iter().map(|(name, e)| {
1228 (
1229 name.as_str(),
1230 ComponentExtern::new(engine, &self.0.instance(), e),
1231 )
1232 })
1233 }
1234
1235 pub fn get_export<'a>(&'a self, engine: &'a Engine, name: &str) -> Option<ComponentExtern<'a>> {
1237 self.0.types[self.0.index]
1238 .exports
1239 .get(name)
1240 .map(|e| ComponentExtern::new(engine, &self.0.instance(), e))
1241 }
1242
1243 pub fn exports<'a>(
1245 &'a self,
1246 engine: &'a Engine,
1247 ) -> impl ExactSizeIterator<Item = (&'a str, ComponentExtern<'a>)> + 'a {
1248 self.0.types[self.0.index].exports.iter().map(|(name, e)| {
1249 (
1250 name.as_str(),
1251 ComponentExtern::new(engine, &self.0.instance(), e),
1252 )
1253 })
1254 }
1255
1256 #[doc(hidden)]
1257 pub fn instance_type(&self) -> InstanceType<'_> {
1258 InstanceType {
1259 types: &self.0.types,
1260 resources: self.0.resources.as_ref(),
1261 }
1262 }
1263}
1264
1265#[derive(Clone, Debug)]
1267pub struct ComponentInstance(Handle<TypeComponentInstanceIndex>);
1268
1269impl ComponentInstance {
1270 pub(crate) fn from(index: TypeComponentInstanceIndex, ty: &InstanceType<'_>) -> Self {
1271 Self(Handle::new(index, ty))
1272 }
1273
1274 pub fn get_export<'a>(&'a self, engine: &'a Engine, name: &str) -> Option<ComponentExtern<'a>> {
1276 self.0.types[self.0.index]
1277 .exports
1278 .get(name)
1279 .map(|e| ComponentExtern::new(engine, &self.0.instance(), e))
1280 }
1281
1282 pub fn exports<'a>(
1284 &'a self,
1285 engine: &'a Engine,
1286 ) -> impl ExactSizeIterator<Item = (&'a str, ComponentExtern<'a>)> {
1287 self.0.types[self.0.index].exports.iter().map(|(name, e)| {
1288 (
1289 name.as_str(),
1290 ComponentExtern::new(engine, &self.0.instance(), e),
1291 )
1292 })
1293 }
1294}
1295
1296#[derive(Clone, Debug)]
1301pub struct ComponentExtern<'a> {
1302 pub ty: ComponentItem,
1304 pub implements: Option<&'a str>,
1306 pub external_id: Option<&'a str>,
1311}
1312
1313impl<'a> ComponentExtern<'a> {
1314 fn new(
1315 engine: &'a Engine,
1316 instance_ty: &InstanceType<'_>,
1317 env: &'a wasmtime_environ::component::ComponentExtern,
1318 ) -> Self {
1319 Self {
1320 implements: env.data.implements.as_deref(),
1321 external_id: env.data.external_id.as_deref(),
1322 ty: ComponentItem::from(engine, &env.ty, instance_ty),
1323 }
1324 }
1325
1326 pub fn is_implements(&self, name: &str) -> bool {
1337 let implements = match self.implements {
1338 Some(s) => s,
1339 None => return false,
1340 };
1341 if name == implements {
1342 return true;
1343 }
1344
1345 let reduced = |name| alternate_lookup_key(name).map_or(name, |(name, _)| name);
1349 reduced(implements) == reduced(name)
1350 }
1351}
1352
1353#[derive(Clone, Debug)]
1355pub enum ComponentItem {
1356 ComponentFunc(ComponentFunc),
1358 CoreFunc(FuncType),
1360 Module(Module),
1362 Component(Component),
1364 ComponentInstance(ComponentInstance),
1366 Type(Type),
1368 Resource(ResourceType),
1370}
1371
1372impl ComponentItem {
1373 pub(crate) fn from(engine: &Engine, def: &TypeDef, ty: &InstanceType<'_>) -> Self {
1374 match def {
1375 TypeDef::Component(idx) => Self::Component(Component::from(*idx, ty)),
1376 TypeDef::ComponentInstance(idx) => {
1377 Self::ComponentInstance(ComponentInstance::from(*idx, ty))
1378 }
1379 TypeDef::ComponentFunc(idx) => Self::ComponentFunc(ComponentFunc::from(*idx, ty)),
1380 TypeDef::Interface(iface_ty) => Self::Type(Type::from(iface_ty, ty)),
1381 TypeDef::Module(idx) => Self::Module(Module::from(*idx, ty)),
1382 TypeDef::CoreFunc(idx) => {
1383 let subty = &ty.types[*idx];
1384 Self::CoreFunc(
1385 FuncType::from_wasm_func_type(
1386 engine,
1387 subty.is_final,
1388 subty.supertype,
1389 subty.unwrap_func().try_clone().panic_on_oom(),
1390 )
1391 .panic_on_oom(),
1392 )
1393 }
1394 TypeDef::Resource(idx) => match ty.types[*idx] {
1395 TypeResourceTable::Concrete {
1396 ty: resource_index, ..
1397 } => {
1398 let ty = match ty.resources.and_then(|t| t.get(resource_index)) {
1399 Some(ty) => *ty,
1402
1403 None => ResourceType::uninstantiated(&ty.types, resource_index),
1405 };
1406 Self::Resource(ty)
1407 }
1408 TypeResourceTable::Abstract(resource_index) => {
1409 Self::Resource(ResourceType::abstract_(&ty.types, resource_index))
1410 }
1411 },
1412 }
1413 }
1414 pub(crate) fn from_export(engine: &Engine, export: &Export, ty: &InstanceType<'_>) -> Self {
1415 match export {
1416 Export::Instance { ty: idx, .. } => {
1417 Self::ComponentInstance(ComponentInstance::from(*idx, ty))
1418 }
1419 Export::LiftedFunction { ty: idx, .. } => {
1420 Self::ComponentFunc(ComponentFunc::from(*idx, ty))
1421 }
1422 Export::ModuleStatic { ty: idx, .. } | Export::ModuleImport { ty: idx, .. } => {
1423 Self::Module(Module::from(*idx, ty))
1424 }
1425 Export::Type(idx) => Self::from(engine, idx, ty),
1426 }
1427 }
1428}