1use crate::encoding::{Instance, Item, LibraryInfo, MainOrAdapter};
2use crate::{ComponentEncoder, StringEncoding};
3use anyhow::{anyhow, bail, Context, Result};
4use indexmap::{map::Entry, IndexMap, IndexSet};
5use std::hash::{Hash, Hasher};
6use std::mem;
7use wasm_encoder::ExportKind;
8use wasmparser::names::{ComponentName, ComponentNameKind};
9use wasmparser::{
10 types::TypesRef, Encoding, ExternalKind, FuncType, Parser, Payload, TypeRef, ValType,
11 ValidPayload, Validator,
12};
13use wit_parser::{
14 abi::{AbiVariant, WasmSignature, WasmType},
15 Function, InterfaceId, PackageName, Resolve, Type, TypeDefKind, TypeId, World, WorldId,
16 WorldItem, WorldKey,
17};
18
19fn wasm_sig_to_func_type(signature: WasmSignature) -> FuncType {
20 fn from_wasm_type(ty: &WasmType) -> ValType {
21 match ty {
22 WasmType::I32 => ValType::I32,
23 WasmType::I64 => ValType::I64,
24 WasmType::F32 => ValType::F32,
25 WasmType::F64 => ValType::F64,
26 WasmType::Pointer => ValType::I32,
27 WasmType::PointerOrI64 => ValType::I64,
28 WasmType::Length => ValType::I32,
29 }
30 }
31
32 FuncType::new(
33 signature.params.iter().map(from_wasm_type),
34 signature.results.iter().map(from_wasm_type),
35 )
36}
37
38#[derive(Default)]
46pub struct ValidatedModule {
47 pub imports: ImportMap,
49
50 pub exports: ExportMap,
52}
53
54impl ValidatedModule {
55 fn new(
56 encoder: &ComponentEncoder,
57 bytes: &[u8],
58 exports: &IndexSet<WorldKey>,
59 info: Option<&LibraryInfo>,
60 ) -> Result<ValidatedModule> {
61 let mut validator = Validator::new();
62 let mut ret = ValidatedModule::default();
63
64 for payload in Parser::new(0).parse_all(bytes) {
65 let payload = payload?;
66 if let ValidPayload::End(_) = validator.payload(&payload)? {
67 break;
68 }
69
70 let types = validator.types(0).unwrap();
71
72 match payload {
73 Payload::Version { encoding, .. } if encoding != Encoding::Module => {
74 bail!("data is not a WebAssembly module");
75 }
76 Payload::ImportSection(s) => {
77 for import in s {
78 let import = import?;
79 ret.imports.add(import, encoder, info, types)?;
80 }
81 }
82 Payload::ExportSection(s) => {
83 for export in s {
84 let export = export?;
85 ret.exports.add(export, encoder, &exports, types)?;
86 }
87 }
88 _ => continue,
89 }
90 }
91
92 ret.exports.validate(encoder, exports)?;
93
94 Ok(ret)
95 }
96}
97
98#[derive(Default)]
104pub struct ImportMap {
105 names: IndexMap<String, ImportInstance>,
109}
110
111pub enum ImportInstance {
112 Whole(MainOrAdapter),
115
116 Names(IndexMap<String, Import>),
118}
119
120#[derive(Debug, Eq, PartialEq, Clone)]
137pub struct PayloadInfo {
138 pub name: String,
141 pub ty: TypeId,
143 pub function: String,
146 pub key: WorldKey,
148 pub interface: Option<InterfaceId>,
150 pub imported: bool,
155}
156
157impl PayloadInfo {
158 pub fn payload(&self, resolve: &Resolve) -> Option<Type> {
160 match resolve.types[self.ty].kind {
161 TypeDefKind::Future(payload) | TypeDefKind::Stream(payload) => payload,
162 _ => unreachable!(),
163 }
164 }
165}
166
167impl Hash for PayloadInfo {
168 fn hash<H: Hasher>(&self, state: &mut H) {
173 self.name.hash(state);
174 self.ty.hash(state);
175 self.key.hash(state);
176 self.interface.hash(state);
177 self.imported.hash(state);
178 }
179}
180
181#[derive(Debug, Clone)]
188pub enum Import {
189 WorldFunc(WorldKey, String, AbiVariant),
192
193 InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
199
200 ImportedResourceDrop(WorldKey, Option<InterfaceId>, TypeId),
206
207 ExportedResourceDrop(WorldKey, TypeId),
213
214 ExportedResourceNew(WorldKey, TypeId),
220
221 ExportedResourceRep(WorldKey, TypeId),
227
228 AdapterExport(FuncType),
234
235 MainModuleMemory,
239
240 MainModuleExport { name: String, kind: ExportKind },
242
243 Item(Item),
249
250 ExportedTaskReturn(WorldKey, Option<InterfaceId>, String, Option<Type>),
259
260 ExportedTaskCancel,
264
265 ContextGet(u32),
267 ContextSet(u32),
269
270 BackpressureSet,
275
276 WaitableSetNew,
278
279 WaitableSetWait { async_: bool },
285
286 WaitableSetPoll { async_: bool },
292
293 WaitableSetDrop,
295
296 WaitableJoin,
298
299 Yield { async_: bool },
304
305 SubtaskDrop,
309
310 SubtaskCancel { async_: bool },
314
315 StreamNew(PayloadInfo),
319
320 StreamRead { async_: bool, info: PayloadInfo },
325
326 StreamWrite { async_: bool, info: PayloadInfo },
331
332 StreamCancelRead { info: PayloadInfo, async_: bool },
337
338 StreamCancelWrite { info: PayloadInfo, async_: bool },
343
344 StreamCloseReadable(PayloadInfo),
348
349 StreamCloseWritable(PayloadInfo),
353
354 FutureNew(PayloadInfo),
358
359 FutureRead { async_: bool, info: PayloadInfo },
364
365 FutureWrite { async_: bool, info: PayloadInfo },
369
370 FutureCancelRead { info: PayloadInfo, async_: bool },
375
376 FutureCancelWrite { info: PayloadInfo, async_: bool },
381
382 FutureCloseReadable(PayloadInfo),
386
387 FutureCloseWritable(PayloadInfo),
391
392 ErrorContextNew { encoding: StringEncoding },
397
398 ErrorContextDebugMessage { encoding: StringEncoding },
404
405 ErrorContextDrop,
410}
411
412impl ImportMap {
413 pub fn required_from_adapter(&self, name: &str) -> IndexMap<String, FuncType> {
415 let names = match self.names.get(name) {
416 Some(ImportInstance::Names(names)) => names,
417 _ => return IndexMap::new(),
418 };
419 names
420 .iter()
421 .map(|(name, import)| {
422 (
423 name.clone(),
424 match import {
425 Import::AdapterExport(ty) => ty.clone(),
426 _ => unreachable!(),
427 },
428 )
429 })
430 .collect()
431 }
432
433 pub fn imports(&self) -> impl Iterator<Item = (&str, &str, &Import)> + '_ {
437 self.names
438 .iter()
439 .filter_map(|(module, m)| match m {
440 ImportInstance::Names(names) => Some((module, names)),
441 ImportInstance::Whole(_) => None,
442 })
443 .flat_map(|(module, m)| {
444 m.iter()
445 .map(move |(field, import)| (module.as_str(), field.as_str(), import))
446 })
447 }
448
449 pub fn modules(&self) -> &IndexMap<String, ImportInstance> {
451 &self.names
452 }
453
454 fn add(
457 &mut self,
458 import: wasmparser::Import<'_>,
459 encoder: &ComponentEncoder,
460 library_info: Option<&LibraryInfo>,
461 types: TypesRef<'_>,
462 ) -> Result<()> {
463 if self.classify_import_with_library(import, library_info)? {
464 return Ok(());
465 }
466 let item = self.classify(import, encoder, types).with_context(|| {
467 format!(
468 "failed to resolve import `{}::{}`",
469 import.module, import.name,
470 )
471 })?;
472 self.insert_import(import, item)
473 }
474
475 fn classify(
481 &self,
482 import: wasmparser::Import<'_>,
483 encoder: &ComponentEncoder,
484 types: TypesRef<'_>,
485 ) -> Result<Import> {
486 if import.module == "env" && import.name == "memory" {
489 return Ok(Import::MainModuleMemory);
490 }
491
492 if import.module == "__main_module__" {
494 return Ok(Import::MainModuleExport {
495 name: import.name.to_string(),
496 kind: match import.ty {
497 TypeRef::Func(_) => ExportKind::Func,
498 TypeRef::Table(_) => ExportKind::Table,
499 TypeRef::Memory(_) => ExportKind::Memory,
500 TypeRef::Global(_) => ExportKind::Global,
501 TypeRef::Tag(_) => ExportKind::Tag,
502 },
503 });
504 }
505
506 let ty_index = match import.ty {
507 TypeRef::Func(ty) => ty,
508 _ => bail!("module is only allowed to import functions"),
509 };
510 let ty = types[types.core_type_at_in_module(ty_index)].unwrap_func();
511
512 if encoder.adapters.contains_key(import.module) {
515 return Ok(Import::AdapterExport(ty.clone()));
516 }
517
518 let (module, names) = match import.module.strip_prefix("cm32p2") {
519 Some(suffix) => (suffix, STANDARD),
520 None if encoder.reject_legacy_names => (import.module, STANDARD),
521 None => (import.module, LEGACY),
522 };
523 self.classify_component_model_import(module, import.name, encoder, ty, names)
524 }
525
526 fn classify_component_model_import(
529 &self,
530 module: &str,
531 name: &str,
532 encoder: &ComponentEncoder,
533 ty: &FuncType,
534 names: &dyn NameMangling,
535 ) -> Result<Import> {
536 let resolve = &encoder.metadata.resolve;
537 let world_id = encoder.metadata.world;
538 let world = &resolve.worlds[world_id];
539
540 let (async_, name) = if let Some(name) = names.async_lower_name(name) {
541 (true, name)
542 } else {
543 (false, name)
544 };
545 let abi = if async_ {
546 AbiVariant::GuestImportAsync
547 } else {
548 AbiVariant::GuestImport
549 };
550 let validate_not_async = || {
551 if async_ {
552 bail!("`{name}` cannot be marked `async`")
553 }
554 Ok(())
555 };
556
557 if module == names.import_root() {
558 if Some(name) == names.error_context_drop() {
559 validate_not_async()?;
560 let expected = FuncType::new([ValType::I32], []);
561 validate_func_sig(name, &expected, ty)?;
562 return Ok(Import::ErrorContextDrop);
563 }
564
565 if Some(name) == names.backpressure_set() {
566 validate_not_async()?;
567 let expected = FuncType::new([ValType::I32], []);
568 validate_func_sig(name, &expected, ty)?;
569 return Ok(Import::BackpressureSet);
570 }
571
572 if Some(name) == names.waitable_set_new() {
573 validate_not_async()?;
574 let expected = FuncType::new([], [ValType::I32]);
575 validate_func_sig(name, &expected, ty)?;
576 return Ok(Import::WaitableSetNew);
577 }
578
579 if Some(name) == names.waitable_set_wait() {
580 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
581 validate_func_sig(name, &expected, ty)?;
582 return Ok(Import::WaitableSetWait {
583 async_: abi == AbiVariant::GuestImportAsync,
584 });
585 }
586
587 if Some(name) == names.waitable_set_poll() {
588 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
589 validate_func_sig(name, &expected, ty)?;
590 return Ok(Import::WaitableSetPoll {
591 async_: abi == AbiVariant::GuestImportAsync,
592 });
593 }
594
595 if Some(name) == names.waitable_set_drop() {
596 validate_not_async()?;
597 let expected = FuncType::new([ValType::I32], []);
598 validate_func_sig(name, &expected, ty)?;
599 return Ok(Import::WaitableSetDrop);
600 }
601
602 if Some(name) == names.waitable_join() {
603 validate_not_async()?;
604 let expected = FuncType::new([ValType::I32; 2], []);
605 validate_func_sig(name, &expected, ty)?;
606 return Ok(Import::WaitableJoin);
607 }
608
609 if Some(name) == names.yield_() {
610 let expected = FuncType::new([], [ValType::I32]);
611 validate_func_sig(name, &expected, ty)?;
612 return Ok(Import::Yield { async_ });
613 }
614
615 if Some(name) == names.subtask_drop() {
616 validate_not_async()?;
617 let expected = FuncType::new([ValType::I32], []);
618 validate_func_sig(name, &expected, ty)?;
619 return Ok(Import::SubtaskDrop);
620 }
621
622 if Some(name) == names.subtask_cancel() {
623 let expected = FuncType::new([ValType::I32], [ValType::I32]);
624 validate_func_sig(name, &expected, ty)?;
625 return Ok(Import::SubtaskCancel { async_ });
626 }
627
628 if let Some(encoding) = names.error_context_new(name) {
629 validate_not_async()?;
630 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
631 validate_func_sig(name, &expected, ty)?;
632 return Ok(Import::ErrorContextNew { encoding });
633 }
634
635 if let Some(encoding) = names.error_context_debug_message(name) {
636 validate_not_async()?;
637 let expected = FuncType::new([ValType::I32; 2], []);
638 validate_func_sig(name, &expected, ty)?;
639 return Ok(Import::ErrorContextDebugMessage { encoding });
640 }
641
642 if let Some(i) = names.context_get(name) {
643 validate_not_async()?;
644 let expected = FuncType::new([], [ValType::I32]);
645 validate_func_sig(name, &expected, ty)?;
646 return Ok(Import::ContextGet(i));
647 }
648 if let Some(i) = names.context_set(name) {
649 validate_not_async()?;
650 let expected = FuncType::new([ValType::I32], []);
651 validate_func_sig(name, &expected, ty)?;
652 return Ok(Import::ContextSet(i));
653 }
654
655 let key = WorldKey::Name(name.to_string());
656 if let Some(WorldItem::Function(func)) = world.imports.get(&key) {
657 validate_func(resolve, ty, func, abi)?;
658 return Ok(Import::WorldFunc(key, func.name.clone(), abi));
659 }
660
661 if let Some(import) =
662 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, async_, true, names)?
663 {
664 return Ok(import);
665 }
666
667 match world.imports.get(&key) {
668 Some(_) => bail!("expected world top-level import `{name}` to be a function"),
669 None => bail!("no top-level imported function `{name}` specified"),
670 }
671 }
672
673 if matches!(
675 module.strip_prefix(names.import_exported_intrinsic_prefix()),
676 Some(module) if module == names.import_root()
677 ) {
678 if let Some(import) =
679 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, async_, false, names)?
680 {
681 return Ok(import);
682 }
683 }
684
685 let interface = match module.strip_prefix(names.import_non_root_prefix()) {
686 Some(name) => name,
687 None => bail!("unknown or invalid component model import syntax"),
688 };
689
690 if let Some(interface) = interface.strip_prefix(names.import_exported_intrinsic_prefix()) {
691 let (key, id) = names.module_to_interface(interface, resolve, &world.exports)?;
692
693 if let Some(import) = self.maybe_classify_wit_intrinsic(
694 name,
695 Some((key, id)),
696 encoder,
697 ty,
698 async_,
699 false,
700 names,
701 )? {
702 return Ok(import);
703 }
704 bail!("unknown function `{name}`")
705 }
706
707 let (key, id) = names.module_to_interface(interface, resolve, &world.imports)?;
708 let interface = &resolve.interfaces[id];
709 if let Some(f) = interface.functions.get(name) {
710 validate_func(resolve, ty, f, abi).with_context(|| {
711 let name = resolve.name_world_key(&key);
712 format!("failed to validate import interface `{name}`")
713 })?;
714 return Ok(Import::InterfaceFunc(key, id, f.name.clone(), abi));
715 }
716
717 if let Some(import) = self.maybe_classify_wit_intrinsic(
718 name,
719 Some((key, id)),
720 encoder,
721 ty,
722 async_,
723 true,
724 names,
725 )? {
726 return Ok(import);
727 }
728 bail!(
729 "import interface `{module}` is missing function \
730 `{name}` that is required by the module",
731 )
732 }
733
734 fn maybe_classify_wit_intrinsic(
764 &self,
765 name: &str,
766 key_and_id: Option<(WorldKey, InterfaceId)>,
767 encoder: &ComponentEncoder,
768 ty: &FuncType,
769 async_: bool,
770 import: bool,
771 names: &dyn NameMangling,
772 ) -> Result<Option<Import>> {
773 let resolve = &encoder.metadata.resolve;
774 let world_id = encoder.metadata.world;
775 let world = &resolve.worlds[world_id];
776
777 let (key, id) = match key_and_id {
782 Some((key, id)) => (Some(key), Some(id)),
783 None => (None, None),
784 };
785
786 let resource_test = |name: &str| match id {
788 Some(id) => resource_test_for_interface(resolve, id)(name),
789 None => resource_test_for_world(resolve, world_id)(name),
790 };
791
792 if let Some(resource) = names.resource_drop_name(name) {
794 if async_ {
795 bail!("async `resource.drop` calls not supported");
796 }
797 if let Some(resource_id) = resource_test(resource) {
798 let key = key.unwrap_or_else(|| WorldKey::Name(resource.to_string()));
799 let expected = FuncType::new([ValType::I32], []);
800 validate_func_sig(name, &expected, ty)?;
801 return Ok(Some(if import {
802 Import::ImportedResourceDrop(key, id, resource_id)
803 } else {
804 Import::ExportedResourceDrop(key, resource_id)
805 }));
806 }
807 }
808
809 if !import {
812 if let Some(name) = names.resource_new_name(name) {
813 if let Some(id) = resource_test(name) {
814 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
815 let expected = FuncType::new([ValType::I32], [ValType::I32]);
816 validate_func_sig(name, &expected, ty)?;
817 return Ok(Some(Import::ExportedResourceNew(key, id)));
818 }
819 }
820 if let Some(name) = names.resource_rep_name(name) {
821 if let Some(id) = resource_test(name) {
822 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
823 let expected = FuncType::new([ValType::I32], [ValType::I32]);
824 validate_func_sig(name, &expected, ty)?;
825 return Ok(Some(Import::ExportedResourceRep(key, id)));
826 }
827 }
828 if let Some(name) = names.task_return_name(name) {
829 let func = get_function(resolve, world, name, id, import)?;
830 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
831 return Ok(Some(Import::ExportedTaskReturn(
834 key,
835 id,
836 func.name.clone(),
837 func.result,
838 )));
839 }
840 if Some(name) == names.task_cancel() {
841 if async_ {
842 bail!("async `task.cancel` calls not supported");
843 }
844 let expected = FuncType::new([], []);
845 validate_func_sig(name, &expected, ty)?;
846 return Ok(Some(Import::ExportedTaskCancel));
847 }
848 }
849
850 let prefixed_payload = |prefix: &str| {
856 let (type_index, func_name) = prefixed_integer(name, prefix)?;
859 let type_index = type_index as usize;
860
861 let function = get_function(resolve, world, func_name, id, import).ok()?;
866 let ty = *function.find_futures_and_streams(resolve).get(type_index)?;
867
868 Some(PayloadInfo {
870 name: name.to_string(),
871 ty,
872 function: function.name.clone(),
873 key: key
874 .clone()
875 .unwrap_or_else(|| WorldKey::Name(name.to_string())),
876 interface: id,
877 imported: import,
878 })
879 };
880
881 let import = if let Some(info) = prefixed_payload("[future-new-") {
885 if async_ {
886 bail!("async `future.new` calls not supported");
887 }
888 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
889 Import::FutureNew(info)
890 } else if let Some(info) = prefixed_payload("[future-write-") {
891 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
892 Import::FutureWrite { async_, info }
893 } else if let Some(info) = prefixed_payload("[future-read-") {
894 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
895 Import::FutureRead { async_, info }
896 } else if let Some(info) = prefixed_payload("[future-cancel-write-") {
897 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
898 Import::FutureCancelWrite { async_, info }
899 } else if let Some(info) = prefixed_payload("[future-cancel-read-") {
900 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
901 Import::FutureCancelRead { async_, info }
902 } else if let Some(info) = prefixed_payload("[future-close-writable-") {
903 if async_ {
904 bail!("async `future.close-writable` calls not supported");
905 }
906 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
907 Import::FutureCloseWritable(info)
908 } else if let Some(info) = prefixed_payload("[future-close-readable-") {
909 if async_ {
910 bail!("async `future.close-readable` calls not supported");
911 }
912 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
913 Import::FutureCloseReadable(info)
914 } else if let Some(info) = prefixed_payload("[stream-new-") {
915 if async_ {
916 bail!("async `stream.new` calls not supported");
917 }
918 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
919 Import::StreamNew(info)
920 } else if let Some(info) = prefixed_payload("[stream-write-") {
921 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
922 Import::StreamWrite { async_, info }
923 } else if let Some(info) = prefixed_payload("[stream-read-") {
924 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
925 Import::StreamRead { async_, info }
926 } else if let Some(info) = prefixed_payload("[stream-cancel-write-") {
927 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
928 Import::StreamCancelWrite { async_, info }
929 } else if let Some(info) = prefixed_payload("[stream-cancel-read-") {
930 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
931 Import::StreamCancelRead { async_, info }
932 } else if let Some(info) = prefixed_payload("[stream-close-writable-") {
933 if async_ {
934 bail!("async `stream.close-writable` calls not supported");
935 }
936 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
937 Import::StreamCloseWritable(info)
938 } else if let Some(info) = prefixed_payload("[stream-close-readable-") {
939 if async_ {
940 bail!("async `stream.close-readable` calls not supported");
941 }
942 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
943 Import::StreamCloseReadable(info)
944 } else {
945 return Ok(None);
946 };
947 Ok(Some(import))
948 }
949
950 fn classify_import_with_library(
951 &mut self,
952 import: wasmparser::Import<'_>,
953 library_info: Option<&LibraryInfo>,
954 ) -> Result<bool> {
955 let info = match library_info {
956 Some(info) => info,
957 None => return Ok(false),
958 };
959 let Some((_, instance)) = info
960 .arguments
961 .iter()
962 .find(|(name, _items)| *name == import.module)
963 else {
964 return Ok(false);
965 };
966 match instance {
967 Instance::MainOrAdapter(module) => match self.names.get(import.module) {
968 Some(ImportInstance::Whole(which)) => {
969 if which != module {
970 bail!("different whole modules imported under the same name");
971 }
972 }
973 Some(ImportInstance::Names(_)) => {
974 bail!("cannot mix individual imports and whole module imports")
975 }
976 None => {
977 let instance = ImportInstance::Whole(module.clone());
978 self.names.insert(import.module.to_string(), instance);
979 }
980 },
981 Instance::Items(items) => {
982 let Some(item) = items.iter().find(|i| i.alias == import.name) else {
983 return Ok(false);
984 };
985 self.insert_import(import, Import::Item(item.clone()))?;
986 }
987 }
988 Ok(true)
989 }
990
991 fn insert_import(&mut self, import: wasmparser::Import<'_>, item: Import) -> Result<()> {
995 let entry = self
996 .names
997 .entry(import.module.to_string())
998 .or_insert(ImportInstance::Names(IndexMap::default()));
999 let names = match entry {
1000 ImportInstance::Names(names) => names,
1001 _ => bail!("cannot mix individual imports with module imports"),
1002 };
1003 let entry = match names.entry(import.name.to_string()) {
1004 Entry::Occupied(_) => {
1005 bail!(
1006 "module has duplicate import for `{}::{}`",
1007 import.module,
1008 import.name
1009 );
1010 }
1011 Entry::Vacant(v) => v,
1012 };
1013 log::trace!(
1014 "classifying import `{}::{} as {item:?}",
1015 import.module,
1016 import.name
1017 );
1018 entry.insert(item);
1019 Ok(())
1020 }
1021}
1022
1023#[derive(Default)]
1026pub struct ExportMap {
1027 names: IndexMap<String, Export>,
1028 raw_exports: IndexMap<String, FuncType>,
1029}
1030
1031#[derive(Debug)]
1034pub enum Export {
1035 WorldFunc(WorldKey, String, AbiVariant),
1038
1039 WorldFuncPostReturn(WorldKey),
1041
1042 InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
1044
1045 InterfaceFuncPostReturn(WorldKey, String),
1047
1048 ResourceDtor(TypeId),
1050
1051 Memory,
1053
1054 GeneralPurposeRealloc,
1056
1057 GeneralPurposeExportRealloc,
1059
1060 GeneralPurposeImportRealloc,
1062
1063 Initialize,
1065
1066 ReallocForAdapter,
1068
1069 WorldFuncCallback(WorldKey),
1070
1071 InterfaceFuncCallback(WorldKey, String),
1072}
1073
1074impl ExportMap {
1075 fn add(
1076 &mut self,
1077 export: wasmparser::Export<'_>,
1078 encoder: &ComponentEncoder,
1079 exports: &IndexSet<WorldKey>,
1080 types: TypesRef<'_>,
1081 ) -> Result<()> {
1082 if let Some(item) = self.classify(export, encoder, exports, types)? {
1083 log::debug!("classifying export `{}` as {item:?}", export.name);
1084 let prev = self.names.insert(export.name.to_string(), item);
1085 assert!(prev.is_none());
1086 }
1087 Ok(())
1088 }
1089
1090 fn classify(
1091 &mut self,
1092 export: wasmparser::Export<'_>,
1093 encoder: &ComponentEncoder,
1094 exports: &IndexSet<WorldKey>,
1095 types: TypesRef<'_>,
1096 ) -> Result<Option<Export>> {
1097 match export.kind {
1098 ExternalKind::Func => {
1099 let ty = types[types.core_function_at(export.index)].unwrap_func();
1100 self.raw_exports.insert(export.name.to_string(), ty.clone());
1101 }
1102 _ => {}
1103 }
1104
1105 if export.name == "canonical_abi_realloc" {
1107 return Ok(Some(Export::GeneralPurposeRealloc));
1108 } else if export.name == "cabi_import_realloc" {
1109 return Ok(Some(Export::GeneralPurposeImportRealloc));
1110 } else if export.name == "cabi_export_realloc" {
1111 return Ok(Some(Export::GeneralPurposeExportRealloc));
1112 } else if export.name == "cabi_realloc_adapter" {
1113 return Ok(Some(Export::ReallocForAdapter));
1114 }
1115
1116 let (name, names) = match export.name.strip_prefix("cm32p2") {
1117 Some(name) => (name, STANDARD),
1118 None if encoder.reject_legacy_names => return Ok(None),
1119 None => (export.name, LEGACY),
1120 };
1121
1122 if let Some(export) = self
1123 .classify_component_export(names, name, &export, encoder, exports, types)
1124 .with_context(|| format!("failed to classify export `{}`", export.name))?
1125 {
1126 return Ok(Some(export));
1127 }
1128 log::debug!("unknown export `{}`", export.name);
1129 Ok(None)
1130 }
1131
1132 fn classify_component_export(
1133 &mut self,
1134 names: &dyn NameMangling,
1135 name: &str,
1136 export: &wasmparser::Export<'_>,
1137 encoder: &ComponentEncoder,
1138 exports: &IndexSet<WorldKey>,
1139 types: TypesRef<'_>,
1140 ) -> Result<Option<Export>> {
1141 let resolve = &encoder.metadata.resolve;
1142 let world = encoder.metadata.world;
1143 match export.kind {
1144 ExternalKind::Func => {}
1145 ExternalKind::Memory => {
1146 if name == names.export_memory() {
1147 return Ok(Some(Export::Memory));
1148 }
1149 return Ok(None);
1150 }
1151 _ => return Ok(None),
1152 }
1153 let ty = types[types.core_function_at(export.index)].unwrap_func();
1154
1155 if name == names.export_realloc() {
1157 let expected = FuncType::new([ValType::I32; 4], [ValType::I32]);
1158 validate_func_sig(name, &expected, ty)?;
1159 return Ok(Some(Export::GeneralPurposeRealloc));
1160 } else if name == names.export_initialize() {
1161 let expected = FuncType::new([], []);
1162 validate_func_sig(name, &expected, ty)?;
1163 return Ok(Some(Export::Initialize));
1164 }
1165
1166 let full_name = name;
1167 let (abi, name) = if let Some(name) = names.async_lift_name(name) {
1168 (AbiVariant::GuestExportAsync, name)
1169 } else if let Some(name) = names.async_lift_stackful_name(name) {
1170 (AbiVariant::GuestExportAsyncStackful, name)
1171 } else {
1172 (AbiVariant::GuestExport, name)
1173 };
1174
1175 if let Some((key, id, f)) = names.match_wit_export(name, resolve, world, exports) {
1177 validate_func(resolve, ty, f, abi).with_context(|| {
1178 let key = resolve.name_world_key(key);
1179 format!("failed to validate export for `{key}`")
1180 })?;
1181 match id {
1182 Some(id) => {
1183 return Ok(Some(Export::InterfaceFunc(
1184 key.clone(),
1185 id,
1186 f.name.clone(),
1187 abi,
1188 )));
1189 }
1190 None => {
1191 return Ok(Some(Export::WorldFunc(key.clone(), f.name.clone(), abi)));
1192 }
1193 }
1194 }
1195
1196 if let Some(remaining) = names.strip_post_return(name) {
1198 if let Some((key, id, f)) = names.match_wit_export(remaining, resolve, world, exports) {
1199 validate_post_return(resolve, ty, f).with_context(|| {
1200 let key = resolve.name_world_key(key);
1201 format!("failed to validate export for `{key}`")
1202 })?;
1203 match id {
1204 Some(_id) => {
1205 return Ok(Some(Export::InterfaceFuncPostReturn(
1206 key.clone(),
1207 f.name.clone(),
1208 )));
1209 }
1210 None => {
1211 return Ok(Some(Export::WorldFuncPostReturn(key.clone())));
1212 }
1213 }
1214 }
1215 }
1216
1217 if let Some(suffix) = names.async_lift_callback_name(full_name) {
1218 if let Some((key, id, f)) = names.match_wit_export(suffix, resolve, world, exports) {
1219 validate_func_sig(
1220 full_name,
1221 &FuncType::new([ValType::I32; 3], [ValType::I32]),
1222 ty,
1223 )?;
1224 return Ok(Some(if id.is_some() {
1225 Export::InterfaceFuncCallback(key.clone(), f.name.clone())
1226 } else {
1227 Export::WorldFuncCallback(key.clone())
1228 }));
1229 }
1230 }
1231
1232 if let Some(dtor) = names.match_wit_resource_dtor(name, resolve, world, exports) {
1234 let expected = FuncType::new([ValType::I32], []);
1235 validate_func_sig(full_name, &expected, ty)?;
1236 return Ok(Some(Export::ResourceDtor(dtor)));
1237 }
1238
1239 Ok(None)
1240 }
1241
1242 pub fn post_return(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1245 self.find(|m| match m {
1246 Export::WorldFuncPostReturn(k) => k == key,
1247 Export::InterfaceFuncPostReturn(k, f) => k == key && func.name == *f,
1248 _ => false,
1249 })
1250 }
1251
1252 pub fn callback(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1255 self.find(|m| match m {
1256 Export::WorldFuncCallback(k) => k == key,
1257 Export::InterfaceFuncCallback(k, f) => k == key && func.name == *f,
1258 _ => false,
1259 })
1260 }
1261
1262 pub fn abi(&self, key: &WorldKey, func: &Function) -> Option<AbiVariant> {
1263 self.names.values().find_map(|m| match m {
1264 Export::WorldFunc(k, f, abi) if k == key && func.name == *f => Some(*abi),
1265 Export::InterfaceFunc(k, _, f, abi) if k == key && func.name == *f => Some(*abi),
1266 _ => None,
1267 })
1268 }
1269
1270 pub fn export_realloc_for(&self, key: &WorldKey, func: &str) -> Option<&str> {
1273 let _ = (key, func);
1277
1278 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeExportRealloc)) {
1279 return Some(name);
1280 }
1281 self.general_purpose_realloc()
1282 }
1283
1284 pub fn import_realloc_for(&self, interface: Option<InterfaceId>, func: &str) -> Option<&str> {
1287 let _ = (interface, func);
1291
1292 self.import_realloc_fallback()
1293 }
1294
1295 pub fn import_realloc_fallback(&self) -> Option<&str> {
1299 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeImportRealloc)) {
1300 return Some(name);
1301 }
1302 self.general_purpose_realloc()
1303 }
1304
1305 pub fn realloc_to_import_into_adapter(&self) -> Option<&str> {
1307 if let Some(name) = self.find(|m| matches!(m, Export::ReallocForAdapter)) {
1308 return Some(name);
1309 }
1310 self.general_purpose_realloc()
1311 }
1312
1313 fn general_purpose_realloc(&self) -> Option<&str> {
1314 self.find(|m| matches!(m, Export::GeneralPurposeRealloc))
1315 }
1316
1317 pub fn memory(&self) -> Option<&str> {
1319 self.find(|m| matches!(m, Export::Memory))
1320 }
1321
1322 pub fn initialize(&self) -> Option<&str> {
1324 self.find(|m| matches!(m, Export::Initialize))
1325 }
1326
1327 pub fn resource_dtor(&self, ty: TypeId) -> Option<&str> {
1329 self.find(|m| match m {
1330 Export::ResourceDtor(t) => *t == ty,
1331 _ => false,
1332 })
1333 }
1334
1335 fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1338 let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1339 Some(name)
1340 }
1341
1342 pub fn iter(&self) -> impl Iterator<Item = (&str, &Export)> + '_ {
1344 self.names.iter().map(|(n, e)| (n.as_str(), e))
1345 }
1346
1347 fn validate(&self, encoder: &ComponentEncoder, exports: &IndexSet<WorldKey>) -> Result<()> {
1348 let resolve = &encoder.metadata.resolve;
1349 let world = encoder.metadata.world;
1350 if self
1353 .names
1354 .values()
1355 .filter(|m| matches!(m, Export::Memory))
1356 .count()
1357 > 1
1358 {
1359 bail!("cannot componentize module that exports multiple memories")
1360 }
1361
1362 for export in exports {
1364 let require_interface_func = |interface: InterfaceId, name: &str| -> Result<()> {
1365 let result = self.find(|e| match e {
1366 Export::InterfaceFunc(_, id, s, _) => interface == *id && name == s,
1367 _ => false,
1368 });
1369 if result.is_some() {
1370 Ok(())
1371 } else {
1372 let export = resolve.name_world_key(export);
1373 bail!("failed to find export of interface `{export}` function `{name}`")
1374 }
1375 };
1376 let require_world_func = |name: &str| -> Result<()> {
1377 let result = self.find(|e| match e {
1378 Export::WorldFunc(_, s, _) => name == s,
1379 _ => false,
1380 });
1381 if result.is_some() {
1382 Ok(())
1383 } else {
1384 bail!("failed to find export of function `{name}`")
1385 }
1386 };
1387 match &resolve.worlds[world].exports[export] {
1388 WorldItem::Interface { id, .. } => {
1389 for (name, _) in resolve.interfaces[*id].functions.iter() {
1390 require_interface_func(*id, name)?;
1391 }
1392 }
1393 WorldItem::Function(f) => {
1394 require_world_func(&f.name)?;
1395 }
1396 WorldItem::Type(_) => unreachable!(),
1397 }
1398 }
1399
1400 Ok(())
1401 }
1402}
1403
1404trait NameMangling {
1426 fn import_root(&self) -> &str;
1427 fn import_non_root_prefix(&self) -> &str;
1428 fn import_exported_intrinsic_prefix(&self) -> &str;
1429 fn export_memory(&self) -> &str;
1430 fn export_initialize(&self) -> &str;
1431 fn export_realloc(&self) -> &str;
1432 fn resource_drop_name<'a>(&self, s: &'a str) -> Option<&'a str>;
1433 fn resource_new_name<'a>(&self, s: &'a str) -> Option<&'a str>;
1434 fn resource_rep_name<'a>(&self, s: &'a str) -> Option<&'a str>;
1435 fn task_return_name<'a>(&self, s: &'a str) -> Option<&'a str>;
1436 fn task_cancel(&self) -> Option<&str>;
1437 fn backpressure_set(&self) -> Option<&str>;
1438 fn waitable_set_new(&self) -> Option<&str>;
1439 fn waitable_set_wait(&self) -> Option<&str>;
1440 fn waitable_set_poll(&self) -> Option<&str>;
1441 fn waitable_set_drop(&self) -> Option<&str>;
1442 fn waitable_join(&self) -> Option<&str>;
1443 fn yield_(&self) -> Option<&str>;
1444 fn subtask_drop(&self) -> Option<&str>;
1445 fn subtask_cancel(&self) -> Option<&str>;
1446 fn async_lift_callback_name<'a>(&self, s: &'a str) -> Option<&'a str>;
1447 fn async_lower_name<'a>(&self, s: &'a str) -> Option<&'a str>;
1448 fn async_lift_name<'a>(&self, s: &'a str) -> Option<&'a str>;
1449 fn async_lift_stackful_name<'a>(&self, s: &'a str) -> Option<&'a str>;
1450 fn error_context_new(&self, s: &str) -> Option<StringEncoding>;
1451 fn error_context_debug_message(&self, s: &str) -> Option<StringEncoding>;
1452 fn error_context_drop(&self) -> Option<&str>;
1453 fn context_get(&self, name: &str) -> Option<u32>;
1454 fn context_set(&self, name: &str) -> Option<u32>;
1455 fn module_to_interface(
1456 &self,
1457 module: &str,
1458 resolve: &Resolve,
1459 items: &IndexMap<WorldKey, WorldItem>,
1460 ) -> Result<(WorldKey, InterfaceId)>;
1461 fn strip_post_return<'a>(&self, s: &'a str) -> Option<&'a str>;
1462 fn match_wit_export<'a>(
1463 &self,
1464 export_name: &str,
1465 resolve: &'a Resolve,
1466 world: WorldId,
1467 exports: &'a IndexSet<WorldKey>,
1468 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)>;
1469 fn match_wit_resource_dtor<'a>(
1470 &self,
1471 export_name: &str,
1472 resolve: &'a Resolve,
1473 world: WorldId,
1474 exports: &'a IndexSet<WorldKey>,
1475 ) -> Option<TypeId>;
1476}
1477
1478struct Standard;
1481
1482const STANDARD: &'static dyn NameMangling = &Standard;
1483
1484impl NameMangling for Standard {
1485 fn import_root(&self) -> &str {
1486 ""
1487 }
1488 fn import_non_root_prefix(&self) -> &str {
1489 "|"
1490 }
1491 fn import_exported_intrinsic_prefix(&self) -> &str {
1492 "_ex_"
1493 }
1494 fn export_memory(&self) -> &str {
1495 "_memory"
1496 }
1497 fn export_initialize(&self) -> &str {
1498 "_initialize"
1499 }
1500 fn export_realloc(&self) -> &str {
1501 "_realloc"
1502 }
1503 fn resource_drop_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1504 s.strip_suffix("_drop")
1505 }
1506 fn resource_new_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1507 s.strip_suffix("_new")
1508 }
1509 fn resource_rep_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1510 s.strip_suffix("_rep")
1511 }
1512 fn task_return_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1513 _ = s;
1514 None
1515 }
1516 fn task_cancel(&self) -> Option<&str> {
1517 None
1518 }
1519 fn backpressure_set(&self) -> Option<&str> {
1520 None
1521 }
1522 fn waitable_set_new(&self) -> Option<&str> {
1523 None
1524 }
1525 fn waitable_set_wait(&self) -> Option<&str> {
1526 None
1527 }
1528 fn waitable_set_poll(&self) -> Option<&str> {
1529 None
1530 }
1531 fn waitable_set_drop(&self) -> Option<&str> {
1532 None
1533 }
1534 fn waitable_join(&self) -> Option<&str> {
1535 None
1536 }
1537 fn yield_(&self) -> Option<&str> {
1538 None
1539 }
1540 fn subtask_drop(&self) -> Option<&str> {
1541 None
1542 }
1543 fn subtask_cancel(&self) -> Option<&str> {
1544 None
1545 }
1546 fn async_lift_callback_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1547 _ = s;
1548 None
1549 }
1550 fn async_lower_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1551 _ = s;
1552 None
1553 }
1554 fn async_lift_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1555 _ = s;
1556 None
1557 }
1558 fn async_lift_stackful_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1559 _ = s;
1560 None
1561 }
1562 fn error_context_new(&self, _: &str) -> Option<StringEncoding> {
1563 None
1564 }
1565 fn error_context_debug_message(&self, _: &str) -> Option<StringEncoding> {
1566 None
1567 }
1568 fn error_context_drop(&self) -> Option<&str> {
1569 None
1570 }
1571 fn context_get(&self, _: &str) -> Option<u32> {
1572 None
1573 }
1574 fn context_set(&self, _: &str) -> Option<u32> {
1575 None
1576 }
1577 fn module_to_interface(
1578 &self,
1579 interface: &str,
1580 resolve: &Resolve,
1581 items: &IndexMap<WorldKey, WorldItem>,
1582 ) -> Result<(WorldKey, InterfaceId)> {
1583 for (key, item) in items.iter() {
1584 let id = match key {
1585 WorldKey::Name(name) => match item {
1587 WorldItem::Interface { id, .. } if name == interface => *id,
1588 _ => continue,
1589 },
1590 WorldKey::Interface(id) => {
1592 if resolve.canonicalized_id_of(*id).as_deref() != Some(interface) {
1593 continue;
1594 }
1595 *id
1596 }
1597 };
1598 return Ok((key.clone(), id));
1599 }
1600 bail!("failed to find world item corresponding to interface `{interface}`")
1601 }
1602 fn strip_post_return<'a>(&self, s: &'a str) -> Option<&'a str> {
1603 s.strip_suffix("_post")
1604 }
1605 fn match_wit_export<'a>(
1606 &self,
1607 export_name: &str,
1608 resolve: &'a Resolve,
1609 world: WorldId,
1610 exports: &'a IndexSet<WorldKey>,
1611 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
1612 if let Some(world_export_name) = export_name.strip_prefix("||") {
1613 let key = exports.get(&WorldKey::Name(world_export_name.to_string()))?;
1614 match &resolve.worlds[world].exports[key] {
1615 WorldItem::Function(f) => return Some((key, None, f)),
1616 _ => return None,
1617 }
1618 }
1619
1620 let (key, id, func_name) =
1621 self.match_wit_interface(export_name, resolve, world, exports)?;
1622 let func = resolve.interfaces[id].functions.get(func_name)?;
1623 Some((key, Some(id), func))
1624 }
1625
1626 fn match_wit_resource_dtor<'a>(
1627 &self,
1628 export_name: &str,
1629 resolve: &'a Resolve,
1630 world: WorldId,
1631 exports: &'a IndexSet<WorldKey>,
1632 ) -> Option<TypeId> {
1633 let (_key, id, name) =
1634 self.match_wit_interface(export_name.strip_suffix("_dtor")?, resolve, world, exports)?;
1635 let ty = *resolve.interfaces[id].types.get(name)?;
1636 match resolve.types[ty].kind {
1637 TypeDefKind::Resource => Some(ty),
1638 _ => None,
1639 }
1640 }
1641}
1642
1643impl Standard {
1644 fn match_wit_interface<'a, 'b>(
1645 &self,
1646 export_name: &'b str,
1647 resolve: &'a Resolve,
1648 world: WorldId,
1649 exports: &'a IndexSet<WorldKey>,
1650 ) -> Option<(&'a WorldKey, InterfaceId, &'b str)> {
1651 let world = &resolve.worlds[world];
1652 let export_name = export_name.strip_prefix("|")?;
1653
1654 for export in exports {
1655 let id = match &world.exports[export] {
1656 WorldItem::Interface { id, .. } => *id,
1657 WorldItem::Function(_) => continue,
1658 WorldItem::Type(_) => unreachable!(),
1659 };
1660 let remaining = match export {
1661 WorldKey::Name(name) => export_name.strip_prefix(name),
1662 WorldKey::Interface(_) => {
1663 let prefix = resolve.canonicalized_id_of(id).unwrap();
1664 export_name.strip_prefix(&prefix)
1665 }
1666 };
1667 let item_name = match remaining.and_then(|s| s.strip_prefix("|")) {
1668 Some(name) => name,
1669 None => continue,
1670 };
1671 return Some((export, id, item_name));
1672 }
1673
1674 None
1675 }
1676}
1677
1678struct Legacy;
1681
1682const LEGACY: &'static dyn NameMangling = &Legacy;
1683
1684impl NameMangling for Legacy {
1685 fn import_root(&self) -> &str {
1686 "$root"
1687 }
1688 fn import_non_root_prefix(&self) -> &str {
1689 ""
1690 }
1691 fn import_exported_intrinsic_prefix(&self) -> &str {
1692 "[export]"
1693 }
1694 fn export_memory(&self) -> &str {
1695 "memory"
1696 }
1697 fn export_initialize(&self) -> &str {
1698 "_initialize"
1699 }
1700 fn export_realloc(&self) -> &str {
1701 "cabi_realloc"
1702 }
1703 fn resource_drop_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1704 s.strip_prefix("[resource-drop]")
1705 }
1706 fn resource_new_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1707 s.strip_prefix("[resource-new]")
1708 }
1709 fn resource_rep_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1710 s.strip_prefix("[resource-rep]")
1711 }
1712 fn task_return_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1713 s.strip_prefix("[task-return]")
1714 }
1715 fn task_cancel(&self) -> Option<&str> {
1716 Some("[task-cancel]")
1717 }
1718 fn backpressure_set(&self) -> Option<&str> {
1719 Some("[backpressure-set]")
1720 }
1721 fn waitable_set_new(&self) -> Option<&str> {
1722 Some("[waitable-set-new]")
1723 }
1724 fn waitable_set_wait(&self) -> Option<&str> {
1725 Some("[waitable-set-wait]")
1726 }
1727 fn waitable_set_poll(&self) -> Option<&str> {
1728 Some("[waitable-set-poll]")
1729 }
1730 fn waitable_set_drop(&self) -> Option<&str> {
1731 Some("[waitable-set-drop]")
1732 }
1733 fn waitable_join(&self) -> Option<&str> {
1734 Some("[waitable-join]")
1735 }
1736 fn yield_(&self) -> Option<&str> {
1737 Some("[yield]")
1738 }
1739 fn subtask_drop(&self) -> Option<&str> {
1740 Some("[subtask-drop]")
1741 }
1742 fn subtask_cancel(&self) -> Option<&str> {
1743 Some("[subtask-cancel]")
1744 }
1745 fn async_lift_callback_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1746 s.strip_prefix("[callback][async-lift]")
1747 }
1748 fn async_lower_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1749 s.strip_prefix("[async-lower]")
1750 }
1751 fn async_lift_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1752 s.strip_prefix("[async-lift]")
1753 }
1754 fn async_lift_stackful_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1755 s.strip_prefix("[async-lift-stackful]")
1756 }
1757 fn error_context_new(&self, name: &str) -> Option<StringEncoding> {
1758 match name {
1759 "[error-context-new-utf8]" => Some(StringEncoding::UTF8),
1760 "[error-context-new-utf16]" => Some(StringEncoding::UTF16),
1761 "[error-context-new-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
1762 _ => None,
1763 }
1764 }
1765 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding> {
1766 match name {
1767 "[error-context-debug-message-utf8]" => Some(StringEncoding::UTF8),
1768 "[error-context-debug-message-utf16]" => Some(StringEncoding::UTF16),
1769 "[error-context-debug-message-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
1770 _ => None,
1771 }
1772 }
1773 fn error_context_drop(&self) -> Option<&str> {
1774 Some("[error-context-drop]")
1775 }
1776 fn context_get(&self, name: &str) -> Option<u32> {
1777 let (n, rest) = prefixed_integer(name, "[context-get-")?;
1778 if rest.is_empty() {
1779 Some(n)
1780 } else {
1781 None
1782 }
1783 }
1784 fn context_set(&self, name: &str) -> Option<u32> {
1785 let (n, rest) = prefixed_integer(name, "[context-set-")?;
1786 if rest.is_empty() {
1787 Some(n)
1788 } else {
1789 None
1790 }
1791 }
1792 fn module_to_interface(
1793 &self,
1794 module: &str,
1795 resolve: &Resolve,
1796 items: &IndexMap<WorldKey, WorldItem>,
1797 ) -> Result<(WorldKey, InterfaceId)> {
1798 let bare_name = WorldKey::Name(module.to_string());
1800 if let Some(WorldItem::Interface { id, .. }) = items.get(&bare_name) {
1801 return Ok((bare_name, *id));
1802 }
1803
1804 let kebab_name = ComponentName::new(module, 0);
1810 let name = match kebab_name.as_ref().map(|k| k.kind()) {
1811 Ok(ComponentNameKind::Interface(name)) => name,
1812 _ => bail!("module requires an import interface named `{module}`"),
1813 };
1814
1815 let pkgname = PackageName {
1817 namespace: name.namespace().to_string(),
1818 name: name.package().to_string(),
1819 version: name.version(),
1820 };
1821 if let Some(pkg) = resolve.package_names.get(&pkgname) {
1822 if let Some(id) = resolve.packages[*pkg]
1823 .interfaces
1824 .get(name.interface().as_str())
1825 {
1826 let key = WorldKey::Interface(*id);
1827 if items.contains_key(&key) {
1828 return Ok((key, *id));
1829 }
1830 }
1831 }
1832
1833 for (key, _) in items {
1838 let id = match key {
1839 WorldKey::Interface(id) => *id,
1840 WorldKey::Name(_) => continue,
1841 };
1842 let interface = &resolve.interfaces[id];
1844 if interface.name.as_ref().unwrap() != name.interface().as_str() {
1845 continue;
1846 }
1847
1848 let pkg = &resolve.packages[interface.package.unwrap()];
1850 if pkg.name.namespace != pkgname.namespace || pkg.name.name != pkgname.name {
1851 continue;
1852 }
1853
1854 let module_version = match name.version() {
1855 Some(version) => version,
1856 None => continue,
1857 };
1858 let pkg_version = match &pkg.name.version {
1859 Some(version) => version,
1860 None => continue,
1861 };
1862
1863 let module_compat = PackageName::version_compat_track(&module_version);
1865 let pkg_compat = PackageName::version_compat_track(pkg_version);
1866 if module_compat == pkg_compat {
1867 return Ok((key.clone(), id));
1868 }
1869 }
1870
1871 bail!("module requires an import interface named `{module}`")
1872 }
1873 fn strip_post_return<'a>(&self, s: &'a str) -> Option<&'a str> {
1874 s.strip_prefix("cabi_post_")
1875 }
1876 fn match_wit_export<'a>(
1877 &self,
1878 export_name: &str,
1879 resolve: &'a Resolve,
1880 world: WorldId,
1881 exports: &'a IndexSet<WorldKey>,
1882 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
1883 let world = &resolve.worlds[world];
1884 for name in exports {
1885 match &world.exports[name] {
1886 WorldItem::Function(f) => {
1887 if f.legacy_core_export_name(None) == export_name {
1888 return Some((name, None, f));
1889 }
1890 }
1891 WorldItem::Interface { id, .. } => {
1892 let string = resolve.name_world_key(name);
1893 for (_, func) in resolve.interfaces[*id].functions.iter() {
1894 if func.legacy_core_export_name(Some(&string)) == export_name {
1895 return Some((name, Some(*id), func));
1896 }
1897 }
1898 }
1899
1900 WorldItem::Type(_) => unreachable!(),
1901 }
1902 }
1903
1904 None
1905 }
1906
1907 fn match_wit_resource_dtor<'a>(
1908 &self,
1909 export_name: &str,
1910 resolve: &'a Resolve,
1911 world: WorldId,
1912 exports: &'a IndexSet<WorldKey>,
1913 ) -> Option<TypeId> {
1914 let world = &resolve.worlds[world];
1915 for name in exports {
1916 let id = match &world.exports[name] {
1917 WorldItem::Interface { id, .. } => *id,
1918 WorldItem::Function(_) => continue,
1919 WorldItem::Type(_) => unreachable!(),
1920 };
1921 let name = resolve.name_world_key(name);
1922 let resource = match export_name
1923 .strip_prefix(&name)
1924 .and_then(|s| s.strip_prefix("#[dtor]"))
1925 .and_then(|r| resolve.interfaces[id].types.get(r))
1926 {
1927 Some(id) => *id,
1928 None => continue,
1929 };
1930
1931 match resolve.types[resource].kind {
1932 TypeDefKind::Resource => {}
1933 _ => continue,
1934 }
1935
1936 return Some(resource);
1937 }
1938
1939 None
1940 }
1941}
1942
1943pub fn validate_module(encoder: &ComponentEncoder, bytes: &[u8]) -> Result<ValidatedModule> {
1955 ValidatedModule::new(encoder, bytes, &encoder.main_module_exports, None)
1956}
1957
1958pub fn validate_adapter_module(
1976 encoder: &ComponentEncoder,
1977 bytes: &[u8],
1978 required_by_import: &IndexMap<String, FuncType>,
1979 exports: &IndexSet<WorldKey>,
1980 library_info: Option<&LibraryInfo>,
1981) -> Result<ValidatedModule> {
1982 let ret = ValidatedModule::new(encoder, bytes, exports, library_info)?;
1983
1984 for (name, required_ty) in required_by_import {
1985 let actual = match ret.exports.raw_exports.get(name) {
1986 Some(ty) => ty,
1987 None => bail!("adapter module did not export `{name}`"),
1988 };
1989 validate_func_sig(name, required_ty, &actual)?;
1990 }
1991
1992 Ok(ret)
1993}
1994
1995fn resource_test_for_interface<'a>(
1996 resolve: &'a Resolve,
1997 id: InterfaceId,
1998) -> impl Fn(&str) -> Option<TypeId> + 'a {
1999 let interface = &resolve.interfaces[id];
2000 move |name: &str| {
2001 let ty = match interface.types.get(name) {
2002 Some(ty) => *ty,
2003 None => return None,
2004 };
2005 if matches!(resolve.types[ty].kind, TypeDefKind::Resource) {
2006 Some(ty)
2007 } else {
2008 None
2009 }
2010 }
2011}
2012
2013fn resource_test_for_world<'a>(
2014 resolve: &'a Resolve,
2015 id: WorldId,
2016) -> impl Fn(&str) -> Option<TypeId> + 'a {
2017 let world = &resolve.worlds[id];
2018 move |name: &str| match world.imports.get(&WorldKey::Name(name.to_string()))? {
2019 WorldItem::Type(r) => {
2020 if matches!(resolve.types[*r].kind, TypeDefKind::Resource) {
2021 Some(*r)
2022 } else {
2023 None
2024 }
2025 }
2026 _ => None,
2027 }
2028}
2029
2030fn validate_func(
2031 resolve: &Resolve,
2032 ty: &wasmparser::FuncType,
2033 func: &Function,
2034 abi: AbiVariant,
2035) -> Result<()> {
2036 validate_func_sig(
2037 &func.name,
2038 &wasm_sig_to_func_type(resolve.wasm_signature(abi, func)),
2039 ty,
2040 )
2041}
2042
2043fn validate_post_return(
2044 resolve: &Resolve,
2045 ty: &wasmparser::FuncType,
2046 func: &Function,
2047) -> Result<()> {
2048 let mut sig = resolve.wasm_signature(AbiVariant::GuestExport, func);
2054 sig.params = mem::take(&mut sig.results);
2055 validate_func_sig(
2056 &format!("{} post-return", func.name),
2057 &wasm_sig_to_func_type(sig),
2058 ty,
2059 )
2060}
2061
2062fn validate_func_sig(name: &str, expected: &FuncType, ty: &wasmparser::FuncType) -> Result<()> {
2063 if ty != expected {
2064 bail!(
2065 "type mismatch for function `{}`: expected `{:?} -> {:?}` but found `{:?} -> {:?}`",
2066 name,
2067 expected.params(),
2068 expected.results(),
2069 ty.params(),
2070 ty.results()
2071 );
2072 }
2073
2074 Ok(())
2075}
2076
2077fn prefixed_integer<'a>(name: &'a str, prefix: &str) -> Option<(u32, &'a str)> {
2079 assert!(prefix.starts_with("["));
2080 assert!(prefix.ends_with("-"));
2081 let suffix = name.strip_prefix(prefix)?;
2082 let index = suffix.find(']')?;
2083 let rest = &suffix[index + 1..];
2084 let n = suffix[..index].parse().ok()?;
2085 Some((n, rest))
2086}
2087
2088fn get_function<'a>(
2089 resolve: &'a Resolve,
2090 world: &'a World,
2091 name: &str,
2092 interface: Option<InterfaceId>,
2093 imported: bool,
2094) -> Result<&'a Function> {
2095 let function = if let Some(id) = interface {
2096 return resolve.interfaces[id]
2097 .functions
2098 .get(name)
2099 .ok_or_else(|| anyhow!("no export `{name}` found"));
2100 } else if imported {
2101 world.imports.get(&WorldKey::Name(name.to_string()))
2102 } else {
2103 world.exports.get(&WorldKey::Name(name.to_string()))
2104 };
2105 let Some(WorldItem::Function(function)) = function else {
2106 bail!("no export `{name}` found");
2107 };
2108 Ok(function)
2109}