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