1use crate::encoding::{State, TypeEncoder};
2use indexmap::IndexMap;
3use petgraph::{
4 dot::{Config, Dot},
5 graph::NodeIndex,
6 stable_graph::StableDiGraph,
7 visit::{Dfs, EdgeRef, IntoNodeIdentifiers, Reversed, VisitMap, Visitable},
8 Direction,
9};
10use semver::Version;
11use std::{
12 borrow::Cow,
13 collections::{HashMap, HashSet},
14 fmt::{self, Write},
15 ops::Index,
16};
17use thiserror::Error;
18use wac_types::{
19 BorrowedKey, BorrowedPackageKey, DefinedType, ItemKind, Package, PackageKey, SubtypeChecker,
20 Type, TypeAggregator, Types, ValueType,
21};
22use wasm_encoder::{
23 Alias, ComponentBuilder, ComponentExportKind, ComponentNameSection, ComponentTypeRef,
24 ComponentValType, NameMap, TypeBounds,
25};
26use wasmparser::{
27 names::{ComponentName, ComponentNameKind},
28 BinaryReaderError, Validator, WasmFeatures,
29};
30
31#[derive(Debug, Error)]
34pub enum DefineTypeError {
35 #[error("the provided type has already been defined in the graph")]
37 TypeAlreadyDefined,
38 #[error("a resource type cannot be defined in the graph")]
40 CannotDefineResource,
41 #[error("type name `{name}` conflicts with an existing export of the same name")]
43 ExportConflict {
44 name: String,
46 },
47 #[error("type name `{name}` is not valid")]
49 InvalidExternName {
50 name: String,
52 #[source]
54 source: anyhow::Error,
55 },
56}
57
58#[derive(Debug, Error)]
61pub enum ImportError {
62 #[error("import name `{name}` already exists in the graph")]
64 ImportAlreadyExists {
65 name: String,
67 node: NodeId,
69 },
70 #[error("import name `{name}` is not valid")]
72 InvalidImportName {
73 name: String,
75 #[source]
77 source: anyhow::Error,
78 },
79}
80
81#[derive(Debug, Error)]
84pub enum RegisterPackageError {
85 #[error("package `{key}` has already been registered in the graph")]
87 PackageAlreadyRegistered {
88 key: PackageKey,
90 },
91}
92
93#[derive(Debug, Error)]
96pub enum AliasError {
97 #[error("expected source node to be an instance, but the node is a {kind}")]
99 NodeIsNotAnInstance {
100 node: NodeId,
102 kind: String,
104 },
105 #[error("instance does not have an export named `{export}`")]
107 InstanceMissingExport {
108 node: NodeId,
110 export: String,
112 },
113}
114
115#[derive(Debug, Error)]
118pub enum ExportError {
119 #[error("an export with the name `{name}` already exists")]
121 ExportAlreadyExists {
122 name: String,
124 node: NodeId,
126 },
127 #[error("export name `{name}` is not valid")]
129 InvalidExportName {
130 name: String,
132 #[source]
134 source: anyhow::Error,
135 },
136}
137
138#[derive(Debug, Error)]
141pub enum UnexportError {
142 #[error("cannot unexport a type definition")]
144 MustExportDefinition,
145}
146
147#[derive(Debug, Error)]
150pub enum InstantiationArgumentError {
151 #[error("the specified node is not an instantiation")]
153 NodeIsNotAnInstantiation {
154 node: NodeId,
156 },
157 #[error("argument name `{name}` is not an import of package `{package}`")]
159 InvalidArgumentName {
160 node: NodeId,
162 name: String,
164 package: String,
166 },
167 #[error("mismatched instantiation argument `{name}`")]
169 ArgumentTypeMismatch {
170 name: String,
172 #[source]
174 source: anyhow::Error,
175 },
176 #[error("argument `{name}` has already been passed to the instantiation")]
178 ArgumentAlreadyPassed {
179 node: NodeId,
181 name: String,
183 },
184}
185
186#[derive(Debug, Error)]
188pub enum EncodeError {
189 #[error("encoding produced a component that failed validation")]
191 ValidationFailure {
192 #[source]
194 source: BinaryReaderError,
195 },
196 #[error("the graph contains a cycle and cannot be encoded")]
198 GraphContainsCycle {
199 node: NodeId,
201 },
202 #[error("an instantiation of package `{package}` implicitly imports an item named `{name}`, but it conflicts with an explicit import of the same name")]
204 ImplicitImportConflict {
205 import: NodeId,
207 instantiation: NodeId,
209 package: PackageKey,
211 name: String,
213 },
214 #[error("failed to merge the type definition for implicit import `{import}` due to conflicting types")]
216 ImportTypeMergeConflict {
217 import: String,
219 first: NodeId,
221 second: NodeId,
223 #[source]
225 source: anyhow::Error,
226 },
227}
228
229#[derive(Debug, Error)]
231pub enum DecodeError {}
232
233#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
235pub struct PackageId {
236 index: usize,
238 generation: usize,
242}
243
244#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
246pub struct NodeId(NodeIndex);
247
248impl fmt::Display for NodeId {
249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250 self.0.index().fmt(f)
251 }
252}
253
254#[derive(Debug, Clone)]
256pub enum NodeKind {
257 Definition,
259 Import(String),
263 Instantiation(HashSet<usize>),
267 Alias,
269}
270
271#[derive(Debug, Clone)]
273struct RegisteredPackage {
274 package: Option<Package>,
276 generation: usize,
282}
283
284impl RegisteredPackage {
285 fn new(generation: usize) -> Self {
286 Self {
287 package: None,
288 generation,
289 }
290 }
291}
292
293#[derive(Debug, Clone)]
295pub struct Node {
296 kind: NodeKind,
298 package: Option<PackageId>,
300 item_kind: ItemKind,
302 name: Option<String>,
306 export: Option<String>,
308}
309
310impl Node {
311 fn new(kind: NodeKind, item_kind: ItemKind, package: Option<PackageId>) -> Self {
312 Self {
313 kind,
314 item_kind,
315 package,
316 name: None,
317 export: None,
318 }
319 }
320
321 pub fn kind(&self) -> &NodeKind {
323 &self.kind
324 }
325
326 pub fn package(&self) -> Option<PackageId> {
330 self.package
331 }
332
333 pub fn item_kind(&self) -> ItemKind {
335 self.item_kind
336 }
337
338 pub fn name(&self) -> Option<&str> {
344 self.name.as_deref()
345 }
346
347 pub fn import_name(&self) -> Option<&str> {
351 match &self.kind {
352 NodeKind::Import(name) => Some(name),
353 _ => None,
354 }
355 }
356
357 pub fn export_name(&self) -> Option<&str> {
361 self.export.as_deref()
362 }
363
364 fn add_satisfied_arg(&mut self, index: usize) {
365 match &mut self.kind {
366 NodeKind::Instantiation(satisfied) => {
367 let inserted = satisfied.insert(index);
368 assert!(inserted);
369 }
370 _ => panic!("expected the node to be an instantiation"),
371 }
372 }
373
374 fn remove_satisfied_arg(&mut self, index: usize) {
375 match &mut self.kind {
376 NodeKind::Instantiation(satisfied) => {
377 let removed = satisfied.remove(&index);
378 assert!(removed);
379 }
380 _ => panic!("expected the node to be an instantiation"),
381 }
382 }
383
384 fn is_arg_satisfied(&self, index: usize) -> bool {
385 match &self.kind {
386 NodeKind::Instantiation(satisfied) => satisfied.contains(&index),
387 _ => panic!("expected the node to be an instantiation"),
388 }
389 }
390}
391
392#[derive(Clone)]
394enum Edge {
395 Alias(usize),
399 Argument(usize),
404 Dependency,
406}
407
408impl fmt::Debug for Edge {
409 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
410 match self {
411 Edge::Alias(_) => write!(f, "aliased export"),
412 Edge::Argument(_) => write!(f, "argument to"),
413 Edge::Dependency => write!(f, "dependency of"),
414 }
415 }
416}
417
418#[derive(Default, Clone)]
445pub struct CompositionGraph {
446 graph: StableDiGraph<Node, Edge>,
448 imports: HashMap<String, NodeIndex>,
450 exports: IndexMap<String, NodeIndex>,
452 defined: HashMap<Type, NodeIndex>,
454 package_map: HashMap<PackageKey, PackageId>,
456 packages: Vec<RegisteredPackage>,
458 free_packages: Vec<usize>,
460 types: Types,
462 type_check_cache: HashSet<(ItemKind, ItemKind)>,
464}
465
466impl CompositionGraph {
467 pub fn new() -> Self {
469 Self::default()
470 }
471
472 pub fn types(&self) -> &Types {
474 &self.types
475 }
476
477 pub fn types_mut(&mut self) -> &mut Types {
481 &mut self.types
482 }
483
484 pub fn nodes(&self) -> impl Iterator<Item = &Node> + '_ {
486 self.graph.node_weights()
487 }
488
489 pub fn node_ids(&self) -> impl Iterator<Item = NodeId> + '_ {
491 self.graph.node_indices().map(NodeId)
492 }
493
494 pub fn packages(&self) -> impl Iterator<Item = &Package> + '_ {
496 self.packages.iter().filter_map(|p| p.package.as_ref())
497 }
498
499 pub fn register_package(
509 &mut self,
510 package: wac_types::Package,
511 ) -> Result<PackageId, RegisterPackageError> {
512 let key = PackageKey::new(&package);
513 if self.package_map.contains_key(&key) {
514 return Err(RegisterPackageError::PackageAlreadyRegistered { key });
515 }
516
517 assert!(
518 self.types.contains(Type::World(package.ty())),
519 "the package type is not present in the types collection"
520 );
521
522 log::debug!("registering package `{key}` with the graph");
523 let id = self.alloc_package(package);
524 let prev = self.package_map.insert(key, id);
525 assert!(prev.is_none());
526 Ok(id)
527 }
528
529 pub fn unregister_package(&mut self, package: PackageId) {
537 assert_eq!(
538 self.packages
539 .get(package.index)
540 .expect("invalid package id")
541 .generation,
542 package.generation,
543 "invalid package id"
544 );
545
546 self.graph
548 .retain_nodes(|g, i| g[i].package != Some(package));
549
550 let entry = &mut self.packages[package.index];
552 let key = entry.package.as_ref().unwrap().key();
553 log::debug!("unregistering package `{key}` with the graph");
554 let prev = self.package_map.remove(&key as &dyn BorrowedKey);
555 assert!(
556 prev.is_some(),
557 "package should exist in the package map (this is a bug)"
558 );
559
560 *entry = RegisteredPackage::new(entry.generation.wrapping_add(1));
562 self.free_packages.push(package.index);
563 }
564
565 pub fn get_package_by_name(
570 &self,
571 name: &str,
572 version: Option<&Version>,
573 ) -> Option<(PackageId, &wac_types::Package)> {
574 let key: BorrowedPackageKey<'_> = BorrowedPackageKey::from_name_and_version(name, version);
575 let id = self.package_map.get(&key as &dyn BorrowedKey)?;
576 Some((*id, self.packages[id.index].package.as_ref().unwrap()))
577 }
578
579 pub fn define_type(
595 &mut self,
596 name: impl Into<String>,
597 ty: Type,
598 ) -> Result<NodeId, DefineTypeError> {
599 assert!(
600 self.types.contains(ty),
601 "type not contained in types collection"
602 );
603
604 if self.defined.contains_key(&ty) {
605 return Err(DefineTypeError::TypeAlreadyDefined);
606 }
607
608 if let Type::Resource(_) = ty {
609 return Err(DefineTypeError::CannotDefineResource);
610 }
611
612 let name = name.into();
613 if self.exports.contains_key(&name) {
614 return Err(DefineTypeError::ExportConflict { name });
615 }
616
617 ComponentName::new(&name, 0).map_err(|e| {
619 let msg = e.to_string();
620 DefineTypeError::InvalidExternName {
621 name: name.to_string(),
622 source: anyhow::anyhow!(
623 "{msg}",
624 msg = msg.strip_suffix(" (at offset 0x0)").unwrap_or(&msg)
625 ),
626 }
627 })?;
628
629 let mut node = Node::new(NodeKind::Definition, ItemKind::Type(ty), None);
630 node.export = Some(name.clone());
631 let index = self.graph.add_node(node);
632 log::debug!(
633 "adding type definition `{name}` to the graph as node index {index}",
634 index = index.index()
635 );
636
637 ty.visit_defined_types(&self.types, &mut |_, id| {
639 let dep_ty = Type::Value(ValueType::Defined(id));
640 if dep_ty != ty {
641 if let Some(dep) = self.defined.get(&dep_ty) {
642 if !self
643 .graph
644 .edges_connecting(*dep, index)
645 .any(|e| matches!(e.weight(), Edge::Dependency))
646 {
647 log::debug!(
648 "adding dependency edge from type `{from}` (dependency) to type `{name}` (dependent)",
649 from = self.graph[*dep].export.as_ref().unwrap()
650 );
651 self.graph.add_edge(*dep, index, Edge::Dependency);
652 }
653 }
654 }
655
656 Ok(())
657 })?;
658
659 for (other_ty, other) in &self.defined {
661 other_ty.visit_defined_types(&self.types, &mut |_, id| {
662 let dep_ty = Type::Value(ValueType::Defined(id));
663 if dep_ty == ty
664 && !self
665 .graph
666 .edges_connecting(index, *other)
667 .any(|e| matches!(e.weight(), Edge::Dependency))
668 {
669 log::debug!(
670 "adding dependency edge from type `{name}` (dependency) to type `{to}` (dependent)",
671 to = self.graph[index].export.as_ref().unwrap(),
672 );
673 self.graph.add_edge(index, *other, Edge::Dependency);
674 }
675
676 Ok(())
677 })?;
678 }
679
680 self.defined.insert(ty, index);
681 let prev = self.exports.insert(name, index);
682 assert!(prev.is_none());
683 Ok(NodeId(index))
684 }
685
686 pub fn import(
696 &mut self,
697 name: impl Into<String>,
698 kind: ItemKind,
699 ) -> Result<NodeId, ImportError> {
700 assert!(
701 self.types.contains(kind.ty()),
702 "provided type is not in the types collection"
703 );
704
705 let name = name.into();
706 if let Some(existing) = self.imports.get(&name) {
707 return Err(ImportError::ImportAlreadyExists {
708 name,
709 node: NodeId(*existing),
710 });
711 }
712
713 ComponentName::new(&name, 0).map_err(|e| {
715 let msg = e.to_string();
716 ImportError::InvalidImportName {
717 name: name.to_string(),
718 source: anyhow::anyhow!(
719 "{msg}",
720 msg = msg.strip_suffix(" (at offset 0x0)").unwrap_or(&msg)
721 ),
722 }
723 })?;
724
725 let node = Node::new(NodeKind::Import(name.clone()), kind, None);
726 let index = self.graph.add_node(node);
727 log::debug!(
728 "adding import `{name}` to the graph as node index {index}",
729 index = index.index()
730 );
731 let prev = self.imports.insert(name, index);
732 assert!(prev.is_none());
733 Ok(NodeId(index))
734 }
735
736 pub fn get_import_name(&self, node: NodeId) -> Option<&str> {
744 let node = self.graph.node_weight(node.0).expect("invalid node id");
745 match &node.kind {
746 NodeKind::Import(name) => Some(name),
747 _ => None,
748 }
749 }
750
751 pub fn instantiate(&mut self, package: PackageId) -> NodeId {
761 let pkg = &self[package];
762 let node = Node::new(
763 NodeKind::Instantiation(Default::default()),
764 ItemKind::Instance(pkg.instance_type()),
765 Some(package),
766 );
767 let index = self.graph.add_node(node);
768 log::debug!(
769 "adding instantiation of package `{key}` to the graph as node index {index}",
770 key = self[package].key(),
771 index = index.index()
772 );
773 NodeId(index)
774 }
775
776 pub fn alias_instance_export(
789 &mut self,
790 instance: NodeId,
791 export: &str,
792 ) -> Result<NodeId, AliasError> {
793 let instance_node = self.graph.node_weight(instance.0).expect("invalid node id");
794
795 let exports = match instance_node.item_kind {
797 ItemKind::Instance(id) => &self.types[id].exports,
798 _ => {
799 return Err(AliasError::NodeIsNotAnInstance {
800 node: instance,
801 kind: instance_node.item_kind.desc(&self.types).to_string(),
802 });
803 }
804 };
805
806 let (index, _, kind) =
808 exports
809 .get_full(export)
810 .ok_or_else(|| AliasError::InstanceMissingExport {
811 node: instance,
812 export: export.to_string(),
813 })?;
814
815 for e in self.graph.edges_directed(instance.0, Direction::Outgoing) {
817 assert_eq!(e.source(), instance.0);
818 if let Edge::Alias(i) = e.weight() {
819 if *i == index {
820 return Ok(NodeId(e.target()));
821 }
822 }
823 }
824
825 let node = Node::new(NodeKind::Alias, *kind, instance_node.package);
827 let node_index = self.graph.add_node(node);
828 log::debug!(
829 "adding alias for export `{export}` to the graph as node index {index}",
830 index = node_index.index()
831 );
832 self.graph
833 .add_edge(instance.0, node_index, Edge::Alias(index));
834 Ok(NodeId(node_index))
835 }
836
837 pub fn get_alias_source(&self, alias: NodeId) -> Option<(NodeId, &str)> {
841 for e in self.graph.edges_directed(alias.0, Direction::Incoming) {
842 assert_eq!(e.target(), alias.0);
843
844 if let Edge::Alias(index) = e.weight() {
845 match self.graph[e.source()].item_kind {
846 ItemKind::Instance(id) => {
847 let export = self.types[id].exports.get_index(*index).unwrap().0;
848 return Some((NodeId(e.source()), export));
849 }
850 _ => panic!("alias source should be an instance"),
851 }
852 }
853 }
854
855 None
856 }
857
858 pub fn get_instantiation_arguments(
865 &self,
866 instantiation: NodeId,
867 ) -> impl Iterator<Item = (&str, NodeId)> {
868 self.graph
869 .edges_directed(instantiation.0, Direction::Incoming)
870 .filter_map(|e| {
871 let target = &self.graph[e.target()];
872 let imports = match target.kind {
873 NodeKind::Instantiation(_) => {
874 let package = &self.packages[target.package?.index].package.as_ref()?;
875 &self.types[package.ty()].imports
876 }
877 _ => return None,
878 };
879
880 match e.weight() {
881 Edge::Alias(_) | Edge::Dependency => None,
882 Edge::Argument(i) => Some((
883 imports.get_index(*i).unwrap().0.as_ref(),
884 NodeId(e.source()),
885 )),
886 }
887 })
888 }
889
890 pub fn set_node_name(&mut self, node: NodeId, name: impl Into<String>) {
898 let node = &mut self.graph[node.0];
899 node.name = Some(name.into());
900 }
901
902 pub fn export(&mut self, node: NodeId, name: impl Into<String>) -> Result<(), ExportError> {
910 let name = name.into();
911 if let Some(existing) = self.exports.get(&name) {
912 return Err(ExportError::ExportAlreadyExists {
913 name,
914 node: NodeId(*existing),
915 });
916 }
917
918 let map_reader_err = |e: BinaryReaderError| {
919 let msg = e.to_string();
920 ExportError::InvalidExportName {
921 name: name.to_string(),
922 source: anyhow::anyhow!(
923 "{msg}",
924 msg = msg.strip_suffix(" (at offset 0x0)").unwrap_or(&msg)
925 ),
926 }
927 };
928
929 match ComponentName::new(&name, 0).map_err(map_reader_err)?.kind() {
931 ComponentNameKind::Hash(_)
932 | ComponentNameKind::Url(_)
933 | ComponentNameKind::Dependency(_) => {
934 return Err(ExportError::InvalidExportName {
935 name: name.to_string(),
936 source: anyhow::anyhow!("export name cannot be a hash, url, or dependency"),
937 });
938 }
939 _ => {}
940 };
941
942 log::debug!("exporting node {index} as `{name}`", index = node.0.index());
943 self.graph[node.0].export = Some(name.clone());
944 let prev = self.exports.insert(name, node.0);
945 assert!(prev.is_none());
946 Ok(())
947 }
948
949 pub fn get_export(&self, name: &str) -> Option<NodeId> {
953 self.exports.get(name).map(|i| NodeId(*i))
954 }
955
956 pub fn unexport(&mut self, node: NodeId) -> Result<(), UnexportError> {
965 let node = &mut self.graph[node.0];
966 if let NodeKind::Definition = node.kind {
967 return Err(UnexportError::MustExportDefinition);
968 }
969
970 if let Some(name) = node.export.take() {
971 log::debug!("unmarked node for export as `{name}`");
972 let removed = self.exports.swap_remove(&name);
973 assert!(removed.is_some());
974 }
975
976 Ok(())
977 }
978
979 pub fn remove_node(&mut self, node: NodeId) {
992 for node in self
994 .graph
995 .edges_directed(node.0, Direction::Outgoing)
996 .filter_map(|e| {
997 assert_eq!(e.source(), node.0);
998 match e.weight() {
999 Edge::Alias(_) | Edge::Dependency => Some(NodeId(e.target())),
1000 Edge::Argument(_) => None,
1001 }
1002 })
1003 .collect::<Vec<_>>()
1004 {
1005 self.remove_node(node);
1006 }
1007
1008 log::debug!(
1010 "removing node {index} from the graph",
1011 index = node.0.index()
1012 );
1013 let node = self.graph.remove_node(node.0).expect("invalid node id");
1014
1015 if let Some(name) = node.import_name() {
1017 log::debug!("removing import node `{name}`");
1018 let removed = self.imports.remove(name);
1019 assert!(removed.is_some());
1020 }
1021
1022 if let Some(name) = &node.export {
1024 log::debug!("removing export of node as `{name}`");
1025 let removed = self.exports.swap_remove(name);
1026 assert!(removed.is_some());
1027 }
1028
1029 if let NodeKind::Definition = node.kind {
1030 log::debug!(
1031 "removing type definition `{name}`",
1032 name = node.name.as_ref().unwrap()
1033 );
1034 let removed = self.defined.remove(&node.item_kind.ty());
1035 assert!(removed.is_some());
1036 }
1037 }
1038
1039 pub fn set_instantiation_argument(
1060 &mut self,
1061 instantiation: NodeId,
1062 argument_name: &str,
1063 argument: NodeId,
1064 ) -> Result<(), InstantiationArgumentError> {
1065 fn add_edge(
1066 graph: &mut CompositionGraph,
1067 argument: NodeId,
1068 instantiation: NodeId,
1069 argument_name: &str,
1070 cache: &mut HashSet<(ItemKind, ItemKind)>,
1071 ) -> Result<(), InstantiationArgumentError> {
1072 let instantiation_node = &graph.graph[instantiation.0];
1074
1075 if !matches!(instantiation_node.kind, NodeKind::Instantiation(_)) {
1076 return Err(InstantiationArgumentError::NodeIsNotAnInstantiation {
1077 node: instantiation,
1078 });
1079 }
1080
1081 let package = graph.packages[instantiation_node.package.unwrap().index]
1083 .package
1084 .as_ref()
1085 .unwrap();
1086 let package_type = &graph.types[package.ty()];
1087
1088 let (argument_index, _, expected_argument_kind) = package_type
1090 .imports
1091 .get_full(argument_name)
1092 .ok_or(InstantiationArgumentError::InvalidArgumentName {
1093 node: instantiation,
1094 name: argument_name.to_string(),
1095 package: package.name().to_string(),
1096 })?;
1097
1098 for e in graph
1099 .graph
1100 .edges_directed(instantiation.0, Direction::Incoming)
1101 {
1102 assert_eq!(e.target(), instantiation.0);
1103 match e.weight() {
1104 Edge::Alias(_) | Edge::Dependency => {
1105 panic!("unexpected edge for an instantiation")
1106 }
1107 Edge::Argument(i) => {
1108 if *i == argument_index {
1109 if e.source() == argument.0 {
1110 return Ok(());
1111 }
1112
1113 return Err(InstantiationArgumentError::ArgumentAlreadyPassed {
1114 node: instantiation,
1115 name: argument_name.to_string(),
1116 });
1117 }
1118 }
1119 }
1120 }
1121
1122 let argument_node = &graph.graph[argument.0];
1124
1125 let mut checker = SubtypeChecker::new(cache);
1126 checker
1127 .is_subtype(
1128 argument_node.item_kind,
1129 &graph.types,
1130 *expected_argument_kind,
1131 &graph.types,
1132 )
1133 .map_err(|e| InstantiationArgumentError::ArgumentTypeMismatch {
1134 name: argument_name.to_string(),
1135 source: e,
1136 })?;
1137
1138 graph
1140 .graph
1141 .add_edge(argument.0, instantiation.0, Edge::Argument(argument_index));
1142
1143 graph.graph[instantiation.0].add_satisfied_arg(argument_index);
1144 Ok(())
1145 }
1146
1147 let mut cache = std::mem::take(&mut self.type_check_cache);
1149 let result = add_edge(self, argument, instantiation, argument_name, &mut cache);
1150 self.type_check_cache = cache;
1151 result
1152 }
1153
1154 pub fn unset_instantiation_argument(
1169 &mut self,
1170 instantiation: NodeId,
1171 argument_name: &str,
1172 argument: NodeId,
1173 ) -> Result<(), InstantiationArgumentError> {
1174 let instantiation_node = &self.graph[instantiation.0];
1176 if !matches!(instantiation_node.kind, NodeKind::Instantiation(_)) {
1177 return Err(InstantiationArgumentError::NodeIsNotAnInstantiation {
1178 node: instantiation,
1179 });
1180 }
1181
1182 let package = self.packages[instantiation_node.package.unwrap().index]
1184 .package
1185 .as_ref()
1186 .unwrap();
1187 let package_type = &self.types[package.ty()];
1188
1189 let argument_index = package_type.imports.get_index_of(argument_name).ok_or(
1190 InstantiationArgumentError::InvalidArgumentName {
1191 node: instantiation,
1192 name: argument_name.to_string(),
1193 package: package.name().to_string(),
1194 },
1195 )?;
1196
1197 let mut edge = None;
1199 for e in self.graph.edges_connecting(argument.0, instantiation.0) {
1200 match e.weight() {
1201 Edge::Alias(_) | Edge::Dependency => {
1202 panic!("unexpected edge for an instantiation")
1203 }
1204 Edge::Argument(i) => {
1205 if *i == argument_index {
1206 edge = Some(e.id());
1207 break;
1208 }
1209 }
1210 }
1211 }
1212
1213 if let Some(edge) = edge {
1214 self.graph[instantiation.0].remove_satisfied_arg(argument_index);
1215 self.graph.remove_edge(edge);
1216 }
1217
1218 Ok(())
1219 }
1220
1221 pub fn encode(&self, options: EncodeOptions) -> Result<Vec<u8>, EncodeError> {
1225 let bytes = CompositionGraphEncoder::new(self).encode(options)?;
1226
1227 if options.validate {
1228 Validator::new_with_features(WasmFeatures::all())
1229 .validate_all(&bytes)
1230 .map_err(|e| EncodeError::ValidationFailure { source: e })?;
1231 }
1232
1233 Ok(bytes)
1234 }
1235
1236 pub fn decode(_data: &[u8]) -> Result<CompositionGraph, DecodeError> {
1238 todo!("decoding of composition graphs is not yet implemented")
1239 }
1240
1241 fn alloc_package(&mut self, package: wac_types::Package) -> PackageId {
1242 let (index, entry) = if let Some(index) = self.free_packages.pop() {
1243 let entry = &mut self.packages[index];
1244 assert!(entry.package.is_none());
1245 (index, entry)
1246 } else {
1247 let index = self.packages.len();
1248 self.packages.push(RegisteredPackage::new(0));
1249 (index, &mut self.packages[index])
1250 };
1251
1252 entry.package = Some(package);
1253
1254 PackageId {
1255 index,
1256 generation: entry.generation,
1257 }
1258 }
1259
1260 pub fn imports(&self) -> impl Iterator<Item = (&str, ItemKind, Option<NodeId>)> {
1264 let mut imports = Vec::new();
1265 for index in self.graph.node_indices() {
1266 let node = &self.graph[index];
1267 if !matches!(node.kind, NodeKind::Instantiation(_)) {
1268 continue;
1269 }
1270
1271 let package = &self[node.package.unwrap()];
1272 let world = &self.types[package.ty()];
1273
1274 let unsatisfied_args = world
1275 .imports
1276 .iter()
1277 .enumerate()
1278 .filter(|(i, _)| !node.is_arg_satisfied(*i));
1279
1280 for (_, (name, item_kind)) in unsatisfied_args {
1282 imports.push((name.as_str(), *item_kind, None));
1283 }
1284 }
1285
1286 for n in self.node_ids() {
1287 let node = &self.graph[n.0];
1288 if let NodeKind::Import(name) = &node.kind {
1289 imports.push((name.as_str(), node.item_kind, Some(n)));
1290 }
1291 }
1292 imports.into_iter()
1293 }
1294}
1295
1296impl Index<NodeId> for CompositionGraph {
1297 type Output = Node;
1298
1299 fn index(&self, index: NodeId) -> &Self::Output {
1300 &self.graph[index.0]
1301 }
1302}
1303
1304impl Index<PackageId> for CompositionGraph {
1305 type Output = Package;
1306
1307 fn index(&self, index: PackageId) -> &Self::Output {
1308 let PackageId { index, generation } = index;
1309 let entry = self.packages.get(index).expect("invalid package id");
1310 if entry.generation != generation {
1311 panic!("invalid package id");
1312 }
1313
1314 entry.package.as_ref().unwrap()
1315 }
1316}
1317
1318impl fmt::Debug for CompositionGraph {
1319 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1320 let node_attr = |_, (i, node): (_, &Node)| {
1321 let label = match &node.kind {
1322 NodeKind::Definition => format!(
1323 r#"type definition \"{name}\""#,
1324 name = node.export.as_ref().unwrap()
1325 ),
1326 NodeKind::Import(name) => format!(r#"import \"{name}\""#),
1327 NodeKind::Instantiation(_) => {
1328 let package = &self[node.package.unwrap()];
1329 format!(r#"instantiation of package \"{key}\""#, key = package.key())
1330 }
1331 NodeKind::Alias => {
1332 let (_, source) = self.get_alias_source(NodeId(i)).unwrap();
1333 format!(r#"alias of export \"{source}\""#)
1334 }
1335 };
1336
1337 let mut desc = String::new();
1338 write!(
1339 &mut desc,
1340 r#"label = "{label}"; kind = "{kind}""#,
1341 kind = node.item_kind.desc(&self.types)
1342 )
1343 .unwrap();
1344
1345 if let Some(export) = &node.export {
1346 write!(&mut desc, r#"; export = "{export}""#).unwrap();
1347 }
1348
1349 desc
1350 };
1351
1352 let dot = Dot::with_attr_getters(
1353 &self.graph,
1354 &[Config::NodeNoLabel],
1355 &|_, _| String::new(),
1356 &node_attr,
1357 );
1358
1359 write!(f, "{:?}", dot)
1360 }
1361}
1362
1363#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1364pub struct Processor<'a> {
1366 pub name: &'a str,
1368 pub version: &'a str,
1370}
1371
1372#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1374pub struct EncodeOptions<'a> {
1375 pub define_components: bool,
1381
1382 pub validate: bool,
1386
1387 pub processor: Option<Processor<'a>>,
1389}
1390
1391impl Default for EncodeOptions<'_> {
1392 fn default() -> Self {
1393 Self {
1394 define_components: true,
1395 validate: true,
1396 processor: None,
1397 }
1398 }
1399}
1400
1401struct CompositionGraphEncoder<'a>(&'a CompositionGraph);
1403
1404impl<'a> CompositionGraphEncoder<'a> {
1405 fn new(graph: &'a CompositionGraph) -> Self {
1406 Self(graph)
1407 }
1408
1409 fn encode(self, options: EncodeOptions) -> Result<Vec<u8>, EncodeError> {
1410 let mut state = State::new();
1411
1412 let (import_nodes, other_nodes) = self
1414 .toposort()
1415 .map_err(|n| EncodeError::GraphContainsCycle { node: NodeId(n) })?
1416 .into_iter()
1417 .partition::<Vec<_>, _>(|index| {
1418 let node = &self.0.graph[*index];
1419 matches!(node.kind, NodeKind::Import(_))
1420 });
1421
1422 self.encode_imports(&mut state, import_nodes)?;
1424
1425 for n in other_nodes {
1427 let node = &self.0.graph[n];
1428 let index = match &node.kind {
1429 NodeKind::Definition => self.definition(&mut state, node),
1430 NodeKind::Instantiation(_) => self.instantiation(&mut state, n, node, options),
1431 NodeKind::Alias => self.alias(&mut state, n),
1432 NodeKind::Import(_) => unreachable!(),
1434 };
1435
1436 let prev = state.node_indexes.insert(n, index);
1437 assert!(prev.is_none());
1438 }
1439
1440 for (name, node) in self
1443 .0
1444 .exports
1445 .iter()
1446 .filter(|(_, n)| !matches!(self.0.graph[**n].kind, NodeKind::Definition))
1447 {
1448 let index = state.node_indexes[node];
1449 let node = &self.0.graph[*node];
1450 state
1451 .builder()
1452 .export(name, node.item_kind.into(), index, None);
1453 }
1454
1455 let mut builder = std::mem::take(state.builder());
1456 self.encode_names(&state, &mut builder);
1457
1458 if let Some(processor) = &options.processor {
1459 let mut section = wasm_metadata::Producers::empty();
1460 section.add("processed-by", processor.name, processor.version);
1461 builder.raw_custom_section(§ion.raw_custom_section());
1462 }
1463
1464 Ok(builder.finish())
1465 }
1466
1467 fn toposort(&self) -> Result<Vec<NodeIndex>, NodeIndex> {
1474 let graph = &self.0.graph;
1475 let mut dfs = Dfs::empty(graph);
1476 dfs.reset(graph);
1477 let mut finished = graph.visit_map();
1478
1479 let mut finish_stack = Vec::new();
1480 for i in graph.node_identifiers().rev() {
1481 if dfs.discovered.is_visited(&i) {
1482 continue;
1483 }
1484 dfs.stack.push(i);
1485 while let Some(&nx) = dfs.stack.last() {
1486 if dfs.discovered.visit(nx) {
1487 for succ in graph.neighbors(nx) {
1489 if succ == nx {
1490 return Err(nx);
1492 }
1493 if !dfs.discovered.is_visited(&succ) {
1494 dfs.stack.push(succ);
1495 }
1496 }
1497 } else {
1498 dfs.stack.pop();
1499 if finished.visit(nx) {
1500 finish_stack.push(nx);
1502 }
1503 }
1504 }
1505 }
1506 finish_stack.reverse();
1507
1508 dfs.reset(graph);
1509 for &i in &finish_stack {
1510 dfs.move_to(i);
1511 let mut cycle = false;
1512 while let Some(j) = dfs.next(Reversed(graph)) {
1513 if cycle {
1514 return Err(j);
1515 }
1516 cycle = true;
1517 }
1518 }
1519
1520 Ok(finish_stack)
1521 }
1522
1523 fn encode_imports(
1527 &self,
1528 state: &mut State,
1529 import_nodes: Vec<NodeIndex>,
1530 ) -> Result<(), EncodeError> {
1531 let mut explicit_imports = HashMap::new();
1532 let mut implicit_imports = Vec::new();
1533 let aggregator =
1534 self.resolve_imports(import_nodes, &mut implicit_imports, &mut explicit_imports)?;
1535
1536 let mut encoded = HashMap::new();
1537
1538 for (name, kind) in aggregator.imports() {
1540 log::debug!("import `{name}` is being imported");
1541 let index = self.import(state, name, aggregator.types(), kind);
1542 encoded.insert(name, (kind.into(), index));
1543 }
1544
1545 for (name, node) in implicit_imports {
1547 let (kind, index) = encoded[name];
1548 state
1549 .implicit_args
1550 .entry(node)
1551 .or_default()
1552 .push((name.to_owned(), kind, index));
1553 }
1554
1555 for (name, node_index) in explicit_imports {
1557 let (_, encoded_index) = encoded[name];
1558 state.node_indexes.insert(node_index, encoded_index);
1559 }
1560
1561 Ok(())
1562 }
1563
1564 fn resolve_imports(
1569 &'a self,
1570 import_nodes: Vec<NodeIndex>,
1571 implicit_imports: &mut Vec<(&'a str, NodeIndex)>,
1572 explicit_imports: &mut HashMap<&'a str, NodeIndex>,
1573 ) -> Result<TypeAggregator, EncodeError> {
1574 let mut instantiations = HashMap::new();
1575 let mut aggregator = TypeAggregator::default();
1576 let mut cache = Default::default();
1577 let mut checker = SubtypeChecker::new(&mut cache);
1578
1579 log::debug!("populating implicit imports");
1580
1581 for index in self.0.graph.node_indices() {
1583 let node = &self.0.graph[index];
1584 if !matches!(node.kind, NodeKind::Instantiation(_)) {
1585 continue;
1586 }
1587
1588 let package = &self.0[node.package.unwrap()];
1589 let world = &self.0.types[package.ty()];
1590
1591 let unsatisfied_args = world
1592 .imports
1593 .iter()
1594 .enumerate()
1595 .filter(|(i, _)| !node.is_arg_satisfied(*i));
1596
1597 for (_, (name, kind)) in unsatisfied_args {
1599 if let Some(import) = self.0.imports.get(name).copied() {
1600 return Err(EncodeError::ImplicitImportConflict {
1601 import: NodeId(import),
1602 instantiation: NodeId(index),
1603 package: PackageKey::new(package),
1604 name: name.to_string(),
1605 });
1606 }
1607
1608 instantiations.entry(name).or_insert(index);
1609
1610 aggregator = aggregator
1611 .aggregate(name, &self.0.types, *kind, &mut checker)
1612 .map_err(|e| EncodeError::ImportTypeMergeConflict {
1613 import: name.clone(),
1614 first: NodeId(instantiations[&name]),
1615 second: NodeId(index),
1616 source: e,
1617 })?;
1618 implicit_imports.push((name, index));
1619 }
1620 }
1621
1622 log::debug!("populating explicit imports");
1623
1624 for n in import_nodes {
1625 let node = &self.0.graph[n];
1626 if let NodeKind::Import(name) = &node.kind {
1627 explicit_imports.insert(name.as_str(), n);
1628 aggregator = aggregator
1629 .aggregate(name, self.0.types(), node.item_kind, &mut checker)
1630 .unwrap();
1631 }
1632 }
1633 Ok(aggregator)
1634 }
1635
1636 fn definition(&self, state: &mut State, node: &Node) -> u32 {
1637 let name = node.export.as_deref().unwrap();
1638
1639 log::debug!(
1640 "encoding definition for {kind} `{name}`",
1641 kind = node.item_kind.desc(&self.0.types)
1642 );
1643
1644 let encoder = TypeEncoder::new(&self.0.types);
1646 let (ty, index) = match node.item_kind {
1647 ItemKind::Type(ty) => match ty {
1648 Type::Resource(_) => panic!("resources cannot be defined"),
1649 Type::Func(_) => (ty, encoder.ty(state, ty, None)),
1650 Type::Value(vt) => {
1651 if let ValueType::Defined(id) = vt {
1653 if let DefinedType::Alias(aliased @ ValueType::Defined(_)) =
1654 &self.0.types()[id]
1655 {
1656 (ty, state.current.type_indexes[&Type::Value(*aliased)])
1657 } else {
1658 (ty, encoder.ty(state, ty, None))
1659 }
1660 } else {
1661 (ty, encoder.ty(state, ty, None))
1662 }
1663 }
1664 Type::Interface(id) => (ty, encoder.interface(state, id)),
1665 Type::World(id) => (ty, encoder.world(state, id)),
1666 Type::Module(_) => (ty, encoder.ty(state, ty, None)),
1667 },
1668 _ => panic!("only types can be defined"),
1669 };
1670
1671 let index = state
1672 .builder()
1673 .export(name, ComponentExportKind::Type, index, None);
1674
1675 state.current.type_indexes.insert(ty, index);
1677
1678 log::debug!("definition `{name}` encoded to type index {index}");
1679 index
1680 }
1681
1682 fn import(&self, state: &mut State, name: &str, types: &Types, kind: ItemKind) -> u32 {
1683 if let ItemKind::Instance(id) = kind {
1686 if let Some(id) = &types[id].id {
1687 if let Some(index) = state.current.instances.get(id) {
1688 return *index;
1689 }
1690 }
1691 }
1692
1693 let encoder = TypeEncoder::new(types);
1695 if let ItemKind::Type(Type::Resource(id)) = kind {
1696 return encoder.import_resource(state, name, id);
1697 }
1698
1699 log::debug!(
1700 "encoding import of {kind} `{name}`",
1701 kind = kind.desc(types)
1702 );
1703
1704 let ty = encoder.ty(state, kind.ty(), None);
1706 let index = state.builder().import(
1707 name,
1708 match kind {
1709 ItemKind::Type(_) => ComponentTypeRef::Type(TypeBounds::Eq(ty)),
1710 ItemKind::Func(_) => ComponentTypeRef::Func(ty),
1711 ItemKind::Instance(_) => ComponentTypeRef::Instance(ty),
1712 ItemKind::Component(_) => ComponentTypeRef::Component(ty),
1713 ItemKind::Module(_) => ComponentTypeRef::Module(ty),
1714 ItemKind::Value(_) => ComponentTypeRef::Value(ComponentValType::Type(ty)),
1715 },
1716 );
1717
1718 log::debug!(
1719 "import `{name}` encoded to {desc} index {index}",
1720 desc = kind.desc(types)
1721 );
1722
1723 match kind {
1724 ItemKind::Type(ty) => {
1725 state.current.type_indexes.insert(ty, index);
1727 }
1728 ItemKind::Instance(id) => {
1729 if let Some(id) = &types[id].id {
1730 log::debug!(
1731 "interface `{id}` is available for aliasing as instance index {index}"
1732 );
1733 state.current.instances.insert(id.clone(), index);
1734 }
1735 }
1736 _ => {}
1737 }
1738
1739 index
1740 }
1741
1742 fn instantiation(
1743 &self,
1744 state: &mut State,
1745 index: NodeIndex,
1746 node: &Node,
1747 options: EncodeOptions,
1748 ) -> u32 {
1749 let package_id = node.package.expect("instantiation requires a package");
1750 let package = self.0.packages[package_id.index].package.as_ref().unwrap();
1751 let imports = &self.0.types[package.ty()].imports;
1752
1753 let component_index = if let Some(index) = state.packages.get(&package_id) {
1754 *index
1755 } else {
1756 let index = if options.define_components {
1757 state.builder().component_raw(package.bytes())
1758 } else {
1759 let encoder = TypeEncoder::new(&self.0.types);
1760 let ty = encoder.component(state, package.ty());
1761 state.builder().import(
1762 &Self::package_import_name(package),
1763 ComponentTypeRef::Component(ty),
1764 )
1765 };
1766
1767 state.packages.insert(package_id, index);
1768 index
1769 };
1770
1771 let mut arguments = Vec::with_capacity(imports.len());
1772 arguments.extend(
1773 self.0
1774 .graph
1775 .edges_directed(index, Direction::Incoming)
1776 .map(|e| {
1777 let kind = self.0.graph[e.source()].item_kind.into();
1778 let index = state.node_indexes[&e.source()];
1779 match e.weight() {
1780 Edge::Alias(_) | Edge::Dependency => {
1781 panic!("unexpected edge for an instantiation")
1782 }
1783 Edge::Argument(i) => (
1784 Cow::Borrowed(imports.get_index(*i).unwrap().0.as_str()),
1785 kind,
1786 index,
1787 ),
1788 }
1789 }),
1790 );
1791
1792 if let Some(implicit) = state.implicit_args.remove(&index) {
1793 arguments.extend(implicit.into_iter().map(|(n, k, i)| (n.into(), k, i)));
1794 }
1795
1796 log::debug!(
1797 "instantiating package `{package}` with arguments: {arguments:?}",
1798 package = package.name(),
1799 );
1800
1801 let index = state.builder().instantiate(component_index, arguments);
1802
1803 log::debug!(
1804 "instantiation of package `{package}` encoded to instance index {index}",
1805 package = package.name(),
1806 );
1807
1808 index
1809 }
1810
1811 fn alias(&self, state: &mut State, node: NodeIndex) -> u32 {
1812 let (source, export) = self
1813 .0
1814 .get_alias_source(NodeId(node))
1815 .expect("alias should have a source");
1816
1817 let source_node = &self.0[source];
1818 let exports = match source_node.item_kind {
1819 ItemKind::Instance(id) => &self.0.types[id].exports,
1820 _ => panic!("expected the source of an alias to be an instance"),
1821 };
1822
1823 let kind = exports[export];
1824 let instance = state.node_indexes[&source.0];
1825
1826 log::debug!(
1827 "encoding alias for {kind} export `{export}` of instance index {instance}",
1828 kind = kind.desc(&self.0.types),
1829 );
1830
1831 let index = state.builder().alias(Alias::InstanceExport {
1832 instance,
1833 kind: kind.into(),
1834 name: export,
1835 });
1836
1837 log::debug!(
1838 "alias of export `{export}` encoded to {kind} index {index}",
1839 kind = kind.desc(&self.0.types)
1840 );
1841 index
1842 }
1843
1844 fn package_import_name(package: &Package) -> String {
1845 let mut name = String::new();
1846
1847 write!(&mut name, "unlocked-dep=<{name}", name = package.name()).unwrap();
1848 if let Some(version) = package.version() {
1849 write!(&mut name, "@{{>={version}}}", version = version).unwrap();
1850 }
1851
1852 write!(&mut name, ">").unwrap();
1853 name
1854 }
1855
1856 fn encode_names(&self, state: &State, encoded: &mut ComponentBuilder) {
1857 let mut names = ComponentNameSection::new();
1858 let mut types = NameMap::new();
1859 let mut funcs = NameMap::new();
1860 let mut instances = NameMap::new();
1861 let mut components = NameMap::new();
1862 let mut modules = NameMap::new();
1863 let mut values = NameMap::new();
1864
1865 for index in self.0.graph.node_indices() {
1866 let node = &self.0.graph[index];
1867 if let Some(name) = &node.name {
1868 let map = match node.item_kind {
1869 ItemKind::Type(_) => &mut types,
1870 ItemKind::Func(_) => &mut funcs,
1871 ItemKind::Instance(_) => &mut instances,
1872 ItemKind::Component(_) => &mut components,
1873 ItemKind::Module(_) => &mut modules,
1874 ItemKind::Value(_) => &mut values,
1875 };
1876
1877 let index = state.node_indexes[&index];
1878 map.append(index, name)
1879 }
1880 }
1881
1882 if !types.is_empty() {
1883 names.types(&types);
1884 }
1885
1886 if !funcs.is_empty() {
1887 names.funcs(&funcs);
1888 }
1889
1890 if !instances.is_empty() {
1891 names.instances(&instances);
1892 }
1893
1894 if !components.is_empty() {
1895 names.components(&components);
1896 }
1897
1898 if !modules.is_empty() {
1899 names.core_modules(&modules);
1900 }
1901
1902 if !values.is_empty() {
1903 names.values(&values);
1904 }
1905
1906 if !names.is_empty() {
1907 encoded.custom_section(&names.as_custom());
1908 }
1909 }
1910}
1911
1912#[cfg(test)]
1913mod test {
1914 use super::*;
1915 use wac_types::{DefinedType, PrimitiveType, Resource, ValueType};
1916
1917 #[test]
1918 fn it_adds_a_type_definition() {
1919 let mut graph = CompositionGraph::new();
1920 let id = graph
1921 .types_mut()
1922 .add_defined_type(DefinedType::Alias(ValueType::Primitive(
1923 PrimitiveType::Bool,
1924 )));
1925 assert!(graph
1926 .define_type("foo", Type::Value(ValueType::Defined(id)))
1927 .is_ok());
1928 }
1929
1930 #[test]
1931 fn it_cannot_define_a_resource() {
1932 let mut graph = CompositionGraph::new();
1933 let id = graph.types_mut().add_resource(Resource {
1934 name: "a".to_string(),
1935 alias: None,
1936 });
1937 assert!(matches!(
1938 graph.define_type("foo", Type::Resource(id)).unwrap_err(),
1939 DefineTypeError::CannotDefineResource
1940 ));
1941 }
1942
1943 #[test]
1944 fn it_must_export_a_type_definition() {
1945 let mut graph = CompositionGraph::new();
1946 let id = graph
1947 .types_mut()
1948 .add_defined_type(DefinedType::Alias(ValueType::Primitive(PrimitiveType::S32)));
1949 let id = graph
1950 .define_type("foo", Type::Value(ValueType::Defined(id)))
1951 .unwrap();
1952 assert!(matches!(
1953 graph.unexport(id).unwrap_err(),
1954 UnexportError::MustExportDefinition
1955 ));
1956 }
1957}