1use crate::component::{MAX_FLAT_PARAMS, MAX_FLAT_RESULTS};
2use crate::{EntityType, ModuleInternedTypeIndex, ModuleTypes, PrimaryMap};
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: PrimaryMap<TypeModuleIndex, TypeModule>,
290 pub(super) components: PrimaryMap<TypeComponentIndex, TypeComponent>,
291 pub(super) component_instances: PrimaryMap<TypeComponentInstanceIndex, TypeComponentInstance>,
292 pub(super) functions: PrimaryMap<TypeFuncIndex, TypeFunc>,
293 pub(super) lists: PrimaryMap<TypeListIndex, TypeList>,
294 pub(super) maps: PrimaryMap<TypeMapIndex, TypeMap>,
295 pub(super) records: PrimaryMap<TypeRecordIndex, TypeRecord>,
296 pub(super) variants: PrimaryMap<TypeVariantIndex, TypeVariant>,
297 pub(super) tuples: PrimaryMap<TypeTupleIndex, TypeTuple>,
298 pub(super) enums: PrimaryMap<TypeEnumIndex, TypeEnum>,
299 pub(super) flags: PrimaryMap<TypeFlagsIndex, TypeFlags>,
300 pub(super) options: PrimaryMap<TypeOptionIndex, TypeOption>,
301 pub(super) results: PrimaryMap<TypeResultIndex, TypeResult>,
302 pub(super) resource_tables: PrimaryMap<TypeResourceTableIndex, TypeResourceTable>,
303 pub(super) module_types: Option<ModuleTypes>,
304 pub(super) futures: PrimaryMap<TypeFutureIndex, TypeFuture>,
305 pub(super) future_tables: PrimaryMap<TypeFutureTableIndex, TypeFutureTable>,
306 pub(super) streams: PrimaryMap<TypeStreamIndex, TypeStream>,
307 pub(super) stream_tables: PrimaryMap<TypeStreamTableIndex, TypeStreamTable>,
308 pub(super) error_context_tables:
309 PrimaryMap<TypeComponentLocalErrorContextTableIndex, TypeErrorContextTable>,
310 pub(super) fixed_length_lists: PrimaryMap<TypeFixedLengthListIndex, TypeFixedLengthList>,
311}
312
313impl TypeTrace for ComponentTypes {
314 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
315 where
316 F: FnMut(crate::EngineOrModuleTypeIndex) -> Result<(), E>,
317 {
318 for (_, m) in &self.modules {
319 m.trace(func)?;
320 }
321 if let Some(m) = self.module_types.as_ref() {
322 m.trace(func)?;
323 }
324 Ok(())
325 }
326
327 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
328 where
329 F: FnMut(&mut crate::EngineOrModuleTypeIndex) -> Result<(), E>,
330 {
331 for (_, m) in &mut self.modules {
332 m.trace_mut(func)?;
333 }
334 if let Some(m) = self.module_types.as_mut() {
335 m.trace_mut(func)?;
336 }
337 Ok(())
338 }
339}
340
341impl ComponentTypes {
342 pub fn module_types(&self) -> &ModuleTypes {
344 self.module_types.as_ref().unwrap()
345 }
346
347 pub fn module_types_mut(&mut self) -> &mut ModuleTypes {
349 self.module_types.as_mut().unwrap()
350 }
351
352 pub fn canonical_abi(&self, ty: &InterfaceType) -> &CanonicalAbiInfo {
354 match ty {
355 InterfaceType::U8 | InterfaceType::S8 | InterfaceType::Bool => {
356 &CanonicalAbiInfo::SCALAR1
357 }
358
359 InterfaceType::U16 | InterfaceType::S16 => &CanonicalAbiInfo::SCALAR2,
360
361 InterfaceType::U32
362 | InterfaceType::S32
363 | InterfaceType::Float32
364 | InterfaceType::Char
365 | InterfaceType::Own(_)
366 | InterfaceType::Borrow(_)
367 | InterfaceType::Future(_)
368 | InterfaceType::Stream(_)
369 | InterfaceType::ErrorContext(_) => &CanonicalAbiInfo::SCALAR4,
370
371 InterfaceType::U64 | InterfaceType::S64 | InterfaceType::Float64 => {
372 &CanonicalAbiInfo::SCALAR8
373 }
374
375 InterfaceType::String | InterfaceType::List(_) | InterfaceType::Map(_) => {
376 &CanonicalAbiInfo::POINTER_PAIR
377 }
378
379 InterfaceType::Record(i) => &self[*i].abi,
380 InterfaceType::Variant(i) => &self[*i].abi,
381 InterfaceType::Tuple(i) => &self[*i].abi,
382 InterfaceType::Flags(i) => &self[*i].abi,
383 InterfaceType::Enum(i) => &self[*i].abi,
384 InterfaceType::Option(i) => &self[*i].abi,
385 InterfaceType::Result(i) => &self[*i].abi,
386 InterfaceType::FixedLengthList(i) => &self[*i].abi,
387 }
388 }
389
390 pub fn push_resource_table(&mut self, table: TypeResourceTable) -> TypeResourceTableIndex {
392 self.resource_tables.push(table)
393 }
394}
395
396macro_rules! impl_index {
397 ($(impl Index<$ty:ident> for ComponentTypes { $output:ident => $field:ident })*) => ($(
398 impl core::ops::Index<$ty> for ComponentTypes {
399 type Output = $output;
400 #[inline]
401 fn index(&self, idx: $ty) -> &$output {
402 &self.$field[idx]
403 }
404 }
405
406 #[cfg(feature = "compile")]
407 impl core::ops::Index<$ty> for super::ComponentTypesBuilder {
408 type Output = $output;
409 #[inline]
410 fn index(&self, idx: $ty) -> &$output {
411 &self.component_types()[idx]
412 }
413 }
414 )*)
415}
416
417impl_index! {
418 impl Index<TypeModuleIndex> for ComponentTypes { TypeModule => modules }
419 impl Index<TypeComponentIndex> for ComponentTypes { TypeComponent => components }
420 impl Index<TypeComponentInstanceIndex> for ComponentTypes { TypeComponentInstance => component_instances }
421 impl Index<TypeFuncIndex> for ComponentTypes { TypeFunc => functions }
422 impl Index<TypeRecordIndex> for ComponentTypes { TypeRecord => records }
423 impl Index<TypeVariantIndex> for ComponentTypes { TypeVariant => variants }
424 impl Index<TypeTupleIndex> for ComponentTypes { TypeTuple => tuples }
425 impl Index<TypeEnumIndex> for ComponentTypes { TypeEnum => enums }
426 impl Index<TypeFlagsIndex> for ComponentTypes { TypeFlags => flags }
427 impl Index<TypeOptionIndex> for ComponentTypes { TypeOption => options }
428 impl Index<TypeResultIndex> for ComponentTypes { TypeResult => results }
429 impl Index<TypeListIndex> for ComponentTypes { TypeList => lists }
430 impl Index<TypeMapIndex> for ComponentTypes { TypeMap => maps }
431 impl Index<TypeResourceTableIndex> for ComponentTypes { TypeResourceTable => resource_tables }
432 impl Index<TypeFutureIndex> for ComponentTypes { TypeFuture => futures }
433 impl Index<TypeStreamIndex> for ComponentTypes { TypeStream => streams }
434 impl Index<TypeFutureTableIndex> for ComponentTypes { TypeFutureTable => future_tables }
435 impl Index<TypeStreamTableIndex> for ComponentTypes { TypeStreamTable => stream_tables }
436 impl Index<TypeComponentLocalErrorContextTableIndex> for ComponentTypes { TypeErrorContextTable => error_context_tables }
437 impl Index<TypeFixedLengthListIndex> for ComponentTypes { TypeFixedLengthList => fixed_length_lists }
438}
439
440impl<T> Index<T> for ComponentTypes
443where
444 ModuleTypes: Index<T>,
445{
446 type Output = <ModuleTypes as Index<T>>::Output;
447 fn index(&self, idx: T) -> &Self::Output {
448 self.module_types.as_ref().unwrap().index(idx)
449 }
450}
451
452#[derive(Clone, Debug, Serialize, Deserialize)]
457pub struct ComponentExtern {
458 pub data: ComponentExternData,
461 pub ty: TypeDef,
463}
464
465#[derive(Clone, Debug, Serialize, Deserialize)]
467pub struct ComponentExternData {
468 pub implements: Option<String>,
472 pub external_id: Option<String>,
475}
476
477#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
483pub enum TypeDef {
484 Component(TypeComponentIndex),
486 ComponentInstance(TypeComponentInstanceIndex),
488 ComponentFunc(TypeFuncIndex),
490 Interface(InterfaceType),
492 Module(TypeModuleIndex),
494 CoreFunc(ModuleInternedTypeIndex),
496 Resource(TypeResourceTableIndex),
501}
502
503impl TypeDef {
504 pub fn desc(&self) -> &str {
506 match self {
507 TypeDef::Component(_) => "component",
508 TypeDef::ComponentInstance(_) => "instance",
509 TypeDef::ComponentFunc(_) => "function",
510 TypeDef::Interface(_) => "type",
511 TypeDef::Module(_) => "core module",
512 TypeDef::CoreFunc(_) => "core function",
513 TypeDef::Resource(_) => "resource",
514 }
515 }
516}
517
518#[derive(Serialize, Deserialize, Default)]
528pub struct TypeModule {
529 pub imports: IndexMap<(String, String), EntityType>,
537
538 pub exports: IndexMap<String, EntityType>,
543}
544
545impl TypeTrace for TypeModule {
546 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
547 where
548 F: FnMut(crate::EngineOrModuleTypeIndex) -> Result<(), E>,
549 {
550 for ty in self.imports.values() {
551 ty.trace(func)?;
552 }
553 for ty in self.exports.values() {
554 ty.trace(func)?;
555 }
556 Ok(())
557 }
558
559 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
560 where
561 F: FnMut(&mut crate::EngineOrModuleTypeIndex) -> Result<(), E>,
562 {
563 for ty in self.imports.values_mut() {
564 ty.trace_mut(func)?;
565 }
566 for ty in self.exports.values_mut() {
567 ty.trace_mut(func)?;
568 }
569 Ok(())
570 }
571}
572
573#[derive(Serialize, Deserialize, Default)]
575pub struct TypeComponent {
576 pub imports: IndexMap<String, ComponentExtern>,
578 pub exports: IndexMap<String, ComponentExtern>,
580}
581
582#[derive(Serialize, Deserialize, Default)]
587pub struct TypeComponentInstance {
588 pub exports: IndexMap<String, ComponentExtern>,
590}
591
592#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
594pub struct TypeFunc {
595 pub async_: bool,
597 pub param_names: Vec<String>,
599 pub params: TypeTupleIndex,
601 pub results: TypeTupleIndex,
603}
604
605#[derive(Serialize, Deserialize, Copy, Clone, Hash, Eq, PartialEq, Debug)]
612#[expect(missing_docs, reason = "self-describing variants")]
613pub enum InterfaceType {
614 Bool,
615 S8,
616 U8,
617 S16,
618 U16,
619 S32,
620 U32,
621 S64,
622 U64,
623 Float32,
624 Float64,
625 Char,
626 String,
627 Record(TypeRecordIndex),
628 Variant(TypeVariantIndex),
629 List(TypeListIndex),
630 Tuple(TypeTupleIndex),
631 Map(TypeMapIndex),
632 Flags(TypeFlagsIndex),
633 Enum(TypeEnumIndex),
634 Option(TypeOptionIndex),
635 Result(TypeResultIndex),
636 Own(TypeResourceTableIndex),
637 Borrow(TypeResourceTableIndex),
638 Future(TypeFutureTableIndex),
639 Stream(TypeStreamTableIndex),
640 ErrorContext(TypeComponentLocalErrorContextTableIndex),
641 FixedLengthList(TypeFixedLengthListIndex),
642}
643
644#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
647pub struct CanonicalAbiInfo {
648 pub size32: u32,
650 pub align32: u32,
652 pub size64: u32,
654 pub align64: u32,
656 pub flat_count: Option<u8>,
663}
664
665impl Default for CanonicalAbiInfo {
666 fn default() -> CanonicalAbiInfo {
667 CanonicalAbiInfo {
668 size32: 0,
669 align32: 1,
670 size64: 0,
671 align64: 1,
672 flat_count: Some(0),
673 }
674 }
675}
676
677const fn align_to(a: u32, b: u32) -> u32 {
678 assert!(b.is_power_of_two());
679 (a + (b - 1)) & !(b - 1)
680}
681
682const fn max(a: u32, b: u32) -> u32 {
683 if a > b { a } else { b }
684}
685
686impl CanonicalAbiInfo {
687 pub const ZERO: CanonicalAbiInfo = CanonicalAbiInfo {
689 size32: 0,
690 align32: 1,
691 size64: 0,
692 align64: 1,
693 flat_count: Some(0),
694 };
695
696 pub const SCALAR1: CanonicalAbiInfo = CanonicalAbiInfo::scalar(1);
698 pub const SCALAR2: CanonicalAbiInfo = CanonicalAbiInfo::scalar(2);
700 pub const SCALAR4: CanonicalAbiInfo = CanonicalAbiInfo::scalar(4);
702 pub const SCALAR8: CanonicalAbiInfo = CanonicalAbiInfo::scalar(8);
704
705 const fn scalar(size: u32) -> CanonicalAbiInfo {
706 CanonicalAbiInfo {
707 size32: size,
708 align32: size,
709 size64: size,
710 align64: size,
711 flat_count: Some(1),
712 }
713 }
714
715 pub const POINTER_PAIR: CanonicalAbiInfo = CanonicalAbiInfo {
717 size32: 8,
718 align32: 4,
719 size64: 16,
720 align64: 8,
721 flat_count: Some(2),
722 };
723
724 pub fn record<'a>(fields: impl Iterator<Item = &'a CanonicalAbiInfo>) -> CanonicalAbiInfo {
726 let mut ret = CanonicalAbiInfo::default();
730 for field in fields {
731 ret.size32 = align_to(ret.size32, field.align32) + field.size32;
732 ret.align32 = ret.align32.max(field.align32);
733 ret.size64 = align_to(ret.size64, field.align64) + field.size64;
734 ret.align64 = ret.align64.max(field.align64);
735 ret.flat_count = add_flat(ret.flat_count, field.flat_count);
736 }
737 ret.size32 = align_to(ret.size32, ret.align32);
738 ret.size64 = align_to(ret.size64, ret.align64);
739 return ret;
740 }
741
742 pub const fn record_static(fields: &[CanonicalAbiInfo]) -> CanonicalAbiInfo {
744 let mut ret = CanonicalAbiInfo::ZERO;
748 let mut i = 0;
749 while i < fields.len() {
750 let field = &fields[i];
751 ret.size32 = align_to(ret.size32, field.align32) + field.size32;
752 ret.align32 = max(ret.align32, field.align32);
753 ret.size64 = align_to(ret.size64, field.align64) + field.size64;
754 ret.align64 = max(ret.align64, field.align64);
755 ret.flat_count = add_flat(ret.flat_count, field.flat_count);
756 i += 1;
757 }
758 ret.size32 = align_to(ret.size32, ret.align32);
759 ret.size64 = align_to(ret.size64, ret.align64);
760 return ret;
761 }
762
763 pub const fn fixed_length_list_static(
765 element: &CanonicalAbiInfo,
766 count: usize,
767 ) -> CanonicalAbiInfo {
768 if count <= u32::MAX as usize {
769 let count = count as u32;
770 CanonicalAbiInfo {
771 size32: element.size32.saturating_mul(count),
772 align32: element.align32,
773 size64: element.size64.saturating_mul(count),
774 align64: element.align64,
775
776 flat_count: match element.flat_count {
777 None => None,
778 Some(c) =>
779 {
781 match count.checked_mul(c as u32) {
782 Some(product) => {
783 if product as usize > MAX_FLAT_TYPES || product > u8::MAX as u32 {
784 None
785 } else {
786 Some(product as u8)
787 }
788 }
789 None => None,
790 }
791 }
792 },
793 }
794 } else {
795 CanonicalAbiInfo {
796 size32: u32::MAX,
797 align32: element.align32,
798 size64: u32::MAX,
799 align64: element.align64,
800 flat_count: None,
801 }
802 }
803 }
804
805 pub fn next_field32(&self, offset: &mut u32) -> u32 {
808 *offset = align_to(*offset, self.align32) + self.size32;
809 *offset - self.size32
810 }
811
812 pub fn next_field32_size(&self, offset: &mut usize) -> usize {
814 let cur = u32::try_from(*offset).unwrap();
815 let cur = align_to(cur, self.align32) + self.size32;
816 *offset = usize::try_from(cur).unwrap();
817 usize::try_from(cur - self.size32).unwrap()
818 }
819
820 pub fn next_field64(&self, offset: &mut u32) -> u32 {
823 *offset = align_to(*offset, self.align64) + self.size64;
824 *offset - self.size64
825 }
826
827 pub fn next_field64_size(&self, offset: &mut usize) -> usize {
829 let cur = u32::try_from(*offset).unwrap();
830 let cur = align_to(cur, self.align64) + self.size64;
831 *offset = usize::try_from(cur).unwrap();
832 usize::try_from(cur - self.size64).unwrap()
833 }
834
835 pub const fn flags(count: usize) -> CanonicalAbiInfo {
837 let (size, align, flat_count) = match FlagsSize::from_count(count) {
838 FlagsSize::Size0 => (0, 1, 0),
839 FlagsSize::Size1 => (1, 1, 1),
840 FlagsSize::Size2 => (2, 2, 1),
841 FlagsSize::Size4Plus(n) => ((n as u32) * 4, 4, n),
842 };
843 CanonicalAbiInfo {
844 size32: size,
845 align32: align,
846 size64: size,
847 align64: align,
848 flat_count: Some(flat_count),
849 }
850 }
851
852 fn variant<'a, I>(cases: I) -> CanonicalAbiInfo
853 where
854 I: IntoIterator<Item = Option<&'a CanonicalAbiInfo>>,
855 I::IntoIter: ExactSizeIterator,
856 {
857 let cases = cases.into_iter();
861 let discrim_size = u32::from(DiscriminantSize::from_count(cases.len()).unwrap());
862 let mut max_size32 = 0;
863 let mut max_align32 = discrim_size;
864 let mut max_size64 = 0;
865 let mut max_align64 = discrim_size;
866 let mut max_case_count = Some(0);
867 for case in cases {
868 if let Some(case) = case {
869 max_size32 = max_size32.max(case.size32);
870 max_align32 = max_align32.max(case.align32);
871 max_size64 = max_size64.max(case.size64);
872 max_align64 = max_align64.max(case.align64);
873 max_case_count = max_flat(max_case_count, case.flat_count);
874 }
875 }
876 CanonicalAbiInfo {
877 size32: align_to(
878 align_to(discrim_size, max_align32) + max_size32,
879 max_align32,
880 ),
881 align32: max_align32,
882 size64: align_to(
883 align_to(discrim_size, max_align64) + max_size64,
884 max_align64,
885 ),
886 align64: max_align64,
887 flat_count: add_flat(max_case_count, Some(1)),
888 }
889 }
890
891 pub const fn variant_static(cases: &[Option<CanonicalAbiInfo>]) -> CanonicalAbiInfo {
893 let discrim_size = match DiscriminantSize::from_count(cases.len()) {
897 Some(size) => size.byte_size(),
898 None => unreachable!(),
899 };
900 let mut max_size32 = 0;
901 let mut max_align32 = discrim_size;
902 let mut max_size64 = 0;
903 let mut max_align64 = discrim_size;
904 let mut max_case_count = Some(0);
905 let mut i = 0;
906 while i < cases.len() {
907 let case = &cases[i];
908 if let Some(case) = case {
909 max_size32 = max(max_size32, case.size32);
910 max_align32 = max(max_align32, case.align32);
911 max_size64 = max(max_size64, case.size64);
912 max_align64 = max(max_align64, case.align64);
913 max_case_count = max_flat(max_case_count, case.flat_count);
914 }
915 i += 1;
916 }
917 CanonicalAbiInfo {
918 size32: align_to(
919 align_to(discrim_size, max_align32) + max_size32,
920 max_align32,
921 ),
922 align32: max_align32,
923 size64: align_to(
924 align_to(discrim_size, max_align64) + max_size64,
925 max_align64,
926 ),
927 align64: max_align64,
928 flat_count: add_flat(max_case_count, Some(1)),
929 }
930 }
931
932 pub const fn enum_(cases: usize) -> CanonicalAbiInfo {
934 let discrim_size = match DiscriminantSize::from_count(cases) {
938 Some(size) => size.byte_size(),
939 None => unreachable!(),
940 };
941 CanonicalAbiInfo {
942 size32: discrim_size,
943 align32: discrim_size,
944 size64: discrim_size,
945 align64: discrim_size,
946 flat_count: Some(1),
947 }
948 }
949
950 pub fn flat_count(&self, max: usize) -> Option<usize> {
953 let flat = usize::from(self.flat_count?);
954 if flat > max { None } else { Some(flat) }
955 }
956}
957
958#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
960pub struct VariantInfo {
961 #[serde(with = "serde_discrim_size")]
963 pub size: DiscriminantSize,
964 pub payload_offset32: u32,
967 pub payload_offset64: u32,
970}
971
972impl VariantInfo {
973 pub fn new<'a, I>(cases: I) -> (VariantInfo, CanonicalAbiInfo)
976 where
977 I: IntoIterator<Item = Option<&'a CanonicalAbiInfo>>,
978 I::IntoIter: ExactSizeIterator,
979 {
980 let cases = cases.into_iter();
981 let size = DiscriminantSize::from_count(cases.len()).unwrap();
982 let abi = CanonicalAbiInfo::variant(cases);
983 (
984 VariantInfo {
985 size,
986 payload_offset32: align_to(u32::from(size), abi.align32),
987 payload_offset64: align_to(u32::from(size), abi.align64),
988 },
989 abi,
990 )
991 }
992 pub const fn new_static(cases: &[Option<CanonicalAbiInfo>]) -> VariantInfo {
994 let size = match DiscriminantSize::from_count(cases.len()) {
995 Some(size) => size,
996 None => unreachable!(),
997 };
998 let abi = CanonicalAbiInfo::variant_static(cases);
999 VariantInfo {
1000 size,
1001 payload_offset32: align_to(size.byte_size(), abi.align32),
1002 payload_offset64: align_to(size.byte_size(), abi.align64),
1003 }
1004 }
1005}
1006
1007mod serde_discrim_size {
1008 use super::DiscriminantSize;
1009 use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
1010
1011 pub fn serialize<S>(disc: &DiscriminantSize, ser: S) -> Result<S::Ok, S::Error>
1012 where
1013 S: Serializer,
1014 {
1015 u32::from(*disc).serialize(ser)
1016 }
1017
1018 pub fn deserialize<'de, D>(deser: D) -> Result<DiscriminantSize, D::Error>
1019 where
1020 D: Deserializer<'de>,
1021 {
1022 match u32::deserialize(deser)? {
1023 1 => Ok(DiscriminantSize::Size1),
1024 2 => Ok(DiscriminantSize::Size2),
1025 4 => Ok(DiscriminantSize::Size4),
1026 _ => Err(D::Error::custom("invalid discriminant size")),
1027 }
1028 }
1029}
1030
1031#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1035pub struct TypeRecord {
1036 pub fields: Box<[RecordField]>,
1038 pub abi: CanonicalAbiInfo,
1040}
1041
1042#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1044pub struct RecordField {
1045 pub name: String,
1047 pub ty: InterfaceType,
1049}
1050
1051#[derive(Serialize, Deserialize, Clone, Debug)]
1057pub struct TypeVariant {
1058 pub cases: IndexMap<String, Option<InterfaceType>>,
1060 pub abi: CanonicalAbiInfo,
1062 pub info: VariantInfo,
1064}
1065
1066impl PartialEq for TypeVariant {
1069 fn eq(&self, other: &TypeVariant) -> bool {
1070 let TypeVariant { cases, abi, info } = self;
1071 cases.len() == other.cases.len()
1072 && cases.iter().eq(other.cases.iter())
1073 && *abi == other.abi
1074 && *info == other.info
1075 }
1076}
1077
1078impl Eq for TypeVariant {}
1079
1080impl Hash for TypeVariant {
1081 fn hash<H: Hasher>(&self, h: &mut H) {
1082 let TypeVariant { cases, abi, info } = self;
1083 cases.len().hash(h);
1084 for pair in cases {
1085 pair.hash(h);
1086 }
1087 abi.hash(h);
1088 info.hash(h);
1089 }
1090}
1091
1092#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1097pub struct TypeTuple {
1098 pub types: Box<[InterfaceType]>,
1100 pub abi: CanonicalAbiInfo,
1102}
1103
1104#[derive(Serialize, Deserialize, Clone, Debug)]
1109pub struct TypeFlags {
1110 pub names: IndexSet<String>,
1112 pub abi: CanonicalAbiInfo,
1114}
1115
1116impl PartialEq for TypeFlags {
1119 fn eq(&self, other: &TypeFlags) -> bool {
1120 let TypeFlags { names, abi } = self;
1121 names.len() == other.names.len() && names.iter().eq(other.names.iter()) && *abi == other.abi
1122 }
1123}
1124
1125impl Eq for TypeFlags {}
1126
1127impl Hash for TypeFlags {
1128 fn hash<H: Hasher>(&self, h: &mut H) {
1129 let TypeFlags { names, abi } = self;
1130 names.len().hash(h);
1131 for name in names {
1132 name.hash(h);
1133 }
1134 abi.hash(h);
1135 }
1136}
1137
1138#[derive(Serialize, Deserialize, Clone, Debug)]
1144pub struct TypeEnum {
1145 pub names: IndexSet<String>,
1147 pub abi: CanonicalAbiInfo,
1149 pub info: VariantInfo,
1151}
1152
1153impl PartialEq for TypeEnum {
1156 fn eq(&self, other: &TypeEnum) -> bool {
1157 let TypeEnum { names, abi, info } = self;
1158 names.len() == other.names.len()
1159 && names.iter().eq(other.names.iter())
1160 && *abi == other.abi
1161 && *info == other.info
1162 }
1163}
1164
1165impl Eq for TypeEnum {}
1166
1167impl Hash for TypeEnum {
1168 fn hash<H: Hasher>(&self, h: &mut H) {
1169 let TypeEnum { names, abi, info } = self;
1170 names.len().hash(h);
1171 for name in names {
1172 name.hash(h);
1173 }
1174 abi.hash(h);
1175 info.hash(h);
1176 }
1177}
1178
1179#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1181pub struct TypeOption {
1182 pub ty: InterfaceType,
1184 pub abi: CanonicalAbiInfo,
1186 pub info: VariantInfo,
1188}
1189
1190#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1192pub struct TypeResult {
1193 pub ok: Option<InterfaceType>,
1195 pub err: Option<InterfaceType>,
1197 pub abi: CanonicalAbiInfo,
1199 pub info: VariantInfo,
1201}
1202
1203#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1205pub struct TypeFuture {
1206 pub payload: Option<InterfaceType>,
1208}
1209
1210#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1212pub struct TypeFutureTable {
1213 pub ty: TypeFutureIndex,
1215 pub instance: RuntimeComponentInstanceIndex,
1217}
1218
1219#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1221pub struct TypeStream {
1222 pub payload: Option<InterfaceType>,
1224}
1225
1226#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1228pub struct TypeStreamTable {
1229 pub ty: TypeStreamIndex,
1231 pub instance: RuntimeComponentInstanceIndex,
1233}
1234
1235#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1237pub struct TypeErrorContextTable {
1238 pub instance: RuntimeComponentInstanceIndex,
1240}
1241
1242#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1244pub enum TypeResourceTable {
1245 Concrete {
1252 ty: ResourceIndex,
1257
1258 instance: RuntimeComponentInstanceIndex,
1260 },
1261
1262 Abstract(AbstractResourceIndex),
1266}
1267
1268impl TypeResourceTable {
1269 pub fn unwrap_concrete_ty(&self) -> ResourceIndex {
1276 match self {
1277 TypeResourceTable::Concrete { ty, .. } => *ty,
1278 TypeResourceTable::Abstract(_) => panic!("not a concrete resource table"),
1279 }
1280 }
1281
1282 pub fn unwrap_concrete_instance(&self) -> RuntimeComponentInstanceIndex {
1289 match self {
1290 TypeResourceTable::Concrete { instance, .. } => *instance,
1291 TypeResourceTable::Abstract(_) => panic!("not a concrete resource table"),
1292 }
1293 }
1294}
1295
1296#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1298pub struct TypeList {
1299 pub element: InterfaceType,
1301}
1302
1303#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1305pub struct TypeMap {
1306 pub key: InterfaceType,
1308 pub value: InterfaceType,
1310 pub entry_abi: CanonicalAbiInfo,
1312 pub value_offset32: u32,
1315 pub value_offset64: u32,
1318}
1319
1320#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1322pub struct TypeFixedLengthList {
1323 pub element: InterfaceType,
1325 pub size: u32,
1327 pub abi: CanonicalAbiInfo,
1329}
1330
1331pub const MAX_FLAT_TYPES: usize = if MAX_FLAT_PARAMS > MAX_FLAT_RESULTS {
1333 MAX_FLAT_PARAMS
1334} else {
1335 MAX_FLAT_RESULTS
1336};
1337
1338const fn add_flat(a: Option<u8>, b: Option<u8>) -> Option<u8> {
1339 const MAX: u8 = MAX_FLAT_TYPES as u8;
1340 let sum = match (a, b) {
1341 (Some(a), Some(b)) => match a.checked_add(b) {
1342 Some(c) => c,
1343 None => return None,
1344 },
1345 _ => return None,
1346 };
1347 if sum > MAX { None } else { Some(sum) }
1348}
1349
1350const fn max_flat(a: Option<u8>, b: Option<u8>) -> Option<u8> {
1351 match (a, b) {
1352 (Some(a), Some(b)) => {
1353 if a > b {
1354 Some(a)
1355 } else {
1356 Some(b)
1357 }
1358 }
1359 _ => None,
1360 }
1361}
1362
1363pub struct FlatTypes<'a> {
1365 pub memory32: &'a [FlatType],
1367 pub memory64: &'a [FlatType],
1369}
1370
1371impl FlatTypes<'_> {
1372 pub fn len(&self) -> usize {
1376 assert_eq!(self.memory32.len(), self.memory64.len());
1377 self.memory32.len()
1378 }
1379}
1380
1381#[derive(Serialize, Deserialize, Hash, Debug, PartialEq, Eq, Copy, Clone)]
1385#[expect(missing_docs, reason = "self-describing variants")]
1386pub enum FlatType {
1387 I32,
1388 I64,
1389 F32,
1390 F64,
1391}
1392
1393#[cfg(test)]
1394mod tests {
1395 use super::*;
1396
1397 fn variant(cases: &[(&str, InterfaceType)]) -> TypeVariant {
1398 TypeVariant {
1399 cases: cases
1400 .iter()
1401 .map(|(name, ty)| (name.to_string(), Some(*ty)))
1402 .collect(),
1403 abi: CanonicalAbiInfo::default(),
1404 info: VariantInfo {
1405 size: DiscriminantSize::Size1,
1406 payload_offset32: 4,
1407 payload_offset64: 8,
1408 },
1409 }
1410 }
1411
1412 fn flags(names: &[&str]) -> TypeFlags {
1413 TypeFlags {
1414 names: names.iter().map(|n| n.to_string()).collect(),
1415 abi: CanonicalAbiInfo::default(),
1416 }
1417 }
1418
1419 fn enum_(names: &[&str]) -> TypeEnum {
1420 TypeEnum {
1421 names: names.iter().map(|n| n.to_string()).collect(),
1422 abi: CanonicalAbiInfo::default(),
1423 info: VariantInfo {
1424 size: DiscriminantSize::Size1,
1425 payload_offset32: 4,
1426 payload_offset64: 8,
1427 },
1428 }
1429 }
1430
1431 #[test]
1432 fn variant_case_order_is_significant() {
1433 let a = variant(&[("n", InterfaceType::U32), ("s", InterfaceType::String)]);
1434 let b = variant(&[("s", InterfaceType::String), ("n", InterfaceType::U32)]);
1435 assert_ne!(a, b);
1436 assert_eq!(a, a.clone());
1437 }
1438
1439 #[test]
1440 fn flags_name_order_is_significant() {
1441 let a = flags(&["a", "b", "c"]);
1442 let b = flags(&["c", "b", "a"]);
1443
1444 assert_ne!(a, b);
1445 assert_eq!(a, a.clone());
1446 }
1447
1448 #[test]
1449 fn enum_name_order_is_significant() {
1450 let a = enum_(&["red", "green", "blue"]);
1451 let b = enum_(&["blue", "green", "red"]);
1452
1453 assert_ne!(a, b);
1454 assert_eq!(a, a.clone());
1455 }
1456}