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 {
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 BackpressureSet,
288
289 BackpressureInc,
291
292 BackpressureDec,
294
295 WaitableSetNew,
297
298 WaitableSetWait { cancellable: bool },
304
305 WaitableSetPoll { cancellable: bool },
311
312 WaitableSetDrop,
314
315 WaitableJoin,
317
318 ThreadYield { cancellable: bool },
323
324 SubtaskDrop,
328
329 SubtaskCancel { async_: bool },
333
334 StreamNew(PayloadInfo),
338
339 StreamRead { async_: bool, info: PayloadInfo },
344
345 StreamWrite { async_: bool, info: PayloadInfo },
350
351 StreamCancelRead { info: PayloadInfo, async_: bool },
356
357 StreamCancelWrite { info: PayloadInfo, async_: bool },
362
363 StreamDropReadable(PayloadInfo),
367
368 StreamDropWritable(PayloadInfo),
372
373 FutureNew(PayloadInfo),
377
378 FutureRead { async_: bool, info: PayloadInfo },
383
384 FutureWrite { async_: bool, info: PayloadInfo },
388
389 FutureCancelRead { info: PayloadInfo, async_: bool },
394
395 FutureCancelWrite { info: PayloadInfo, async_: bool },
400
401 FutureDropReadable(PayloadInfo),
405
406 FutureDropWritable(PayloadInfo),
410
411 ErrorContextNew { encoding: StringEncoding },
416
417 ErrorContextDebugMessage { encoding: StringEncoding },
423
424 ErrorContextDrop,
429
430 ThreadIndex,
434
435 ThreadNewIndirect,
439
440 ThreadSwitchTo { cancellable: bool },
444
445 ThreadSuspend { cancellable: bool },
450
451 ThreadResumeLater,
455
456 ThreadYieldTo { cancellable: bool },
460}
461
462impl ImportMap {
463 pub fn required_from_adapter(&self, name: &str) -> IndexMap<String, FuncType> {
465 let names = match self.names.get(name) {
466 Some(ImportInstance::Names(names)) => names,
467 _ => return IndexMap::new(),
468 };
469 names
470 .iter()
471 .map(|(_, import)| match import {
472 Import::AdapterExport { ty, func, adapter } => {
473 assert_eq!(adapter, name);
474 (func.clone(), ty.clone())
475 }
476 _ => unreachable!(),
477 })
478 .collect()
479 }
480
481 pub fn imports(&self) -> impl Iterator<Item = (&str, &str, &Import)> + '_ {
485 self.names
486 .iter()
487 .filter_map(|(module, m)| match m {
488 ImportInstance::Names(names) => Some((module, names)),
489 ImportInstance::Whole(_) => None,
490 })
491 .flat_map(|(module, m)| {
492 m.iter()
493 .map(move |(field, import)| (module.as_str(), field.as_str(), import))
494 })
495 }
496
497 pub fn modules(&self) -> &IndexMap<String, ImportInstance> {
499 &self.names
500 }
501
502 fn add(
505 &mut self,
506 import: wasmparser::Import<'_>,
507 encoder: &ComponentEncoder,
508 import_map: Option<&ModuleImportMap>,
509 library_info: Option<&LibraryInfo>,
510 types: TypesRef<'_>,
511 ) -> Result<()> {
512 if self.classify_import_with_library(import, library_info)? {
513 return Ok(());
514 }
515 let mut import_to_classify = import;
516 if let Some(map) = import_map {
517 if let Some(original_name) = map.original_name(&import) {
518 import_to_classify.name = original_name;
519 }
520 }
521 let item = self
522 .classify(import_to_classify, encoder, types)
523 .with_context(|| {
524 format!(
525 "failed to resolve import `{}::{}`",
526 import.module, import.name,
527 )
528 })?;
529 self.insert_import(import, item)
530 }
531
532 fn classify(
538 &self,
539 import: wasmparser::Import<'_>,
540 encoder: &ComponentEncoder,
541 types: TypesRef<'_>,
542 ) -> Result<Import> {
543 if import.module == "env" && import.name == "memory" {
546 return Ok(Import::MainModuleMemory);
547 }
548
549 if import.module == "__main_module__" {
551 return Ok(Import::MainModuleExport {
552 name: import.name.to_string(),
553 kind: match import.ty {
554 TypeRef::Func(_) => ExportKind::Func,
555 TypeRef::Table(_) => ExportKind::Table,
556 TypeRef::Memory(_) => ExportKind::Memory,
557 TypeRef::Global(_) => ExportKind::Global,
558 TypeRef::Tag(_) => ExportKind::Tag,
559 TypeRef::FuncExact(_) => bail!("Unexpected func_exact export"),
560 },
561 });
562 }
563
564 let ty_index = match import.ty {
565 TypeRef::Func(ty) => ty,
566 _ => bail!("module is only allowed to import functions"),
567 };
568 let ty = types[types.core_type_at_in_module(ty_index)].unwrap_func();
569
570 if encoder.adapters.contains_key(import.module) {
573 return Ok(Import::AdapterExport {
574 adapter: import.module.to_string(),
575 func: import.name.to_string(),
576 ty: ty.clone(),
577 });
578 }
579
580 let (module, names) = match import.module.strip_prefix("cm32p2") {
581 Some(suffix) => (suffix, STANDARD),
582 None if encoder.reject_legacy_names => (import.module, STANDARD),
583 None => (import.module, LEGACY),
584 };
585 self.classify_component_model_import(module, import.name, encoder, ty, names)
586 }
587
588 fn classify_component_model_import(
591 &self,
592 module: &str,
593 name: &str,
594 encoder: &ComponentEncoder,
595 ty: &FuncType,
596 names: &dyn NameMangling,
597 ) -> Result<Import> {
598 let resolve = &encoder.metadata.resolve;
599 let world_id = encoder.metadata.world;
600 let world = &resolve.worlds[world_id];
601
602 if module == names.import_root() {
603 if names.error_context_drop(name) {
604 let expected = FuncType::new([ValType::I32], []);
605 validate_func_sig(name, &expected, ty)?;
606 return Ok(Import::ErrorContextDrop);
607 }
608
609 if names.backpressure_set(name) {
610 let expected = FuncType::new([ValType::I32], []);
611 validate_func_sig(name, &expected, ty)?;
612 return Ok(Import::BackpressureSet);
613 }
614
615 if names.backpressure_inc(name) {
616 let expected = FuncType::new([], []);
617 validate_func_sig(name, &expected, ty)?;
618 return Ok(Import::BackpressureInc);
619 }
620
621 if names.backpressure_dec(name) {
622 let expected = FuncType::new([], []);
623 validate_func_sig(name, &expected, ty)?;
624 return Ok(Import::BackpressureDec);
625 }
626
627 if names.waitable_set_new(name) {
628 let expected = FuncType::new([], [ValType::I32]);
629 validate_func_sig(name, &expected, ty)?;
630 return Ok(Import::WaitableSetNew);
631 }
632
633 if let Some(info) = names.waitable_set_wait(name) {
634 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
635 validate_func_sig(name, &expected, ty)?;
636 return Ok(Import::WaitableSetWait {
637 cancellable: info.cancellable,
638 });
639 }
640
641 if let Some(info) = names.waitable_set_poll(name) {
642 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
643 validate_func_sig(name, &expected, ty)?;
644 return Ok(Import::WaitableSetPoll {
645 cancellable: info.cancellable,
646 });
647 }
648
649 if names.waitable_set_drop(name) {
650 let expected = FuncType::new([ValType::I32], []);
651 validate_func_sig(name, &expected, ty)?;
652 return Ok(Import::WaitableSetDrop);
653 }
654
655 if names.waitable_join(name) {
656 let expected = FuncType::new([ValType::I32; 2], []);
657 validate_func_sig(name, &expected, ty)?;
658 return Ok(Import::WaitableJoin);
659 }
660
661 if let Some(info) = names.thread_yield(name) {
662 let expected = FuncType::new([], [ValType::I32]);
663 validate_func_sig(name, &expected, ty)?;
664 return Ok(Import::ThreadYield {
665 cancellable: info.cancellable,
666 });
667 }
668
669 if names.subtask_drop(name) {
670 let expected = FuncType::new([ValType::I32], []);
671 validate_func_sig(name, &expected, ty)?;
672 return Ok(Import::SubtaskDrop);
673 }
674
675 if let Some(info) = names.subtask_cancel(name) {
676 let expected = FuncType::new([ValType::I32], [ValType::I32]);
677 validate_func_sig(name, &expected, ty)?;
678 return Ok(Import::SubtaskCancel {
679 async_: info.async_lowered,
680 });
681 }
682
683 if let Some(encoding) = names.error_context_new(name) {
684 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
685 validate_func_sig(name, &expected, ty)?;
686 return Ok(Import::ErrorContextNew { encoding });
687 }
688
689 if let Some(encoding) = names.error_context_debug_message(name) {
690 let expected = FuncType::new([ValType::I32; 2], []);
691 validate_func_sig(name, &expected, ty)?;
692 return Ok(Import::ErrorContextDebugMessage { encoding });
693 }
694
695 if let Some(i) = names.context_get(name) {
696 let expected = FuncType::new([], [ValType::I32]);
697 validate_func_sig(name, &expected, ty)?;
698 return Ok(Import::ContextGet(i));
699 }
700 if let Some(i) = names.context_set(name) {
701 let expected = FuncType::new([ValType::I32], []);
702 validate_func_sig(name, &expected, ty)?;
703 return Ok(Import::ContextSet(i));
704 }
705 if names.thread_index(name) {
706 let expected = FuncType::new([], [ValType::I32]);
707 validate_func_sig(name, &expected, ty)?;
708 return Ok(Import::ThreadIndex);
709 }
710 if names.thread_new_indirect(name) {
711 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
712 validate_func_sig(name, &expected, ty)?;
713 return Ok(Import::ThreadNewIndirect);
714 }
715 if let Some(info) = names.thread_switch_to(name) {
716 let expected = FuncType::new([ValType::I32], [ValType::I32]);
717 validate_func_sig(name, &expected, ty)?;
718 return Ok(Import::ThreadSwitchTo {
719 cancellable: info.cancellable,
720 });
721 }
722 if let Some(info) = names.thread_suspend(name) {
723 let expected = FuncType::new([], [ValType::I32]);
724 validate_func_sig(name, &expected, ty)?;
725 return Ok(Import::ThreadSuspend {
726 cancellable: info.cancellable,
727 });
728 }
729 if names.thread_resume_later(name) {
730 let expected = FuncType::new([ValType::I32], []);
731 validate_func_sig(name, &expected, ty)?;
732 return Ok(Import::ThreadResumeLater);
733 }
734 if let Some(info) = names.thread_yield_to(name) {
735 let expected = FuncType::new([ValType::I32], [ValType::I32]);
736 validate_func_sig(name, &expected, ty)?;
737 return Ok(Import::ThreadYieldTo {
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
1128impl ExportMap {
1129 fn add(
1130 &mut self,
1131 export: wasmparser::Export<'_>,
1132 encoder: &ComponentEncoder,
1133 exports: &IndexSet<WorldKey>,
1134 types: TypesRef<'_>,
1135 ) -> Result<()> {
1136 if let Some(item) = self.classify(export, encoder, exports, types)? {
1137 log::debug!("classifying export `{}` as {item:?}", export.name);
1138 let prev = self.names.insert(export.name.to_string(), item);
1139 assert!(prev.is_none());
1140 }
1141 Ok(())
1142 }
1143
1144 fn classify(
1145 &mut self,
1146 export: wasmparser::Export<'_>,
1147 encoder: &ComponentEncoder,
1148 exports: &IndexSet<WorldKey>,
1149 types: TypesRef<'_>,
1150 ) -> Result<Option<Export>> {
1151 match export.kind {
1152 ExternalKind::Func => {
1153 let ty = types[types.core_function_at(export.index)].unwrap_func();
1154 self.raw_exports.insert(export.name.to_string(), ty.clone());
1155 }
1156 _ => {}
1157 }
1158
1159 if export.name == "canonical_abi_realloc" {
1161 return Ok(Some(Export::GeneralPurposeRealloc));
1162 } else if export.name == "cabi_import_realloc" {
1163 return Ok(Some(Export::GeneralPurposeImportRealloc));
1164 } else if export.name == "cabi_export_realloc" {
1165 return Ok(Some(Export::GeneralPurposeExportRealloc));
1166 } else if export.name == "cabi_realloc_adapter" {
1167 return Ok(Some(Export::ReallocForAdapter));
1168 }
1169
1170 let (name, names) = match export.name.strip_prefix("cm32p2") {
1171 Some(name) => (name, STANDARD),
1172 None if encoder.reject_legacy_names => return Ok(None),
1173 None => (export.name, LEGACY),
1174 };
1175
1176 if let Some(export) = self
1177 .classify_component_export(names, name, &export, encoder, exports, types)
1178 .with_context(|| format!("failed to classify export `{}`", export.name))?
1179 {
1180 return Ok(Some(export));
1181 }
1182 log::debug!("unknown export `{}`", export.name);
1183 Ok(None)
1184 }
1185
1186 fn classify_component_export(
1187 &mut self,
1188 names: &dyn NameMangling,
1189 name: &str,
1190 export: &wasmparser::Export<'_>,
1191 encoder: &ComponentEncoder,
1192 exports: &IndexSet<WorldKey>,
1193 types: TypesRef<'_>,
1194 ) -> Result<Option<Export>> {
1195 let resolve = &encoder.metadata.resolve;
1196 let world = encoder.metadata.world;
1197 match export.kind {
1198 ExternalKind::Func => {}
1199 ExternalKind::Memory => {
1200 if name == names.export_memory() {
1201 return Ok(Some(Export::Memory));
1202 }
1203 return Ok(None);
1204 }
1205 ExternalKind::Table => {
1206 if Some(name) == names.export_indirect_function_table() {
1207 return Ok(Some(Export::IndirectFunctionTable));
1208 }
1209 return Ok(None);
1210 }
1211 _ => return Ok(None),
1212 }
1213 let ty = types[types.core_function_at(export.index)].unwrap_func();
1214
1215 if name == names.export_realloc() {
1217 let expected = FuncType::new([ValType::I32; 4], [ValType::I32]);
1218 validate_func_sig(name, &expected, ty)?;
1219 return Ok(Some(Export::GeneralPurposeRealloc));
1220 } else if name == names.export_initialize() {
1221 let expected = FuncType::new([], []);
1222 validate_func_sig(name, &expected, ty)?;
1223 return Ok(Some(Export::Initialize));
1224 }
1225
1226 let full_name = name;
1227 let (abi, name) = if let Some(name) = names.async_lift_name(name) {
1228 (AbiVariant::GuestExportAsync, name)
1229 } else if let Some(name) = names.async_lift_stackful_name(name) {
1230 (AbiVariant::GuestExportAsyncStackful, name)
1231 } else {
1232 (AbiVariant::GuestExport, name)
1233 };
1234
1235 if let Some((key, id, f)) = names.match_wit_export(name, resolve, world, exports) {
1237 validate_func(resolve, ty, f, abi).with_context(|| {
1238 let key = resolve.name_world_key(key);
1239 format!("failed to validate export for `{key}`")
1240 })?;
1241 match id {
1242 Some(id) => {
1243 return Ok(Some(Export::InterfaceFunc(
1244 key.clone(),
1245 id,
1246 f.name.clone(),
1247 abi,
1248 )));
1249 }
1250 None => {
1251 return Ok(Some(Export::WorldFunc(key.clone(), f.name.clone(), abi)));
1252 }
1253 }
1254 }
1255
1256 if let Some(remaining) = names.strip_post_return(name) {
1258 if let Some((key, id, f)) = names.match_wit_export(remaining, resolve, world, exports) {
1259 validate_post_return(resolve, ty, f).with_context(|| {
1260 let key = resolve.name_world_key(key);
1261 format!("failed to validate export for `{key}`")
1262 })?;
1263 match id {
1264 Some(_id) => {
1265 return Ok(Some(Export::InterfaceFuncPostReturn(
1266 key.clone(),
1267 f.name.clone(),
1268 )));
1269 }
1270 None => {
1271 return Ok(Some(Export::WorldFuncPostReturn(key.clone())));
1272 }
1273 }
1274 }
1275 }
1276
1277 if let Some(suffix) = names.async_lift_callback_name(full_name) {
1278 if let Some((key, id, f)) = names.match_wit_export(suffix, resolve, world, exports) {
1279 validate_func_sig(
1280 full_name,
1281 &FuncType::new([ValType::I32; 3], [ValType::I32]),
1282 ty,
1283 )?;
1284 return Ok(Some(if id.is_some() {
1285 Export::InterfaceFuncCallback(key.clone(), f.name.clone())
1286 } else {
1287 Export::WorldFuncCallback(key.clone())
1288 }));
1289 }
1290 }
1291
1292 if let Some(dtor) = names.match_wit_resource_dtor(name, resolve, world, exports) {
1294 let expected = FuncType::new([ValType::I32], []);
1295 validate_func_sig(full_name, &expected, ty)?;
1296 return Ok(Some(Export::ResourceDtor(dtor)));
1297 }
1298
1299 Ok(None)
1300 }
1301
1302 pub fn post_return(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1305 self.find(|m| match m {
1306 Export::WorldFuncPostReturn(k) => k == key,
1307 Export::InterfaceFuncPostReturn(k, f) => k == key && func.name == *f,
1308 _ => false,
1309 })
1310 }
1311
1312 pub fn callback(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1315 self.find(|m| match m {
1316 Export::WorldFuncCallback(k) => k == key,
1317 Export::InterfaceFuncCallback(k, f) => k == key && func.name == *f,
1318 _ => false,
1319 })
1320 }
1321
1322 pub fn abi(&self, key: &WorldKey, func: &Function) -> Option<AbiVariant> {
1323 self.names.values().find_map(|m| match m {
1324 Export::WorldFunc(k, f, abi) if k == key && func.name == *f => Some(*abi),
1325 Export::InterfaceFunc(k, _, f, abi) if k == key && func.name == *f => Some(*abi),
1326 _ => None,
1327 })
1328 }
1329
1330 pub fn export_realloc_for(&self, key: &WorldKey, func: &str) -> Option<&str> {
1333 let _ = (key, func);
1337
1338 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeExportRealloc)) {
1339 return Some(name);
1340 }
1341 self.general_purpose_realloc()
1342 }
1343
1344 pub fn import_realloc_for(&self, interface: Option<InterfaceId>, func: &str) -> Option<&str> {
1347 let _ = (interface, func);
1351
1352 self.import_realloc_fallback()
1353 }
1354
1355 pub fn import_realloc_fallback(&self) -> Option<&str> {
1359 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeImportRealloc)) {
1360 return Some(name);
1361 }
1362 self.general_purpose_realloc()
1363 }
1364
1365 pub fn realloc_to_import_into_adapter(&self) -> Option<&str> {
1367 if let Some(name) = self.find(|m| matches!(m, Export::ReallocForAdapter)) {
1368 return Some(name);
1369 }
1370 self.general_purpose_realloc()
1371 }
1372
1373 fn general_purpose_realloc(&self) -> Option<&str> {
1374 self.find(|m| matches!(m, Export::GeneralPurposeRealloc))
1375 }
1376
1377 pub fn memory(&self) -> Option<&str> {
1379 self.find(|m| matches!(m, Export::Memory))
1380 }
1381
1382 pub fn indirect_function_table(&self) -> Option<&str> {
1384 self.find(|t| matches!(t, Export::IndirectFunctionTable))
1385 }
1386
1387 pub fn initialize(&self) -> Option<&str> {
1389 self.find(|m| matches!(m, Export::Initialize))
1390 }
1391
1392 pub fn resource_dtor(&self, ty: TypeId) -> Option<&str> {
1394 self.find(|m| match m {
1395 Export::ResourceDtor(t) => *t == ty,
1396 _ => false,
1397 })
1398 }
1399
1400 fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1403 let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1404 Some(name)
1405 }
1406
1407 pub fn iter(&self) -> impl Iterator<Item = (&str, &Export)> + '_ {
1409 self.names.iter().map(|(n, e)| (n.as_str(), e))
1410 }
1411
1412 fn validate(&self, encoder: &ComponentEncoder, exports: &IndexSet<WorldKey>) -> Result<()> {
1413 let resolve = &encoder.metadata.resolve;
1414 let world = encoder.metadata.world;
1415 if self
1418 .names
1419 .values()
1420 .filter(|m| matches!(m, Export::Memory))
1421 .count()
1422 > 1
1423 {
1424 bail!("cannot componentize module that exports multiple memories")
1425 }
1426
1427 for (name, export) in &self.names {
1429 match export {
1430 Export::WorldFunc(_, _, AbiVariant::GuestExportAsync) => {
1431 if !matches!(
1432 self.names.get(&format!("[callback]{name}")),
1433 Some(Export::WorldFuncCallback(_))
1434 ) {
1435 bail!("missing callback for `{name}`");
1436 }
1437 }
1438 Export::InterfaceFunc(_, _, _, AbiVariant::GuestExportAsync) => {
1439 if !matches!(
1440 self.names.get(&format!("[callback]{name}")),
1441 Some(Export::InterfaceFuncCallback(_, _))
1442 ) {
1443 bail!("missing callback for `{name}`");
1444 }
1445 }
1446 _ => {}
1447 }
1448 }
1449
1450 for export in exports {
1452 let require_interface_func = |interface: InterfaceId, name: &str| -> Result<()> {
1453 let result = self.find(|e| match e {
1454 Export::InterfaceFunc(_, id, s, _) => interface == *id && name == s,
1455 _ => false,
1456 });
1457 if result.is_some() {
1458 Ok(())
1459 } else {
1460 let export = resolve.name_world_key(export);
1461 bail!("failed to find export of interface `{export}` function `{name}`")
1462 }
1463 };
1464 let require_world_func = |name: &str| -> Result<()> {
1465 let result = self.find(|e| match e {
1466 Export::WorldFunc(_, s, _) => name == s,
1467 _ => false,
1468 });
1469 if result.is_some() {
1470 Ok(())
1471 } else {
1472 bail!("failed to find export of function `{name}`")
1473 }
1474 };
1475 match &resolve.worlds[world].exports[export] {
1476 WorldItem::Interface { id, .. } => {
1477 for (name, _) in resolve.interfaces[*id].functions.iter() {
1478 require_interface_func(*id, name)?;
1479 }
1480 }
1481 WorldItem::Function(f) => {
1482 require_world_func(&f.name)?;
1483 }
1484 WorldItem::Type(_) => unreachable!(),
1485 }
1486 }
1487
1488 Ok(())
1489 }
1490}
1491
1492struct MaybeCancellable<T> {
1494 #[allow(unused)]
1495 inner: T,
1496 cancellable: bool,
1497}
1498
1499struct MaybeAsyncLowered<T> {
1501 inner: T,
1502 async_lowered: bool,
1503}
1504
1505struct PayloadLookupContext<'a> {
1508 resolve: &'a Resolve,
1509 world: &'a World,
1510 id: Option<InterfaceId>,
1511 import: bool,
1512 key: Option<WorldKey>,
1513}
1514
1515trait NameMangling {
1537 fn import_root(&self) -> &str;
1538 fn import_non_root_prefix(&self) -> &str;
1539 fn import_exported_intrinsic_prefix(&self) -> &str;
1540 fn export_memory(&self) -> &str;
1541 fn export_initialize(&self) -> &str;
1542 fn export_realloc(&self) -> &str;
1543 fn export_indirect_function_table(&self) -> Option<&str>;
1544 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1545 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1546 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1547 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1548 fn task_cancel(&self, name: &str) -> bool;
1549 fn backpressure_set(&self, name: &str) -> bool;
1550 fn backpressure_inc(&self, name: &str) -> bool;
1551 fn backpressure_dec(&self, name: &str) -> bool;
1552 fn waitable_set_new(&self, name: &str) -> bool;
1553 fn waitable_set_wait(&self, name: &str) -> Option<MaybeCancellable<()>>;
1554 fn waitable_set_poll(&self, name: &str) -> Option<MaybeCancellable<()>>;
1555 fn waitable_set_drop(&self, name: &str) -> bool;
1556 fn waitable_join(&self, name: &str) -> bool;
1557 fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>>;
1558 fn subtask_drop(&self, name: &str) -> bool;
1559 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>>;
1560 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1561 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1562 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1563 fn error_context_new(&self, name: &str) -> Option<StringEncoding>;
1564 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding>;
1565 fn error_context_drop(&self, name: &str) -> bool;
1566 fn context_get(&self, name: &str) -> Option<u32>;
1567 fn context_set(&self, name: &str) -> Option<u32>;
1568 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1569 fn future_write(
1570 &self,
1571 lookup_context: &PayloadLookupContext,
1572 name: &str,
1573 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1574 fn future_read(
1575 &self,
1576 lookup_context: &PayloadLookupContext,
1577 name: &str,
1578 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1579 fn future_cancel_write(
1580 &self,
1581 lookup_context: &PayloadLookupContext,
1582 name: &str,
1583 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1584 fn future_cancel_read(
1585 &self,
1586 lookup_context: &PayloadLookupContext,
1587 name: &str,
1588 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1589 fn future_drop_writable(
1590 &self,
1591 lookup_context: &PayloadLookupContext,
1592 name: &str,
1593 ) -> Option<PayloadInfo>;
1594 fn future_drop_readable(
1595 &self,
1596 lookup_context: &PayloadLookupContext,
1597 name: &str,
1598 ) -> Option<PayloadInfo>;
1599 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1600 fn stream_write(
1601 &self,
1602 lookup_context: &PayloadLookupContext,
1603 name: &str,
1604 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1605 fn stream_read(
1606 &self,
1607 lookup_context: &PayloadLookupContext,
1608 name: &str,
1609 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1610 fn stream_cancel_write(
1611 &self,
1612 lookup_context: &PayloadLookupContext,
1613 name: &str,
1614 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1615 fn stream_cancel_read(
1616 &self,
1617 lookup_context: &PayloadLookupContext,
1618 name: &str,
1619 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1620 fn stream_drop_writable(
1621 &self,
1622 lookup_context: &PayloadLookupContext,
1623 name: &str,
1624 ) -> Option<PayloadInfo>;
1625 fn stream_drop_readable(
1626 &self,
1627 lookup_context: &PayloadLookupContext,
1628 name: &str,
1629 ) -> Option<PayloadInfo>;
1630 fn thread_index(&self, name: &str) -> bool;
1631 fn thread_new_indirect(&self, name: &str) -> bool;
1632 fn thread_switch_to(&self, name: &str) -> Option<MaybeCancellable<()>>;
1633 fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>>;
1634 fn thread_resume_later(&self, name: &str) -> bool;
1635 fn thread_yield_to(&self, name: &str) -> Option<MaybeCancellable<()>>;
1636 fn module_to_interface(
1637 &self,
1638 module: &str,
1639 resolve: &Resolve,
1640 items: &IndexMap<WorldKey, WorldItem>,
1641 ) -> Result<(WorldKey, InterfaceId)>;
1642 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str>;
1643 fn match_wit_export<'a>(
1644 &self,
1645 export_name: &str,
1646 resolve: &'a Resolve,
1647 world: WorldId,
1648 exports: &'a IndexSet<WorldKey>,
1649 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)>;
1650 fn match_wit_resource_dtor<'a>(
1651 &self,
1652 export_name: &str,
1653 resolve: &'a Resolve,
1654 world: WorldId,
1655 exports: &'a IndexSet<WorldKey>,
1656 ) -> Option<TypeId>;
1657 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1658 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1659}
1660
1661struct Standard;
1664
1665const STANDARD: &'static dyn NameMangling = &Standard;
1666
1667impl NameMangling for Standard {
1668 fn import_root(&self) -> &str {
1669 ""
1670 }
1671 fn import_non_root_prefix(&self) -> &str {
1672 "|"
1673 }
1674 fn import_exported_intrinsic_prefix(&self) -> &str {
1675 "_ex_"
1676 }
1677 fn export_memory(&self) -> &str {
1678 "_memory"
1679 }
1680 fn export_initialize(&self) -> &str {
1681 "_initialize"
1682 }
1683 fn export_realloc(&self) -> &str {
1684 "_realloc"
1685 }
1686 fn export_indirect_function_table(&self) -> Option<&str> {
1687 None
1688 }
1689 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1690 name.strip_suffix("_drop")
1691 }
1692 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1693 name.strip_suffix("_new")
1694 }
1695 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1696 name.strip_suffix("_rep")
1697 }
1698 fn task_return_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1699 None
1700 }
1701 fn task_cancel(&self, _name: &str) -> bool {
1702 false
1703 }
1704 fn backpressure_set(&self, _name: &str) -> bool {
1705 false
1706 }
1707 fn backpressure_inc(&self, _name: &str) -> bool {
1708 false
1709 }
1710 fn backpressure_dec(&self, _name: &str) -> bool {
1711 false
1712 }
1713 fn waitable_set_new(&self, _name: &str) -> bool {
1714 false
1715 }
1716 fn waitable_set_wait(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1717 None
1718 }
1719 fn waitable_set_poll(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1720 None
1721 }
1722 fn waitable_set_drop(&self, _name: &str) -> bool {
1723 false
1724 }
1725 fn waitable_join(&self, _name: &str) -> bool {
1726 false
1727 }
1728 fn thread_yield(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1729 None
1730 }
1731 fn subtask_drop(&self, _name: &str) -> bool {
1732 false
1733 }
1734 fn subtask_cancel(&self, _name: &str) -> Option<MaybeAsyncLowered<()>> {
1735 None
1736 }
1737 fn async_lift_callback_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1738 None
1739 }
1740 fn async_lift_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1741 None
1742 }
1743 fn async_lift_stackful_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1744 None
1745 }
1746 fn error_context_new(&self, _name: &str) -> Option<StringEncoding> {
1747 None
1748 }
1749 fn error_context_debug_message(&self, _name: &str) -> Option<StringEncoding> {
1750 None
1751 }
1752 fn error_context_drop(&self, _name: &str) -> bool {
1753 false
1754 }
1755 fn context_get(&self, _name: &str) -> Option<u32> {
1756 None
1757 }
1758 fn context_set(&self, _name: &str) -> Option<u32> {
1759 None
1760 }
1761 fn thread_index(&self, _name: &str) -> bool {
1762 false
1763 }
1764 fn thread_new_indirect(&self, _name: &str) -> bool {
1765 false
1766 }
1767 fn thread_switch_to(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1768 None
1769 }
1770 fn thread_suspend(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1771 None
1772 }
1773 fn thread_resume_later(&self, _name: &str) -> bool {
1774 false
1775 }
1776 fn thread_yield_to(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1777 None
1778 }
1779 fn future_new(
1780 &self,
1781 _lookup_context: &PayloadLookupContext,
1782 _name: &str,
1783 ) -> Option<PayloadInfo> {
1784 None
1785 }
1786 fn future_write(
1787 &self,
1788 _lookup_context: &PayloadLookupContext,
1789 _name: &str,
1790 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1791 None
1792 }
1793 fn future_read(
1794 &self,
1795 _lookup_context: &PayloadLookupContext,
1796 _name: &str,
1797 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1798 None
1799 }
1800 fn future_cancel_write(
1801 &self,
1802 _lookup_context: &PayloadLookupContext,
1803 _name: &str,
1804 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1805 None
1806 }
1807 fn future_cancel_read(
1808 &self,
1809 _lookup_context: &PayloadLookupContext,
1810 _name: &str,
1811 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1812 None
1813 }
1814 fn future_drop_writable(
1815 &self,
1816 _lookup_context: &PayloadLookupContext,
1817 _name: &str,
1818 ) -> Option<PayloadInfo> {
1819 None
1820 }
1821 fn future_drop_readable(
1822 &self,
1823 _lookup_context: &PayloadLookupContext,
1824 _name: &str,
1825 ) -> Option<PayloadInfo> {
1826 None
1827 }
1828 fn stream_new(
1829 &self,
1830 _lookup_context: &PayloadLookupContext,
1831 _name: &str,
1832 ) -> Option<PayloadInfo> {
1833 None
1834 }
1835 fn stream_write(
1836 &self,
1837 _lookup_context: &PayloadLookupContext,
1838 _name: &str,
1839 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1840 None
1841 }
1842 fn stream_read(
1843 &self,
1844 _lookup_context: &PayloadLookupContext,
1845 _name: &str,
1846 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1847 None
1848 }
1849 fn stream_cancel_write(
1850 &self,
1851 _lookup_context: &PayloadLookupContext,
1852 _name: &str,
1853 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1854 None
1855 }
1856 fn stream_cancel_read(
1857 &self,
1858 _lookup_context: &PayloadLookupContext,
1859 _name: &str,
1860 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1861 None
1862 }
1863 fn stream_drop_writable(
1864 &self,
1865 _lookup_context: &PayloadLookupContext,
1866 _name: &str,
1867 ) -> Option<PayloadInfo> {
1868 None
1869 }
1870 fn stream_drop_readable(
1871 &self,
1872 _lookup_context: &PayloadLookupContext,
1873 _name: &str,
1874 ) -> Option<PayloadInfo> {
1875 None
1876 }
1877 fn module_to_interface(
1878 &self,
1879 interface: &str,
1880 resolve: &Resolve,
1881 items: &IndexMap<WorldKey, WorldItem>,
1882 ) -> Result<(WorldKey, InterfaceId)> {
1883 for (key, item) in items.iter() {
1884 let id = match key {
1885 WorldKey::Name(name) => match item {
1887 WorldItem::Interface { id, .. } if name == interface => *id,
1888 _ => continue,
1889 },
1890 WorldKey::Interface(id) => {
1892 if resolve.canonicalized_id_of(*id).as_deref() != Some(interface) {
1893 continue;
1894 }
1895 *id
1896 }
1897 };
1898 return Ok((key.clone(), id));
1899 }
1900 bail!("failed to find world item corresponding to interface `{interface}`")
1901 }
1902 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
1903 name.strip_suffix("_post")
1904 }
1905 fn match_wit_export<'a>(
1906 &self,
1907 export_name: &str,
1908 resolve: &'a Resolve,
1909 world: WorldId,
1910 exports: &'a IndexSet<WorldKey>,
1911 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
1912 if let Some(world_export_name) = export_name.strip_prefix("||") {
1913 let key = exports.get(&WorldKey::Name(world_export_name.to_string()))?;
1914 match &resolve.worlds[world].exports[key] {
1915 WorldItem::Function(f) => return Some((key, None, f)),
1916 _ => return None,
1917 }
1918 }
1919
1920 let (key, id, func_name) =
1921 self.match_wit_interface(export_name, resolve, world, exports)?;
1922 let func = resolve.interfaces[id].functions.get(func_name)?;
1923 Some((key, Some(id), func))
1924 }
1925
1926 fn match_wit_resource_dtor<'a>(
1927 &self,
1928 export_name: &str,
1929 resolve: &'a Resolve,
1930 world: WorldId,
1931 exports: &'a IndexSet<WorldKey>,
1932 ) -> Option<TypeId> {
1933 let (_key, id, name) =
1934 self.match_wit_interface(export_name.strip_suffix("_dtor")?, resolve, world, exports)?;
1935 let ty = *resolve.interfaces[id].types.get(name)?;
1936 match resolve.types[ty].kind {
1937 TypeDefKind::Resource => Some(ty),
1938 _ => None,
1939 }
1940 }
1941
1942 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
1943 (name, AbiVariant::GuestImport)
1944 }
1945 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
1946 (name, AbiVariant::GuestImport)
1947 }
1948}
1949
1950impl Standard {
1951 fn match_wit_interface<'a, 'b>(
1952 &self,
1953 export_name: &'b str,
1954 resolve: &'a Resolve,
1955 world: WorldId,
1956 exports: &'a IndexSet<WorldKey>,
1957 ) -> Option<(&'a WorldKey, InterfaceId, &'b str)> {
1958 let world = &resolve.worlds[world];
1959 let export_name = export_name.strip_prefix("|")?;
1960
1961 for export in exports {
1962 let id = match &world.exports[export] {
1963 WorldItem::Interface { id, .. } => *id,
1964 WorldItem::Function(_) => continue,
1965 WorldItem::Type(_) => unreachable!(),
1966 };
1967 let remaining = match export {
1968 WorldKey::Name(name) => export_name.strip_prefix(name),
1969 WorldKey::Interface(_) => {
1970 let prefix = resolve.canonicalized_id_of(id).unwrap();
1971 export_name.strip_prefix(&prefix)
1972 }
1973 };
1974 let item_name = match remaining.and_then(|s| s.strip_prefix("|")) {
1975 Some(name) => name,
1976 None => continue,
1977 };
1978 return Some((export, id, item_name));
1979 }
1980
1981 None
1982 }
1983}
1984
1985struct Legacy;
1988
1989const LEGACY: &'static dyn NameMangling = &Legacy;
1990
1991impl Legacy {
1992 fn prefixed_payload(
1998 &self,
1999 lookup_context: &PayloadLookupContext,
2000 name: &str,
2001 prefix: &str,
2002 ) -> Option<PayloadInfo> {
2003 let (index_or_unit, func_name) = prefixed_intrinsic(name, prefix)?;
2006 let ty = match index_or_unit {
2007 "unit" => {
2008 if name.starts_with("[future") {
2009 PayloadType::UnitFuture
2010 } else if name.starts_with("[stream") {
2011 PayloadType::UnitStream
2012 } else {
2013 unreachable!()
2014 }
2015 }
2016 other => {
2017 let type_index = other.parse::<u32>().ok()? as usize;
2021
2022 let function = get_function(
2027 lookup_context.resolve,
2028 lookup_context.world,
2029 func_name,
2030 lookup_context.id,
2031 lookup_context.import,
2032 )
2033 .ok()?;
2034 PayloadType::Type {
2035 id: *function
2036 .find_futures_and_streams(lookup_context.resolve)
2037 .get(type_index)?,
2038 function: function.name.clone(),
2039 }
2040 }
2041 };
2042
2043 Some(PayloadInfo {
2045 name: name.to_string(),
2046 ty,
2047 key: lookup_context
2048 .key
2049 .clone()
2050 .unwrap_or_else(|| WorldKey::Name(name.to_string())),
2051 interface: lookup_context.id,
2052 imported: lookup_context.import,
2053 })
2054 }
2055
2056 fn maybe_async_lowered_payload(
2057 &self,
2058 lookup_context: &PayloadLookupContext,
2059 name: &str,
2060 prefix: &str,
2061 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2062 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2063 let payload = self.prefixed_payload(lookup_context, clean_name, prefix)?;
2064 Some(MaybeAsyncLowered {
2065 inner: payload,
2066 async_lowered,
2067 })
2068 }
2069
2070 fn strip_async_lowered_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2071 name.strip_prefix("[async-lower]")
2072 .map_or((false, name), |s| (true, s))
2073 }
2074 fn match_with_async_lowered_prefix(
2075 &self,
2076 name: &str,
2077 expected: &str,
2078 ) -> Option<MaybeAsyncLowered<()>> {
2079 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2080 if clean_name == expected {
2081 Some(MaybeAsyncLowered {
2082 inner: (),
2083 async_lowered,
2084 })
2085 } else {
2086 None
2087 }
2088 }
2089 fn strip_cancellable_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2090 name.strip_prefix("[cancellable]")
2091 .map_or((false, name), |s| (true, s))
2092 }
2093 fn match_with_cancellable_prefix(
2094 &self,
2095 name: &str,
2096 expected: &str,
2097 ) -> Option<MaybeCancellable<()>> {
2098 let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2099 if clean_name == expected {
2100 Some(MaybeCancellable {
2101 inner: (),
2102 cancellable,
2103 })
2104 } else {
2105 None
2106 }
2107 }
2108}
2109
2110impl NameMangling for Legacy {
2111 fn import_root(&self) -> &str {
2112 "$root"
2113 }
2114 fn import_non_root_prefix(&self) -> &str {
2115 ""
2116 }
2117 fn import_exported_intrinsic_prefix(&self) -> &str {
2118 "[export]"
2119 }
2120 fn export_memory(&self) -> &str {
2121 "memory"
2122 }
2123 fn export_initialize(&self) -> &str {
2124 "_initialize"
2125 }
2126 fn export_realloc(&self) -> &str {
2127 "cabi_realloc"
2128 }
2129 fn export_indirect_function_table(&self) -> Option<&str> {
2130 Some("__indirect_function_table")
2131 }
2132 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2133 name.strip_prefix("[resource-drop]")
2134 }
2135 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2136 name.strip_prefix("[resource-new]")
2137 }
2138 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2139 name.strip_prefix("[resource-rep]")
2140 }
2141 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2142 name.strip_prefix("[task-return]")
2143 }
2144 fn task_cancel(&self, name: &str) -> bool {
2145 name == "[task-cancel]"
2146 }
2147 fn backpressure_set(&self, name: &str) -> bool {
2148 name == "[backpressure-set]"
2149 }
2150 fn backpressure_inc(&self, name: &str) -> bool {
2151 name == "[backpressure-inc]"
2152 }
2153 fn backpressure_dec(&self, name: &str) -> bool {
2154 name == "[backpressure-dec]"
2155 }
2156 fn waitable_set_new(&self, name: &str) -> bool {
2157 name == "[waitable-set-new]"
2158 }
2159 fn waitable_set_wait(&self, name: &str) -> Option<MaybeCancellable<()>> {
2160 self.match_with_cancellable_prefix(name, "[waitable-set-wait]")
2161 }
2162 fn waitable_set_poll(&self, name: &str) -> Option<MaybeCancellable<()>> {
2163 self.match_with_cancellable_prefix(name, "[waitable-set-poll]")
2164 }
2165 fn waitable_set_drop(&self, name: &str) -> bool {
2166 name == "[waitable-set-drop]"
2167 }
2168 fn waitable_join(&self, name: &str) -> bool {
2169 name == "[waitable-join]"
2170 }
2171 fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>> {
2172 self.match_with_cancellable_prefix(name, "[thread-yield]")
2173 }
2174 fn subtask_drop(&self, name: &str) -> bool {
2175 name == "[subtask-drop]"
2176 }
2177 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>> {
2178 self.match_with_async_lowered_prefix(name, "[subtask-cancel]")
2179 }
2180 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2181 name.strip_prefix("[callback][async-lift]")
2182 }
2183 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2184 name.strip_prefix("[async-lift]")
2185 }
2186 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2187 name.strip_prefix("[async-lift-stackful]")
2188 }
2189 fn error_context_new(&self, name: &str) -> Option<StringEncoding> {
2190 match name {
2191 "[error-context-new-utf8]" => Some(StringEncoding::UTF8),
2192 "[error-context-new-utf16]" => Some(StringEncoding::UTF16),
2193 "[error-context-new-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2194 _ => None,
2195 }
2196 }
2197 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding> {
2198 match name {
2199 "[error-context-debug-message-utf8]" => Some(StringEncoding::UTF8),
2200 "[error-context-debug-message-utf16]" => Some(StringEncoding::UTF16),
2201 "[error-context-debug-message-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2202 _ => None,
2203 }
2204 }
2205 fn error_context_drop(&self, name: &str) -> bool {
2206 name == "[error-context-drop]"
2207 }
2208 fn context_get(&self, name: &str) -> Option<u32> {
2209 let (n, rest) = prefixed_integer(name, "[context-get-")?;
2210 if rest.is_empty() { Some(n) } else { None }
2211 }
2212 fn context_set(&self, name: &str) -> Option<u32> {
2213 let (n, rest) = prefixed_integer(name, "[context-set-")?;
2214 if rest.is_empty() { Some(n) } else { None }
2215 }
2216 fn thread_index(&self, name: &str) -> bool {
2217 name == "[thread-index]"
2218 }
2219 fn thread_new_indirect(&self, name: &str) -> bool {
2220 name == "[thread-new-indirect-v0]"
2222 }
2223 fn thread_switch_to(&self, name: &str) -> Option<MaybeCancellable<()>> {
2224 self.match_with_cancellable_prefix(name, "[thread-switch-to]")
2225 }
2226 fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>> {
2227 self.match_with_cancellable_prefix(name, "[thread-suspend]")
2228 }
2229 fn thread_resume_later(&self, name: &str) -> bool {
2230 name == "[thread-resume-later]"
2231 }
2232 fn thread_yield_to(&self, name: &str) -> Option<MaybeCancellable<()>> {
2233 self.match_with_cancellable_prefix(name, "[thread-yield-to]")
2234 }
2235 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2236 self.prefixed_payload(lookup_context, name, "[future-new-")
2237 }
2238 fn future_write(
2239 &self,
2240 lookup_context: &PayloadLookupContext,
2241 name: &str,
2242 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2243 self.maybe_async_lowered_payload(lookup_context, name, "[future-write-")
2244 }
2245 fn future_read(
2246 &self,
2247 lookup_context: &PayloadLookupContext,
2248 name: &str,
2249 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2250 self.maybe_async_lowered_payload(lookup_context, name, "[future-read-")
2251 }
2252 fn future_cancel_write(
2253 &self,
2254 lookup_context: &PayloadLookupContext,
2255 name: &str,
2256 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2257 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-write-")
2258 }
2259 fn future_cancel_read(
2260 &self,
2261 lookup_context: &PayloadLookupContext,
2262 name: &str,
2263 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2264 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-read-")
2265 }
2266 fn future_drop_writable(
2267 &self,
2268 lookup_context: &PayloadLookupContext,
2269 name: &str,
2270 ) -> Option<PayloadInfo> {
2271 self.prefixed_payload(lookup_context, name, "[future-drop-writable-")
2272 }
2273 fn future_drop_readable(
2274 &self,
2275 lookup_context: &PayloadLookupContext,
2276 name: &str,
2277 ) -> Option<PayloadInfo> {
2278 self.prefixed_payload(lookup_context, name, "[future-drop-readable-")
2279 }
2280 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2281 self.prefixed_payload(lookup_context, name, "[stream-new-")
2282 }
2283 fn stream_write(
2284 &self,
2285 lookup_context: &PayloadLookupContext,
2286 name: &str,
2287 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2288 self.maybe_async_lowered_payload(lookup_context, name, "[stream-write-")
2289 }
2290 fn stream_read(
2291 &self,
2292 lookup_context: &PayloadLookupContext,
2293 name: &str,
2294 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2295 self.maybe_async_lowered_payload(lookup_context, name, "[stream-read-")
2296 }
2297 fn stream_cancel_write(
2298 &self,
2299 lookup_context: &PayloadLookupContext,
2300 name: &str,
2301 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2302 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-write-")
2303 }
2304 fn stream_cancel_read(
2305 &self,
2306 lookup_context: &PayloadLookupContext,
2307 name: &str,
2308 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2309 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-read-")
2310 }
2311 fn stream_drop_writable(
2312 &self,
2313 lookup_context: &PayloadLookupContext,
2314 name: &str,
2315 ) -> Option<PayloadInfo> {
2316 self.prefixed_payload(lookup_context, name, "[stream-drop-writable-")
2317 }
2318 fn stream_drop_readable(
2319 &self,
2320 lookup_context: &PayloadLookupContext,
2321 name: &str,
2322 ) -> Option<PayloadInfo> {
2323 self.prefixed_payload(lookup_context, name, "[stream-drop-readable-")
2324 }
2325 fn module_to_interface(
2326 &self,
2327 module: &str,
2328 resolve: &Resolve,
2329 items: &IndexMap<WorldKey, WorldItem>,
2330 ) -> Result<(WorldKey, InterfaceId)> {
2331 let bare_name = WorldKey::Name(module.to_string());
2333 if let Some(WorldItem::Interface { id, .. }) = items.get(&bare_name) {
2334 return Ok((bare_name, *id));
2335 }
2336
2337 let kebab_name = ComponentName::new(module, 0);
2343 let name = match kebab_name.as_ref().map(|k| k.kind()) {
2344 Ok(ComponentNameKind::Interface(name)) => name,
2345 _ => bail!("module requires an import interface named `{module}`"),
2346 };
2347
2348 let pkgname = PackageName {
2350 namespace: name.namespace().to_string(),
2351 name: name.package().to_string(),
2352 version: name.version(),
2353 };
2354 if let Some(pkg) = resolve.package_names.get(&pkgname) {
2355 if let Some(id) = resolve.packages[*pkg]
2356 .interfaces
2357 .get(name.interface().as_str())
2358 {
2359 let key = WorldKey::Interface(*id);
2360 if items.contains_key(&key) {
2361 return Ok((key, *id));
2362 }
2363 }
2364 }
2365
2366 for (key, _) in items {
2371 let id = match key {
2372 WorldKey::Interface(id) => *id,
2373 WorldKey::Name(_) => continue,
2374 };
2375 let interface = &resolve.interfaces[id];
2377 if interface.name.as_ref().unwrap() != name.interface().as_str() {
2378 continue;
2379 }
2380
2381 let pkg = &resolve.packages[interface.package.unwrap()];
2383 if pkg.name.namespace != pkgname.namespace || pkg.name.name != pkgname.name {
2384 continue;
2385 }
2386
2387 let module_version = match name.version() {
2388 Some(version) => version,
2389 None => continue,
2390 };
2391 let pkg_version = match &pkg.name.version {
2392 Some(version) => version,
2393 None => continue,
2394 };
2395
2396 let module_compat = PackageName::version_compat_track(&module_version);
2398 let pkg_compat = PackageName::version_compat_track(pkg_version);
2399 if module_compat == pkg_compat {
2400 return Ok((key.clone(), id));
2401 }
2402 }
2403
2404 bail!("module requires an import interface named `{module}`")
2405 }
2406 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
2407 name.strip_prefix("cabi_post_")
2408 }
2409 fn match_wit_export<'a>(
2410 &self,
2411 export_name: &str,
2412 resolve: &'a Resolve,
2413 world: WorldId,
2414 exports: &'a IndexSet<WorldKey>,
2415 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
2416 let world = &resolve.worlds[world];
2417 for name in exports {
2418 match &world.exports[name] {
2419 WorldItem::Function(f) => {
2420 if f.legacy_core_export_name(None) == export_name {
2421 return Some((name, None, f));
2422 }
2423 }
2424 WorldItem::Interface { id, .. } => {
2425 let string = resolve.name_world_key(name);
2426 for (_, func) in resolve.interfaces[*id].functions.iter() {
2427 if func.legacy_core_export_name(Some(&string)) == export_name {
2428 return Some((name, Some(*id), func));
2429 }
2430 }
2431 }
2432
2433 WorldItem::Type(_) => unreachable!(),
2434 }
2435 }
2436
2437 None
2438 }
2439
2440 fn match_wit_resource_dtor<'a>(
2441 &self,
2442 export_name: &str,
2443 resolve: &'a Resolve,
2444 world: WorldId,
2445 exports: &'a IndexSet<WorldKey>,
2446 ) -> Option<TypeId> {
2447 let world = &resolve.worlds[world];
2448 for name in exports {
2449 let id = match &world.exports[name] {
2450 WorldItem::Interface { id, .. } => *id,
2451 WorldItem::Function(_) => continue,
2452 WorldItem::Type(_) => unreachable!(),
2453 };
2454 let name = resolve.name_world_key(name);
2455 let resource = match export_name
2456 .strip_prefix(&name)
2457 .and_then(|s| s.strip_prefix("#[dtor]"))
2458 .and_then(|r| resolve.interfaces[id].types.get(r))
2459 {
2460 Some(id) => *id,
2461 None => continue,
2462 };
2463
2464 match resolve.types[resource].kind {
2465 TypeDefKind::Resource => {}
2466 _ => continue,
2467 }
2468
2469 return Some(resource);
2470 }
2471
2472 None
2473 }
2474
2475 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2476 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2477 (
2478 name,
2479 if async_abi {
2480 AbiVariant::GuestImportAsync
2481 } else {
2482 AbiVariant::GuestImport
2483 },
2484 )
2485 }
2486 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2487 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2488 (
2489 name,
2490 if async_abi {
2491 AbiVariant::GuestImportAsync
2492 } else {
2493 AbiVariant::GuestImport
2494 },
2495 )
2496 }
2497}
2498
2499pub fn validate_module(
2511 encoder: &ComponentEncoder,
2512 bytes: &[u8],
2513 import_map: Option<&ModuleImportMap>,
2514) -> Result<ValidatedModule> {
2515 ValidatedModule::new(
2516 encoder,
2517 bytes,
2518 &encoder.main_module_exports,
2519 import_map,
2520 None,
2521 )
2522}
2523
2524pub fn validate_adapter_module(
2542 encoder: &ComponentEncoder,
2543 bytes: &[u8],
2544 required_by_import: &IndexMap<String, FuncType>,
2545 exports: &IndexSet<WorldKey>,
2546 library_info: Option<&LibraryInfo>,
2547) -> Result<ValidatedModule> {
2548 let ret = ValidatedModule::new(encoder, bytes, exports, None, library_info)?;
2549
2550 for (name, required_ty) in required_by_import {
2551 let actual = match ret.exports.raw_exports.get(name) {
2552 Some(ty) => ty,
2553 None => return Err(AdapterModuleDidNotExport(name.clone()).into()),
2554 };
2555 validate_func_sig(name, required_ty, &actual)?;
2556 }
2557
2558 Ok(ret)
2559}
2560
2561#[derive(Debug, Clone)]
2568pub struct AdapterModuleDidNotExport(String);
2569
2570impl fmt::Display for AdapterModuleDidNotExport {
2571 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2572 write!(f, "adapter module did not export `{}`", self.0)
2573 }
2574}
2575
2576impl std::error::Error for AdapterModuleDidNotExport {}
2577
2578fn resource_test_for_interface<'a>(
2579 resolve: &'a Resolve,
2580 id: InterfaceId,
2581) -> impl Fn(&str) -> Option<TypeId> + 'a {
2582 let interface = &resolve.interfaces[id];
2583 move |name: &str| {
2584 let ty = match interface.types.get(name) {
2585 Some(ty) => *ty,
2586 None => return None,
2587 };
2588 if matches!(resolve.types[ty].kind, TypeDefKind::Resource) {
2589 Some(ty)
2590 } else {
2591 None
2592 }
2593 }
2594}
2595
2596fn resource_test_for_world<'a>(
2597 resolve: &'a Resolve,
2598 id: WorldId,
2599) -> impl Fn(&str) -> Option<TypeId> + 'a {
2600 let world = &resolve.worlds[id];
2601 move |name: &str| match world.imports.get(&WorldKey::Name(name.to_string()))? {
2602 WorldItem::Type(r) => {
2603 if matches!(resolve.types[*r].kind, TypeDefKind::Resource) {
2604 Some(*r)
2605 } else {
2606 None
2607 }
2608 }
2609 _ => None,
2610 }
2611}
2612
2613fn validate_func(
2614 resolve: &Resolve,
2615 ty: &wasmparser::FuncType,
2616 func: &Function,
2617 abi: AbiVariant,
2618) -> Result<()> {
2619 validate_func_sig(
2620 &func.name,
2621 &wasm_sig_to_func_type(resolve.wasm_signature(abi, func)),
2622 ty,
2623 )
2624}
2625
2626fn validate_post_return(
2627 resolve: &Resolve,
2628 ty: &wasmparser::FuncType,
2629 func: &Function,
2630) -> Result<()> {
2631 let mut sig = resolve.wasm_signature(AbiVariant::GuestExport, func);
2637 sig.params = mem::take(&mut sig.results);
2638 validate_func_sig(
2639 &format!("{} post-return", func.name),
2640 &wasm_sig_to_func_type(sig),
2641 ty,
2642 )
2643}
2644
2645fn validate_func_sig(name: &str, expected: &FuncType, ty: &wasmparser::FuncType) -> Result<()> {
2646 if ty != expected {
2647 bail!(
2648 "type mismatch for function `{}`: expected `{:?} -> {:?}` but found `{:?} -> {:?}`",
2649 name,
2650 expected.params(),
2651 expected.results(),
2652 ty.params(),
2653 ty.results()
2654 );
2655 }
2656
2657 Ok(())
2658}
2659
2660fn prefixed_intrinsic<'a>(name: &'a str, prefix: &str) -> Option<(&'a str, &'a str)> {
2662 assert!(prefix.starts_with("["));
2663 assert!(prefix.ends_with("-"));
2664 let suffix = name.strip_prefix(prefix)?;
2665 let index = suffix.find(']')?;
2666 let rest = &suffix[index + 1..];
2667 Some((&suffix[..index], rest))
2668}
2669
2670fn prefixed_integer<'a>(name: &'a str, prefix: &str) -> Option<(u32, &'a str)> {
2672 let (suffix, rest) = prefixed_intrinsic(name, prefix)?;
2673 let n = suffix.parse().ok()?;
2674 Some((n, rest))
2675}
2676
2677fn get_function<'a>(
2678 resolve: &'a Resolve,
2679 world: &'a World,
2680 name: &str,
2681 interface: Option<InterfaceId>,
2682 imported: bool,
2683) -> Result<&'a Function> {
2684 let function = if let Some(id) = interface {
2685 return resolve.interfaces[id]
2686 .functions
2687 .get(name)
2688 .ok_or_else(|| anyhow!("no export `{name}` found"));
2689 } else if imported {
2690 world.imports.get(&WorldKey::Name(name.to_string()))
2691 } else {
2692 world.exports.get(&WorldKey::Name(name.to_string()))
2693 };
2694 let Some(WorldItem::Function(function)) = function else {
2695 bail!("no export `{name}` found");
2696 };
2697 Ok(function)
2698}