1use crate::encoding::{Instance, Item, LibraryInfo, MainOrAdapter, ModuleImportMap};
2use crate::{ComponentEncoder, StringEncoding};
3use anyhow::{Context, Result, anyhow, bail};
4use indexmap::{IndexMap, IndexSet, map::Entry};
5use std::fmt;
6use std::hash::Hash;
7use std::mem;
8use wasm_encoder::ExportKind;
9use wasmparser::names::{ComponentName, ComponentNameKind};
10use wasmparser::{
11 Encoding, ExternalKind, FuncType, Parser, Payload, TypeRef, ValType, ValidPayload, Validator,
12 WasmFeatures, types::TypesRef,
13};
14use wit_parser::{
15 Function, InterfaceId, PackageName, Resolve, Type, TypeDefKind, TypeId, World, WorldId,
16 WorldItem, WorldKey,
17 abi::{AbiVariant, WasmSignature, WasmType},
18};
19
20fn wasm_sig_to_func_type(signature: WasmSignature) -> FuncType {
21 fn from_wasm_type(ty: &WasmType) -> ValType {
22 match ty {
23 WasmType::I32 => ValType::I32,
24 WasmType::I64 => ValType::I64,
25 WasmType::F32 => ValType::F32,
26 WasmType::F64 => ValType::F64,
27 WasmType::Pointer => ValType::I32,
28 WasmType::PointerOrI64 => ValType::I64,
29 WasmType::Length => ValType::I32,
30 }
31 }
32
33 FuncType::new(
34 signature.params.iter().map(from_wasm_type),
35 signature.results.iter().map(from_wasm_type),
36 )
37}
38
39#[derive(Default)]
47pub struct ValidatedModule {
48 pub imports: ImportMap,
50
51 pub exports: ExportMap,
53}
54
55impl ValidatedModule {
56 fn new(
57 encoder: &ComponentEncoder,
58 bytes: &[u8],
59 exports: &IndexSet<WorldKey>,
60 import_map: Option<&ModuleImportMap>,
61 info: Option<&LibraryInfo>,
62 ) -> Result<ValidatedModule> {
63 let mut validator = Validator::new_with_features(WasmFeatures::all());
64 let mut ret = ValidatedModule::default();
65
66 for payload in Parser::new(0).parse_all(bytes) {
67 let payload = payload?;
68 if let ValidPayload::End(_) = validator.payload(&payload)? {
69 break;
70 }
71
72 let types = validator.types(0).unwrap();
73
74 match payload {
75 Payload::Version { encoding, .. } if encoding != Encoding::Module => {
76 bail!("data is not a WebAssembly module");
77 }
78 Payload::ImportSection(s) => {
79 for import in s.into_imports() {
80 let import = import?;
81 ret.imports.add(import, encoder, import_map, info, types)?;
82 }
83 }
84 Payload::ExportSection(s) => {
85 for export in s {
86 let export = export?;
87 ret.exports.add(export, encoder, &exports, types)?;
88 }
89 }
90 _ => continue,
91 }
92 }
93
94 ret.exports.validate(encoder, exports)?;
95
96 Ok(ret)
97 }
98}
99
100#[derive(Default)]
106pub struct ImportMap {
107 names: IndexMap<String, ImportInstance>,
111}
112
113pub enum ImportInstance {
114 Whole(MainOrAdapter),
117
118 Names(IndexMap<String, Import>),
120}
121
122#[derive(Debug, Eq, PartialEq, Clone, Hash)]
139pub struct PayloadInfo {
140 pub name: String,
143 pub ty: PayloadType,
148 pub key: WorldKey,
150 pub interface: Option<InterfaceId>,
152 pub imported: bool,
157}
158
159#[derive(Debug, Eq, PartialEq, Clone, Hash)]
161pub enum PayloadType {
162 Type {
165 id: TypeId,
166 function: String,
169 },
170 UnitFuture,
172 UnitStream,
174}
175
176impl PayloadInfo {
177 pub fn payload(&self, resolve: &Resolve) -> Option<Type> {
179 let id = match self.ty {
180 PayloadType::Type { id, .. } => id,
181 PayloadType::UnitFuture | PayloadType::UnitStream => return None,
182 };
183 match resolve.types[id].kind {
184 TypeDefKind::Future(payload) | TypeDefKind::Stream(payload) => payload,
185 _ => unreachable!(),
186 }
187 }
188}
189
190#[derive(Debug, Clone)]
197pub enum Import {
198 WorldFunc(WorldKey, String, AbiVariant),
201
202 InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
208
209 ImportedResourceDrop(WorldKey, Option<InterfaceId>, TypeId),
215
216 ExportedResourceDrop(WorldKey, TypeId),
222
223 ExportedResourceNew(WorldKey, TypeId),
229
230 ExportedResourceRep(WorldKey, TypeId),
236
237 AdapterExport {
243 adapter: String,
244 func: String,
245 ty: FuncType,
246 },
247
248 MainModuleMemory,
252
253 MainModuleExport { name: String, kind: ExportKind },
255
256 Item(Item),
262
263 ExportedTaskReturn(WorldKey, Option<InterfaceId>, String, Option<Type>),
272
273 ExportedTaskCancel,
277
278 ContextGet(u32),
280 ContextSet(u32),
282
283 BackpressureInc,
285
286 BackpressureDec,
288
289 WaitableSetNew,
291
292 WaitableSetWait { cancellable: bool },
298
299 WaitableSetPoll { cancellable: bool },
305
306 WaitableSetDrop,
308
309 WaitableJoin,
311
312 ThreadYield { cancellable: bool },
317
318 SubtaskDrop,
322
323 SubtaskCancel { async_: bool },
327
328 StreamNew(PayloadInfo),
332
333 StreamRead { async_: bool, info: PayloadInfo },
338
339 StreamWrite { async_: bool, info: PayloadInfo },
344
345 StreamCancelRead { info: PayloadInfo, async_: bool },
350
351 StreamCancelWrite { info: PayloadInfo, async_: bool },
356
357 StreamDropReadable(PayloadInfo),
361
362 StreamDropWritable(PayloadInfo),
366
367 FutureNew(PayloadInfo),
371
372 FutureRead { async_: bool, info: PayloadInfo },
377
378 FutureWrite { async_: bool, info: PayloadInfo },
382
383 FutureCancelRead { info: PayloadInfo, async_: bool },
388
389 FutureCancelWrite { info: PayloadInfo, async_: bool },
394
395 FutureDropReadable(PayloadInfo),
399
400 FutureDropWritable(PayloadInfo),
404
405 ErrorContextNew { encoding: StringEncoding },
410
411 ErrorContextDebugMessage { encoding: StringEncoding },
417
418 ErrorContextDrop,
423
424 ThreadIndex,
428
429 ThreadNewIndirect,
433
434 ThreadSwitchTo { cancellable: bool },
438
439 ThreadSuspend { cancellable: bool },
444
445 ThreadResumeLater,
449
450 ThreadYieldTo { cancellable: bool },
454}
455
456impl ImportMap {
457 pub fn required_from_adapter(&self, name: &str) -> IndexMap<String, FuncType> {
459 let names = match self.names.get(name) {
460 Some(ImportInstance::Names(names)) => names,
461 _ => return IndexMap::new(),
462 };
463 names
464 .iter()
465 .map(|(_, import)| match import {
466 Import::AdapterExport { ty, func, adapter } => {
467 assert_eq!(adapter, name);
468 (func.clone(), ty.clone())
469 }
470 _ => unreachable!(),
471 })
472 .collect()
473 }
474
475 pub fn imports(&self) -> impl Iterator<Item = (&str, &str, &Import)> + '_ {
479 self.names
480 .iter()
481 .filter_map(|(module, m)| match m {
482 ImportInstance::Names(names) => Some((module, names)),
483 ImportInstance::Whole(_) => None,
484 })
485 .flat_map(|(module, m)| {
486 m.iter()
487 .map(move |(field, import)| (module.as_str(), field.as_str(), import))
488 })
489 }
490
491 pub fn modules(&self) -> &IndexMap<String, ImportInstance> {
493 &self.names
494 }
495
496 fn add(
499 &mut self,
500 import: wasmparser::Import<'_>,
501 encoder: &ComponentEncoder,
502 import_map: Option<&ModuleImportMap>,
503 library_info: Option<&LibraryInfo>,
504 types: TypesRef<'_>,
505 ) -> Result<()> {
506 if self.classify_import_with_library(import, library_info)? {
507 return Ok(());
508 }
509 let mut import_to_classify = import;
510 if let Some(map) = import_map {
511 if let Some(original_name) = map.original_name(&import) {
512 import_to_classify.name = original_name;
513 }
514 }
515 let item = self
516 .classify(import_to_classify, encoder, types)
517 .with_context(|| {
518 format!(
519 "failed to resolve import `{}::{}`",
520 import.module, import.name,
521 )
522 })?;
523 self.insert_import(import, item)
524 }
525
526 fn classify(
532 &self,
533 import: wasmparser::Import<'_>,
534 encoder: &ComponentEncoder,
535 types: TypesRef<'_>,
536 ) -> Result<Import> {
537 if import.module == "env" && import.name == "memory" {
540 return Ok(Import::MainModuleMemory);
541 }
542
543 if import.module == "__main_module__" {
545 return Ok(Import::MainModuleExport {
546 name: import.name.to_string(),
547 kind: match import.ty {
548 TypeRef::Func(_) => ExportKind::Func,
549 TypeRef::Table(_) => ExportKind::Table,
550 TypeRef::Memory(_) => ExportKind::Memory,
551 TypeRef::Global(_) => ExportKind::Global,
552 TypeRef::Tag(_) => ExportKind::Tag,
553 TypeRef::FuncExact(_) => bail!("Unexpected func_exact export"),
554 },
555 });
556 }
557
558 let ty_index = match import.ty {
559 TypeRef::Func(ty) => ty,
560 _ => bail!("module is only allowed to import functions"),
561 };
562 let ty = types[types.core_type_at_in_module(ty_index)].unwrap_func();
563
564 if encoder.adapters.contains_key(import.module) {
567 return Ok(Import::AdapterExport {
568 adapter: import.module.to_string(),
569 func: import.name.to_string(),
570 ty: ty.clone(),
571 });
572 }
573
574 let (module, names) = match import.module.strip_prefix("cm32p2") {
575 Some(suffix) => (suffix, STANDARD),
576 None if encoder.reject_legacy_names => (import.module, STANDARD),
577 None => (import.module, LEGACY),
578 };
579 self.classify_component_model_import(module, import.name, encoder, ty, names)
580 }
581
582 fn classify_component_model_import(
585 &self,
586 module: &str,
587 name: &str,
588 encoder: &ComponentEncoder,
589 ty: &FuncType,
590 names: &dyn NameMangling,
591 ) -> Result<Import> {
592 let resolve = &encoder.metadata.resolve;
593 let world_id = encoder.metadata.world;
594 let world = &resolve.worlds[world_id];
595
596 if module == names.import_root() {
597 if names.error_context_drop(name) {
598 let expected = FuncType::new([ValType::I32], []);
599 validate_func_sig(name, &expected, ty)?;
600 return Ok(Import::ErrorContextDrop);
601 }
602
603 if names.backpressure_inc(name) {
604 let expected = FuncType::new([], []);
605 validate_func_sig(name, &expected, ty)?;
606 return Ok(Import::BackpressureInc);
607 }
608
609 if names.backpressure_dec(name) {
610 let expected = FuncType::new([], []);
611 validate_func_sig(name, &expected, ty)?;
612 return Ok(Import::BackpressureDec);
613 }
614
615 if names.waitable_set_new(name) {
616 let expected = FuncType::new([], [ValType::I32]);
617 validate_func_sig(name, &expected, ty)?;
618 return Ok(Import::WaitableSetNew);
619 }
620
621 if let Some(info) = names.waitable_set_wait(name) {
622 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
623 validate_func_sig(name, &expected, ty)?;
624 return Ok(Import::WaitableSetWait {
625 cancellable: info.cancellable,
626 });
627 }
628
629 if let Some(info) = names.waitable_set_poll(name) {
630 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
631 validate_func_sig(name, &expected, ty)?;
632 return Ok(Import::WaitableSetPoll {
633 cancellable: info.cancellable,
634 });
635 }
636
637 if names.waitable_set_drop(name) {
638 let expected = FuncType::new([ValType::I32], []);
639 validate_func_sig(name, &expected, ty)?;
640 return Ok(Import::WaitableSetDrop);
641 }
642
643 if names.waitable_join(name) {
644 let expected = FuncType::new([ValType::I32; 2], []);
645 validate_func_sig(name, &expected, ty)?;
646 return Ok(Import::WaitableJoin);
647 }
648
649 if let Some(info) = names.thread_yield(name) {
650 let expected = FuncType::new([], [ValType::I32]);
651 validate_func_sig(name, &expected, ty)?;
652 return Ok(Import::ThreadYield {
653 cancellable: info.cancellable,
654 });
655 }
656
657 if names.subtask_drop(name) {
658 let expected = FuncType::new([ValType::I32], []);
659 validate_func_sig(name, &expected, ty)?;
660 return Ok(Import::SubtaskDrop);
661 }
662
663 if let Some(info) = names.subtask_cancel(name) {
664 let expected = FuncType::new([ValType::I32], [ValType::I32]);
665 validate_func_sig(name, &expected, ty)?;
666 return Ok(Import::SubtaskCancel {
667 async_: info.async_lowered,
668 });
669 }
670
671 if let Some(encoding) = names.error_context_new(name) {
672 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
673 validate_func_sig(name, &expected, ty)?;
674 return Ok(Import::ErrorContextNew { encoding });
675 }
676
677 if let Some(encoding) = names.error_context_debug_message(name) {
678 let expected = FuncType::new([ValType::I32; 2], []);
679 validate_func_sig(name, &expected, ty)?;
680 return Ok(Import::ErrorContextDebugMessage { encoding });
681 }
682
683 if let Some(i) = names.context_get(name) {
684 let expected = FuncType::new([], [ValType::I32]);
685 validate_func_sig(name, &expected, ty)?;
686 return Ok(Import::ContextGet(i));
687 }
688 if let Some(i) = names.context_set(name) {
689 let expected = FuncType::new([ValType::I32], []);
690 validate_func_sig(name, &expected, ty)?;
691 return Ok(Import::ContextSet(i));
692 }
693 if names.thread_index(name) {
694 let expected = FuncType::new([], [ValType::I32]);
695 validate_func_sig(name, &expected, ty)?;
696 return Ok(Import::ThreadIndex);
697 }
698 if names.thread_new_indirect(name) {
699 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
700 validate_func_sig(name, &expected, ty)?;
701 return Ok(Import::ThreadNewIndirect);
702 }
703 if let Some(info) = names.thread_switch_to(name) {
704 let expected = FuncType::new([ValType::I32], [ValType::I32]);
705 validate_func_sig(name, &expected, ty)?;
706 return Ok(Import::ThreadSwitchTo {
707 cancellable: info.cancellable,
708 });
709 }
710 if let Some(info) = names.thread_suspend(name) {
711 let expected = FuncType::new([], [ValType::I32]);
712 validate_func_sig(name, &expected, ty)?;
713 return Ok(Import::ThreadSuspend {
714 cancellable: info.cancellable,
715 });
716 }
717 if names.thread_resume_later(name) {
718 let expected = FuncType::new([ValType::I32], []);
719 validate_func_sig(name, &expected, ty)?;
720 return Ok(Import::ThreadResumeLater);
721 }
722 if let Some(info) = names.thread_yield_to(name) {
723 let expected = FuncType::new([ValType::I32], [ValType::I32]);
724 validate_func_sig(name, &expected, ty)?;
725 return Ok(Import::ThreadYieldTo {
726 cancellable: info.cancellable,
727 });
728 }
729
730 let (key_name, abi) = names.world_key_name_and_abi(name);
731 let key = WorldKey::Name(key_name.to_string());
732 if let Some(WorldItem::Function(func)) = world.imports.get(&key) {
733 validate_func(resolve, ty, func, abi)?;
734 return Ok(Import::WorldFunc(key, func.name.clone(), abi));
735 }
736
737 if let Some(import) =
738 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, true, names)?
739 {
740 return Ok(import);
741 }
742
743 match world.imports.get(&key) {
744 Some(_) => bail!("expected world top-level import `{name}` to be a function"),
745 None => bail!("no top-level imported function `{name}` specified"),
746 }
747 }
748
749 if matches!(
751 module.strip_prefix(names.import_exported_intrinsic_prefix()),
752 Some(module) if module == names.import_root()
753 ) {
754 if let Some(import) =
755 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, false, names)?
756 {
757 return Ok(import);
758 }
759 }
760
761 let interface = match module.strip_prefix(names.import_non_root_prefix()) {
762 Some(name) => name,
763 None => bail!("unknown or invalid component model import syntax"),
764 };
765
766 if let Some(interface) = interface.strip_prefix(names.import_exported_intrinsic_prefix()) {
767 let (key, id) = names.module_to_interface(interface, resolve, &world.exports)?;
768
769 if let Some(import) =
770 self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, false, names)?
771 {
772 return Ok(import);
773 }
774 bail!("unknown function `{name}`")
775 }
776
777 let (key, id) = names.module_to_interface(interface, resolve, &world.imports)?;
778 let interface = &resolve.interfaces[id];
779 let (function_name, abi) = names.interface_function_name_and_abi(name);
780 if let Some(f) = interface.functions.get(function_name) {
781 validate_func(resolve, ty, f, abi).with_context(|| {
782 let name = resolve.name_world_key(&key);
783 format!("failed to validate import interface `{name}`")
784 })?;
785 return Ok(Import::InterfaceFunc(key, id, f.name.clone(), abi));
786 }
787
788 if let Some(import) =
789 self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, true, names)?
790 {
791 return Ok(import);
792 }
793 bail!(
794 "import interface `{module}` is missing function \
795 `{name}` that is required by the module",
796 )
797 }
798
799 fn maybe_classify_wit_intrinsic(
827 &self,
828 name: &str,
829 key_and_id: Option<(WorldKey, InterfaceId)>,
830 encoder: &ComponentEncoder,
831 ty: &FuncType,
832 import: bool,
833 names: &dyn NameMangling,
834 ) -> Result<Option<Import>> {
835 let resolve = &encoder.metadata.resolve;
836 let world_id = encoder.metadata.world;
837 let world = &resolve.worlds[world_id];
838
839 let (key, id) = match key_and_id {
844 Some((key, id)) => (Some(key), Some(id)),
845 None => (None, None),
846 };
847
848 let resource_test = |name: &str| match id {
850 Some(id) => resource_test_for_interface(resolve, id)(name),
851 None => resource_test_for_world(resolve, world_id)(name),
852 };
853
854 if let Some(resource) = names.resource_drop_name(name) {
856 if let Some(resource_id) = resource_test(resource) {
857 let key = key.unwrap_or_else(|| WorldKey::Name(resource.to_string()));
858 let expected = FuncType::new([ValType::I32], []);
859 validate_func_sig(name, &expected, ty)?;
860 return Ok(Some(if import {
861 Import::ImportedResourceDrop(key, id, resource_id)
862 } else {
863 Import::ExportedResourceDrop(key, resource_id)
864 }));
865 }
866 }
867
868 if !import {
871 if let Some(name) = names.resource_new_name(name) {
872 if let Some(id) = resource_test(name) {
873 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
874 let expected = FuncType::new([ValType::I32], [ValType::I32]);
875 validate_func_sig(name, &expected, ty)?;
876 return Ok(Some(Import::ExportedResourceNew(key, id)));
877 }
878 }
879 if let Some(name) = names.resource_rep_name(name) {
880 if let Some(id) = resource_test(name) {
881 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
882 let expected = FuncType::new([ValType::I32], [ValType::I32]);
883 validate_func_sig(name, &expected, ty)?;
884 return Ok(Some(Import::ExportedResourceRep(key, id)));
885 }
886 }
887 if let Some(name) = names.task_return_name(name) {
888 let func = get_function(resolve, world, name, id, import)?;
889 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
890 return Ok(Some(Import::ExportedTaskReturn(
893 key,
894 id,
895 func.name.clone(),
896 func.result,
897 )));
898 }
899 if names.task_cancel(name) {
900 let expected = FuncType::new([], []);
901 validate_func_sig(name, &expected, ty)?;
902 return Ok(Some(Import::ExportedTaskCancel));
903 }
904 }
905
906 let lookup_context = PayloadLookupContext {
907 resolve,
908 world,
909 key,
910 id,
911 import,
912 };
913
914 let import = if let Some(info) = names.future_new(&lookup_context, name) {
918 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
919 Import::FutureNew(info)
920 } else if let Some(info) = names.future_write(&lookup_context, name) {
921 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
922 Import::FutureWrite {
923 async_: info.async_lowered,
924 info: info.inner,
925 }
926 } else if let Some(info) = names.future_read(&lookup_context, name) {
927 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
928 Import::FutureRead {
929 async_: info.async_lowered,
930 info: info.inner,
931 }
932 } else if let Some(info) = names.future_cancel_write(&lookup_context, name) {
933 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
934 Import::FutureCancelWrite {
935 async_: info.async_lowered,
936 info: info.inner,
937 }
938 } else if let Some(info) = names.future_cancel_read(&lookup_context, name) {
939 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
940 Import::FutureCancelRead {
941 async_: info.async_lowered,
942 info: info.inner,
943 }
944 } else if let Some(info) = names.future_drop_writable(&lookup_context, name) {
945 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
946 Import::FutureDropWritable(info)
947 } else if let Some(info) = names.future_drop_readable(&lookup_context, name) {
948 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
949 Import::FutureDropReadable(info)
950 } else if let Some(info) = names.stream_new(&lookup_context, name) {
951 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
952 Import::StreamNew(info)
953 } else if let Some(info) = names.stream_write(&lookup_context, name) {
954 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
955 Import::StreamWrite {
956 async_: info.async_lowered,
957 info: info.inner,
958 }
959 } else if let Some(info) = names.stream_read(&lookup_context, name) {
960 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
961 Import::StreamRead {
962 async_: info.async_lowered,
963 info: info.inner,
964 }
965 } else if let Some(info) = names.stream_cancel_write(&lookup_context, name) {
966 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
967 Import::StreamCancelWrite {
968 async_: info.async_lowered,
969 info: info.inner,
970 }
971 } else if let Some(info) = names.stream_cancel_read(&lookup_context, name) {
972 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
973 Import::StreamCancelRead {
974 async_: info.async_lowered,
975 info: info.inner,
976 }
977 } else if let Some(info) = names.stream_drop_writable(&lookup_context, name) {
978 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
979 Import::StreamDropWritable(info)
980 } else if let Some(info) = names.stream_drop_readable(&lookup_context, name) {
981 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
982 Import::StreamDropReadable(info)
983 } else {
984 return Ok(None);
985 };
986 Ok(Some(import))
987 }
988
989 fn classify_import_with_library(
990 &mut self,
991 import: wasmparser::Import<'_>,
992 library_info: Option<&LibraryInfo>,
993 ) -> Result<bool> {
994 let info = match library_info {
995 Some(info) => info,
996 None => return Ok(false),
997 };
998 let Some((_, instance)) = info
999 .arguments
1000 .iter()
1001 .find(|(name, _items)| *name == import.module)
1002 else {
1003 return Ok(false);
1004 };
1005 match instance {
1006 Instance::MainOrAdapter(module) => match self.names.get(import.module) {
1007 Some(ImportInstance::Whole(which)) => {
1008 if which != module {
1009 bail!("different whole modules imported under the same name");
1010 }
1011 }
1012 Some(ImportInstance::Names(_)) => {
1013 bail!("cannot mix individual imports and whole module imports")
1014 }
1015 None => {
1016 let instance = ImportInstance::Whole(module.clone());
1017 self.names.insert(import.module.to_string(), instance);
1018 }
1019 },
1020 Instance::Items(items) => {
1021 let Some(item) = items.iter().find(|i| i.alias == import.name) else {
1022 return Ok(false);
1023 };
1024 self.insert_import(import, Import::Item(item.clone()))?;
1025 }
1026 }
1027 Ok(true)
1028 }
1029
1030 fn insert_import(&mut self, import: wasmparser::Import<'_>, item: Import) -> Result<()> {
1034 let entry = self
1035 .names
1036 .entry(import.module.to_string())
1037 .or_insert(ImportInstance::Names(IndexMap::default()));
1038 let names = match entry {
1039 ImportInstance::Names(names) => names,
1040 _ => bail!("cannot mix individual imports with module imports"),
1041 };
1042 let entry = match names.entry(import.name.to_string()) {
1043 Entry::Occupied(_) => {
1044 bail!(
1045 "module has duplicate import for `{}::{}`",
1046 import.module,
1047 import.name
1048 );
1049 }
1050 Entry::Vacant(v) => v,
1051 };
1052 log::trace!(
1053 "classifying import `{}::{} as {item:?}",
1054 import.module,
1055 import.name
1056 );
1057 entry.insert(item);
1058 Ok(())
1059 }
1060}
1061
1062#[derive(Default)]
1065pub struct ExportMap {
1066 names: IndexMap<String, Export>,
1067 raw_exports: IndexMap<String, FuncType>,
1068}
1069
1070#[derive(Debug)]
1073pub enum Export {
1074 WorldFunc(WorldKey, String, AbiVariant),
1077
1078 WorldFuncPostReturn(WorldKey),
1080
1081 InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
1083
1084 InterfaceFuncPostReturn(WorldKey, String),
1086
1087 ResourceDtor(TypeId),
1089
1090 Memory,
1092
1093 GeneralPurposeRealloc,
1095
1096 GeneralPurposeExportRealloc,
1098
1099 GeneralPurposeImportRealloc,
1101
1102 Initialize,
1104
1105 ReallocForAdapter,
1107
1108 WorldFuncCallback(WorldKey),
1109
1110 InterfaceFuncCallback(WorldKey, String),
1111
1112 IndirectFunctionTable,
1114}
1115
1116impl ExportMap {
1117 fn add(
1118 &mut self,
1119 export: wasmparser::Export<'_>,
1120 encoder: &ComponentEncoder,
1121 exports: &IndexSet<WorldKey>,
1122 types: TypesRef<'_>,
1123 ) -> Result<()> {
1124 if let Some(item) = self.classify(export, encoder, exports, types)? {
1125 log::debug!("classifying export `{}` as {item:?}", export.name);
1126 let prev = self.names.insert(export.name.to_string(), item);
1127 assert!(prev.is_none());
1128 }
1129 Ok(())
1130 }
1131
1132 fn classify(
1133 &mut self,
1134 export: wasmparser::Export<'_>,
1135 encoder: &ComponentEncoder,
1136 exports: &IndexSet<WorldKey>,
1137 types: TypesRef<'_>,
1138 ) -> Result<Option<Export>> {
1139 match export.kind {
1140 ExternalKind::Func => {
1141 let ty = types[types.core_function_at(export.index)].unwrap_func();
1142 self.raw_exports.insert(export.name.to_string(), ty.clone());
1143 }
1144 _ => {}
1145 }
1146
1147 if export.name == "canonical_abi_realloc" {
1149 return Ok(Some(Export::GeneralPurposeRealloc));
1150 } else if export.name == "cabi_import_realloc" {
1151 return Ok(Some(Export::GeneralPurposeImportRealloc));
1152 } else if export.name == "cabi_export_realloc" {
1153 return Ok(Some(Export::GeneralPurposeExportRealloc));
1154 } else if export.name == "cabi_realloc_adapter" {
1155 return Ok(Some(Export::ReallocForAdapter));
1156 }
1157
1158 let (name, names) = match export.name.strip_prefix("cm32p2") {
1159 Some(name) => (name, STANDARD),
1160 None if encoder.reject_legacy_names => return Ok(None),
1161 None => (export.name, LEGACY),
1162 };
1163
1164 if let Some(export) = self
1165 .classify_component_export(names, name, &export, encoder, exports, types)
1166 .with_context(|| format!("failed to classify export `{}`", export.name))?
1167 {
1168 return Ok(Some(export));
1169 }
1170 log::debug!("unknown export `{}`", export.name);
1171 Ok(None)
1172 }
1173
1174 fn classify_component_export(
1175 &mut self,
1176 names: &dyn NameMangling,
1177 name: &str,
1178 export: &wasmparser::Export<'_>,
1179 encoder: &ComponentEncoder,
1180 exports: &IndexSet<WorldKey>,
1181 types: TypesRef<'_>,
1182 ) -> Result<Option<Export>> {
1183 let resolve = &encoder.metadata.resolve;
1184 let world = encoder.metadata.world;
1185 match export.kind {
1186 ExternalKind::Func => {}
1187 ExternalKind::Memory => {
1188 if name == names.export_memory() {
1189 return Ok(Some(Export::Memory));
1190 }
1191 return Ok(None);
1192 }
1193 ExternalKind::Table => {
1194 if Some(name) == names.export_indirect_function_table() {
1195 return Ok(Some(Export::IndirectFunctionTable));
1196 }
1197 return Ok(None);
1198 }
1199 _ => return Ok(None),
1200 }
1201 let ty = types[types.core_function_at(export.index)].unwrap_func();
1202
1203 if name == names.export_realloc() {
1205 let expected = FuncType::new([ValType::I32; 4], [ValType::I32]);
1206 validate_func_sig(name, &expected, ty)?;
1207 return Ok(Some(Export::GeneralPurposeRealloc));
1208 } else if name == names.export_initialize() {
1209 let expected = FuncType::new([], []);
1210 validate_func_sig(name, &expected, ty)?;
1211 return Ok(Some(Export::Initialize));
1212 }
1213
1214 let full_name = name;
1215 let (abi, name) = if let Some(name) = names.async_lift_name(name) {
1216 (AbiVariant::GuestExportAsync, name)
1217 } else if let Some(name) = names.async_lift_stackful_name(name) {
1218 (AbiVariant::GuestExportAsyncStackful, name)
1219 } else {
1220 (AbiVariant::GuestExport, name)
1221 };
1222
1223 if let Some((key, id, f)) = names.match_wit_export(name, resolve, world, exports) {
1225 validate_func(resolve, ty, f, abi).with_context(|| {
1226 let key = resolve.name_world_key(key);
1227 format!("failed to validate export for `{key}`")
1228 })?;
1229 match id {
1230 Some(id) => {
1231 return Ok(Some(Export::InterfaceFunc(
1232 key.clone(),
1233 id,
1234 f.name.clone(),
1235 abi,
1236 )));
1237 }
1238 None => {
1239 return Ok(Some(Export::WorldFunc(key.clone(), f.name.clone(), abi)));
1240 }
1241 }
1242 }
1243
1244 if let Some(remaining) = names.strip_post_return(name) {
1246 if let Some((key, id, f)) = names.match_wit_export(remaining, resolve, world, exports) {
1247 validate_post_return(resolve, ty, f).with_context(|| {
1248 let key = resolve.name_world_key(key);
1249 format!("failed to validate export for `{key}`")
1250 })?;
1251 match id {
1252 Some(_id) => {
1253 return Ok(Some(Export::InterfaceFuncPostReturn(
1254 key.clone(),
1255 f.name.clone(),
1256 )));
1257 }
1258 None => {
1259 return Ok(Some(Export::WorldFuncPostReturn(key.clone())));
1260 }
1261 }
1262 }
1263 }
1264
1265 if let Some(suffix) = names.async_lift_callback_name(full_name) {
1266 if let Some((key, id, f)) = names.match_wit_export(suffix, resolve, world, exports) {
1267 validate_func_sig(
1268 full_name,
1269 &FuncType::new([ValType::I32; 3], [ValType::I32]),
1270 ty,
1271 )?;
1272 return Ok(Some(if id.is_some() {
1273 Export::InterfaceFuncCallback(key.clone(), f.name.clone())
1274 } else {
1275 Export::WorldFuncCallback(key.clone())
1276 }));
1277 }
1278 }
1279
1280 if let Some(dtor) = names.match_wit_resource_dtor(name, resolve, world, exports) {
1282 let expected = FuncType::new([ValType::I32], []);
1283 validate_func_sig(full_name, &expected, ty)?;
1284 return Ok(Some(Export::ResourceDtor(dtor)));
1285 }
1286
1287 Ok(None)
1288 }
1289
1290 pub fn post_return(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1293 self.find(|m| match m {
1294 Export::WorldFuncPostReturn(k) => k == key,
1295 Export::InterfaceFuncPostReturn(k, f) => k == key && func.name == *f,
1296 _ => false,
1297 })
1298 }
1299
1300 pub fn callback(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1303 self.find(|m| match m {
1304 Export::WorldFuncCallback(k) => k == key,
1305 Export::InterfaceFuncCallback(k, f) => k == key && func.name == *f,
1306 _ => false,
1307 })
1308 }
1309
1310 pub fn abi(&self, key: &WorldKey, func: &Function) -> Option<AbiVariant> {
1311 self.names.values().find_map(|m| match m {
1312 Export::WorldFunc(k, f, abi) if k == key && func.name == *f => Some(*abi),
1313 Export::InterfaceFunc(k, _, f, abi) if k == key && func.name == *f => Some(*abi),
1314 _ => None,
1315 })
1316 }
1317
1318 pub fn export_realloc_for(&self, key: &WorldKey, func: &str) -> Option<&str> {
1321 let _ = (key, func);
1325
1326 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeExportRealloc)) {
1327 return Some(name);
1328 }
1329 self.general_purpose_realloc()
1330 }
1331
1332 pub fn import_realloc_for(&self, interface: Option<InterfaceId>, func: &str) -> Option<&str> {
1335 let _ = (interface, func);
1339
1340 self.import_realloc_fallback()
1341 }
1342
1343 pub fn import_realloc_fallback(&self) -> Option<&str> {
1347 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeImportRealloc)) {
1348 return Some(name);
1349 }
1350 self.general_purpose_realloc()
1351 }
1352
1353 pub fn realloc_to_import_into_adapter(&self) -> Option<&str> {
1355 if let Some(name) = self.find(|m| matches!(m, Export::ReallocForAdapter)) {
1356 return Some(name);
1357 }
1358 self.general_purpose_realloc()
1359 }
1360
1361 fn general_purpose_realloc(&self) -> Option<&str> {
1362 self.find(|m| matches!(m, Export::GeneralPurposeRealloc))
1363 }
1364
1365 pub fn memory(&self) -> Option<&str> {
1367 self.find(|m| matches!(m, Export::Memory))
1368 }
1369
1370 pub fn indirect_function_table(&self) -> Option<&str> {
1372 self.find(|t| matches!(t, Export::IndirectFunctionTable))
1373 }
1374
1375 pub fn initialize(&self) -> Option<&str> {
1377 self.find(|m| matches!(m, Export::Initialize))
1378 }
1379
1380 pub fn resource_dtor(&self, ty: TypeId) -> Option<&str> {
1382 self.find(|m| match m {
1383 Export::ResourceDtor(t) => *t == ty,
1384 _ => false,
1385 })
1386 }
1387
1388 fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1391 let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1392 Some(name)
1393 }
1394
1395 pub fn iter(&self) -> impl Iterator<Item = (&str, &Export)> + '_ {
1397 self.names.iter().map(|(n, e)| (n.as_str(), e))
1398 }
1399
1400 fn validate(&self, encoder: &ComponentEncoder, exports: &IndexSet<WorldKey>) -> Result<()> {
1401 let resolve = &encoder.metadata.resolve;
1402 let world = encoder.metadata.world;
1403 if self
1406 .names
1407 .values()
1408 .filter(|m| matches!(m, Export::Memory))
1409 .count()
1410 > 1
1411 {
1412 bail!("cannot componentize module that exports multiple memories")
1413 }
1414
1415 for (name, export) in &self.names {
1417 match export {
1418 Export::WorldFunc(_, _, AbiVariant::GuestExportAsync) => {
1419 if !matches!(
1420 self.names.get(&format!("[callback]{name}")),
1421 Some(Export::WorldFuncCallback(_))
1422 ) {
1423 bail!("missing callback for `{name}`");
1424 }
1425 }
1426 Export::InterfaceFunc(_, _, _, AbiVariant::GuestExportAsync) => {
1427 if !matches!(
1428 self.names.get(&format!("[callback]{name}")),
1429 Some(Export::InterfaceFuncCallback(_, _))
1430 ) {
1431 bail!("missing callback for `{name}`");
1432 }
1433 }
1434 _ => {}
1435 }
1436 }
1437
1438 for export in exports {
1440 let require_interface_func = |interface: InterfaceId, name: &str| -> Result<()> {
1441 let result = self.find(|e| match e {
1442 Export::InterfaceFunc(_, id, s, _) => interface == *id && name == s,
1443 _ => false,
1444 });
1445 if result.is_some() {
1446 Ok(())
1447 } else {
1448 let export = resolve.name_world_key(export);
1449 bail!("failed to find export of interface `{export}` function `{name}`")
1450 }
1451 };
1452 let require_world_func = |name: &str| -> Result<()> {
1453 let result = self.find(|e| match e {
1454 Export::WorldFunc(_, s, _) => name == s,
1455 _ => false,
1456 });
1457 if result.is_some() {
1458 Ok(())
1459 } else {
1460 bail!("failed to find export of function `{name}`")
1461 }
1462 };
1463 match &resolve.worlds[world].exports[export] {
1464 WorldItem::Interface { id, .. } => {
1465 for (name, _) in resolve.interfaces[*id].functions.iter() {
1466 require_interface_func(*id, name)?;
1467 }
1468 }
1469 WorldItem::Function(f) => {
1470 require_world_func(&f.name)?;
1471 }
1472 WorldItem::Type(_) => unreachable!(),
1473 }
1474 }
1475
1476 Ok(())
1477 }
1478}
1479
1480struct MaybeCancellable<T> {
1482 #[allow(unused)]
1483 inner: T,
1484 cancellable: bool,
1485}
1486
1487struct MaybeAsyncLowered<T> {
1489 inner: T,
1490 async_lowered: bool,
1491}
1492
1493struct PayloadLookupContext<'a> {
1496 resolve: &'a Resolve,
1497 world: &'a World,
1498 id: Option<InterfaceId>,
1499 import: bool,
1500 key: Option<WorldKey>,
1501}
1502
1503trait NameMangling {
1525 fn import_root(&self) -> &str;
1526 fn import_non_root_prefix(&self) -> &str;
1527 fn import_exported_intrinsic_prefix(&self) -> &str;
1528 fn export_memory(&self) -> &str;
1529 fn export_initialize(&self) -> &str;
1530 fn export_realloc(&self) -> &str;
1531 fn export_indirect_function_table(&self) -> Option<&str>;
1532 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1533 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1534 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1535 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1536 fn task_cancel(&self, name: &str) -> bool;
1537 fn backpressure_inc(&self, name: &str) -> bool;
1538 fn backpressure_dec(&self, name: &str) -> bool;
1539 fn waitable_set_new(&self, name: &str) -> bool;
1540 fn waitable_set_wait(&self, name: &str) -> Option<MaybeCancellable<()>>;
1541 fn waitable_set_poll(&self, name: &str) -> Option<MaybeCancellable<()>>;
1542 fn waitable_set_drop(&self, name: &str) -> bool;
1543 fn waitable_join(&self, name: &str) -> bool;
1544 fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>>;
1545 fn subtask_drop(&self, name: &str) -> bool;
1546 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>>;
1547 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1548 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1549 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1550 fn error_context_new(&self, name: &str) -> Option<StringEncoding>;
1551 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding>;
1552 fn error_context_drop(&self, name: &str) -> bool;
1553 fn context_get(&self, name: &str) -> Option<u32>;
1554 fn context_set(&self, name: &str) -> Option<u32>;
1555 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1556 fn future_write(
1557 &self,
1558 lookup_context: &PayloadLookupContext,
1559 name: &str,
1560 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1561 fn future_read(
1562 &self,
1563 lookup_context: &PayloadLookupContext,
1564 name: &str,
1565 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1566 fn future_cancel_write(
1567 &self,
1568 lookup_context: &PayloadLookupContext,
1569 name: &str,
1570 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1571 fn future_cancel_read(
1572 &self,
1573 lookup_context: &PayloadLookupContext,
1574 name: &str,
1575 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1576 fn future_drop_writable(
1577 &self,
1578 lookup_context: &PayloadLookupContext,
1579 name: &str,
1580 ) -> Option<PayloadInfo>;
1581 fn future_drop_readable(
1582 &self,
1583 lookup_context: &PayloadLookupContext,
1584 name: &str,
1585 ) -> Option<PayloadInfo>;
1586 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1587 fn stream_write(
1588 &self,
1589 lookup_context: &PayloadLookupContext,
1590 name: &str,
1591 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1592 fn stream_read(
1593 &self,
1594 lookup_context: &PayloadLookupContext,
1595 name: &str,
1596 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1597 fn stream_cancel_write(
1598 &self,
1599 lookup_context: &PayloadLookupContext,
1600 name: &str,
1601 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1602 fn stream_cancel_read(
1603 &self,
1604 lookup_context: &PayloadLookupContext,
1605 name: &str,
1606 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1607 fn stream_drop_writable(
1608 &self,
1609 lookup_context: &PayloadLookupContext,
1610 name: &str,
1611 ) -> Option<PayloadInfo>;
1612 fn stream_drop_readable(
1613 &self,
1614 lookup_context: &PayloadLookupContext,
1615 name: &str,
1616 ) -> Option<PayloadInfo>;
1617 fn thread_index(&self, name: &str) -> bool;
1618 fn thread_new_indirect(&self, name: &str) -> bool;
1619 fn thread_switch_to(&self, name: &str) -> Option<MaybeCancellable<()>>;
1620 fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>>;
1621 fn thread_resume_later(&self, name: &str) -> bool;
1622 fn thread_yield_to(&self, name: &str) -> Option<MaybeCancellable<()>>;
1623 fn module_to_interface(
1624 &self,
1625 module: &str,
1626 resolve: &Resolve,
1627 items: &IndexMap<WorldKey, WorldItem>,
1628 ) -> Result<(WorldKey, InterfaceId)>;
1629 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str>;
1630 fn match_wit_export<'a>(
1631 &self,
1632 export_name: &str,
1633 resolve: &'a Resolve,
1634 world: WorldId,
1635 exports: &'a IndexSet<WorldKey>,
1636 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)>;
1637 fn match_wit_resource_dtor<'a>(
1638 &self,
1639 export_name: &str,
1640 resolve: &'a Resolve,
1641 world: WorldId,
1642 exports: &'a IndexSet<WorldKey>,
1643 ) -> Option<TypeId>;
1644 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1645 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1646}
1647
1648struct Standard;
1651
1652const STANDARD: &'static dyn NameMangling = &Standard;
1653
1654impl NameMangling for Standard {
1655 fn import_root(&self) -> &str {
1656 ""
1657 }
1658 fn import_non_root_prefix(&self) -> &str {
1659 "|"
1660 }
1661 fn import_exported_intrinsic_prefix(&self) -> &str {
1662 "_ex_"
1663 }
1664 fn export_memory(&self) -> &str {
1665 "_memory"
1666 }
1667 fn export_initialize(&self) -> &str {
1668 "_initialize"
1669 }
1670 fn export_realloc(&self) -> &str {
1671 "_realloc"
1672 }
1673 fn export_indirect_function_table(&self) -> Option<&str> {
1674 None
1675 }
1676 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1677 name.strip_suffix("_drop")
1678 }
1679 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1680 name.strip_suffix("_new")
1681 }
1682 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1683 name.strip_suffix("_rep")
1684 }
1685 fn task_return_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1686 None
1687 }
1688 fn task_cancel(&self, _name: &str) -> bool {
1689 false
1690 }
1691 fn backpressure_inc(&self, _name: &str) -> bool {
1692 false
1693 }
1694 fn backpressure_dec(&self, _name: &str) -> bool {
1695 false
1696 }
1697 fn waitable_set_new(&self, _name: &str) -> bool {
1698 false
1699 }
1700 fn waitable_set_wait(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1701 None
1702 }
1703 fn waitable_set_poll(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1704 None
1705 }
1706 fn waitable_set_drop(&self, _name: &str) -> bool {
1707 false
1708 }
1709 fn waitable_join(&self, _name: &str) -> bool {
1710 false
1711 }
1712 fn thread_yield(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1713 None
1714 }
1715 fn subtask_drop(&self, _name: &str) -> bool {
1716 false
1717 }
1718 fn subtask_cancel(&self, _name: &str) -> Option<MaybeAsyncLowered<()>> {
1719 None
1720 }
1721 fn async_lift_callback_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1722 None
1723 }
1724 fn async_lift_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1725 None
1726 }
1727 fn async_lift_stackful_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1728 None
1729 }
1730 fn error_context_new(&self, _name: &str) -> Option<StringEncoding> {
1731 None
1732 }
1733 fn error_context_debug_message(&self, _name: &str) -> Option<StringEncoding> {
1734 None
1735 }
1736 fn error_context_drop(&self, _name: &str) -> bool {
1737 false
1738 }
1739 fn context_get(&self, _name: &str) -> Option<u32> {
1740 None
1741 }
1742 fn context_set(&self, _name: &str) -> Option<u32> {
1743 None
1744 }
1745 fn thread_index(&self, _name: &str) -> bool {
1746 false
1747 }
1748 fn thread_new_indirect(&self, _name: &str) -> bool {
1749 false
1750 }
1751 fn thread_switch_to(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1752 None
1753 }
1754 fn thread_suspend(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1755 None
1756 }
1757 fn thread_resume_later(&self, _name: &str) -> bool {
1758 false
1759 }
1760 fn thread_yield_to(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1761 None
1762 }
1763 fn future_new(
1764 &self,
1765 _lookup_context: &PayloadLookupContext,
1766 _name: &str,
1767 ) -> Option<PayloadInfo> {
1768 None
1769 }
1770 fn future_write(
1771 &self,
1772 _lookup_context: &PayloadLookupContext,
1773 _name: &str,
1774 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1775 None
1776 }
1777 fn future_read(
1778 &self,
1779 _lookup_context: &PayloadLookupContext,
1780 _name: &str,
1781 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1782 None
1783 }
1784 fn future_cancel_write(
1785 &self,
1786 _lookup_context: &PayloadLookupContext,
1787 _name: &str,
1788 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1789 None
1790 }
1791 fn future_cancel_read(
1792 &self,
1793 _lookup_context: &PayloadLookupContext,
1794 _name: &str,
1795 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1796 None
1797 }
1798 fn future_drop_writable(
1799 &self,
1800 _lookup_context: &PayloadLookupContext,
1801 _name: &str,
1802 ) -> Option<PayloadInfo> {
1803 None
1804 }
1805 fn future_drop_readable(
1806 &self,
1807 _lookup_context: &PayloadLookupContext,
1808 _name: &str,
1809 ) -> Option<PayloadInfo> {
1810 None
1811 }
1812 fn stream_new(
1813 &self,
1814 _lookup_context: &PayloadLookupContext,
1815 _name: &str,
1816 ) -> Option<PayloadInfo> {
1817 None
1818 }
1819 fn stream_write(
1820 &self,
1821 _lookup_context: &PayloadLookupContext,
1822 _name: &str,
1823 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1824 None
1825 }
1826 fn stream_read(
1827 &self,
1828 _lookup_context: &PayloadLookupContext,
1829 _name: &str,
1830 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1831 None
1832 }
1833 fn stream_cancel_write(
1834 &self,
1835 _lookup_context: &PayloadLookupContext,
1836 _name: &str,
1837 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1838 None
1839 }
1840 fn stream_cancel_read(
1841 &self,
1842 _lookup_context: &PayloadLookupContext,
1843 _name: &str,
1844 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1845 None
1846 }
1847 fn stream_drop_writable(
1848 &self,
1849 _lookup_context: &PayloadLookupContext,
1850 _name: &str,
1851 ) -> Option<PayloadInfo> {
1852 None
1853 }
1854 fn stream_drop_readable(
1855 &self,
1856 _lookup_context: &PayloadLookupContext,
1857 _name: &str,
1858 ) -> Option<PayloadInfo> {
1859 None
1860 }
1861 fn module_to_interface(
1862 &self,
1863 interface: &str,
1864 resolve: &Resolve,
1865 items: &IndexMap<WorldKey, WorldItem>,
1866 ) -> Result<(WorldKey, InterfaceId)> {
1867 for (key, item) in items.iter() {
1868 let id = match key {
1869 WorldKey::Name(name) => match item {
1871 WorldItem::Interface { id, .. } if name == interface => *id,
1872 _ => continue,
1873 },
1874 WorldKey::Interface(id) => {
1876 if resolve.canonicalized_id_of(*id).as_deref() != Some(interface) {
1877 continue;
1878 }
1879 *id
1880 }
1881 };
1882 return Ok((key.clone(), id));
1883 }
1884 bail!("failed to find world item corresponding to interface `{interface}`")
1885 }
1886 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
1887 name.strip_suffix("_post")
1888 }
1889 fn match_wit_export<'a>(
1890 &self,
1891 export_name: &str,
1892 resolve: &'a Resolve,
1893 world: WorldId,
1894 exports: &'a IndexSet<WorldKey>,
1895 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
1896 if let Some(world_export_name) = export_name.strip_prefix("||") {
1897 let key = exports.get(&WorldKey::Name(world_export_name.to_string()))?;
1898 match &resolve.worlds[world].exports[key] {
1899 WorldItem::Function(f) => return Some((key, None, f)),
1900 _ => return None,
1901 }
1902 }
1903
1904 let (key, id, func_name) =
1905 self.match_wit_interface(export_name, resolve, world, exports)?;
1906 let func = resolve.interfaces[id].functions.get(func_name)?;
1907 Some((key, Some(id), func))
1908 }
1909
1910 fn match_wit_resource_dtor<'a>(
1911 &self,
1912 export_name: &str,
1913 resolve: &'a Resolve,
1914 world: WorldId,
1915 exports: &'a IndexSet<WorldKey>,
1916 ) -> Option<TypeId> {
1917 let (_key, id, name) =
1918 self.match_wit_interface(export_name.strip_suffix("_dtor")?, resolve, world, exports)?;
1919 let ty = *resolve.interfaces[id].types.get(name)?;
1920 match resolve.types[ty].kind {
1921 TypeDefKind::Resource => Some(ty),
1922 _ => None,
1923 }
1924 }
1925
1926 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
1927 (name, AbiVariant::GuestImport)
1928 }
1929 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
1930 (name, AbiVariant::GuestImport)
1931 }
1932}
1933
1934impl Standard {
1935 fn match_wit_interface<'a, 'b>(
1936 &self,
1937 export_name: &'b str,
1938 resolve: &'a Resolve,
1939 world: WorldId,
1940 exports: &'a IndexSet<WorldKey>,
1941 ) -> Option<(&'a WorldKey, InterfaceId, &'b str)> {
1942 let world = &resolve.worlds[world];
1943 let export_name = export_name.strip_prefix("|")?;
1944
1945 for export in exports {
1946 let id = match &world.exports[export] {
1947 WorldItem::Interface { id, .. } => *id,
1948 WorldItem::Function(_) => continue,
1949 WorldItem::Type(_) => unreachable!(),
1950 };
1951 let remaining = match export {
1952 WorldKey::Name(name) => export_name.strip_prefix(name),
1953 WorldKey::Interface(_) => {
1954 let prefix = resolve.canonicalized_id_of(id).unwrap();
1955 export_name.strip_prefix(&prefix)
1956 }
1957 };
1958 let item_name = match remaining.and_then(|s| s.strip_prefix("|")) {
1959 Some(name) => name,
1960 None => continue,
1961 };
1962 return Some((export, id, item_name));
1963 }
1964
1965 None
1966 }
1967}
1968
1969struct Legacy;
1972
1973const LEGACY: &'static dyn NameMangling = &Legacy;
1974
1975impl Legacy {
1976 fn prefixed_payload(
1982 &self,
1983 lookup_context: &PayloadLookupContext,
1984 name: &str,
1985 prefix: &str,
1986 ) -> Option<PayloadInfo> {
1987 let (index_or_unit, func_name) = prefixed_intrinsic(name, prefix)?;
1990 let ty = match index_or_unit {
1991 "unit" => {
1992 if name.starts_with("[future") {
1993 PayloadType::UnitFuture
1994 } else if name.starts_with("[stream") {
1995 PayloadType::UnitStream
1996 } else {
1997 unreachable!()
1998 }
1999 }
2000 other => {
2001 let type_index = other.parse::<u32>().ok()? as usize;
2005
2006 let function = get_function(
2011 lookup_context.resolve,
2012 lookup_context.world,
2013 func_name,
2014 lookup_context.id,
2015 lookup_context.import,
2016 )
2017 .ok()?;
2018 PayloadType::Type {
2019 id: *function
2020 .find_futures_and_streams(lookup_context.resolve)
2021 .get(type_index)?,
2022 function: function.name.clone(),
2023 }
2024 }
2025 };
2026
2027 Some(PayloadInfo {
2029 name: name.to_string(),
2030 ty,
2031 key: lookup_context
2032 .key
2033 .clone()
2034 .unwrap_or_else(|| WorldKey::Name(name.to_string())),
2035 interface: lookup_context.id,
2036 imported: lookup_context.import,
2037 })
2038 }
2039
2040 fn maybe_async_lowered_payload(
2041 &self,
2042 lookup_context: &PayloadLookupContext,
2043 name: &str,
2044 prefix: &str,
2045 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2046 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2047 let payload = self.prefixed_payload(lookup_context, clean_name, prefix)?;
2048 Some(MaybeAsyncLowered {
2049 inner: payload,
2050 async_lowered,
2051 })
2052 }
2053
2054 fn strip_async_lowered_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2055 name.strip_prefix("[async-lower]")
2056 .map_or((false, name), |s| (true, s))
2057 }
2058 fn match_with_async_lowered_prefix(
2059 &self,
2060 name: &str,
2061 expected: &str,
2062 ) -> Option<MaybeAsyncLowered<()>> {
2063 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2064 if clean_name == expected {
2065 Some(MaybeAsyncLowered {
2066 inner: (),
2067 async_lowered,
2068 })
2069 } else {
2070 None
2071 }
2072 }
2073 fn strip_cancellable_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2074 name.strip_prefix("[cancellable]")
2075 .map_or((false, name), |s| (true, s))
2076 }
2077 fn match_with_cancellable_prefix(
2078 &self,
2079 name: &str,
2080 expected: &str,
2081 ) -> Option<MaybeCancellable<()>> {
2082 let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2083 if clean_name == expected {
2084 Some(MaybeCancellable {
2085 inner: (),
2086 cancellable,
2087 })
2088 } else {
2089 None
2090 }
2091 }
2092}
2093
2094impl NameMangling for Legacy {
2095 fn import_root(&self) -> &str {
2096 "$root"
2097 }
2098 fn import_non_root_prefix(&self) -> &str {
2099 ""
2100 }
2101 fn import_exported_intrinsic_prefix(&self) -> &str {
2102 "[export]"
2103 }
2104 fn export_memory(&self) -> &str {
2105 "memory"
2106 }
2107 fn export_initialize(&self) -> &str {
2108 "_initialize"
2109 }
2110 fn export_realloc(&self) -> &str {
2111 "cabi_realloc"
2112 }
2113 fn export_indirect_function_table(&self) -> Option<&str> {
2114 Some("__indirect_function_table")
2115 }
2116 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2117 name.strip_prefix("[resource-drop]")
2118 }
2119 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2120 name.strip_prefix("[resource-new]")
2121 }
2122 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2123 name.strip_prefix("[resource-rep]")
2124 }
2125 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2126 name.strip_prefix("[task-return]")
2127 }
2128 fn task_cancel(&self, name: &str) -> bool {
2129 name == "[task-cancel]"
2130 }
2131 fn backpressure_inc(&self, name: &str) -> bool {
2132 name == "[backpressure-inc]"
2133 }
2134 fn backpressure_dec(&self, name: &str) -> bool {
2135 name == "[backpressure-dec]"
2136 }
2137 fn waitable_set_new(&self, name: &str) -> bool {
2138 name == "[waitable-set-new]"
2139 }
2140 fn waitable_set_wait(&self, name: &str) -> Option<MaybeCancellable<()>> {
2141 self.match_with_cancellable_prefix(name, "[waitable-set-wait]")
2142 }
2143 fn waitable_set_poll(&self, name: &str) -> Option<MaybeCancellable<()>> {
2144 self.match_with_cancellable_prefix(name, "[waitable-set-poll]")
2145 }
2146 fn waitable_set_drop(&self, name: &str) -> bool {
2147 name == "[waitable-set-drop]"
2148 }
2149 fn waitable_join(&self, name: &str) -> bool {
2150 name == "[waitable-join]"
2151 }
2152 fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>> {
2153 self.match_with_cancellable_prefix(name, "[thread-yield]")
2154 }
2155 fn subtask_drop(&self, name: &str) -> bool {
2156 name == "[subtask-drop]"
2157 }
2158 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>> {
2159 self.match_with_async_lowered_prefix(name, "[subtask-cancel]")
2160 }
2161 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2162 name.strip_prefix("[callback][async-lift]")
2163 }
2164 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2165 name.strip_prefix("[async-lift]")
2166 }
2167 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2168 name.strip_prefix("[async-lift-stackful]")
2169 }
2170 fn error_context_new(&self, name: &str) -> Option<StringEncoding> {
2171 match name {
2172 "[error-context-new-utf8]" => Some(StringEncoding::UTF8),
2173 "[error-context-new-utf16]" => Some(StringEncoding::UTF16),
2174 "[error-context-new-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2175 _ => None,
2176 }
2177 }
2178 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding> {
2179 match name {
2180 "[error-context-debug-message-utf8]" => Some(StringEncoding::UTF8),
2181 "[error-context-debug-message-utf16]" => Some(StringEncoding::UTF16),
2182 "[error-context-debug-message-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2183 _ => None,
2184 }
2185 }
2186 fn error_context_drop(&self, name: &str) -> bool {
2187 name == "[error-context-drop]"
2188 }
2189 fn context_get(&self, name: &str) -> Option<u32> {
2190 let (n, rest) = prefixed_integer(name, "[context-get-")?;
2191 if rest.is_empty() { Some(n) } else { None }
2192 }
2193 fn context_set(&self, name: &str) -> Option<u32> {
2194 let (n, rest) = prefixed_integer(name, "[context-set-")?;
2195 if rest.is_empty() { Some(n) } else { None }
2196 }
2197 fn thread_index(&self, name: &str) -> bool {
2198 name == "[thread-index]"
2199 }
2200 fn thread_new_indirect(&self, name: &str) -> bool {
2201 name == "[thread-new-indirect-v0]"
2203 }
2204 fn thread_switch_to(&self, name: &str) -> Option<MaybeCancellable<()>> {
2205 self.match_with_cancellable_prefix(name, "[thread-switch-to]")
2206 }
2207 fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>> {
2208 self.match_with_cancellable_prefix(name, "[thread-suspend]")
2209 }
2210 fn thread_resume_later(&self, name: &str) -> bool {
2211 name == "[thread-resume-later]"
2212 }
2213 fn thread_yield_to(&self, name: &str) -> Option<MaybeCancellable<()>> {
2214 self.match_with_cancellable_prefix(name, "[thread-yield-to]")
2215 }
2216 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2217 self.prefixed_payload(lookup_context, name, "[future-new-")
2218 }
2219 fn future_write(
2220 &self,
2221 lookup_context: &PayloadLookupContext,
2222 name: &str,
2223 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2224 self.maybe_async_lowered_payload(lookup_context, name, "[future-write-")
2225 }
2226 fn future_read(
2227 &self,
2228 lookup_context: &PayloadLookupContext,
2229 name: &str,
2230 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2231 self.maybe_async_lowered_payload(lookup_context, name, "[future-read-")
2232 }
2233 fn future_cancel_write(
2234 &self,
2235 lookup_context: &PayloadLookupContext,
2236 name: &str,
2237 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2238 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-write-")
2239 }
2240 fn future_cancel_read(
2241 &self,
2242 lookup_context: &PayloadLookupContext,
2243 name: &str,
2244 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2245 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-read-")
2246 }
2247 fn future_drop_writable(
2248 &self,
2249 lookup_context: &PayloadLookupContext,
2250 name: &str,
2251 ) -> Option<PayloadInfo> {
2252 self.prefixed_payload(lookup_context, name, "[future-drop-writable-")
2253 }
2254 fn future_drop_readable(
2255 &self,
2256 lookup_context: &PayloadLookupContext,
2257 name: &str,
2258 ) -> Option<PayloadInfo> {
2259 self.prefixed_payload(lookup_context, name, "[future-drop-readable-")
2260 }
2261 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2262 self.prefixed_payload(lookup_context, name, "[stream-new-")
2263 }
2264 fn stream_write(
2265 &self,
2266 lookup_context: &PayloadLookupContext,
2267 name: &str,
2268 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2269 self.maybe_async_lowered_payload(lookup_context, name, "[stream-write-")
2270 }
2271 fn stream_read(
2272 &self,
2273 lookup_context: &PayloadLookupContext,
2274 name: &str,
2275 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2276 self.maybe_async_lowered_payload(lookup_context, name, "[stream-read-")
2277 }
2278 fn stream_cancel_write(
2279 &self,
2280 lookup_context: &PayloadLookupContext,
2281 name: &str,
2282 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2283 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-write-")
2284 }
2285 fn stream_cancel_read(
2286 &self,
2287 lookup_context: &PayloadLookupContext,
2288 name: &str,
2289 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2290 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-read-")
2291 }
2292 fn stream_drop_writable(
2293 &self,
2294 lookup_context: &PayloadLookupContext,
2295 name: &str,
2296 ) -> Option<PayloadInfo> {
2297 self.prefixed_payload(lookup_context, name, "[stream-drop-writable-")
2298 }
2299 fn stream_drop_readable(
2300 &self,
2301 lookup_context: &PayloadLookupContext,
2302 name: &str,
2303 ) -> Option<PayloadInfo> {
2304 self.prefixed_payload(lookup_context, name, "[stream-drop-readable-")
2305 }
2306 fn module_to_interface(
2307 &self,
2308 module: &str,
2309 resolve: &Resolve,
2310 items: &IndexMap<WorldKey, WorldItem>,
2311 ) -> Result<(WorldKey, InterfaceId)> {
2312 let bare_name = WorldKey::Name(module.to_string());
2314 if let Some(WorldItem::Interface { id, .. }) = items.get(&bare_name) {
2315 return Ok((bare_name, *id));
2316 }
2317
2318 let kebab_name = ComponentName::new(module, 0);
2324 let name = match kebab_name.as_ref().map(|k| k.kind()) {
2325 Ok(ComponentNameKind::Interface(name)) => name,
2326 _ => bail!("module requires an import interface named `{module}`"),
2327 };
2328
2329 let pkgname = PackageName {
2331 namespace: name.namespace().to_string(),
2332 name: name.package().to_string(),
2333 version: name.version(),
2334 };
2335 if let Some(pkg) = resolve.package_names.get(&pkgname) {
2336 if let Some(id) = resolve.packages[*pkg]
2337 .interfaces
2338 .get(name.interface().as_str())
2339 {
2340 let key = WorldKey::Interface(*id);
2341 if items.contains_key(&key) {
2342 return Ok((key, *id));
2343 }
2344 }
2345 }
2346
2347 for (key, _) in items {
2352 let id = match key {
2353 WorldKey::Interface(id) => *id,
2354 WorldKey::Name(_) => continue,
2355 };
2356 let interface = &resolve.interfaces[id];
2358 if interface.name.as_ref().unwrap() != name.interface().as_str() {
2359 continue;
2360 }
2361
2362 let pkg = &resolve.packages[interface.package.unwrap()];
2364 if pkg.name.namespace != pkgname.namespace || pkg.name.name != pkgname.name {
2365 continue;
2366 }
2367
2368 let module_version = match name.version() {
2369 Some(version) => version,
2370 None => continue,
2371 };
2372 let pkg_version = match &pkg.name.version {
2373 Some(version) => version,
2374 None => continue,
2375 };
2376
2377 let module_compat = PackageName::version_compat_track(&module_version);
2379 let pkg_compat = PackageName::version_compat_track(pkg_version);
2380 if module_compat == pkg_compat {
2381 return Ok((key.clone(), id));
2382 }
2383 }
2384
2385 bail!("module requires an import interface named `{module}`")
2386 }
2387 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
2388 name.strip_prefix("cabi_post_")
2389 }
2390 fn match_wit_export<'a>(
2391 &self,
2392 export_name: &str,
2393 resolve: &'a Resolve,
2394 world: WorldId,
2395 exports: &'a IndexSet<WorldKey>,
2396 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
2397 let world = &resolve.worlds[world];
2398 for name in exports {
2399 match &world.exports[name] {
2400 WorldItem::Function(f) => {
2401 if f.legacy_core_export_name(None) == export_name {
2402 return Some((name, None, f));
2403 }
2404 }
2405 WorldItem::Interface { id, .. } => {
2406 let string = resolve.name_world_key(name);
2407 for (_, func) in resolve.interfaces[*id].functions.iter() {
2408 if func.legacy_core_export_name(Some(&string)) == export_name {
2409 return Some((name, Some(*id), func));
2410 }
2411 }
2412 }
2413
2414 WorldItem::Type(_) => unreachable!(),
2415 }
2416 }
2417
2418 None
2419 }
2420
2421 fn match_wit_resource_dtor<'a>(
2422 &self,
2423 export_name: &str,
2424 resolve: &'a Resolve,
2425 world: WorldId,
2426 exports: &'a IndexSet<WorldKey>,
2427 ) -> Option<TypeId> {
2428 let world = &resolve.worlds[world];
2429 for name in exports {
2430 let id = match &world.exports[name] {
2431 WorldItem::Interface { id, .. } => *id,
2432 WorldItem::Function(_) => continue,
2433 WorldItem::Type(_) => unreachable!(),
2434 };
2435 let name = resolve.name_world_key(name);
2436 let resource = match export_name
2437 .strip_prefix(&name)
2438 .and_then(|s| s.strip_prefix("#[dtor]"))
2439 .and_then(|r| resolve.interfaces[id].types.get(r))
2440 {
2441 Some(id) => *id,
2442 None => continue,
2443 };
2444
2445 match resolve.types[resource].kind {
2446 TypeDefKind::Resource => {}
2447 _ => continue,
2448 }
2449
2450 return Some(resource);
2451 }
2452
2453 None
2454 }
2455
2456 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2457 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2458 (
2459 name,
2460 if async_abi {
2461 AbiVariant::GuestImportAsync
2462 } else {
2463 AbiVariant::GuestImport
2464 },
2465 )
2466 }
2467 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2468 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2469 (
2470 name,
2471 if async_abi {
2472 AbiVariant::GuestImportAsync
2473 } else {
2474 AbiVariant::GuestImport
2475 },
2476 )
2477 }
2478}
2479
2480pub fn validate_module(
2492 encoder: &ComponentEncoder,
2493 bytes: &[u8],
2494 import_map: Option<&ModuleImportMap>,
2495) -> Result<ValidatedModule> {
2496 ValidatedModule::new(
2497 encoder,
2498 bytes,
2499 &encoder.main_module_exports,
2500 import_map,
2501 None,
2502 )
2503}
2504
2505pub fn validate_adapter_module(
2523 encoder: &ComponentEncoder,
2524 bytes: &[u8],
2525 required_by_import: &IndexMap<String, FuncType>,
2526 exports: &IndexSet<WorldKey>,
2527 library_info: Option<&LibraryInfo>,
2528) -> Result<ValidatedModule> {
2529 let ret = ValidatedModule::new(encoder, bytes, exports, None, library_info)?;
2530
2531 for (name, required_ty) in required_by_import {
2532 let actual = match ret.exports.raw_exports.get(name) {
2533 Some(ty) => ty,
2534 None => return Err(AdapterModuleDidNotExport(name.clone()).into()),
2535 };
2536 validate_func_sig(name, required_ty, &actual)?;
2537 }
2538
2539 Ok(ret)
2540}
2541
2542#[derive(Debug, Clone)]
2549pub struct AdapterModuleDidNotExport(String);
2550
2551impl fmt::Display for AdapterModuleDidNotExport {
2552 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2553 write!(f, "adapter module did not export `{}`", self.0)
2554 }
2555}
2556
2557impl std::error::Error for AdapterModuleDidNotExport {}
2558
2559fn resource_test_for_interface<'a>(
2560 resolve: &'a Resolve,
2561 id: InterfaceId,
2562) -> impl Fn(&str) -> Option<TypeId> + 'a {
2563 let interface = &resolve.interfaces[id];
2564 move |name: &str| {
2565 let ty = match interface.types.get(name) {
2566 Some(ty) => *ty,
2567 None => return None,
2568 };
2569 if matches!(resolve.types[ty].kind, TypeDefKind::Resource) {
2570 Some(ty)
2571 } else {
2572 None
2573 }
2574 }
2575}
2576
2577fn resource_test_for_world<'a>(
2578 resolve: &'a Resolve,
2579 id: WorldId,
2580) -> impl Fn(&str) -> Option<TypeId> + 'a {
2581 let world = &resolve.worlds[id];
2582 move |name: &str| match world.imports.get(&WorldKey::Name(name.to_string()))? {
2583 WorldItem::Type(r) => {
2584 if matches!(resolve.types[*r].kind, TypeDefKind::Resource) {
2585 Some(*r)
2586 } else {
2587 None
2588 }
2589 }
2590 _ => None,
2591 }
2592}
2593
2594fn validate_func(
2595 resolve: &Resolve,
2596 ty: &wasmparser::FuncType,
2597 func: &Function,
2598 abi: AbiVariant,
2599) -> Result<()> {
2600 validate_func_sig(
2601 &func.name,
2602 &wasm_sig_to_func_type(resolve.wasm_signature(abi, func)),
2603 ty,
2604 )
2605}
2606
2607fn validate_post_return(
2608 resolve: &Resolve,
2609 ty: &wasmparser::FuncType,
2610 func: &Function,
2611) -> Result<()> {
2612 let mut sig = resolve.wasm_signature(AbiVariant::GuestExport, func);
2618 sig.params = mem::take(&mut sig.results);
2619 validate_func_sig(
2620 &format!("{} post-return", func.name),
2621 &wasm_sig_to_func_type(sig),
2622 ty,
2623 )
2624}
2625
2626fn validate_func_sig(name: &str, expected: &FuncType, ty: &wasmparser::FuncType) -> Result<()> {
2627 if ty != expected {
2628 bail!(
2629 "type mismatch for function `{}`: expected `{:?} -> {:?}` but found `{:?} -> {:?}`",
2630 name,
2631 expected.params(),
2632 expected.results(),
2633 ty.params(),
2634 ty.results()
2635 );
2636 }
2637
2638 Ok(())
2639}
2640
2641fn prefixed_intrinsic<'a>(name: &'a str, prefix: &str) -> Option<(&'a str, &'a str)> {
2643 assert!(prefix.starts_with("["));
2644 assert!(prefix.ends_with("-"));
2645 let suffix = name.strip_prefix(prefix)?;
2646 let index = suffix.find(']')?;
2647 let rest = &suffix[index + 1..];
2648 Some((&suffix[..index], rest))
2649}
2650
2651fn prefixed_integer<'a>(name: &'a str, prefix: &str) -> Option<(u32, &'a str)> {
2653 let (suffix, rest) = prefixed_intrinsic(name, prefix)?;
2654 let n = suffix.parse().ok()?;
2655 Some((n, rest))
2656}
2657
2658fn get_function<'a>(
2659 resolve: &'a Resolve,
2660 world: &'a World,
2661 name: &str,
2662 interface: Option<InterfaceId>,
2663 imported: bool,
2664) -> Result<&'a Function> {
2665 let function = if let Some(id) = interface {
2666 return resolve.interfaces[id]
2667 .functions
2668 .get(name)
2669 .ok_or_else(|| anyhow!("no export `{name}` found"));
2670 } else if imported {
2671 world.imports.get(&WorldKey::Name(name.to_string()))
2672 } else {
2673 world.exports.get(&WorldKey::Name(name.to_string()))
2674 };
2675 let Some(WorldItem::Function(function)) = function else {
2676 bail!("no export `{name}` found");
2677 };
2678 Ok(function)
2679}