1use crate::component::{MAX_FLAT_PARAMS, MAX_FLAT_RESULTS};
2use crate::{EntityType, ModuleInternedTypeIndex, ModuleTypes, PanicOnOom as _};
3use crate::{TypeTrace, prelude::*};
4use core::hash::{Hash, Hasher};
5use core::ops::Index;
6use serde_derive::{Deserialize, Serialize};
7use wasmparser::component_types::ComponentAnyTypeId;
8use wasmtime_component_util::{DiscriminantSize, FlagsSize};
9
10pub use crate::StaticModuleIndex;
11
12macro_rules! indices {
13 ($(
14 $(#[$a:meta])*
15 pub struct $name:ident(u32);
16 )*) => ($(
17 $(#[$a])*
18 #[derive(
19 Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug,
20 Serialize, Deserialize,
21 )]
22 #[repr(transparent)]
23 pub struct $name(u32);
24 cranelift_entity::entity_impl!($name);
25 impl TryClone for $name {
26 #[inline]
27 fn try_clone(&self) -> Result<Self, OutOfMemory> {
28 Ok(*self)
29 }
30 }
31 )*);
32}
33
34indices! {
35 pub struct ComponentTypeIndex(u32);
43
44 pub struct ModuleIndex(u32);
46
47 pub struct ComponentIndex(u32);
49
50 pub struct ModuleInstanceIndex(u32);
52
53 pub struct ComponentInstanceIndex(u32);
55
56 pub struct ComponentFuncIndex(u32);
58
59 pub struct TypeComponentIndex(u32);
67
68 pub struct TypeComponentInstanceIndex(u32);
71
72 pub struct TypeModuleIndex(u32);
75
76 pub struct TypeFuncIndex(u32);
79
80 pub struct TypeRecordIndex(u32);
82 pub struct TypeVariantIndex(u32);
84 pub struct TypeTupleIndex(u32);
86 pub struct TypeFlagsIndex(u32);
88 pub struct TypeEnumIndex(u32);
90 pub struct TypeOptionIndex(u32);
93 pub struct TypeResultIndex(u32);
96 pub struct TypeListIndex(u32);
98 pub struct TypeMapIndex(u32);
100 pub struct TypeFixedLengthListIndex(u32);
102 pub struct TypeFutureIndex(u32);
104
105 pub struct TypeFutureTableIndex(u32);
110
111 pub struct TypeStreamIndex(u32);
113
114 pub struct TypeStreamTableIndex(u32);
119
120 pub struct TypeComponentLocalErrorContextTableIndex(u32);
125
126 pub struct TypeComponentGlobalErrorContextTableIndex(u32);
132
133 pub struct TypeResourceTableIndex(u32);
148
149 pub struct ResourceIndex(u32);
162
163 pub struct DefinedResourceIndex(u32);
169
170 pub struct ModuleUpvarIndex(u32);
177
178 pub struct ComponentUpvarIndex(u32);
180
181 pub struct StaticComponentIndex(u32);
183
184 pub struct RuntimeInstanceIndex(u32);
193
194 pub struct RuntimeComponentInstanceIndex(u32);
196
197 pub struct ImportIndex(u32);
202
203 pub struct RuntimeImportIndex(u32);
209
210 pub struct LoweredIndex(u32);
216
217 pub struct RuntimeMemoryIndex(u32);
225
226 pub struct RuntimeReallocIndex(u32);
228
229 pub struct RuntimeCallbackIndex(u32);
231
232 pub struct RuntimePostReturnIndex(u32);
234
235 pub struct RuntimeTableIndex(u32);
242
243 pub struct TrampolineIndex(u32);
250
251 pub struct ExportIndex(u32);
253
254 pub struct OptionsIndex(u32);
256
257 pub struct AbstractResourceIndex(u32);
264}
265
266pub use crate::{FuncIndex, GlobalIndex, MemoryIndex, TableIndex};
269
270#[derive(Debug, Clone, Copy)]
273#[expect(missing_docs, reason = "self-describing variants")]
274pub enum ComponentItem {
275 Func(ComponentFuncIndex),
276 Module(ModuleIndex),
277 Component(ComponentIndex),
278 ComponentInstance(ComponentInstanceIndex),
279 Type(ComponentAnyTypeId),
280}
281
282#[derive(Default, Serialize, Deserialize)]
288pub struct ComponentTypes {
289 pub(super) modules: TryPrimaryMap<TypeModuleIndex, TypeModule>,
290 pub(super) components: TryPrimaryMap<TypeComponentIndex, TypeComponent>,
291 pub(super) component_instances:
292 TryPrimaryMap<TypeComponentInstanceIndex, TypeComponentInstance>,
293 pub(super) functions: TryPrimaryMap<TypeFuncIndex, TypeFunc>,
294 pub(super) lists: TryPrimaryMap<TypeListIndex, TypeList>,
295 pub(super) maps: TryPrimaryMap<TypeMapIndex, TypeMap>,
296 pub(super) records: TryPrimaryMap<TypeRecordIndex, TypeRecord>,
297 pub(super) variants: TryPrimaryMap<TypeVariantIndex, TypeVariant>,
298 pub(super) tuples: TryPrimaryMap<TypeTupleIndex, TypeTuple>,
299 pub(super) enums: TryPrimaryMap<TypeEnumIndex, TypeEnum>,
300 pub(super) flags: TryPrimaryMap<TypeFlagsIndex, TypeFlags>,
301 pub(super) options: TryPrimaryMap<TypeOptionIndex, TypeOption>,
302 pub(super) results: TryPrimaryMap<TypeResultIndex, TypeResult>,
303 pub(super) resource_tables: TryPrimaryMap<TypeResourceTableIndex, TypeResourceTable>,
304 pub(super) module_types: Option<ModuleTypes>,
305 pub(super) futures: TryPrimaryMap<TypeFutureIndex, TypeFuture>,
306 pub(super) future_tables: TryPrimaryMap<TypeFutureTableIndex, TypeFutureTable>,
307 pub(super) streams: TryPrimaryMap<TypeStreamIndex, TypeStream>,
308 pub(super) stream_tables: TryPrimaryMap<TypeStreamTableIndex, TypeStreamTable>,
309 pub(super) error_context_tables:
310 TryPrimaryMap<TypeComponentLocalErrorContextTableIndex, TypeErrorContextTable>,
311 pub(super) fixed_length_lists: TryPrimaryMap<TypeFixedLengthListIndex, TypeFixedLengthList>,
312}
313
314impl TypeTrace for ComponentTypes {
315 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
316 where
317 F: FnMut(crate::EngineOrModuleTypeIndex) -> Result<(), E>,
318 {
319 for (_, m) in &self.modules {
320 m.trace(func)?;
321 }
322 if let Some(m) = self.module_types.as_ref() {
323 m.trace(func)?;
324 }
325 Ok(())
326 }
327
328 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
329 where
330 F: FnMut(&mut crate::EngineOrModuleTypeIndex) -> Result<(), E>,
331 {
332 for (_, m) in &mut self.modules {
333 m.trace_mut(func)?;
334 }
335 if let Some(m) = self.module_types.as_mut() {
336 m.trace_mut(func)?;
337 }
338 Ok(())
339 }
340}
341
342impl ComponentTypes {
343 pub fn resource_owned_by_own_instance(
346 &self,
347 ty: TypeResourceTableIndex,
348 defined_resource_instance: impl FnOnce(ResourceIndex) -> Option<RuntimeComponentInstanceIndex>,
349 ) -> bool {
350 let (resource_ty, resource_instance) = match self[ty] {
351 TypeResourceTable::Concrete { ty, instance } => (ty, instance),
352 TypeResourceTable::Abstract(_) => return false,
355 };
356 defined_resource_instance(resource_ty) == Some(resource_instance)
359 }
360
361 pub fn module_types(&self) -> &ModuleTypes {
363 self.module_types.as_ref().unwrap()
364 }
365
366 pub fn module_types_mut(&mut self) -> &mut ModuleTypes {
368 self.module_types.as_mut().unwrap()
369 }
370
371 pub fn canonical_abi(&self, ty: &InterfaceType) -> &CanonicalAbiInfo {
373 match ty {
374 InterfaceType::U8 | InterfaceType::S8 | InterfaceType::Bool => {
375 &CanonicalAbiInfo::SCALAR1
376 }
377
378 InterfaceType::U16 | InterfaceType::S16 => &CanonicalAbiInfo::SCALAR2,
379
380 InterfaceType::U32
381 | InterfaceType::S32
382 | InterfaceType::Float32
383 | InterfaceType::Char
384 | InterfaceType::Own(_)
385 | InterfaceType::Borrow(_)
386 | InterfaceType::Future(_)
387 | InterfaceType::Stream(_)
388 | InterfaceType::ErrorContext(_) => &CanonicalAbiInfo::SCALAR4,
389
390 InterfaceType::U64 | InterfaceType::S64 | InterfaceType::Float64 => {
391 &CanonicalAbiInfo::SCALAR8
392 }
393
394 InterfaceType::String | InterfaceType::List(_) | InterfaceType::Map(_) => {
395 &CanonicalAbiInfo::POINTER_PAIR
396 }
397
398 InterfaceType::Record(i) => &self[*i].abi,
399 InterfaceType::Variant(i) => &self[*i].abi,
400 InterfaceType::Tuple(i) => &self[*i].abi,
401 InterfaceType::Flags(i) => &self[*i].abi,
402 InterfaceType::Enum(i) => &self[*i].abi,
403 InterfaceType::Option(i) => &self[*i].abi,
404 InterfaceType::Result(i) => &self[*i].abi,
405 InterfaceType::FixedLengthList(i) => &self[*i].abi,
406 }
407 }
408
409 pub fn push_resource_table(&mut self, table: TypeResourceTable) -> TypeResourceTableIndex {
411 self.resource_tables.push(table).panic_on_oom()
412 }
413}
414
415macro_rules! impl_index {
416 ($(impl Index<$ty:ident> for ComponentTypes { $output:ident => $field:ident })*) => ($(
417 impl core::ops::Index<$ty> for ComponentTypes {
418 type Output = $output;
419 #[inline]
420 fn index(&self, idx: $ty) -> &$output {
421 &self.$field[idx]
422 }
423 }
424
425 #[cfg(feature = "compile")]
426 impl core::ops::Index<$ty> for super::ComponentTypesBuilder {
427 type Output = $output;
428 #[inline]
429 fn index(&self, idx: $ty) -> &$output {
430 &self.component_types()[idx]
431 }
432 }
433 )*)
434}
435
436impl_index! {
437 impl Index<TypeModuleIndex> for ComponentTypes { TypeModule => modules }
438 impl Index<TypeComponentIndex> for ComponentTypes { TypeComponent => components }
439 impl Index<TypeComponentInstanceIndex> for ComponentTypes { TypeComponentInstance => component_instances }
440 impl Index<TypeFuncIndex> for ComponentTypes { TypeFunc => functions }
441 impl Index<TypeRecordIndex> for ComponentTypes { TypeRecord => records }
442 impl Index<TypeVariantIndex> for ComponentTypes { TypeVariant => variants }
443 impl Index<TypeTupleIndex> for ComponentTypes { TypeTuple => tuples }
444 impl Index<TypeEnumIndex> for ComponentTypes { TypeEnum => enums }
445 impl Index<TypeFlagsIndex> for ComponentTypes { TypeFlags => flags }
446 impl Index<TypeOptionIndex> for ComponentTypes { TypeOption => options }
447 impl Index<TypeResultIndex> for ComponentTypes { TypeResult => results }
448 impl Index<TypeListIndex> for ComponentTypes { TypeList => lists }
449 impl Index<TypeMapIndex> for ComponentTypes { TypeMap => maps }
450 impl Index<TypeResourceTableIndex> for ComponentTypes { TypeResourceTable => resource_tables }
451 impl Index<TypeFutureIndex> for ComponentTypes { TypeFuture => futures }
452 impl Index<TypeStreamIndex> for ComponentTypes { TypeStream => streams }
453 impl Index<TypeFutureTableIndex> for ComponentTypes { TypeFutureTable => future_tables }
454 impl Index<TypeStreamTableIndex> for ComponentTypes { TypeStreamTable => stream_tables }
455 impl Index<TypeComponentLocalErrorContextTableIndex> for ComponentTypes { TypeErrorContextTable => error_context_tables }
456 impl Index<TypeFixedLengthListIndex> for ComponentTypes { TypeFixedLengthList => fixed_length_lists }
457}
458
459impl<T> Index<T> for ComponentTypes
462where
463 ModuleTypes: Index<T>,
464{
465 type Output = <ModuleTypes as Index<T>>::Output;
466 fn index(&self, idx: T) -> &Self::Output {
467 self.module_types.as_ref().unwrap().index(idx)
468 }
469}
470
471#[derive(Debug, Serialize, Deserialize)]
476pub struct ComponentExtern {
477 pub data: ComponentExternData,
480 pub ty: TypeDef,
482}
483
484impl TryClone for ComponentExtern {
485 fn try_clone(&self) -> Result<Self, OutOfMemory> {
486 Ok(ComponentExtern {
487 data: self.data.try_clone()?,
488 ty: self.ty,
489 })
490 }
491}
492
493#[derive(Debug, Serialize, Deserialize)]
495pub struct ComponentExternData {
496 pub implements: Option<TryString>,
503 pub external_id: Option<TryString>,
506}
507
508impl TryClone for ComponentExternData {
509 fn try_clone(&self) -> Result<Self, OutOfMemory> {
510 Ok(ComponentExternData {
511 implements: self.implements.try_clone()?,
512 external_id: self.external_id.try_clone()?,
513 })
514 }
515}
516
517#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
523pub enum TypeDef {
524 Component(TypeComponentIndex),
526 ComponentInstance(TypeComponentInstanceIndex),
528 ComponentFunc(TypeFuncIndex),
530 Interface(InterfaceType),
532 Module(TypeModuleIndex),
534 CoreFunc(ModuleInternedTypeIndex),
536 Resource(TypeResourceTableIndex),
541}
542
543impl TypeDef {
544 pub fn desc(&self) -> &str {
546 match self {
547 TypeDef::Component(_) => "component",
548 TypeDef::ComponentInstance(_) => "instance",
549 TypeDef::ComponentFunc(_) => "function",
550 TypeDef::Interface(_) => "type",
551 TypeDef::Module(_) => "core module",
552 TypeDef::CoreFunc(_) => "core function",
553 TypeDef::Resource(_) => "resource",
554 }
555 }
556}
557
558#[derive(Serialize, Deserialize, Default)]
568pub struct TypeModule {
569 pub imports: TryIndexMap<(TryString, TryString), EntityType>,
577
578 pub exports: TryIndexMap<TryString, EntityType>,
583}
584
585impl TypeTrace for TypeModule {
586 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
587 where
588 F: FnMut(crate::EngineOrModuleTypeIndex) -> Result<(), E>,
589 {
590 for ty in self.imports.values() {
591 ty.trace(func)?;
592 }
593 for ty in self.exports.values() {
594 ty.trace(func)?;
595 }
596 Ok(())
597 }
598
599 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
600 where
601 F: FnMut(&mut crate::EngineOrModuleTypeIndex) -> Result<(), E>,
602 {
603 for ty in self.imports.values_mut() {
604 ty.trace_mut(func)?;
605 }
606 for ty in self.exports.values_mut() {
607 ty.trace_mut(func)?;
608 }
609 Ok(())
610 }
611}
612
613#[derive(Serialize, Deserialize, Default)]
615pub struct TypeComponent {
616 pub imports: TryIndexMap<TryString, ComponentExtern>,
618 pub exports: TryIndexMap<TryString, ComponentExtern>,
620}
621
622#[derive(Serialize, Deserialize, Default)]
627pub struct TypeComponentInstance {
628 pub exports: TryIndexMap<TryString, ComponentExtern>,
630}
631
632#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
634pub struct TypeFunc {
635 pub async_: bool,
637 pub param_names: TryVec<TryString>,
639 pub params: TypeTupleIndex,
641 pub results: TypeTupleIndex,
643}
644
645impl TryClone for TypeFunc {
646 fn try_clone(&self) -> Result<Self, OutOfMemory> {
647 Ok(TypeFunc {
648 async_: self.async_,
649 param_names: self.param_names.try_clone()?,
650 params: self.params,
651 results: self.results,
652 })
653 }
654}
655
656#[derive(Serialize, Deserialize, Copy, Clone, Hash, Eq, PartialEq, Debug)]
663#[expect(missing_docs, reason = "self-describing variants")]
664pub enum InterfaceType {
665 Bool,
666 S8,
667 U8,
668 S16,
669 U16,
670 S32,
671 U32,
672 S64,
673 U64,
674 Float32,
675 Float64,
676 Char,
677 String,
678 Record(TypeRecordIndex),
679 Variant(TypeVariantIndex),
680 List(TypeListIndex),
681 Tuple(TypeTupleIndex),
682 Map(TypeMapIndex),
683 Flags(TypeFlagsIndex),
684 Enum(TypeEnumIndex),
685 Option(TypeOptionIndex),
686 Result(TypeResultIndex),
687 Own(TypeResourceTableIndex),
688 Borrow(TypeResourceTableIndex),
689 Future(TypeFutureTableIndex),
690 Stream(TypeStreamTableIndex),
691 ErrorContext(TypeComponentLocalErrorContextTableIndex),
692 FixedLengthList(TypeFixedLengthListIndex),
693}
694
695impl TryClone for InterfaceType {
696 fn try_clone(&self) -> Result<Self, OutOfMemory> {
697 Ok(*self)
698 }
699}
700
701#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
704pub struct CanonicalAbiInfo {
705 pub size32: u32,
707 pub align32: u32,
709 pub size64: u32,
711 pub align64: u32,
713 pub flat_count: Option<u8>,
720}
721
722impl Default for CanonicalAbiInfo {
723 fn default() -> CanonicalAbiInfo {
724 CanonicalAbiInfo {
725 size32: 0,
726 align32: 1,
727 size64: 0,
728 align64: 1,
729 flat_count: Some(0),
730 }
731 }
732}
733
734const fn align_to(a: u32, b: u32) -> u32 {
735 assert!(b.is_power_of_two());
736 (a + (b - 1)) & !(b - 1)
737}
738
739const fn max(a: u32, b: u32) -> u32 {
740 if a > b { a } else { b }
741}
742
743impl CanonicalAbiInfo {
744 pub const ZERO: CanonicalAbiInfo = CanonicalAbiInfo {
746 size32: 0,
747 align32: 1,
748 size64: 0,
749 align64: 1,
750 flat_count: Some(0),
751 };
752
753 pub const SCALAR1: CanonicalAbiInfo = CanonicalAbiInfo::scalar(1);
755 pub const SCALAR2: CanonicalAbiInfo = CanonicalAbiInfo::scalar(2);
757 pub const SCALAR4: CanonicalAbiInfo = CanonicalAbiInfo::scalar(4);
759 pub const SCALAR8: CanonicalAbiInfo = CanonicalAbiInfo::scalar(8);
761
762 const fn scalar(size: u32) -> CanonicalAbiInfo {
763 CanonicalAbiInfo {
764 size32: size,
765 align32: size,
766 size64: size,
767 align64: size,
768 flat_count: Some(1),
769 }
770 }
771
772 pub const POINTER_PAIR: CanonicalAbiInfo = CanonicalAbiInfo {
774 size32: 8,
775 align32: 4,
776 size64: 16,
777 align64: 8,
778 flat_count: Some(2),
779 };
780
781 pub fn record<'a>(fields: impl Iterator<Item = &'a CanonicalAbiInfo>) -> CanonicalAbiInfo {
783 let mut ret = CanonicalAbiInfo::default();
787 for field in fields {
788 ret.size32 = align_to(ret.size32, field.align32) + field.size32;
789 ret.align32 = ret.align32.max(field.align32);
790 ret.size64 = align_to(ret.size64, field.align64) + field.size64;
791 ret.align64 = ret.align64.max(field.align64);
792 ret.flat_count = add_flat(ret.flat_count, field.flat_count);
793 }
794 ret.size32 = align_to(ret.size32, ret.align32);
795 ret.size64 = align_to(ret.size64, ret.align64);
796 return ret;
797 }
798
799 pub const fn record_static(fields: &[CanonicalAbiInfo]) -> CanonicalAbiInfo {
801 let mut ret = CanonicalAbiInfo::ZERO;
805 let mut i = 0;
806 while i < fields.len() {
807 let field = &fields[i];
808 ret.size32 = align_to(ret.size32, field.align32) + field.size32;
809 ret.align32 = max(ret.align32, field.align32);
810 ret.size64 = align_to(ret.size64, field.align64) + field.size64;
811 ret.align64 = max(ret.align64, field.align64);
812 ret.flat_count = add_flat(ret.flat_count, field.flat_count);
813 i += 1;
814 }
815 ret.size32 = align_to(ret.size32, ret.align32);
816 ret.size64 = align_to(ret.size64, ret.align64);
817 return ret;
818 }
819
820 pub const fn fixed_length_list_static(
822 element: &CanonicalAbiInfo,
823 count: usize,
824 ) -> CanonicalAbiInfo {
825 if count <= u32::MAX as usize {
826 let count = count as u32;
827 CanonicalAbiInfo {
828 size32: element.size32.saturating_mul(count),
829 align32: element.align32,
830 size64: element.size64.saturating_mul(count),
831 align64: element.align64,
832
833 flat_count: match element.flat_count {
834 None => None,
835 Some(c) =>
836 {
838 match count.checked_mul(c as u32) {
839 Some(product) => {
840 if product as usize > MAX_FLAT_TYPES || product > u8::MAX as u32 {
841 None
842 } else {
843 Some(product as u8)
844 }
845 }
846 None => None,
847 }
848 }
849 },
850 }
851 } else {
852 CanonicalAbiInfo {
853 size32: u32::MAX,
854 align32: element.align32,
855 size64: u32::MAX,
856 align64: element.align64,
857 flat_count: None,
858 }
859 }
860 }
861
862 pub fn next_field32(&self, offset: &mut u32) -> u32 {
865 *offset = align_to(*offset, self.align32) + self.size32;
866 *offset - self.size32
867 }
868
869 pub fn next_field32_size(&self, offset: &mut usize) -> usize {
871 let cur = u32::try_from(*offset).unwrap();
872 let cur = align_to(cur, self.align32) + self.size32;
873 *offset = usize::try_from(cur).unwrap();
874 usize::try_from(cur - self.size32).unwrap()
875 }
876
877 pub fn next_field64(&self, offset: &mut u32) -> u32 {
880 *offset = align_to(*offset, self.align64) + self.size64;
881 *offset - self.size64
882 }
883
884 pub fn next_field64_size(&self, offset: &mut usize) -> usize {
886 let cur = u32::try_from(*offset).unwrap();
887 let cur = align_to(cur, self.align64) + self.size64;
888 *offset = usize::try_from(cur).unwrap();
889 usize::try_from(cur - self.size64).unwrap()
890 }
891
892 pub const fn flags(count: usize) -> CanonicalAbiInfo {
894 let (size, align, flat_count) = match FlagsSize::from_count(count) {
895 FlagsSize::Size0 => (0, 1, 0),
896 FlagsSize::Size1 => (1, 1, 1),
897 FlagsSize::Size2 => (2, 2, 1),
898 FlagsSize::Size4Plus(n) => ((n as u32) * 4, 4, n),
899 };
900 CanonicalAbiInfo {
901 size32: size,
902 align32: align,
903 size64: size,
904 align64: align,
905 flat_count: Some(flat_count),
906 }
907 }
908
909 fn variant<'a, I>(cases: I) -> CanonicalAbiInfo
910 where
911 I: IntoIterator<Item = Option<&'a CanonicalAbiInfo>>,
912 I::IntoIter: ExactSizeIterator,
913 {
914 let cases = cases.into_iter();
918 let discrim_size = u32::from(DiscriminantSize::from_count(cases.len()).unwrap());
919 let mut max_size32 = 0;
920 let mut max_align32 = discrim_size;
921 let mut max_size64 = 0;
922 let mut max_align64 = discrim_size;
923 let mut max_case_count = Some(0);
924 for case in cases {
925 if let Some(case) = case {
926 max_size32 = max_size32.max(case.size32);
927 max_align32 = max_align32.max(case.align32);
928 max_size64 = max_size64.max(case.size64);
929 max_align64 = max_align64.max(case.align64);
930 max_case_count = max_flat(max_case_count, case.flat_count);
931 }
932 }
933 CanonicalAbiInfo {
934 size32: align_to(
935 align_to(discrim_size, max_align32) + max_size32,
936 max_align32,
937 ),
938 align32: max_align32,
939 size64: align_to(
940 align_to(discrim_size, max_align64) + max_size64,
941 max_align64,
942 ),
943 align64: max_align64,
944 flat_count: add_flat(max_case_count, Some(1)),
945 }
946 }
947
948 pub const fn variant_static(cases: &[Option<CanonicalAbiInfo>]) -> CanonicalAbiInfo {
950 let discrim_size = match DiscriminantSize::from_count(cases.len()) {
954 Some(size) => size.byte_size(),
955 None => unreachable!(),
956 };
957 let mut max_size32 = 0;
958 let mut max_align32 = discrim_size;
959 let mut max_size64 = 0;
960 let mut max_align64 = discrim_size;
961 let mut max_case_count = Some(0);
962 let mut i = 0;
963 while i < cases.len() {
964 let case = &cases[i];
965 if let Some(case) = case {
966 max_size32 = max(max_size32, case.size32);
967 max_align32 = max(max_align32, case.align32);
968 max_size64 = max(max_size64, case.size64);
969 max_align64 = max(max_align64, case.align64);
970 max_case_count = max_flat(max_case_count, case.flat_count);
971 }
972 i += 1;
973 }
974 CanonicalAbiInfo {
975 size32: align_to(
976 align_to(discrim_size, max_align32) + max_size32,
977 max_align32,
978 ),
979 align32: max_align32,
980 size64: align_to(
981 align_to(discrim_size, max_align64) + max_size64,
982 max_align64,
983 ),
984 align64: max_align64,
985 flat_count: add_flat(max_case_count, Some(1)),
986 }
987 }
988
989 pub const fn enum_(cases: usize) -> CanonicalAbiInfo {
991 let discrim_size = match DiscriminantSize::from_count(cases) {
995 Some(size) => size.byte_size(),
996 None => unreachable!(),
997 };
998 CanonicalAbiInfo {
999 size32: discrim_size,
1000 align32: discrim_size,
1001 size64: discrim_size,
1002 align64: discrim_size,
1003 flat_count: Some(1),
1004 }
1005 }
1006
1007 pub fn flat_count(&self, max: usize) -> Option<usize> {
1010 let flat = usize::from(self.flat_count?);
1011 if flat > max { None } else { Some(flat) }
1012 }
1013}
1014
1015#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1017pub struct VariantInfo {
1018 #[serde(with = "serde_discrim_size")]
1020 pub size: DiscriminantSize,
1021 pub payload_offset32: u32,
1024 pub payload_offset64: u32,
1027}
1028
1029impl VariantInfo {
1030 pub fn new<'a, I>(cases: I) -> (VariantInfo, CanonicalAbiInfo)
1033 where
1034 I: IntoIterator<Item = Option<&'a CanonicalAbiInfo>>,
1035 I::IntoIter: ExactSizeIterator,
1036 {
1037 let cases = cases.into_iter();
1038 let size = DiscriminantSize::from_count(cases.len()).unwrap();
1039 let abi = CanonicalAbiInfo::variant(cases);
1040 (
1041 VariantInfo {
1042 size,
1043 payload_offset32: align_to(u32::from(size), abi.align32),
1044 payload_offset64: align_to(u32::from(size), abi.align64),
1045 },
1046 abi,
1047 )
1048 }
1049 pub const fn new_static(cases: &[Option<CanonicalAbiInfo>]) -> VariantInfo {
1051 let size = match DiscriminantSize::from_count(cases.len()) {
1052 Some(size) => size,
1053 None => unreachable!(),
1054 };
1055 let abi = CanonicalAbiInfo::variant_static(cases);
1056 VariantInfo {
1057 size,
1058 payload_offset32: align_to(size.byte_size(), abi.align32),
1059 payload_offset64: align_to(size.byte_size(), abi.align64),
1060 }
1061 }
1062}
1063
1064mod serde_discrim_size {
1065 use super::DiscriminantSize;
1066 use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
1067
1068 pub fn serialize<S>(disc: &DiscriminantSize, ser: S) -> Result<S::Ok, S::Error>
1069 where
1070 S: Serializer,
1071 {
1072 u32::from(*disc).serialize(ser)
1073 }
1074
1075 pub fn deserialize<'de, D>(deser: D) -> Result<DiscriminantSize, D::Error>
1076 where
1077 D: Deserializer<'de>,
1078 {
1079 match u32::deserialize(deser)? {
1080 1 => Ok(DiscriminantSize::Size1),
1081 2 => Ok(DiscriminantSize::Size2),
1082 4 => Ok(DiscriminantSize::Size4),
1083 _ => Err(D::Error::custom("invalid discriminant size")),
1084 }
1085 }
1086}
1087
1088#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
1092pub struct TypeRecord {
1093 pub fields: TryVec<RecordField>,
1095 pub abi: CanonicalAbiInfo,
1097}
1098
1099impl TryClone for TypeRecord {
1100 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1101 Ok(TypeRecord {
1102 fields: self.fields.try_clone()?,
1103 abi: self.abi.clone(),
1104 })
1105 }
1106}
1107
1108#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
1110pub struct RecordField {
1111 pub name: TryString,
1113 pub ty: InterfaceType,
1115}
1116
1117impl TryClone for RecordField {
1118 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1119 Ok(RecordField {
1120 name: self.name.try_clone()?,
1121 ty: self.ty,
1122 })
1123 }
1124}
1125
1126#[derive(Serialize, Deserialize, Debug)]
1132pub struct TypeVariant {
1133 pub cases: TryIndexMap<TryString, Option<InterfaceType>>,
1135 pub abi: CanonicalAbiInfo,
1137 pub info: VariantInfo,
1139}
1140
1141impl PartialEq for TypeVariant {
1144 fn eq(&self, other: &TypeVariant) -> bool {
1145 let TypeVariant { cases, abi, info } = self;
1146 cases.len() == other.cases.len()
1147 && cases.iter().eq(other.cases.iter())
1148 && *abi == other.abi
1149 && *info == other.info
1150 }
1151}
1152
1153impl Eq for TypeVariant {}
1154
1155impl TryClone for TypeVariant {
1156 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1157 Ok(TypeVariant {
1158 cases: self.cases.try_clone()?,
1159 abi: self.abi.clone(),
1160 info: self.info.clone(),
1161 })
1162 }
1163}
1164
1165impl Hash for TypeVariant {
1166 fn hash<H: Hasher>(&self, h: &mut H) {
1167 let TypeVariant { cases, abi, info } = self;
1168 cases.len().hash(h);
1169 for pair in cases {
1170 pair.hash(h);
1171 }
1172 abi.hash(h);
1173 info.hash(h);
1174 }
1175}
1176
1177#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
1182pub struct TypeTuple {
1183 pub types: TryVec<InterfaceType>,
1185 pub abi: CanonicalAbiInfo,
1187}
1188
1189impl TryClone for TypeTuple {
1190 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1191 Ok(TypeTuple {
1192 types: self.types.try_clone()?,
1193 abi: self.abi.clone(),
1194 })
1195 }
1196}
1197
1198#[derive(Serialize, Deserialize, Debug)]
1203pub struct TypeFlags {
1204 pub names: TryIndexSet<TryString>,
1206 pub abi: CanonicalAbiInfo,
1208}
1209
1210impl PartialEq for TypeFlags {
1213 fn eq(&self, other: &TypeFlags) -> bool {
1214 let TypeFlags { names, abi } = self;
1215 names.len() == other.names.len() && names.iter().eq(other.names.iter()) && *abi == other.abi
1216 }
1217}
1218
1219impl Eq for TypeFlags {}
1220
1221impl TryClone for TypeFlags {
1222 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1223 Ok(TypeFlags {
1224 names: self.names.try_clone()?,
1225 abi: self.abi.clone(),
1226 })
1227 }
1228}
1229
1230impl Hash for TypeFlags {
1231 fn hash<H: Hasher>(&self, h: &mut H) {
1232 let TypeFlags { names, abi } = self;
1233 names.len().hash(h);
1234 for name in names {
1235 name.hash(h);
1236 }
1237 abi.hash(h);
1238 }
1239}
1240
1241#[derive(Serialize, Deserialize, Debug)]
1247pub struct TypeEnum {
1248 pub names: TryIndexSet<TryString>,
1250 pub abi: CanonicalAbiInfo,
1252 pub info: VariantInfo,
1254}
1255
1256impl PartialEq for TypeEnum {
1259 fn eq(&self, other: &TypeEnum) -> bool {
1260 let TypeEnum { names, abi, info } = self;
1261 names.len() == other.names.len()
1262 && names.iter().eq(other.names.iter())
1263 && *abi == other.abi
1264 && *info == other.info
1265 }
1266}
1267
1268impl Eq for TypeEnum {}
1269
1270impl TryClone for TypeEnum {
1271 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1272 Ok(TypeEnum {
1273 names: self.names.try_clone()?,
1274 abi: self.abi.clone(),
1275 info: self.info.clone(),
1276 })
1277 }
1278}
1279
1280impl Hash for TypeEnum {
1281 fn hash<H: Hasher>(&self, h: &mut H) {
1282 let TypeEnum { names, abi, info } = self;
1283 names.len().hash(h);
1284 for name in names {
1285 name.hash(h);
1286 }
1287 abi.hash(h);
1288 info.hash(h);
1289 }
1290}
1291
1292#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1294pub struct TypeOption {
1295 pub ty: InterfaceType,
1297 pub abi: CanonicalAbiInfo,
1299 pub info: VariantInfo,
1301}
1302
1303#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1305pub struct TypeResult {
1306 pub ok: Option<InterfaceType>,
1308 pub err: Option<InterfaceType>,
1310 pub abi: CanonicalAbiInfo,
1312 pub info: VariantInfo,
1314}
1315
1316#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1318pub struct TypeFuture {
1319 pub payload: Option<InterfaceType>,
1321}
1322
1323#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1325pub struct TypeFutureTable {
1326 pub ty: TypeFutureIndex,
1328 pub instance: RuntimeComponentInstanceIndex,
1330}
1331
1332#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1334pub struct TypeStream {
1335 pub payload: Option<InterfaceType>,
1337}
1338
1339#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1341pub struct TypeStreamTable {
1342 pub ty: TypeStreamIndex,
1344 pub instance: RuntimeComponentInstanceIndex,
1346}
1347
1348#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1350pub struct TypeErrorContextTable {
1351 pub instance: RuntimeComponentInstanceIndex,
1353}
1354
1355#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1357pub enum TypeResourceTable {
1358 Concrete {
1365 ty: ResourceIndex,
1370
1371 instance: RuntimeComponentInstanceIndex,
1373 },
1374
1375 Abstract(AbstractResourceIndex),
1379}
1380
1381impl TypeResourceTable {
1382 pub fn unwrap_concrete_ty(&self) -> ResourceIndex {
1389 match self {
1390 TypeResourceTable::Concrete { ty, .. } => *ty,
1391 TypeResourceTable::Abstract(_) => panic!("not a concrete resource table"),
1392 }
1393 }
1394
1395 pub fn unwrap_concrete_instance(&self) -> RuntimeComponentInstanceIndex {
1402 match self {
1403 TypeResourceTable::Concrete { instance, .. } => *instance,
1404 TypeResourceTable::Abstract(_) => panic!("not a concrete resource table"),
1405 }
1406 }
1407}
1408
1409#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1411pub struct TypeList {
1412 pub element: InterfaceType,
1414}
1415
1416#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1418pub struct TypeMap {
1419 pub key: InterfaceType,
1421 pub value: InterfaceType,
1423 pub entry_abi: CanonicalAbiInfo,
1425 pub value_offset32: u32,
1428 pub value_offset64: u32,
1431}
1432
1433#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1435pub struct TypeFixedLengthList {
1436 pub element: InterfaceType,
1438 pub size: u32,
1440 pub abi: CanonicalAbiInfo,
1442}
1443
1444macro_rules! impl_try_clone_via_clone {
1445 ($($ty:ty),* $(,)?) => {$(
1446 impl TryClone for $ty {
1447 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1448 Ok(self.clone())
1449 }
1450 }
1451 )*};
1452}
1453
1454impl_try_clone_via_clone! {
1456 TypeOption,
1457 TypeResult,
1458 TypeFuture,
1459 TypeFutureTable,
1460 TypeStream,
1461 TypeStreamTable,
1462 TypeErrorContextTable,
1463 TypeResourceTable,
1464 TypeList,
1465 TypeMap,
1466 TypeFixedLengthList,
1467}
1468
1469pub const MAX_FLAT_TYPES: usize = if MAX_FLAT_PARAMS > MAX_FLAT_RESULTS {
1471 MAX_FLAT_PARAMS
1472} else {
1473 MAX_FLAT_RESULTS
1474};
1475
1476const fn add_flat(a: Option<u8>, b: Option<u8>) -> Option<u8> {
1477 const MAX: u8 = MAX_FLAT_TYPES as u8;
1478 let sum = match (a, b) {
1479 (Some(a), Some(b)) => match a.checked_add(b) {
1480 Some(c) => c,
1481 None => return None,
1482 },
1483 _ => return None,
1484 };
1485 if sum > MAX { None } else { Some(sum) }
1486}
1487
1488const fn max_flat(a: Option<u8>, b: Option<u8>) -> Option<u8> {
1489 match (a, b) {
1490 (Some(a), Some(b)) => {
1491 if a > b {
1492 Some(a)
1493 } else {
1494 Some(b)
1495 }
1496 }
1497 _ => None,
1498 }
1499}
1500
1501pub struct FlatTypes<'a> {
1503 pub memory32: &'a [FlatType],
1505 pub memory64: &'a [FlatType],
1507}
1508
1509impl FlatTypes<'_> {
1510 pub fn len(&self) -> usize {
1514 assert_eq!(self.memory32.len(), self.memory64.len());
1515 self.memory32.len()
1516 }
1517}
1518
1519#[derive(Serialize, Deserialize, Hash, Debug, PartialEq, Eq, Copy, Clone)]
1523#[expect(missing_docs, reason = "self-describing variants")]
1524pub enum FlatType {
1525 I32,
1526 I64,
1527 F32,
1528 F64,
1529}
1530
1531#[cfg(test)]
1532mod tests {
1533 use super::*;
1534
1535 fn variant(cases: &[(&str, InterfaceType)]) -> TypeVariant {
1536 TypeVariant {
1537 cases: cases
1538 .iter()
1539 .map(|(name, ty)| Ok((TryString::try_from(*name)?, Some(*ty))))
1540 .try_collect::<_, OutOfMemory>()
1541 .panic_on_oom(),
1542 abi: CanonicalAbiInfo::default(),
1543 info: VariantInfo {
1544 size: DiscriminantSize::Size1,
1545 payload_offset32: 4,
1546 payload_offset64: 8,
1547 },
1548 }
1549 }
1550
1551 fn flags(names: &[&str]) -> TypeFlags {
1552 TypeFlags {
1553 names: names
1554 .iter()
1555 .map(|n| TryString::try_from(*n))
1556 .try_collect::<_, OutOfMemory>()
1557 .panic_on_oom(),
1558 abi: CanonicalAbiInfo::default(),
1559 }
1560 }
1561
1562 fn enum_(names: &[&str]) -> TypeEnum {
1563 TypeEnum {
1564 names: names
1565 .iter()
1566 .map(|n| TryString::try_from(*n))
1567 .try_collect::<_, OutOfMemory>()
1568 .panic_on_oom(),
1569 abi: CanonicalAbiInfo::default(),
1570 info: VariantInfo {
1571 size: DiscriminantSize::Size1,
1572 payload_offset32: 4,
1573 payload_offset64: 8,
1574 },
1575 }
1576 }
1577
1578 #[test]
1579 fn variant_case_order_is_significant() {
1580 let a = variant(&[("n", InterfaceType::U32), ("s", InterfaceType::String)]);
1581 let b = variant(&[("s", InterfaceType::String), ("n", InterfaceType::U32)]);
1582 assert_ne!(a, b);
1583 assert_eq!(a, a.clone_panic_on_oom());
1584 }
1585
1586 #[test]
1587 fn flags_name_order_is_significant() {
1588 let a = flags(&["a", "b", "c"]);
1589 let b = flags(&["c", "b", "a"]);
1590
1591 assert_ne!(a, b);
1592 assert_eq!(a, a.clone_panic_on_oom());
1593 }
1594
1595 #[test]
1596 fn enum_name_order_is_significant() {
1597 let a = enum_(&["red", "green", "blue"]);
1598 let b = enum_(&["blue", "green", "red"]);
1599
1600 assert_ne!(a, b);
1601 assert_eq!(a, a.clone_panic_on_oom());
1602 }
1603}