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