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>, Function),
272
273 ExportedTaskCancel,
277
278 ContextGet {
280 ty: ValType,
282 slot: u32,
284 },
285 ContextSet {
287 ty: ValType,
289 slot: u32,
291 },
292
293 BackpressureInc,
295
296 BackpressureDec,
298
299 WaitableSetNew,
301
302 WaitableSetWait { cancellable: bool },
308
309 WaitableSetPoll { cancellable: bool },
315
316 WaitableSetDrop,
318
319 WaitableJoin,
321
322 ThreadYield { cancellable: bool },
327
328 SubtaskDrop,
332
333 SubtaskCancel { async_: bool },
337
338 StreamNew(PayloadInfo),
342
343 StreamRead { async_: bool, info: PayloadInfo },
348
349 StreamWrite { async_: bool, info: PayloadInfo },
354
355 StreamCancelRead { info: PayloadInfo, async_: bool },
360
361 StreamCancelWrite { info: PayloadInfo, async_: bool },
366
367 StreamDropReadable(PayloadInfo),
371
372 StreamDropWritable(PayloadInfo),
376
377 FutureNew(PayloadInfo),
381
382 FutureRead { async_: bool, info: PayloadInfo },
387
388 FutureWrite { async_: bool, info: PayloadInfo },
392
393 FutureCancelRead { info: PayloadInfo, async_: bool },
398
399 FutureCancelWrite { info: PayloadInfo, async_: bool },
404
405 FutureDropReadable(PayloadInfo),
409
410 FutureDropWritable(PayloadInfo),
414
415 ErrorContextNew { encoding: StringEncoding },
420
421 ErrorContextDebugMessage { encoding: StringEncoding },
427
428 ErrorContextDrop,
433
434 ThreadIndex,
438
439 ThreadNewIndirect,
443
444 ThreadSuspendToSuspended { cancellable: bool },
448
449 ThreadSuspend { cancellable: bool },
454
455 ThreadSuspendTo { cancellable: bool },
459
460 ThreadUnsuspend,
464
465 ThreadYieldToSuspended { cancellable: bool },
469}
470
471impl ImportMap {
472 pub fn required_from_adapter(&self, name: &str) -> IndexMap<String, FuncType> {
474 let names = match self.names.get(name) {
475 Some(ImportInstance::Names(names)) => names,
476 _ => return IndexMap::new(),
477 };
478 names
479 .iter()
480 .map(|(_, import)| match import {
481 Import::AdapterExport { ty, func, adapter } => {
482 assert_eq!(adapter, name);
483 (func.clone(), ty.clone())
484 }
485 _ => unreachable!(),
486 })
487 .collect()
488 }
489
490 pub fn imports(&self) -> impl Iterator<Item = (&str, &str, &Import)> + '_ {
494 self.names
495 .iter()
496 .filter_map(|(module, m)| match m {
497 ImportInstance::Names(names) => Some((module, names)),
498 ImportInstance::Whole(_) => None,
499 })
500 .flat_map(|(module, m)| {
501 m.iter()
502 .map(move |(field, import)| (module.as_str(), field.as_str(), import))
503 })
504 }
505
506 pub fn modules(&self) -> &IndexMap<String, ImportInstance> {
508 &self.names
509 }
510
511 fn add(
514 &mut self,
515 import: wasmparser::Import<'_>,
516 encoder: &ComponentEncoder,
517 import_map: Option<&ModuleImportMap>,
518 library_info: Option<&LibraryInfo>,
519 types: TypesRef<'_>,
520 ) -> Result<()> {
521 if self.classify_import_with_library(import, library_info)? {
522 return Ok(());
523 }
524 let mut import_to_classify = import;
525 if let Some(map) = import_map {
526 if let Some(original_name) = map.original_name(&import) {
527 import_to_classify.name = original_name;
528 }
529 }
530 let item = self
531 .classify(import_to_classify, encoder, types)
532 .with_context(|| {
533 format!(
534 "failed to resolve import `{}::{}`",
535 import.module, import.name,
536 )
537 })?;
538 self.insert_import(import, item)
539 }
540
541 fn classify(
547 &self,
548 import: wasmparser::Import<'_>,
549 encoder: &ComponentEncoder,
550 types: TypesRef<'_>,
551 ) -> Result<Import> {
552 if import.module == "env" && import.name == "memory" {
555 return Ok(Import::MainModuleMemory);
556 }
557
558 if import.module == "__main_module__" {
560 return Ok(Import::MainModuleExport {
561 name: import.name.to_string(),
562 kind: match import.ty {
563 TypeRef::Func(_) => ExportKind::Func,
564 TypeRef::Table(_) => ExportKind::Table,
565 TypeRef::Memory(_) => ExportKind::Memory,
566 TypeRef::Global(_) => ExportKind::Global,
567 TypeRef::Tag(_) => ExportKind::Tag,
568 TypeRef::FuncExact(_) => bail!("Unexpected func_exact export"),
569 },
570 });
571 }
572
573 let ty_index = match import.ty {
574 TypeRef::Func(ty) => ty,
575 _ => bail!("module is only allowed to import functions"),
576 };
577 let ty = types[types.core_type_at_in_module(ty_index)].unwrap_func();
578
579 if encoder.adapters.contains_key(import.module) {
582 return Ok(Import::AdapterExport {
583 adapter: import.module.to_string(),
584 func: import.name.to_string(),
585 ty: ty.clone(),
586 });
587 }
588
589 let (module, names) = match import.module.strip_prefix("cm32p2") {
590 Some(suffix) => (suffix, STANDARD),
591 None if encoder.reject_legacy_names => (import.module, STANDARD),
592 None => (import.module, LEGACY),
593 };
594 self.classify_component_model_import(module, import.name, encoder, ty, names)
595 }
596
597 fn classify_component_model_import(
600 &self,
601 module: &str,
602 name: &str,
603 encoder: &ComponentEncoder,
604 ty: &FuncType,
605 names: &dyn NameMangling,
606 ) -> Result<Import> {
607 let resolve = &encoder.metadata.resolve;
608 let world_id = encoder.metadata.world;
609 let world = &resolve.worlds[world_id];
610
611 if module == names.import_root() {
612 if names.error_context_drop(name) {
613 let expected = FuncType::new([ValType::I32], []);
614 validate_func_sig(name, &expected, ty)?;
615 return Ok(Import::ErrorContextDrop);
616 }
617
618 if names.backpressure_inc(name) {
619 let expected = FuncType::new([], []);
620 validate_func_sig(name, &expected, ty)?;
621 return Ok(Import::BackpressureInc);
622 }
623
624 if names.backpressure_dec(name) {
625 let expected = FuncType::new([], []);
626 validate_func_sig(name, &expected, ty)?;
627 return Ok(Import::BackpressureDec);
628 }
629
630 if names.waitable_set_new(name) {
631 let expected = FuncType::new([], [ValType::I32]);
632 validate_func_sig(name, &expected, ty)?;
633 return Ok(Import::WaitableSetNew);
634 }
635
636 if let Some(info) = names.waitable_set_wait(name) {
637 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
638 validate_func_sig(name, &expected, ty)?;
639 return Ok(Import::WaitableSetWait {
640 cancellable: info.cancellable,
641 });
642 }
643
644 if let Some(info) = names.waitable_set_poll(name) {
645 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
646 validate_func_sig(name, &expected, ty)?;
647 return Ok(Import::WaitableSetPoll {
648 cancellable: info.cancellable,
649 });
650 }
651
652 if names.waitable_set_drop(name) {
653 let expected = FuncType::new([ValType::I32], []);
654 validate_func_sig(name, &expected, ty)?;
655 return Ok(Import::WaitableSetDrop);
656 }
657
658 if names.waitable_join(name) {
659 let expected = FuncType::new([ValType::I32; 2], []);
660 validate_func_sig(name, &expected, ty)?;
661 return Ok(Import::WaitableJoin);
662 }
663
664 if let Some(info) = names.thread_yield(name) {
665 let expected = FuncType::new([], [ValType::I32]);
666 validate_func_sig(name, &expected, ty)?;
667 return Ok(Import::ThreadYield {
668 cancellable: info.cancellable,
669 });
670 }
671
672 if names.subtask_drop(name) {
673 let expected = FuncType::new([ValType::I32], []);
674 validate_func_sig(name, &expected, ty)?;
675 return Ok(Import::SubtaskDrop);
676 }
677
678 if let Some(info) = names.subtask_cancel(name) {
679 let expected = FuncType::new([ValType::I32], [ValType::I32]);
680 validate_func_sig(name, &expected, ty)?;
681 return Ok(Import::SubtaskCancel {
682 async_: info.async_lowered,
683 });
684 }
685
686 if let Some(encoding) = names.error_context_new(name) {
687 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
688 validate_func_sig(name, &expected, ty)?;
689 return Ok(Import::ErrorContextNew { encoding });
690 }
691
692 if let Some(encoding) = names.error_context_debug_message(name) {
693 let expected = FuncType::new([ValType::I32; 2], []);
694 validate_func_sig(name, &expected, ty)?;
695 return Ok(Import::ErrorContextDebugMessage { encoding });
696 }
697
698 if let Some((slot_ty, slot)) = names.context_get(name) {
699 let expected = FuncType::new([], [slot_ty]);
700 validate_func_sig(name, &expected, ty)?;
701 return Ok(Import::ContextGet { ty: slot_ty, slot });
702 }
703 if let Some((slot_ty, slot)) = names.context_set(name) {
704 let expected = FuncType::new([slot_ty], []);
705 validate_func_sig(name, &expected, ty)?;
706 return Ok(Import::ContextSet { ty: slot_ty, slot });
707 }
708 if names.thread_index(name) {
709 let expected = FuncType::new([], [ValType::I32]);
710 validate_func_sig(name, &expected, ty)?;
711 return Ok(Import::ThreadIndex);
712 }
713 if names.thread_new_indirect(name) {
714 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
715 validate_func_sig(name, &expected, ty)?;
716 return Ok(Import::ThreadNewIndirect);
717 }
718 if let Some(info) = names.thread_suspend_to_suspended(name) {
719 let expected = FuncType::new([ValType::I32], [ValType::I32]);
720 validate_func_sig(name, &expected, ty)?;
721 return Ok(Import::ThreadSuspendToSuspended {
722 cancellable: info.cancellable,
723 });
724 }
725 if let Some(info) = names.thread_suspend(name) {
726 let expected = FuncType::new([], [ValType::I32]);
727 validate_func_sig(name, &expected, ty)?;
728 return Ok(Import::ThreadSuspend {
729 cancellable: info.cancellable,
730 });
731 }
732 if let Some(info) = names.thread_suspend_to(name) {
733 let expected = FuncType::new([ValType::I32], [ValType::I32]);
734 validate_func_sig(name, &expected, ty)?;
735 return Ok(Import::ThreadSuspendTo {
736 cancellable: info.cancellable,
737 });
738 }
739 if names.thread_unsuspend(name) {
740 let expected = FuncType::new([ValType::I32], []);
741 validate_func_sig(name, &expected, ty)?;
742 return Ok(Import::ThreadUnsuspend);
743 }
744 if let Some(info) = names.thread_yield_to_suspended(name) {
745 let expected = FuncType::new([ValType::I32], [ValType::I32]);
746 validate_func_sig(name, &expected, ty)?;
747 return Ok(Import::ThreadYieldToSuspended {
748 cancellable: info.cancellable,
749 });
750 }
751
752 let (key_name, abi) = names.world_key_name_and_abi(name);
753 let key = WorldKey::Name(key_name.to_string());
754 if let Some(WorldItem::Function(func)) = world.imports.get(&key) {
755 validate_func(resolve, ty, func, abi)?;
756 return Ok(Import::WorldFunc(key, func.name.clone(), abi));
757 }
758
759 if let Some(import) =
760 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, true, names)?
761 {
762 return Ok(import);
763 }
764
765 match world.imports.get(&key) {
766 Some(_) => bail!("expected world top-level import `{name}` to be a function"),
767 None => bail!("no top-level imported function `{name}` specified"),
768 }
769 }
770
771 if matches!(
773 module.strip_prefix(names.import_exported_intrinsic_prefix()),
774 Some(module) if module == names.import_root()
775 ) {
776 if let Some(import) =
777 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, false, names)?
778 {
779 return Ok(import);
780 }
781 }
782
783 let interface = match module.strip_prefix(names.import_non_root_prefix()) {
784 Some(name) => name,
785 None => bail!("unknown or invalid component model import syntax"),
786 };
787
788 if let Some(interface) = interface.strip_prefix(names.import_exported_intrinsic_prefix()) {
789 let (key, id) = names.module_to_interface(interface, resolve, &world.exports)?;
790
791 if let Some(import) =
792 self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, false, names)?
793 {
794 return Ok(import);
795 }
796 bail!("unknown function `{name}`")
797 }
798
799 let (key, id) = names.module_to_interface(interface, resolve, &world.imports)?;
800 let interface = &resolve.interfaces[id];
801 let (function_name, abi) = names.interface_function_name_and_abi(name);
802 if let Some(f) = interface.functions.get(function_name) {
803 validate_func(resolve, ty, f, abi).with_context(|| {
804 let name = resolve.name_world_key(&key);
805 format!("failed to validate import interface `{name}`")
806 })?;
807 return Ok(Import::InterfaceFunc(key, id, f.name.clone(), abi));
808 }
809
810 if let Some(import) =
811 self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, true, names)?
812 {
813 return Ok(import);
814 }
815 bail!(
816 "import interface `{module}` is missing function \
817 `{name}` that is required by the module",
818 )
819 }
820
821 fn maybe_classify_wit_intrinsic(
849 &self,
850 name: &str,
851 key_and_id: Option<(WorldKey, InterfaceId)>,
852 encoder: &ComponentEncoder,
853 ty: &FuncType,
854 import: bool,
855 names: &dyn NameMangling,
856 ) -> Result<Option<Import>> {
857 let resolve = &encoder.metadata.resolve;
858 let world_id = encoder.metadata.world;
859 let world = &resolve.worlds[world_id];
860
861 let (key, id) = match key_and_id {
866 Some((key, id)) => (Some(key), Some(id)),
867 None => (None, None),
868 };
869
870 let resource_test = |name: &str| match id {
872 Some(id) => resource_test_for_interface(resolve, id)(name),
873 None => resource_test_for_world(resolve, world_id)(name),
874 };
875
876 if let Some(resource) = names.resource_drop_name(name) {
878 if let Some(resource_id) = resource_test(resource) {
879 let key = key.unwrap_or_else(|| WorldKey::Name(resource.to_string()));
880 let expected = FuncType::new([ValType::I32], []);
881 validate_func_sig(name, &expected, ty)?;
882 return Ok(Some(if import {
883 Import::ImportedResourceDrop(key, id, resource_id)
884 } else {
885 Import::ExportedResourceDrop(key, resource_id)
886 }));
887 }
888 }
889
890 if !import {
893 if let Some(name) = names.resource_new_name(name) {
894 if let Some(id) = resource_test(name) {
895 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
896 let expected = FuncType::new([ValType::I32], [ValType::I32]);
897 validate_func_sig(name, &expected, ty)?;
898 return Ok(Some(Import::ExportedResourceNew(key, id)));
899 }
900 }
901 if let Some(name) = names.resource_rep_name(name) {
902 if let Some(id) = resource_test(name) {
903 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
904 let expected = FuncType::new([ValType::I32], [ValType::I32]);
905 validate_func_sig(name, &expected, ty)?;
906 return Ok(Some(Import::ExportedResourceRep(key, id)));
907 }
908 }
909 if let Some(name) = names.task_return_name(name) {
910 let func = get_function(resolve, world, name, id, import)?;
911 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
912 return Ok(Some(Import::ExportedTaskReturn(key, id, func.clone())));
915 }
916 if names.task_cancel(name) {
917 let expected = FuncType::new([], []);
918 validate_func_sig(name, &expected, ty)?;
919 return Ok(Some(Import::ExportedTaskCancel));
920 }
921 }
922
923 let lookup_context = PayloadLookupContext {
924 resolve,
925 world,
926 key,
927 id,
928 import,
929 };
930
931 let import = if let Some(info) = names.future_new(&lookup_context, name) {
935 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
936 Import::FutureNew(info)
937 } else if let Some(info) = names.future_write(&lookup_context, name) {
938 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
939 Import::FutureWrite {
940 async_: info.async_lowered,
941 info: info.inner,
942 }
943 } else if let Some(info) = names.future_read(&lookup_context, name) {
944 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
945 Import::FutureRead {
946 async_: info.async_lowered,
947 info: info.inner,
948 }
949 } else if let Some(info) = names.future_cancel_write(&lookup_context, name) {
950 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
951 Import::FutureCancelWrite {
952 async_: info.async_lowered,
953 info: info.inner,
954 }
955 } else if let Some(info) = names.future_cancel_read(&lookup_context, name) {
956 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
957 Import::FutureCancelRead {
958 async_: info.async_lowered,
959 info: info.inner,
960 }
961 } else if let Some(info) = names.future_drop_writable(&lookup_context, name) {
962 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
963 Import::FutureDropWritable(info)
964 } else if let Some(info) = names.future_drop_readable(&lookup_context, name) {
965 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
966 Import::FutureDropReadable(info)
967 } else if let Some(info) = names.stream_new(&lookup_context, name) {
968 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
969 Import::StreamNew(info)
970 } else if let Some(info) = names.stream_write(&lookup_context, name) {
971 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
972 Import::StreamWrite {
973 async_: info.async_lowered,
974 info: info.inner,
975 }
976 } else if let Some(info) = names.stream_read(&lookup_context, name) {
977 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
978 Import::StreamRead {
979 async_: info.async_lowered,
980 info: info.inner,
981 }
982 } else if let Some(info) = names.stream_cancel_write(&lookup_context, name) {
983 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
984 Import::StreamCancelWrite {
985 async_: info.async_lowered,
986 info: info.inner,
987 }
988 } else if let Some(info) = names.stream_cancel_read(&lookup_context, name) {
989 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
990 Import::StreamCancelRead {
991 async_: info.async_lowered,
992 info: info.inner,
993 }
994 } else if let Some(info) = names.stream_drop_writable(&lookup_context, name) {
995 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
996 Import::StreamDropWritable(info)
997 } else if let Some(info) = names.stream_drop_readable(&lookup_context, name) {
998 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
999 Import::StreamDropReadable(info)
1000 } else {
1001 return Ok(None);
1002 };
1003 Ok(Some(import))
1004 }
1005
1006 fn classify_import_with_library(
1007 &mut self,
1008 import: wasmparser::Import<'_>,
1009 library_info: Option<&LibraryInfo>,
1010 ) -> Result<bool> {
1011 let info = match library_info {
1012 Some(info) => info,
1013 None => return Ok(false),
1014 };
1015 let Some((_, instance)) = info
1016 .arguments
1017 .iter()
1018 .find(|(name, _items)| *name == import.module)
1019 else {
1020 return Ok(false);
1021 };
1022 match instance {
1023 Instance::MainOrAdapter(module) => match self.names.get(import.module) {
1024 Some(ImportInstance::Whole(which)) => {
1025 if which != module {
1026 bail!("different whole modules imported under the same name");
1027 }
1028 }
1029 Some(ImportInstance::Names(_)) => {
1030 bail!("cannot mix individual imports and whole module imports")
1031 }
1032 None => {
1033 let instance = ImportInstance::Whole(module.clone());
1034 self.names.insert(import.module.to_string(), instance);
1035 }
1036 },
1037 Instance::Items(items) => {
1038 let Some(item) = items.iter().find(|i| i.alias == import.name) else {
1039 return Ok(false);
1040 };
1041 self.insert_import(import, Import::Item(item.clone()))?;
1042 }
1043 }
1044 Ok(true)
1045 }
1046
1047 fn insert_import(&mut self, import: wasmparser::Import<'_>, item: Import) -> Result<()> {
1051 let entry = self
1052 .names
1053 .entry(import.module.to_string())
1054 .or_insert(ImportInstance::Names(IndexMap::default()));
1055 let names = match entry {
1056 ImportInstance::Names(names) => names,
1057 _ => bail!("cannot mix individual imports with module imports"),
1058 };
1059 let entry = match names.entry(import.name.to_string()) {
1060 Entry::Occupied(_) => {
1061 bail!(
1062 "module has duplicate import for `{}::{}`",
1063 import.module,
1064 import.name
1065 );
1066 }
1067 Entry::Vacant(v) => v,
1068 };
1069 log::trace!(
1070 "classifying import `{}::{} as {item:?}",
1071 import.module,
1072 import.name
1073 );
1074 entry.insert(item);
1075 Ok(())
1076 }
1077}
1078
1079#[derive(Default)]
1082pub struct ExportMap {
1083 names: IndexMap<String, Export>,
1084 raw_exports: IndexMap<String, FuncType>,
1085}
1086
1087#[derive(Debug)]
1090pub enum Export {
1091 WorldFunc(WorldKey, String, AbiVariant),
1094
1095 WorldFuncPostReturn(WorldKey),
1097
1098 InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
1100
1101 InterfaceFuncPostReturn(WorldKey, String),
1103
1104 ResourceDtor(TypeId),
1106
1107 Memory,
1109
1110 GeneralPurposeRealloc,
1112
1113 GeneralPurposeExportRealloc,
1115
1116 GeneralPurposeImportRealloc,
1118
1119 Initialize,
1121
1122 ReallocForAdapter,
1124
1125 WorldFuncCallback(WorldKey),
1126
1127 InterfaceFuncCallback(WorldKey, String),
1128
1129 IndirectFunctionTable,
1131
1132 WasmInitTask,
1134
1135 WasmInitAsyncTask,
1137}
1138
1139impl ExportMap {
1140 fn add(
1141 &mut self,
1142 export: wasmparser::Export<'_>,
1143 encoder: &ComponentEncoder,
1144 exports: &IndexSet<WorldKey>,
1145 types: TypesRef<'_>,
1146 ) -> Result<()> {
1147 if let Some(item) = self.classify(export, encoder, exports, types)? {
1148 log::debug!("classifying export `{}` as {item:?}", export.name);
1149 let prev = self.names.insert(export.name.to_string(), item);
1150 assert!(prev.is_none());
1151 }
1152 Ok(())
1153 }
1154
1155 fn classify(
1156 &mut self,
1157 export: wasmparser::Export<'_>,
1158 encoder: &ComponentEncoder,
1159 exports: &IndexSet<WorldKey>,
1160 types: TypesRef<'_>,
1161 ) -> Result<Option<Export>> {
1162 match export.kind {
1163 ExternalKind::Func => {
1164 let ty = types[types.core_function_at(export.index)].unwrap_func();
1165 self.raw_exports.insert(export.name.to_string(), ty.clone());
1166 }
1167 _ => {}
1168 }
1169
1170 if export.name == "canonical_abi_realloc" {
1172 return Ok(Some(Export::GeneralPurposeRealloc));
1173 } else if export.name == "cabi_import_realloc" {
1174 return Ok(Some(Export::GeneralPurposeImportRealloc));
1175 } else if export.name == "cabi_export_realloc" {
1176 return Ok(Some(Export::GeneralPurposeExportRealloc));
1177 } else if export.name == "cabi_realloc_adapter" {
1178 return Ok(Some(Export::ReallocForAdapter));
1179 }
1180
1181 let (name, names) = match export.name.strip_prefix("cm32p2") {
1182 Some(name) => (name, STANDARD),
1183 None if encoder.reject_legacy_names => return Ok(None),
1184 None => (export.name, LEGACY),
1185 };
1186
1187 if let Some(export) = self
1188 .classify_component_export(names, name, &export, encoder, exports, types)
1189 .with_context(|| format!("failed to classify export `{}`", export.name))?
1190 {
1191 return Ok(Some(export));
1192 }
1193 log::debug!("unknown export `{}`", export.name);
1194 Ok(None)
1195 }
1196
1197 fn classify_component_export(
1198 &mut self,
1199 names: &dyn NameMangling,
1200 name: &str,
1201 export: &wasmparser::Export<'_>,
1202 encoder: &ComponentEncoder,
1203 exports: &IndexSet<WorldKey>,
1204 types: TypesRef<'_>,
1205 ) -> Result<Option<Export>> {
1206 let resolve = &encoder.metadata.resolve;
1207 let world = encoder.metadata.world;
1208 match export.kind {
1209 ExternalKind::Func => {}
1210 ExternalKind::Memory => {
1211 if name == names.export_memory() {
1212 return Ok(Some(Export::Memory));
1213 }
1214 return Ok(None);
1215 }
1216 ExternalKind::Table => {
1217 if Some(name) == names.export_indirect_function_table() {
1218 return Ok(Some(Export::IndirectFunctionTable));
1219 }
1220 return Ok(None);
1221 }
1222 _ => return Ok(None),
1223 }
1224 let ty = types[types.core_function_at(export.index)].unwrap_func();
1225
1226 if name == names.export_realloc() {
1228 let expected = FuncType::new([ValType::I32; 4], [ValType::I32]);
1229 validate_func_sig(name, &expected, ty)?;
1230 return Ok(Some(Export::GeneralPurposeRealloc));
1231 } else if name == names.export_initialize() {
1232 let expected = FuncType::new([], []);
1233 validate_func_sig(name, &expected, ty)?;
1234 return Ok(Some(Export::Initialize));
1235 } else if Some(name) == names.export_wasm_init_task() {
1236 let expected = FuncType::new([], []);
1237 validate_func_sig(name, &expected, ty)?;
1238 return Ok(Some(Export::WasmInitTask));
1239 } else if Some(name) == names.export_wasm_init_async_task() {
1240 let expected = FuncType::new([], []);
1241 validate_func_sig(name, &expected, ty)?;
1242 return Ok(Some(Export::WasmInitAsyncTask));
1243 }
1244
1245 let full_name = name;
1246 let (abi, name) = if let Some(name) = names.async_lift_name(name) {
1247 (AbiVariant::GuestExportAsync, name)
1248 } else if let Some(name) = names.async_lift_stackful_name(name) {
1249 (AbiVariant::GuestExportAsyncStackful, name)
1250 } else {
1251 (AbiVariant::GuestExport, name)
1252 };
1253
1254 if let Some((key, id, f)) = names.match_wit_export(name, resolve, world, exports) {
1256 validate_func(resolve, ty, f, abi).with_context(|| {
1257 let key = resolve.name_world_key(key);
1258 format!("failed to validate export for `{key}`")
1259 })?;
1260 match id {
1261 Some(id) => {
1262 return Ok(Some(Export::InterfaceFunc(
1263 key.clone(),
1264 id,
1265 f.name.clone(),
1266 abi,
1267 )));
1268 }
1269 None => {
1270 return Ok(Some(Export::WorldFunc(key.clone(), f.name.clone(), abi)));
1271 }
1272 }
1273 }
1274
1275 if let Some(remaining) = names.strip_post_return(name) {
1277 if let Some((key, id, f)) = names.match_wit_export(remaining, resolve, world, exports) {
1278 validate_post_return(resolve, ty, f).with_context(|| {
1279 let key = resolve.name_world_key(key);
1280 format!("failed to validate export for `{key}`")
1281 })?;
1282 match id {
1283 Some(_id) => {
1284 return Ok(Some(Export::InterfaceFuncPostReturn(
1285 key.clone(),
1286 f.name.clone(),
1287 )));
1288 }
1289 None => {
1290 return Ok(Some(Export::WorldFuncPostReturn(key.clone())));
1291 }
1292 }
1293 }
1294 }
1295
1296 if let Some(suffix) = names.async_lift_callback_name(full_name) {
1297 if let Some((key, id, f)) = names.match_wit_export(suffix, resolve, world, exports) {
1298 validate_func_sig(
1299 full_name,
1300 &FuncType::new([ValType::I32; 3], [ValType::I32]),
1301 ty,
1302 )?;
1303 return Ok(Some(if id.is_some() {
1304 Export::InterfaceFuncCallback(key.clone(), f.name.clone())
1305 } else {
1306 Export::WorldFuncCallback(key.clone())
1307 }));
1308 }
1309 }
1310
1311 if let Some(dtor) = names.match_wit_resource_dtor(name, resolve, world, exports) {
1313 let expected = FuncType::new([ValType::I32], []);
1314 validate_func_sig(full_name, &expected, ty)?;
1315 return Ok(Some(Export::ResourceDtor(dtor)));
1316 }
1317
1318 Ok(None)
1319 }
1320
1321 pub fn post_return(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1324 self.find(|m| match m {
1325 Export::WorldFuncPostReturn(k) => k == key,
1326 Export::InterfaceFuncPostReturn(k, f) => k == key && func.name == *f,
1327 _ => false,
1328 })
1329 }
1330
1331 pub fn callback(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1334 self.find(|m| match m {
1335 Export::WorldFuncCallback(k) => k == key,
1336 Export::InterfaceFuncCallback(k, f) => k == key && func.name == *f,
1337 _ => false,
1338 })
1339 }
1340
1341 pub fn abi(&self, key: &WorldKey, func: &Function) -> Option<AbiVariant> {
1342 self.names.values().find_map(|m| match m {
1343 Export::WorldFunc(k, f, abi) if k == key && func.name == *f => Some(*abi),
1344 Export::InterfaceFunc(k, _, f, abi) if k == key && func.name == *f => Some(*abi),
1345 _ => None,
1346 })
1347 }
1348
1349 pub fn export_realloc_for(&self, key: &WorldKey, func: &str) -> Option<&str> {
1352 let _ = (key, func);
1356
1357 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeExportRealloc)) {
1358 return Some(name);
1359 }
1360 self.general_purpose_realloc()
1361 }
1362
1363 pub fn import_realloc_for(&self, interface: Option<InterfaceId>, func: &str) -> Option<&str> {
1366 let _ = (interface, func);
1370
1371 self.import_realloc_fallback()
1372 }
1373
1374 pub fn import_realloc_fallback(&self) -> Option<&str> {
1378 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeImportRealloc)) {
1379 return Some(name);
1380 }
1381 self.general_purpose_realloc()
1382 }
1383
1384 pub fn realloc_to_import_into_adapter(&self) -> Option<&str> {
1386 if let Some(name) = self.find(|m| matches!(m, Export::ReallocForAdapter)) {
1387 return Some(name);
1388 }
1389 self.general_purpose_realloc()
1390 }
1391
1392 fn general_purpose_realloc(&self) -> Option<&str> {
1393 self.find(|m| matches!(m, Export::GeneralPurposeRealloc))
1394 }
1395
1396 pub fn memory(&self) -> Option<&str> {
1398 self.find(|m| matches!(m, Export::Memory))
1399 }
1400
1401 pub fn indirect_function_table(&self) -> Option<&str> {
1403 self.find(|t| matches!(t, Export::IndirectFunctionTable))
1404 }
1405
1406 pub fn wasm_init_task(&self) -> Option<&str> {
1408 self.find(|t| matches!(t, Export::WasmInitTask))
1409 }
1410
1411 pub fn wasm_init_async_task(&self) -> Option<&str> {
1413 self.find(|t| matches!(t, Export::WasmInitAsyncTask))
1414 }
1415
1416 pub fn initialize(&self) -> Option<&str> {
1418 self.find(|m| matches!(m, Export::Initialize))
1419 }
1420
1421 pub fn resource_dtor(&self, ty: TypeId) -> Option<&str> {
1423 self.find(|m| match m {
1424 Export::ResourceDtor(t) => *t == ty,
1425 _ => false,
1426 })
1427 }
1428
1429 fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1432 let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1433 Some(name)
1434 }
1435
1436 pub fn iter(&self) -> impl Iterator<Item = (&str, &Export)> + '_ {
1438 self.names.iter().map(|(n, e)| (n.as_str(), e))
1439 }
1440
1441 fn validate(&self, encoder: &ComponentEncoder, exports: &IndexSet<WorldKey>) -> Result<()> {
1442 let resolve = &encoder.metadata.resolve;
1443 let world = encoder.metadata.world;
1444 if self
1447 .names
1448 .values()
1449 .filter(|m| matches!(m, Export::Memory))
1450 .count()
1451 > 1
1452 {
1453 bail!("cannot componentize module that exports multiple memories")
1454 }
1455
1456 for (name, export) in &self.names {
1458 match export {
1459 Export::WorldFunc(_, _, AbiVariant::GuestExportAsync) => {
1460 if !matches!(
1461 self.names.get(&format!("[callback]{name}")),
1462 Some(Export::WorldFuncCallback(_))
1463 ) {
1464 bail!("missing callback for `{name}`");
1465 }
1466 }
1467 Export::InterfaceFunc(_, _, _, AbiVariant::GuestExportAsync) => {
1468 if !matches!(
1469 self.names.get(&format!("[callback]{name}")),
1470 Some(Export::InterfaceFuncCallback(_, _))
1471 ) {
1472 bail!("missing callback for `{name}`");
1473 }
1474 }
1475 _ => {}
1476 }
1477 }
1478
1479 for export in exports {
1481 let require_interface_func = |interface: InterfaceId, name: &str| -> Result<()> {
1482 let result = self.find(|e| match e {
1483 Export::InterfaceFunc(_, id, s, _) => interface == *id && name == s,
1484 _ => false,
1485 });
1486 if result.is_some() {
1487 Ok(())
1488 } else {
1489 let export = resolve.name_world_key(export);
1490 bail!("failed to find export of interface `{export}` function `{name}`")
1491 }
1492 };
1493 let require_world_func = |name: &str| -> Result<()> {
1494 let result = self.find(|e| match e {
1495 Export::WorldFunc(_, s, _) => name == s,
1496 _ => false,
1497 });
1498 if result.is_some() {
1499 Ok(())
1500 } else {
1501 bail!("failed to find export of function `{name}`")
1502 }
1503 };
1504 match &resolve.worlds[world].exports[export] {
1505 WorldItem::Interface { id, .. } => {
1506 for (name, _) in resolve.interfaces[*id].functions.iter() {
1507 require_interface_func(*id, name)?;
1508 }
1509 }
1510 WorldItem::Function(f) => {
1511 require_world_func(&f.name)?;
1512 }
1513 WorldItem::Type { .. } => unreachable!(),
1514 }
1515 }
1516
1517 Ok(())
1518 }
1519}
1520
1521struct MaybeCancellable<T> {
1523 #[allow(unused)]
1524 inner: T,
1525 cancellable: bool,
1526}
1527
1528struct MaybeAsyncLowered<T> {
1530 inner: T,
1531 async_lowered: bool,
1532}
1533
1534struct PayloadLookupContext<'a> {
1537 resolve: &'a Resolve,
1538 world: &'a World,
1539 id: Option<InterfaceId>,
1540 import: bool,
1541 key: Option<WorldKey>,
1542}
1543
1544trait NameMangling {
1566 fn import_root(&self) -> &str;
1567 fn import_non_root_prefix(&self) -> &str;
1568 fn import_exported_intrinsic_prefix(&self) -> &str;
1569 fn export_memory(&self) -> &str;
1570 fn export_initialize(&self) -> &str;
1571 fn export_realloc(&self) -> &str;
1572 fn export_indirect_function_table(&self) -> Option<&str>;
1573 fn export_wasm_init_task(&self) -> Option<&str>;
1574 fn export_wasm_init_async_task(&self) -> Option<&str>;
1575 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1576 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1577 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1578 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1579 fn task_cancel(&self, name: &str) -> bool;
1580 fn backpressure_inc(&self, name: &str) -> bool;
1581 fn backpressure_dec(&self, name: &str) -> bool;
1582 fn waitable_set_new(&self, name: &str) -> bool;
1583 fn waitable_set_wait(&self, name: &str) -> Option<MaybeCancellable<()>>;
1584 fn waitable_set_poll(&self, name: &str) -> Option<MaybeCancellable<()>>;
1585 fn waitable_set_drop(&self, name: &str) -> bool;
1586 fn waitable_join(&self, name: &str) -> bool;
1587 fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>>;
1588 fn subtask_drop(&self, name: &str) -> bool;
1589 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>>;
1590 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1591 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1592 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1593 fn error_context_new(&self, name: &str) -> Option<StringEncoding>;
1594 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding>;
1595 fn error_context_drop(&self, name: &str) -> bool;
1596 fn context_get(&self, name: &str) -> Option<(ValType, u32)>;
1597 fn context_set(&self, name: &str) -> Option<(ValType, u32)>;
1598 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1599 fn future_write(
1600 &self,
1601 lookup_context: &PayloadLookupContext,
1602 name: &str,
1603 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1604 fn future_read(
1605 &self,
1606 lookup_context: &PayloadLookupContext,
1607 name: &str,
1608 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1609 fn future_cancel_write(
1610 &self,
1611 lookup_context: &PayloadLookupContext,
1612 name: &str,
1613 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1614 fn future_cancel_read(
1615 &self,
1616 lookup_context: &PayloadLookupContext,
1617 name: &str,
1618 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1619 fn future_drop_writable(
1620 &self,
1621 lookup_context: &PayloadLookupContext,
1622 name: &str,
1623 ) -> Option<PayloadInfo>;
1624 fn future_drop_readable(
1625 &self,
1626 lookup_context: &PayloadLookupContext,
1627 name: &str,
1628 ) -> Option<PayloadInfo>;
1629 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1630 fn stream_write(
1631 &self,
1632 lookup_context: &PayloadLookupContext,
1633 name: &str,
1634 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1635 fn stream_read(
1636 &self,
1637 lookup_context: &PayloadLookupContext,
1638 name: &str,
1639 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1640 fn stream_cancel_write(
1641 &self,
1642 lookup_context: &PayloadLookupContext,
1643 name: &str,
1644 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1645 fn stream_cancel_read(
1646 &self,
1647 lookup_context: &PayloadLookupContext,
1648 name: &str,
1649 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1650 fn stream_drop_writable(
1651 &self,
1652 lookup_context: &PayloadLookupContext,
1653 name: &str,
1654 ) -> Option<PayloadInfo>;
1655 fn stream_drop_readable(
1656 &self,
1657 lookup_context: &PayloadLookupContext,
1658 name: &str,
1659 ) -> Option<PayloadInfo>;
1660 fn thread_index(&self, name: &str) -> bool;
1661 fn thread_new_indirect(&self, name: &str) -> bool;
1662 fn thread_suspend_to_suspended(&self, name: &str) -> Option<MaybeCancellable<()>>;
1663 fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>>;
1664 fn thread_suspend_to(&self, name: &str) -> Option<MaybeCancellable<()>>;
1665 fn thread_unsuspend(&self, name: &str) -> bool;
1666 fn thread_yield_to_suspended(&self, name: &str) -> Option<MaybeCancellable<()>>;
1667 fn module_to_interface(
1668 &self,
1669 module: &str,
1670 resolve: &Resolve,
1671 items: &IndexMap<WorldKey, WorldItem>,
1672 ) -> Result<(WorldKey, InterfaceId)>;
1673 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str>;
1674 fn match_wit_export<'a>(
1675 &self,
1676 export_name: &str,
1677 resolve: &'a Resolve,
1678 world: WorldId,
1679 exports: &'a IndexSet<WorldKey>,
1680 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)>;
1681 fn match_wit_resource_dtor<'a>(
1682 &self,
1683 export_name: &str,
1684 resolve: &'a Resolve,
1685 world: WorldId,
1686 exports: &'a IndexSet<WorldKey>,
1687 ) -> Option<TypeId>;
1688 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1689 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1690}
1691
1692struct Standard;
1695
1696const STANDARD: &'static dyn NameMangling = &Standard;
1697
1698impl NameMangling for Standard {
1699 fn import_root(&self) -> &str {
1700 ""
1701 }
1702 fn import_non_root_prefix(&self) -> &str {
1703 "|"
1704 }
1705 fn import_exported_intrinsic_prefix(&self) -> &str {
1706 "_ex_"
1707 }
1708 fn export_memory(&self) -> &str {
1709 "_memory"
1710 }
1711 fn export_initialize(&self) -> &str {
1712 "_initialize"
1713 }
1714 fn export_realloc(&self) -> &str {
1715 "_realloc"
1716 }
1717 fn export_indirect_function_table(&self) -> Option<&str> {
1718 None
1719 }
1720 fn export_wasm_init_task(&self) -> Option<&str> {
1721 None
1722 }
1723 fn export_wasm_init_async_task(&self) -> Option<&str> {
1724 None
1725 }
1726 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1727 name.strip_suffix("_drop")
1728 }
1729 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1730 name.strip_suffix("_new")
1731 }
1732 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1733 name.strip_suffix("_rep")
1734 }
1735 fn task_return_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1736 None
1737 }
1738 fn task_cancel(&self, _name: &str) -> bool {
1739 false
1740 }
1741 fn backpressure_inc(&self, _name: &str) -> bool {
1742 false
1743 }
1744 fn backpressure_dec(&self, _name: &str) -> bool {
1745 false
1746 }
1747 fn waitable_set_new(&self, _name: &str) -> bool {
1748 false
1749 }
1750 fn waitable_set_wait(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1751 None
1752 }
1753 fn waitable_set_poll(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1754 None
1755 }
1756 fn waitable_set_drop(&self, _name: &str) -> bool {
1757 false
1758 }
1759 fn waitable_join(&self, _name: &str) -> bool {
1760 false
1761 }
1762 fn thread_yield(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1763 None
1764 }
1765 fn subtask_drop(&self, _name: &str) -> bool {
1766 false
1767 }
1768 fn subtask_cancel(&self, _name: &str) -> Option<MaybeAsyncLowered<()>> {
1769 None
1770 }
1771 fn async_lift_callback_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1772 None
1773 }
1774 fn async_lift_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1775 None
1776 }
1777 fn async_lift_stackful_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1778 None
1779 }
1780 fn error_context_new(&self, _name: &str) -> Option<StringEncoding> {
1781 None
1782 }
1783 fn error_context_debug_message(&self, _name: &str) -> Option<StringEncoding> {
1784 None
1785 }
1786 fn error_context_drop(&self, _name: &str) -> bool {
1787 false
1788 }
1789 fn context_get(&self, _name: &str) -> Option<(ValType, u32)> {
1790 None
1791 }
1792 fn context_set(&self, _name: &str) -> Option<(ValType, u32)> {
1793 None
1794 }
1795 fn thread_index(&self, _name: &str) -> bool {
1796 false
1797 }
1798 fn thread_new_indirect(&self, _name: &str) -> bool {
1799 false
1800 }
1801 fn thread_suspend_to_suspended(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1802 None
1803 }
1804 fn thread_suspend(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1805 None
1806 }
1807 fn thread_suspend_to(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1808 None
1809 }
1810 fn thread_unsuspend(&self, _name: &str) -> bool {
1811 false
1812 }
1813 fn thread_yield_to_suspended(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1814 None
1815 }
1816 fn future_new(
1817 &self,
1818 _lookup_context: &PayloadLookupContext,
1819 _name: &str,
1820 ) -> Option<PayloadInfo> {
1821 None
1822 }
1823 fn future_write(
1824 &self,
1825 _lookup_context: &PayloadLookupContext,
1826 _name: &str,
1827 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1828 None
1829 }
1830 fn future_read(
1831 &self,
1832 _lookup_context: &PayloadLookupContext,
1833 _name: &str,
1834 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1835 None
1836 }
1837 fn future_cancel_write(
1838 &self,
1839 _lookup_context: &PayloadLookupContext,
1840 _name: &str,
1841 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1842 None
1843 }
1844 fn future_cancel_read(
1845 &self,
1846 _lookup_context: &PayloadLookupContext,
1847 _name: &str,
1848 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1849 None
1850 }
1851 fn future_drop_writable(
1852 &self,
1853 _lookup_context: &PayloadLookupContext,
1854 _name: &str,
1855 ) -> Option<PayloadInfo> {
1856 None
1857 }
1858 fn future_drop_readable(
1859 &self,
1860 _lookup_context: &PayloadLookupContext,
1861 _name: &str,
1862 ) -> Option<PayloadInfo> {
1863 None
1864 }
1865 fn stream_new(
1866 &self,
1867 _lookup_context: &PayloadLookupContext,
1868 _name: &str,
1869 ) -> Option<PayloadInfo> {
1870 None
1871 }
1872 fn stream_write(
1873 &self,
1874 _lookup_context: &PayloadLookupContext,
1875 _name: &str,
1876 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1877 None
1878 }
1879 fn stream_read(
1880 &self,
1881 _lookup_context: &PayloadLookupContext,
1882 _name: &str,
1883 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1884 None
1885 }
1886 fn stream_cancel_write(
1887 &self,
1888 _lookup_context: &PayloadLookupContext,
1889 _name: &str,
1890 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1891 None
1892 }
1893 fn stream_cancel_read(
1894 &self,
1895 _lookup_context: &PayloadLookupContext,
1896 _name: &str,
1897 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1898 None
1899 }
1900 fn stream_drop_writable(
1901 &self,
1902 _lookup_context: &PayloadLookupContext,
1903 _name: &str,
1904 ) -> Option<PayloadInfo> {
1905 None
1906 }
1907 fn stream_drop_readable(
1908 &self,
1909 _lookup_context: &PayloadLookupContext,
1910 _name: &str,
1911 ) -> Option<PayloadInfo> {
1912 None
1913 }
1914 fn module_to_interface(
1915 &self,
1916 interface: &str,
1917 resolve: &Resolve,
1918 items: &IndexMap<WorldKey, WorldItem>,
1919 ) -> Result<(WorldKey, InterfaceId)> {
1920 for (key, item) in items.iter() {
1921 let id = match key {
1922 WorldKey::Name(name) => match item {
1924 WorldItem::Interface { id, .. } if name == interface => *id,
1925 _ => continue,
1926 },
1927 WorldKey::Interface(id) => {
1929 if resolve.canonicalized_id_of(*id).as_deref() != Some(interface) {
1930 continue;
1931 }
1932 *id
1933 }
1934 };
1935 return Ok((key.clone(), id));
1936 }
1937 bail!("failed to find world item corresponding to interface `{interface}`")
1938 }
1939 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
1940 name.strip_suffix("_post")
1941 }
1942 fn match_wit_export<'a>(
1943 &self,
1944 export_name: &str,
1945 resolve: &'a Resolve,
1946 world: WorldId,
1947 exports: &'a IndexSet<WorldKey>,
1948 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
1949 if let Some(world_export_name) = export_name.strip_prefix("||") {
1950 let key = exports.get(&WorldKey::Name(world_export_name.to_string()))?;
1951 match &resolve.worlds[world].exports[key] {
1952 WorldItem::Function(f) => return Some((key, None, f)),
1953 _ => return None,
1954 }
1955 }
1956
1957 let (key, id, func_name) =
1958 self.match_wit_interface(export_name, resolve, world, exports)?;
1959 let func = resolve.interfaces[id].functions.get(func_name)?;
1960 Some((key, Some(id), func))
1961 }
1962
1963 fn match_wit_resource_dtor<'a>(
1964 &self,
1965 export_name: &str,
1966 resolve: &'a Resolve,
1967 world: WorldId,
1968 exports: &'a IndexSet<WorldKey>,
1969 ) -> Option<TypeId> {
1970 let (_key, id, name) =
1971 self.match_wit_interface(export_name.strip_suffix("_dtor")?, resolve, world, exports)?;
1972 let ty = *resolve.interfaces[id].types.get(name)?;
1973 match resolve.types[ty].kind {
1974 TypeDefKind::Resource => Some(ty),
1975 _ => None,
1976 }
1977 }
1978
1979 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
1980 (name, AbiVariant::GuestImport)
1981 }
1982 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
1983 (name, AbiVariant::GuestImport)
1984 }
1985}
1986
1987impl Standard {
1988 fn match_wit_interface<'a, 'b>(
1989 &self,
1990 export_name: &'b str,
1991 resolve: &'a Resolve,
1992 world: WorldId,
1993 exports: &'a IndexSet<WorldKey>,
1994 ) -> Option<(&'a WorldKey, InterfaceId, &'b str)> {
1995 let world = &resolve.worlds[world];
1996 let export_name = export_name.strip_prefix("|")?;
1997
1998 for export in exports {
1999 let id = match &world.exports[export] {
2000 WorldItem::Interface { id, .. } => *id,
2001 WorldItem::Function(_) => continue,
2002 WorldItem::Type { .. } => unreachable!(),
2003 };
2004 let remaining = match export {
2005 WorldKey::Name(name) => export_name.strip_prefix(name),
2006 WorldKey::Interface(_) => {
2007 let prefix = resolve.canonicalized_id_of(id).unwrap();
2008 export_name.strip_prefix(&prefix)
2009 }
2010 };
2011 let item_name = match remaining.and_then(|s| s.strip_prefix("|")) {
2012 Some(name) => name,
2013 None => continue,
2014 };
2015 return Some((export, id, item_name));
2016 }
2017
2018 None
2019 }
2020}
2021
2022struct Legacy;
2025
2026const LEGACY: &'static dyn NameMangling = &Legacy;
2027
2028impl Legacy {
2029 fn prefixed_payload(
2035 &self,
2036 lookup_context: &PayloadLookupContext,
2037 name: &str,
2038 prefix: &str,
2039 ) -> Option<PayloadInfo> {
2040 let (index_or_unit, func_name) = prefixed_intrinsic(name, prefix)?;
2043 let ty = match index_or_unit {
2044 "unit" => {
2045 if name.starts_with("[future") {
2046 PayloadType::UnitFuture
2047 } else if name.starts_with("[stream") {
2048 PayloadType::UnitStream
2049 } else {
2050 unreachable!()
2051 }
2052 }
2053 other => {
2054 let type_index = other.parse::<u32>().ok()? as usize;
2058
2059 let function = get_function(
2064 lookup_context.resolve,
2065 lookup_context.world,
2066 func_name,
2067 lookup_context.id,
2068 lookup_context.import,
2069 )
2070 .ok()?;
2071 PayloadType::Type {
2072 id: *function
2073 .find_futures_and_streams(lookup_context.resolve)
2074 .get(type_index)?,
2075 function: function.name.clone(),
2076 }
2077 }
2078 };
2079
2080 Some(PayloadInfo {
2082 name: name.to_string(),
2083 ty,
2084 key: lookup_context
2085 .key
2086 .clone()
2087 .unwrap_or_else(|| WorldKey::Name(name.to_string())),
2088 interface: lookup_context.id,
2089 imported: lookup_context.import,
2090 })
2091 }
2092
2093 fn maybe_async_lowered_payload(
2094 &self,
2095 lookup_context: &PayloadLookupContext,
2096 name: &str,
2097 prefix: &str,
2098 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2099 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2100 let payload = self.prefixed_payload(lookup_context, clean_name, prefix)?;
2101 Some(MaybeAsyncLowered {
2102 inner: payload,
2103 async_lowered,
2104 })
2105 }
2106
2107 fn strip_async_lowered_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2108 name.strip_prefix("[async-lower]")
2109 .map_or((false, name), |s| (true, s))
2110 }
2111 fn match_with_async_lowered_prefix(
2112 &self,
2113 name: &str,
2114 expected: &str,
2115 ) -> Option<MaybeAsyncLowered<()>> {
2116 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2117 if clean_name == expected {
2118 Some(MaybeAsyncLowered {
2119 inner: (),
2120 async_lowered,
2121 })
2122 } else {
2123 None
2124 }
2125 }
2126 fn strip_cancellable_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2127 name.strip_prefix("[cancellable]")
2128 .map_or((false, name), |s| (true, s))
2129 }
2130 fn match_with_cancellable_prefix(
2131 &self,
2132 name: &str,
2133 expected: &str,
2134 ) -> Option<MaybeCancellable<()>> {
2135 let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2136 if clean_name == expected {
2137 Some(MaybeCancellable {
2138 inner: (),
2139 cancellable,
2140 })
2141 } else {
2142 None
2143 }
2144 }
2145}
2146
2147impl NameMangling for Legacy {
2148 fn import_root(&self) -> &str {
2149 "$root"
2150 }
2151 fn import_non_root_prefix(&self) -> &str {
2152 ""
2153 }
2154 fn import_exported_intrinsic_prefix(&self) -> &str {
2155 "[export]"
2156 }
2157 fn export_memory(&self) -> &str {
2158 "memory"
2159 }
2160 fn export_initialize(&self) -> &str {
2161 "_initialize"
2162 }
2163 fn export_realloc(&self) -> &str {
2164 "cabi_realloc"
2165 }
2166 fn export_indirect_function_table(&self) -> Option<&str> {
2167 Some("__indirect_function_table")
2168 }
2169 fn export_wasm_init_task(&self) -> Option<&str> {
2170 Some("__wasm_init_task")
2171 }
2172 fn export_wasm_init_async_task(&self) -> Option<&str> {
2173 Some("__wasm_init_async_task")
2174 }
2175 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2176 name.strip_prefix("[resource-drop]")
2177 }
2178 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2179 name.strip_prefix("[resource-new]")
2180 }
2181 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2182 name.strip_prefix("[resource-rep]")
2183 }
2184 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2185 name.strip_prefix("[task-return]")
2186 }
2187 fn task_cancel(&self, name: &str) -> bool {
2188 name == "[task-cancel]"
2189 }
2190 fn backpressure_inc(&self, name: &str) -> bool {
2191 name == "[backpressure-inc]"
2192 }
2193 fn backpressure_dec(&self, name: &str) -> bool {
2194 name == "[backpressure-dec]"
2195 }
2196 fn waitable_set_new(&self, name: &str) -> bool {
2197 name == "[waitable-set-new]"
2198 }
2199 fn waitable_set_wait(&self, name: &str) -> Option<MaybeCancellable<()>> {
2200 self.match_with_cancellable_prefix(name, "[waitable-set-wait]")
2201 }
2202 fn waitable_set_poll(&self, name: &str) -> Option<MaybeCancellable<()>> {
2203 self.match_with_cancellable_prefix(name, "[waitable-set-poll]")
2204 }
2205 fn waitable_set_drop(&self, name: &str) -> bool {
2206 name == "[waitable-set-drop]"
2207 }
2208 fn waitable_join(&self, name: &str) -> bool {
2209 name == "[waitable-join]"
2210 }
2211 fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>> {
2212 self.match_with_cancellable_prefix(name, "[thread-yield]")
2213 }
2214 fn subtask_drop(&self, name: &str) -> bool {
2215 name == "[subtask-drop]"
2216 }
2217 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>> {
2218 self.match_with_async_lowered_prefix(name, "[subtask-cancel]")
2219 }
2220 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2221 name.strip_prefix("[callback][async-lift]")
2222 }
2223 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2224 name.strip_prefix("[async-lift]")
2225 }
2226 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2227 name.strip_prefix("[async-lift-stackful]")
2228 }
2229 fn error_context_new(&self, name: &str) -> Option<StringEncoding> {
2230 match name {
2231 "[error-context-new-utf8]" => Some(StringEncoding::UTF8),
2232 "[error-context-new-utf16]" => Some(StringEncoding::UTF16),
2233 "[error-context-new-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2234 _ => None,
2235 }
2236 }
2237 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding> {
2238 match name {
2239 "[error-context-debug-message-utf8]" => Some(StringEncoding::UTF8),
2240 "[error-context-debug-message-utf16]" => Some(StringEncoding::UTF16),
2241 "[error-context-debug-message-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2242 _ => None,
2243 }
2244 }
2245 fn error_context_drop(&self, name: &str) -> bool {
2246 name == "[error-context-drop]"
2247 }
2248 fn context_get(&self, name: &str) -> Option<(ValType, u32)> {
2249 parse_context_name(name, "[context-get-")
2250 }
2251 fn context_set(&self, name: &str) -> Option<(ValType, u32)> {
2252 parse_context_name(name, "[context-set-")
2253 }
2254 fn thread_index(&self, name: &str) -> bool {
2255 name == "[thread-index]"
2256 }
2257 fn thread_new_indirect(&self, name: &str) -> bool {
2258 name == "[thread-new-indirect-v0]"
2260 }
2261 fn thread_suspend_to_suspended(&self, name: &str) -> Option<MaybeCancellable<()>> {
2262 self.match_with_cancellable_prefix(name, "[thread-suspend-to-suspended]")
2263 }
2264 fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>> {
2265 self.match_with_cancellable_prefix(name, "[thread-suspend]")
2266 }
2267 fn thread_suspend_to(&self, name: &str) -> Option<MaybeCancellable<()>> {
2268 self.match_with_cancellable_prefix(name, "[thread-suspend-to]")
2269 }
2270 fn thread_unsuspend(&self, name: &str) -> bool {
2271 name == "[thread-unsuspend]"
2272 }
2273 fn thread_yield_to_suspended(&self, name: &str) -> Option<MaybeCancellable<()>> {
2274 self.match_with_cancellable_prefix(name, "[thread-yield-to-suspended]")
2275 }
2276 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2277 self.prefixed_payload(lookup_context, name, "[future-new-")
2278 }
2279 fn future_write(
2280 &self,
2281 lookup_context: &PayloadLookupContext,
2282 name: &str,
2283 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2284 self.maybe_async_lowered_payload(lookup_context, name, "[future-write-")
2285 }
2286 fn future_read(
2287 &self,
2288 lookup_context: &PayloadLookupContext,
2289 name: &str,
2290 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2291 self.maybe_async_lowered_payload(lookup_context, name, "[future-read-")
2292 }
2293 fn future_cancel_write(
2294 &self,
2295 lookup_context: &PayloadLookupContext,
2296 name: &str,
2297 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2298 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-write-")
2299 }
2300 fn future_cancel_read(
2301 &self,
2302 lookup_context: &PayloadLookupContext,
2303 name: &str,
2304 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2305 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-read-")
2306 }
2307 fn future_drop_writable(
2308 &self,
2309 lookup_context: &PayloadLookupContext,
2310 name: &str,
2311 ) -> Option<PayloadInfo> {
2312 self.prefixed_payload(lookup_context, name, "[future-drop-writable-")
2313 }
2314 fn future_drop_readable(
2315 &self,
2316 lookup_context: &PayloadLookupContext,
2317 name: &str,
2318 ) -> Option<PayloadInfo> {
2319 self.prefixed_payload(lookup_context, name, "[future-drop-readable-")
2320 }
2321 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2322 self.prefixed_payload(lookup_context, name, "[stream-new-")
2323 }
2324 fn stream_write(
2325 &self,
2326 lookup_context: &PayloadLookupContext,
2327 name: &str,
2328 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2329 self.maybe_async_lowered_payload(lookup_context, name, "[stream-write-")
2330 }
2331 fn stream_read(
2332 &self,
2333 lookup_context: &PayloadLookupContext,
2334 name: &str,
2335 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2336 self.maybe_async_lowered_payload(lookup_context, name, "[stream-read-")
2337 }
2338 fn stream_cancel_write(
2339 &self,
2340 lookup_context: &PayloadLookupContext,
2341 name: &str,
2342 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2343 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-write-")
2344 }
2345 fn stream_cancel_read(
2346 &self,
2347 lookup_context: &PayloadLookupContext,
2348 name: &str,
2349 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2350 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-read-")
2351 }
2352 fn stream_drop_writable(
2353 &self,
2354 lookup_context: &PayloadLookupContext,
2355 name: &str,
2356 ) -> Option<PayloadInfo> {
2357 self.prefixed_payload(lookup_context, name, "[stream-drop-writable-")
2358 }
2359 fn stream_drop_readable(
2360 &self,
2361 lookup_context: &PayloadLookupContext,
2362 name: &str,
2363 ) -> Option<PayloadInfo> {
2364 self.prefixed_payload(lookup_context, name, "[stream-drop-readable-")
2365 }
2366 fn module_to_interface(
2367 &self,
2368 module: &str,
2369 resolve: &Resolve,
2370 items: &IndexMap<WorldKey, WorldItem>,
2371 ) -> Result<(WorldKey, InterfaceId)> {
2372 let bare_name = WorldKey::Name(module.to_string());
2374 if let Some(WorldItem::Interface { id, .. }) = items.get(&bare_name) {
2375 return Ok((bare_name, *id));
2376 }
2377
2378 let kebab_name = ComponentName::new(module, 0);
2384 let name = match kebab_name.as_ref().map(|k| k.kind()) {
2385 Ok(ComponentNameKind::Interface(name)) => name,
2386 _ => bail!("module requires an import interface named `{module}`"),
2387 };
2388
2389 let pkgname = PackageName {
2391 namespace: name.namespace().to_string(),
2392 name: name.package().to_string(),
2393 version: name.version(),
2394 };
2395 if let Some(pkg) = resolve.package_names.get(&pkgname) {
2396 if let Some(id) = resolve.packages[*pkg]
2397 .interfaces
2398 .get(name.interface().as_str())
2399 {
2400 let key = WorldKey::Interface(*id);
2401 if items.contains_key(&key) {
2402 return Ok((key, *id));
2403 }
2404 }
2405 }
2406
2407 for (key, _) in items {
2412 let id = match key {
2413 WorldKey::Interface(id) => *id,
2414 WorldKey::Name(_) => continue,
2415 };
2416 let interface = &resolve.interfaces[id];
2418 if interface.name.as_ref().unwrap() != name.interface().as_str() {
2419 continue;
2420 }
2421
2422 let pkg = &resolve.packages[interface.package.unwrap()];
2424 if pkg.name.namespace != pkgname.namespace || pkg.name.name != pkgname.name {
2425 continue;
2426 }
2427
2428 let module_version = match name.version() {
2429 Some(version) => version,
2430 None => continue,
2431 };
2432 let pkg_version = match &pkg.name.version {
2433 Some(version) => version,
2434 None => continue,
2435 };
2436
2437 let module_compat = PackageName::version_compat_track(&module_version);
2439 let pkg_compat = PackageName::version_compat_track(pkg_version);
2440 if module_compat == pkg_compat {
2441 return Ok((key.clone(), id));
2442 }
2443 }
2444
2445 bail!("module requires an import interface named `{module}`")
2446 }
2447 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
2448 name.strip_prefix("cabi_post_")
2449 }
2450 fn match_wit_export<'a>(
2451 &self,
2452 export_name: &str,
2453 resolve: &'a Resolve,
2454 world: WorldId,
2455 exports: &'a IndexSet<WorldKey>,
2456 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
2457 let world = &resolve.worlds[world];
2458 for name in exports {
2459 match &world.exports[name] {
2460 WorldItem::Function(f) => {
2461 if f.legacy_core_export_name(None) == export_name {
2462 return Some((name, None, f));
2463 }
2464 }
2465 WorldItem::Interface { id, .. } => {
2466 let string = resolve.name_world_key(name);
2467 for (_, func) in resolve.interfaces[*id].functions.iter() {
2468 if func.legacy_core_export_name(Some(&string)) == export_name {
2469 return Some((name, Some(*id), func));
2470 }
2471 }
2472 }
2473
2474 WorldItem::Type { .. } => unreachable!(),
2475 }
2476 }
2477
2478 None
2479 }
2480
2481 fn match_wit_resource_dtor<'a>(
2482 &self,
2483 export_name: &str,
2484 resolve: &'a Resolve,
2485 world: WorldId,
2486 exports: &'a IndexSet<WorldKey>,
2487 ) -> Option<TypeId> {
2488 let world = &resolve.worlds[world];
2489 for name in exports {
2490 let id = match &world.exports[name] {
2491 WorldItem::Interface { id, .. } => *id,
2492 WorldItem::Function(_) => continue,
2493 WorldItem::Type { .. } => unreachable!(),
2494 };
2495 let name = resolve.name_world_key(name);
2496 let resource = match export_name
2497 .strip_prefix(&name)
2498 .and_then(|s| s.strip_prefix("#[dtor]"))
2499 .and_then(|r| resolve.interfaces[id].types.get(r))
2500 {
2501 Some(id) => *id,
2502 None => continue,
2503 };
2504
2505 match resolve.types[resource].kind {
2506 TypeDefKind::Resource => {}
2507 _ => continue,
2508 }
2509
2510 return Some(resource);
2511 }
2512
2513 None
2514 }
2515
2516 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2517 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2518 (
2519 name,
2520 if async_abi {
2521 AbiVariant::GuestImportAsync
2522 } else {
2523 AbiVariant::GuestImport
2524 },
2525 )
2526 }
2527 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2528 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2529 (
2530 name,
2531 if async_abi {
2532 AbiVariant::GuestImportAsync
2533 } else {
2534 AbiVariant::GuestImport
2535 },
2536 )
2537 }
2538}
2539
2540pub fn validate_module(
2552 encoder: &ComponentEncoder,
2553 bytes: &[u8],
2554 import_map: Option<&ModuleImportMap>,
2555) -> Result<ValidatedModule> {
2556 ValidatedModule::new(
2557 encoder,
2558 bytes,
2559 &encoder.main_module_exports,
2560 import_map,
2561 None,
2562 )
2563}
2564
2565pub fn validate_adapter_module(
2583 encoder: &ComponentEncoder,
2584 bytes: &[u8],
2585 required_by_import: &IndexMap<String, FuncType>,
2586 exports: &IndexSet<WorldKey>,
2587 library_info: Option<&LibraryInfo>,
2588) -> Result<ValidatedModule> {
2589 let ret = ValidatedModule::new(encoder, bytes, exports, None, library_info)?;
2590
2591 for (name, required_ty) in required_by_import {
2592 let actual = match ret.exports.raw_exports.get(name) {
2593 Some(ty) => ty,
2594 None => return Err(AdapterModuleDidNotExport(name.clone()).into()),
2595 };
2596 validate_func_sig(name, required_ty, &actual)?;
2597 }
2598
2599 Ok(ret)
2600}
2601
2602#[derive(Debug, Clone)]
2609pub struct AdapterModuleDidNotExport(String);
2610
2611impl fmt::Display for AdapterModuleDidNotExport {
2612 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2613 write!(f, "adapter module did not export `{}`", self.0)
2614 }
2615}
2616
2617impl std::error::Error for AdapterModuleDidNotExport {}
2618
2619fn resource_test_for_interface<'a>(
2620 resolve: &'a Resolve,
2621 id: InterfaceId,
2622) -> impl Fn(&str) -> Option<TypeId> + 'a {
2623 let interface = &resolve.interfaces[id];
2624 move |name: &str| {
2625 let ty = match interface.types.get(name) {
2626 Some(ty) => *ty,
2627 None => return None,
2628 };
2629 if matches!(resolve.types[ty].kind, TypeDefKind::Resource) {
2630 Some(ty)
2631 } else {
2632 None
2633 }
2634 }
2635}
2636
2637fn resource_test_for_world<'a>(
2638 resolve: &'a Resolve,
2639 id: WorldId,
2640) -> impl Fn(&str) -> Option<TypeId> + 'a {
2641 let world = &resolve.worlds[id];
2642 move |name: &str| match world.imports.get(&WorldKey::Name(name.to_string()))? {
2643 WorldItem::Type { id, .. } => {
2644 if matches!(resolve.types[*id].kind, TypeDefKind::Resource) {
2645 Some(*id)
2646 } else {
2647 None
2648 }
2649 }
2650 _ => None,
2651 }
2652}
2653
2654fn validate_func(
2655 resolve: &Resolve,
2656 ty: &wasmparser::FuncType,
2657 func: &Function,
2658 abi: AbiVariant,
2659) -> Result<()> {
2660 validate_func_sig(
2661 &func.name,
2662 &wasm_sig_to_func_type(resolve.wasm_signature(abi, func)),
2663 ty,
2664 )
2665}
2666
2667fn validate_post_return(
2668 resolve: &Resolve,
2669 ty: &wasmparser::FuncType,
2670 func: &Function,
2671) -> Result<()> {
2672 let mut sig = resolve.wasm_signature(AbiVariant::GuestExport, func);
2678 sig.params = mem::take(&mut sig.results);
2679 validate_func_sig(
2680 &format!("{} post-return", func.name),
2681 &wasm_sig_to_func_type(sig),
2682 ty,
2683 )
2684}
2685
2686fn validate_func_sig(name: &str, expected: &FuncType, ty: &wasmparser::FuncType) -> Result<()> {
2687 if ty != expected {
2688 bail!(
2689 "type mismatch for function `{}`: expected `{:?} -> {:?}` but found `{:?} -> {:?}`",
2690 name,
2691 expected.params(),
2692 expected.results(),
2693 ty.params(),
2694 ty.results()
2695 );
2696 }
2697
2698 Ok(())
2699}
2700
2701fn prefixed_intrinsic<'a>(name: &'a str, prefix: &str) -> Option<(&'a str, &'a str)> {
2703 assert!(prefix.starts_with("["));
2704 assert!(prefix.ends_with("-"));
2705 let suffix = name.strip_prefix(prefix)?;
2706 let index = suffix.find(']')?;
2707 let rest = &suffix[index + 1..];
2708 Some((&suffix[..index], rest))
2709}
2710
2711fn parse_context_name(name: &str, prefix: &str) -> Option<(ValType, u32)> {
2717 let (suffix, rest) = prefixed_intrinsic(name, prefix)?;
2718 if !rest.is_empty() {
2719 return None;
2720 }
2721 let (ty, slot) = match suffix.split_once('-') {
2722 Some(("i64", slot)) => (ValType::I64, slot),
2723 Some(("i32", slot)) => (ValType::I32, slot),
2724 _ => (ValType::I32, suffix),
2725 };
2726 let slot = slot.parse().ok()?;
2727 Some((ty, slot))
2728}
2729
2730fn get_function<'a>(
2731 resolve: &'a Resolve,
2732 world: &'a World,
2733 name: &str,
2734 interface: Option<InterfaceId>,
2735 imported: bool,
2736) -> Result<&'a Function> {
2737 let function = if let Some(id) = interface {
2738 return resolve.interfaces[id]
2739 .functions
2740 .get(name)
2741 .ok_or_else(|| anyhow!("no export `{name}` found"));
2742 } else if imported {
2743 world.imports.get(&WorldKey::Name(name.to_string()))
2744 } else {
2745 world.exports.get(&WorldKey::Name(name.to_string()))
2746 };
2747 let Some(WorldItem::Function(function)) = function else {
2748 bail!("no export `{name}` found");
2749 };
2750 Ok(function)
2751}