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