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