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.exports
549 .retain(|_, n| self.graph[*n].package != Some(package));
550 self.defined
551 .retain(|_, n| self.graph[*n].package != Some(package));
552 self.imports
553 .retain(|_, n| self.graph[*n].package != Some(package));
554
555 self.graph
557 .retain_nodes(|g, i| g[i].package != Some(package));
558
559 let entry = &mut self.packages[package.index];
561 let key = entry.package.as_ref().unwrap().key();
562 log::debug!("unregistering package `{key}` with the graph");
563 let prev = self.package_map.remove(&key as &dyn BorrowedKey);
564 assert!(
565 prev.is_some(),
566 "package should exist in the package map (this is a bug)"
567 );
568
569 *entry = RegisteredPackage::new(entry.generation.wrapping_add(1));
571 self.free_packages.push(package.index);
572 }
573
574 pub fn get_package_by_name(
579 &self,
580 name: &str,
581 version: Option<&Version>,
582 ) -> Option<(PackageId, &wac_types::Package)> {
583 let key: BorrowedPackageKey<'_> = BorrowedPackageKey::from_name_and_version(name, version);
584 let id = self.package_map.get(&key as &dyn BorrowedKey)?;
585 Some((*id, self.packages[id.index].package.as_ref().unwrap()))
586 }
587
588 pub fn define_type(
604 &mut self,
605 name: impl Into<String>,
606 ty: Type,
607 ) -> Result<NodeId, DefineTypeError> {
608 assert!(
609 self.types.contains(ty),
610 "type not contained in types collection"
611 );
612
613 if self.defined.contains_key(&ty) {
614 return Err(DefineTypeError::TypeAlreadyDefined);
615 }
616
617 if let Type::Resource(_) = ty {
618 return Err(DefineTypeError::CannotDefineResource);
619 }
620
621 let name = name.into();
622 if self.exports.contains_key(&name) {
623 return Err(DefineTypeError::ExportConflict { name });
624 }
625
626 ComponentName::new(&name, 0).map_err(|e| {
628 let msg = e.to_string();
629 DefineTypeError::InvalidExternName {
630 name: name.to_string(),
631 source: anyhow::anyhow!(
632 "{msg}",
633 msg = msg.strip_suffix(" (at offset 0x0)").unwrap_or(&msg)
634 ),
635 }
636 })?;
637
638 let mut node = Node::new(NodeKind::Definition, ItemKind::Type(ty), None);
639 node.export = Some(name.clone());
640 let index = self.graph.add_node(node);
641 log::debug!(
642 "adding type definition `{name}` to the graph as node index {index}",
643 index = index.index()
644 );
645
646 ty.visit_defined_types(&self.types, &mut |_, id| {
648 let dep_ty = Type::Value(ValueType::Defined(id));
649 if dep_ty != ty {
650 if let Some(dep) = self.defined.get(&dep_ty) {
651 if !self
652 .graph
653 .edges_connecting(*dep, index)
654 .any(|e| matches!(e.weight(), Edge::Dependency))
655 {
656 log::debug!(
657 "adding dependency edge from type `{from}` (dependency) to type `{name}` (dependent)",
658 from = self.graph[*dep].export.as_ref().unwrap()
659 );
660 self.graph.add_edge(*dep, index, Edge::Dependency);
661 }
662 }
663 }
664
665 Ok(())
666 })?;
667
668 for (other_ty, other) in &self.defined {
670 other_ty.visit_defined_types(&self.types, &mut |_, id| {
671 let dep_ty = Type::Value(ValueType::Defined(id));
672 if dep_ty == ty
673 && !self
674 .graph
675 .edges_connecting(index, *other)
676 .any(|e| matches!(e.weight(), Edge::Dependency))
677 {
678 log::debug!(
679 "adding dependency edge from type `{name}` (dependency) to type `{to}` (dependent)",
680 to = self.graph[index].export.as_ref().unwrap(),
681 );
682 self.graph.add_edge(index, *other, Edge::Dependency);
683 }
684
685 Ok(())
686 })?;
687 }
688
689 self.defined.insert(ty, index);
690 let prev = self.exports.insert(name, index);
691 assert!(prev.is_none());
692 Ok(NodeId(index))
693 }
694
695 pub fn import(
705 &mut self,
706 name: impl Into<String>,
707 kind: ItemKind,
708 ) -> Result<NodeId, ImportError> {
709 assert!(
710 self.types.contains(kind.ty()),
711 "provided type is not in the types collection"
712 );
713
714 let name = name.into();
715 if let Some(existing) = self.imports.get(&name) {
716 return Err(ImportError::ImportAlreadyExists {
717 name,
718 node: NodeId(*existing),
719 });
720 }
721
722 ComponentName::new(&name, 0).map_err(|e| {
724 let msg = e.to_string();
725 ImportError::InvalidImportName {
726 name: name.to_string(),
727 source: anyhow::anyhow!(
728 "{msg}",
729 msg = msg.strip_suffix(" (at offset 0x0)").unwrap_or(&msg)
730 ),
731 }
732 })?;
733
734 let node = Node::new(NodeKind::Import(name.clone()), kind, None);
735 let index = self.graph.add_node(node);
736 log::debug!(
737 "adding import `{name}` to the graph as node index {index}",
738 index = index.index()
739 );
740 let prev = self.imports.insert(name, index);
741 assert!(prev.is_none());
742 Ok(NodeId(index))
743 }
744
745 pub fn get_import_name(&self, node: NodeId) -> Option<&str> {
753 let node = self.graph.node_weight(node.0).expect("invalid node id");
754 match &node.kind {
755 NodeKind::Import(name) => Some(name),
756 _ => None,
757 }
758 }
759
760 pub fn instantiate(&mut self, package: PackageId) -> NodeId {
770 let pkg = &self[package];
771 let node = Node::new(
772 NodeKind::Instantiation(Default::default()),
773 ItemKind::Instance(pkg.instance_type()),
774 Some(package),
775 );
776 let index = self.graph.add_node(node);
777 log::debug!(
778 "adding instantiation of package `{key}` to the graph as node index {index}",
779 key = self[package].key(),
780 index = index.index()
781 );
782 NodeId(index)
783 }
784
785 pub fn alias_instance_export(
798 &mut self,
799 instance: NodeId,
800 export: &str,
801 ) -> Result<NodeId, AliasError> {
802 let instance_node = self.graph.node_weight(instance.0).expect("invalid node id");
803
804 let exports = match instance_node.item_kind {
806 ItemKind::Instance(id) => &self.types[id].exports,
807 _ => {
808 return Err(AliasError::NodeIsNotAnInstance {
809 node: instance,
810 kind: instance_node.item_kind.desc(&self.types).to_string(),
811 });
812 }
813 };
814
815 let (index, _, kind) =
817 exports
818 .get_full(export)
819 .ok_or_else(|| AliasError::InstanceMissingExport {
820 node: instance,
821 export: export.to_string(),
822 })?;
823
824 for e in self.graph.edges_directed(instance.0, Direction::Outgoing) {
826 assert_eq!(e.source(), instance.0);
827 if let Edge::Alias(i) = e.weight() {
828 if *i == index {
829 return Ok(NodeId(e.target()));
830 }
831 }
832 }
833
834 let node = Node::new(NodeKind::Alias, *kind, instance_node.package);
836 let node_index = self.graph.add_node(node);
837 log::debug!(
838 "adding alias for export `{export}` to the graph as node index {index}",
839 index = node_index.index()
840 );
841 self.graph
842 .add_edge(instance.0, node_index, Edge::Alias(index));
843 Ok(NodeId(node_index))
844 }
845
846 pub fn get_alias_source(&self, alias: NodeId) -> Option<(NodeId, &str)> {
850 for e in self.graph.edges_directed(alias.0, Direction::Incoming) {
851 assert_eq!(e.target(), alias.0);
852
853 if let Edge::Alias(index) = e.weight() {
854 match self.graph[e.source()].item_kind {
855 ItemKind::Instance(id) => {
856 let export = self.types[id].exports.get_index(*index).unwrap().0;
857 return Some((NodeId(e.source()), export));
858 }
859 _ => panic!("alias source should be an instance"),
860 }
861 }
862 }
863
864 None
865 }
866
867 pub fn get_instantiation_arguments(
874 &self,
875 instantiation: NodeId,
876 ) -> impl Iterator<Item = (&str, NodeId)> {
877 self.graph
878 .edges_directed(instantiation.0, Direction::Incoming)
879 .filter_map(|e| {
880 let target = &self.graph[e.target()];
881 let imports = match target.kind {
882 NodeKind::Instantiation(_) => {
883 let package = &self.packages[target.package?.index].package.as_ref()?;
884 &self.types[package.ty()].imports
885 }
886 _ => return None,
887 };
888
889 match e.weight() {
890 Edge::Alias(_) | Edge::Dependency => None,
891 Edge::Argument(i) => Some((
892 imports.get_index(*i).unwrap().0.as_ref(),
893 NodeId(e.source()),
894 )),
895 }
896 })
897 }
898
899 pub fn set_node_name(&mut self, node: NodeId, name: impl Into<String>) {
907 let node = &mut self.graph[node.0];
908 node.name = Some(name.into());
909 }
910
911 pub fn export(&mut self, node: NodeId, name: impl Into<String>) -> Result<(), ExportError> {
919 let name = name.into();
920 if let Some(existing) = self.exports.get(&name) {
921 return Err(ExportError::ExportAlreadyExists {
922 name,
923 node: NodeId(*existing),
924 });
925 }
926
927 let map_reader_err = |e: BinaryReaderError| {
928 let msg = e.to_string();
929 ExportError::InvalidExportName {
930 name: name.to_string(),
931 source: anyhow::anyhow!(
932 "{msg}",
933 msg = msg.strip_suffix(" (at offset 0x0)").unwrap_or(&msg)
934 ),
935 }
936 };
937
938 match ComponentName::new(&name, 0).map_err(map_reader_err)?.kind() {
940 ComponentNameKind::Hash(_)
941 | ComponentNameKind::Url(_)
942 | ComponentNameKind::Dependency(_) => {
943 return Err(ExportError::InvalidExportName {
944 name: name.to_string(),
945 source: anyhow::anyhow!("export name cannot be a hash, url, or dependency"),
946 });
947 }
948 _ => {}
949 };
950
951 log::debug!("exporting node {index} as `{name}`", index = node.0.index());
952 self.graph[node.0].export = Some(name.clone());
953 let prev = self.exports.insert(name, node.0);
954 assert!(prev.is_none());
955 Ok(())
956 }
957
958 pub fn get_export(&self, name: &str) -> Option<NodeId> {
962 self.exports.get(name).map(|i| NodeId(*i))
963 }
964
965 pub fn unexport(&mut self, node: NodeId) -> Result<(), UnexportError> {
974 let node = &mut self.graph[node.0];
975 if let NodeKind::Definition = node.kind {
976 return Err(UnexportError::MustExportDefinition);
977 }
978
979 if let Some(name) = node.export.take() {
980 log::debug!("unmarked node for export as `{name}`");
981 let removed = self.exports.swap_remove(&name);
982 assert!(removed.is_some());
983 }
984
985 Ok(())
986 }
987
988 pub fn remove_node(&mut self, node: NodeId) {
1001 for node in self
1003 .graph
1004 .edges_directed(node.0, Direction::Outgoing)
1005 .filter_map(|e| {
1006 assert_eq!(e.source(), node.0);
1007 match e.weight() {
1008 Edge::Alias(_) | Edge::Dependency => Some(NodeId(e.target())),
1009 Edge::Argument(_) => None,
1010 }
1011 })
1012 .collect::<Vec<_>>()
1013 {
1014 self.remove_node(node);
1015 }
1016
1017 log::debug!(
1019 "removing node {index} from the graph",
1020 index = node.0.index()
1021 );
1022 let node = self.graph.remove_node(node.0).expect("invalid node id");
1023
1024 if let Some(name) = node.import_name() {
1026 log::debug!("removing import node `{name}`");
1027 let removed = self.imports.remove(name);
1028 assert!(removed.is_some());
1029 }
1030
1031 if let Some(name) = &node.export {
1033 log::debug!("removing export of node as `{name}`");
1034 let removed = self.exports.swap_remove(name);
1035 assert!(removed.is_some());
1036 }
1037
1038 if let NodeKind::Definition = node.kind {
1039 log::debug!(
1040 "removing type definition `{name}`",
1041 name = node.export.as_ref().unwrap()
1042 );
1043 let removed = self.defined.remove(&node.item_kind.ty());
1044 assert!(removed.is_some());
1045 }
1046 }
1047
1048 pub fn set_instantiation_argument(
1069 &mut self,
1070 instantiation: NodeId,
1071 argument_name: &str,
1072 argument: NodeId,
1073 ) -> Result<(), InstantiationArgumentError> {
1074 fn add_edge(
1075 graph: &mut CompositionGraph,
1076 argument: NodeId,
1077 instantiation: NodeId,
1078 argument_name: &str,
1079 cache: &mut HashSet<(ItemKind, ItemKind)>,
1080 ) -> Result<(), InstantiationArgumentError> {
1081 let instantiation_node = &graph.graph[instantiation.0];
1083
1084 if !matches!(instantiation_node.kind, NodeKind::Instantiation(_)) {
1085 return Err(InstantiationArgumentError::NodeIsNotAnInstantiation {
1086 node: instantiation,
1087 });
1088 }
1089
1090 let package = graph.packages[instantiation_node.package.unwrap().index]
1092 .package
1093 .as_ref()
1094 .unwrap();
1095 let package_type = &graph.types[package.ty()];
1096
1097 let (argument_index, _, expected_argument_kind) = package_type
1099 .imports
1100 .get_full(argument_name)
1101 .ok_or(InstantiationArgumentError::InvalidArgumentName {
1102 node: instantiation,
1103 name: argument_name.to_string(),
1104 package: package.name().to_string(),
1105 })?;
1106
1107 for e in graph
1108 .graph
1109 .edges_directed(instantiation.0, Direction::Incoming)
1110 {
1111 assert_eq!(e.target(), instantiation.0);
1112 match e.weight() {
1113 Edge::Alias(_) | Edge::Dependency => {
1114 panic!("unexpected edge for an instantiation")
1115 }
1116 Edge::Argument(i) => {
1117 if *i == argument_index {
1118 if e.source() == argument.0 {
1119 return Ok(());
1120 }
1121
1122 return Err(InstantiationArgumentError::ArgumentAlreadyPassed {
1123 node: instantiation,
1124 name: argument_name.to_string(),
1125 });
1126 }
1127 }
1128 }
1129 }
1130
1131 let argument_node = &graph.graph[argument.0];
1133
1134 let mut checker = SubtypeChecker::new(cache);
1135 checker
1136 .is_subtype(
1137 argument_node.item_kind,
1138 &graph.types,
1139 *expected_argument_kind,
1140 &graph.types,
1141 )
1142 .map_err(|e| InstantiationArgumentError::ArgumentTypeMismatch {
1143 name: argument_name.to_string(),
1144 source: e,
1145 })?;
1146
1147 graph
1149 .graph
1150 .add_edge(argument.0, instantiation.0, Edge::Argument(argument_index));
1151
1152 graph.graph[instantiation.0].add_satisfied_arg(argument_index);
1153 Ok(())
1154 }
1155
1156 let mut cache = std::mem::take(&mut self.type_check_cache);
1158 let result = add_edge(self, argument, instantiation, argument_name, &mut cache);
1159 self.type_check_cache = cache;
1160 result
1161 }
1162
1163 pub fn unset_instantiation_argument(
1178 &mut self,
1179 instantiation: NodeId,
1180 argument_name: &str,
1181 argument: NodeId,
1182 ) -> Result<(), InstantiationArgumentError> {
1183 let instantiation_node = &self.graph[instantiation.0];
1185 if !matches!(instantiation_node.kind, NodeKind::Instantiation(_)) {
1186 return Err(InstantiationArgumentError::NodeIsNotAnInstantiation {
1187 node: instantiation,
1188 });
1189 }
1190
1191 let package = self.packages[instantiation_node.package.unwrap().index]
1193 .package
1194 .as_ref()
1195 .unwrap();
1196 let package_type = &self.types[package.ty()];
1197
1198 let argument_index = package_type.imports.get_index_of(argument_name).ok_or(
1199 InstantiationArgumentError::InvalidArgumentName {
1200 node: instantiation,
1201 name: argument_name.to_string(),
1202 package: package.name().to_string(),
1203 },
1204 )?;
1205
1206 let mut edge = None;
1208 for e in self.graph.edges_connecting(argument.0, instantiation.0) {
1209 match e.weight() {
1210 Edge::Alias(_) | Edge::Dependency => {
1211 panic!("unexpected edge for an instantiation")
1212 }
1213 Edge::Argument(i) => {
1214 if *i == argument_index {
1215 edge = Some(e.id());
1216 break;
1217 }
1218 }
1219 }
1220 }
1221
1222 if let Some(edge) = edge {
1223 self.graph[instantiation.0].remove_satisfied_arg(argument_index);
1224 self.graph.remove_edge(edge);
1225 }
1226
1227 Ok(())
1228 }
1229
1230 pub fn encode(&self, options: EncodeOptions) -> Result<Vec<u8>, EncodeError> {
1234 let bytes = CompositionGraphEncoder::new(self).encode(options)?;
1235
1236 if options.validate {
1237 Validator::new_with_features(WasmFeatures::all())
1238 .validate_all(&bytes)
1239 .map_err(|e| EncodeError::ValidationFailure { source: e })?;
1240 }
1241
1242 Ok(bytes)
1243 }
1244
1245 pub fn decode(_data: &[u8]) -> Result<CompositionGraph, DecodeError> {
1247 todo!("decoding of composition graphs is not yet implemented")
1248 }
1249
1250 fn alloc_package(&mut self, package: wac_types::Package) -> PackageId {
1251 let (index, entry) = if let Some(index) = self.free_packages.pop() {
1252 let entry = &mut self.packages[index];
1253 assert!(entry.package.is_none());
1254 (index, entry)
1255 } else {
1256 let index = self.packages.len();
1257 self.packages.push(RegisteredPackage::new(0));
1258 (index, &mut self.packages[index])
1259 };
1260
1261 entry.package = Some(package);
1262
1263 PackageId {
1264 index,
1265 generation: entry.generation,
1266 }
1267 }
1268
1269 pub fn imports(&self) -> impl Iterator<Item = (&str, ItemKind, Option<NodeId>)> {
1273 let mut imports = Vec::new();
1274 for index in self.graph.node_indices() {
1275 let node = &self.graph[index];
1276 if !matches!(node.kind, NodeKind::Instantiation(_)) {
1277 continue;
1278 }
1279
1280 let package = &self[node.package.unwrap()];
1281 let world = &self.types[package.ty()];
1282
1283 let unsatisfied_args = world
1284 .imports
1285 .iter()
1286 .enumerate()
1287 .filter(|(i, _)| !node.is_arg_satisfied(*i));
1288
1289 for (_, (name, item_kind)) in unsatisfied_args {
1291 imports.push((name.as_str(), *item_kind, None));
1292 }
1293 }
1294
1295 for n in self.node_ids() {
1296 let node = &self.graph[n.0];
1297 if let NodeKind::Import(name) = &node.kind {
1298 imports.push((name.as_str(), node.item_kind, Some(n)));
1299 }
1300 }
1301 imports.into_iter()
1302 }
1303}
1304
1305impl Index<NodeId> for CompositionGraph {
1306 type Output = Node;
1307
1308 fn index(&self, index: NodeId) -> &Self::Output {
1309 &self.graph[index.0]
1310 }
1311}
1312
1313impl Index<PackageId> for CompositionGraph {
1314 type Output = Package;
1315
1316 fn index(&self, index: PackageId) -> &Self::Output {
1317 let PackageId { index, generation } = index;
1318 let entry = self.packages.get(index).expect("invalid package id");
1319 if entry.generation != generation {
1320 panic!("invalid package id");
1321 }
1322
1323 entry.package.as_ref().unwrap()
1324 }
1325}
1326
1327impl fmt::Debug for CompositionGraph {
1328 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1329 let node_attr = |_, (i, node): (_, &Node)| {
1330 let label = match &node.kind {
1331 NodeKind::Definition => format!(
1332 r#"type definition \"{name}\""#,
1333 name = node.export.as_ref().unwrap()
1334 ),
1335 NodeKind::Import(name) => format!(r#"import \"{name}\""#),
1336 NodeKind::Instantiation(_) => {
1337 let package = &self[node.package.unwrap()];
1338 format!(r#"instantiation of package \"{key}\""#, key = package.key())
1339 }
1340 NodeKind::Alias => {
1341 let (_, source) = self.get_alias_source(NodeId(i)).unwrap();
1342 format!(r#"alias of export \"{source}\""#)
1343 }
1344 };
1345
1346 let mut desc = String::new();
1347 write!(
1348 &mut desc,
1349 r#"label = "{label}"; kind = "{kind}""#,
1350 kind = node.item_kind.desc(&self.types)
1351 )
1352 .unwrap();
1353
1354 if let Some(export) = &node.export {
1355 write!(&mut desc, r#"; export = "{export}""#).unwrap();
1356 }
1357
1358 desc
1359 };
1360
1361 let dot = Dot::with_attr_getters(
1362 &self.graph,
1363 &[Config::NodeNoLabel],
1364 &|_, _| String::new(),
1365 &node_attr,
1366 );
1367
1368 write!(f, "{:?}", dot)
1369 }
1370}
1371
1372#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1373pub struct Processor<'a> {
1375 pub name: &'a str,
1377 pub version: &'a str,
1379}
1380
1381#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1383pub struct EncodeOptions<'a> {
1384 pub define_components: bool,
1390
1391 pub validate: bool,
1395
1396 pub processor: Option<Processor<'a>>,
1398}
1399
1400impl Default for EncodeOptions<'_> {
1401 fn default() -> Self {
1402 Self {
1403 define_components: true,
1404 validate: true,
1405 processor: None,
1406 }
1407 }
1408}
1409
1410struct CompositionGraphEncoder<'a>(&'a CompositionGraph);
1412
1413impl<'a> CompositionGraphEncoder<'a> {
1414 fn new(graph: &'a CompositionGraph) -> Self {
1415 Self(graph)
1416 }
1417
1418 fn encode(self, options: EncodeOptions) -> Result<Vec<u8>, EncodeError> {
1419 let mut state = State::new();
1420
1421 let (import_nodes, other_nodes) = self
1423 .toposort()
1424 .map_err(|n| EncodeError::GraphContainsCycle { node: NodeId(n) })?
1425 .into_iter()
1426 .partition::<Vec<_>, _>(|index| {
1427 let node = &self.0.graph[*index];
1428 matches!(node.kind, NodeKind::Import(_))
1429 });
1430
1431 self.encode_imports(&mut state, import_nodes)?;
1433
1434 for n in other_nodes {
1436 let node = &self.0.graph[n];
1437 let index = match &node.kind {
1438 NodeKind::Definition => self.definition(&mut state, node),
1439 NodeKind::Instantiation(_) => self.instantiation(&mut state, n, node, options),
1440 NodeKind::Alias => self.alias(&mut state, n),
1441 NodeKind::Import(_) => unreachable!(),
1443 };
1444
1445 let prev = state.node_indexes.insert(n, index);
1446 assert!(prev.is_none());
1447 }
1448
1449 for (name, node) in self
1452 .0
1453 .exports
1454 .iter()
1455 .filter(|(_, n)| !matches!(self.0.graph[**n].kind, NodeKind::Definition))
1456 {
1457 let index = state.node_indexes[node];
1458 let node = &self.0.graph[*node];
1459 state
1460 .builder()
1461 .export(name, node.item_kind.into(), index, None);
1462 }
1463
1464 let mut builder = std::mem::take(state.builder());
1465 self.encode_names(&state, &mut builder);
1466
1467 if let Some(processor) = &options.processor {
1468 let mut section = wasm_metadata::Producers::empty();
1469 section.add("processed-by", processor.name, processor.version);
1470 builder.raw_custom_section(§ion.raw_custom_section());
1471 }
1472
1473 Ok(builder.finish())
1474 }
1475
1476 fn toposort(&self) -> Result<Vec<NodeIndex>, NodeIndex> {
1483 let graph = &self.0.graph;
1484 let mut dfs = Dfs::empty(graph);
1485 dfs.reset(graph);
1486 let mut finished = graph.visit_map();
1487
1488 let mut finish_stack = Vec::new();
1489 for i in graph.node_identifiers().rev() {
1490 if dfs.discovered.is_visited(&i) {
1491 continue;
1492 }
1493 dfs.stack.push(i);
1494 while let Some(&nx) = dfs.stack.last() {
1495 if dfs.discovered.visit(nx) {
1496 for succ in graph.neighbors(nx) {
1498 if succ == nx {
1499 return Err(nx);
1501 }
1502 if !dfs.discovered.is_visited(&succ) {
1503 dfs.stack.push(succ);
1504 }
1505 }
1506 } else {
1507 dfs.stack.pop();
1508 if finished.visit(nx) {
1509 finish_stack.push(nx);
1511 }
1512 }
1513 }
1514 }
1515 finish_stack.reverse();
1516
1517 dfs.reset(graph);
1518 for &i in &finish_stack {
1519 dfs.move_to(i);
1520 let mut cycle = false;
1521 while let Some(j) = dfs.next(Reversed(graph)) {
1522 if cycle {
1523 return Err(j);
1524 }
1525 cycle = true;
1526 }
1527 }
1528
1529 Ok(finish_stack)
1530 }
1531
1532 fn encode_imports(
1536 &self,
1537 state: &mut State,
1538 import_nodes: Vec<NodeIndex>,
1539 ) -> Result<(), EncodeError> {
1540 let mut explicit_imports = HashMap::new();
1541 let mut implicit_imports = Vec::new();
1542 let aggregator =
1543 self.resolve_imports(import_nodes, &mut implicit_imports, &mut explicit_imports)?;
1544
1545 let mut encoded = HashMap::new();
1546
1547 for (name, kind) in aggregator.imports() {
1549 log::debug!("import `{name}` is being imported");
1550 let index = self.import(state, name, aggregator.types(), kind);
1551 encoded.insert(name, (kind.into(), index));
1552 }
1553
1554 for (name, node) in implicit_imports {
1556 let canonical = aggregator.canonical_import_name(name);
1557 let (kind, index) = encoded[canonical];
1558 state
1559 .implicit_args
1560 .entry(node)
1561 .or_default()
1562 .push((name.to_owned(), kind, index));
1563 }
1564
1565 for (name, node_index) in explicit_imports {
1567 let canonical = aggregator.canonical_import_name(name);
1568 let (_, encoded_index) = encoded[canonical];
1569 state.node_indexes.insert(node_index, encoded_index);
1570 }
1571
1572 Ok(())
1573 }
1574
1575 fn resolve_imports(
1580 &'a self,
1581 import_nodes: Vec<NodeIndex>,
1582 implicit_imports: &mut Vec<(&'a str, NodeIndex)>,
1583 explicit_imports: &mut HashMap<&'a str, NodeIndex>,
1584 ) -> Result<TypeAggregator, EncodeError> {
1585 let mut instantiations = HashMap::new();
1586 let mut aggregator = TypeAggregator::default();
1587 let mut cache = Default::default();
1588 let mut checker = SubtypeChecker::new(&mut cache);
1589
1590 log::debug!("populating implicit imports");
1591
1592 for index in self.0.graph.node_indices() {
1594 let node = &self.0.graph[index];
1595 if !matches!(node.kind, NodeKind::Instantiation(_)) {
1596 continue;
1597 }
1598
1599 let package = &self.0[node.package.unwrap()];
1600 let world = &self.0.types[package.ty()];
1601
1602 let unsatisfied_args = world
1603 .imports
1604 .iter()
1605 .enumerate()
1606 .filter(|(i, _)| !node.is_arg_satisfied(*i));
1607
1608 for (_, (name, kind)) in unsatisfied_args {
1610 if let Some(import) = self.0.imports.get(name).copied() {
1611 return Err(EncodeError::ImplicitImportConflict {
1612 import: NodeId(import),
1613 instantiation: NodeId(index),
1614 package: PackageKey::new(package),
1615 name: name.to_string(),
1616 });
1617 }
1618
1619 instantiations.entry(name).or_insert(index);
1620
1621 aggregator = aggregator
1622 .aggregate(name, &self.0.types, *kind, &mut checker)
1623 .map_err(|e| EncodeError::ImportTypeMergeConflict {
1624 import: name.clone(),
1625 first: NodeId(instantiations[&name]),
1626 second: NodeId(index),
1627 source: e,
1628 })?;
1629 implicit_imports.push((name, index));
1630 }
1631 }
1632
1633 log::debug!("populating explicit imports");
1634
1635 for n in import_nodes {
1636 let node = &self.0.graph[n];
1637 if let NodeKind::Import(name) = &node.kind {
1638 explicit_imports.insert(name.as_str(), n);
1639 aggregator = aggregator
1640 .aggregate(name, self.0.types(), node.item_kind, &mut checker)
1641 .unwrap();
1642 }
1643 }
1644 Ok(aggregator)
1645 }
1646
1647 fn definition(&self, state: &mut State, node: &Node) -> u32 {
1648 let name = node.export.as_deref().unwrap();
1649
1650 log::debug!(
1651 "encoding definition for {kind} `{name}`",
1652 kind = node.item_kind.desc(&self.0.types)
1653 );
1654
1655 let encoder = TypeEncoder::new(&self.0.types);
1657 let (ty, index) = match node.item_kind {
1658 ItemKind::Type(ty) => match ty {
1659 Type::Resource(_) => panic!("resources cannot be defined"),
1660 Type::Func(_) => (ty, encoder.ty(state, ty, None)),
1661 Type::Value(vt) => {
1662 if let ValueType::Defined(id) = vt {
1664 if let DefinedType::Alias(aliased @ ValueType::Defined(_)) =
1665 &self.0.types()[id]
1666 {
1667 (ty, state.current.type_indexes[&Type::Value(*aliased)])
1668 } else {
1669 (ty, encoder.ty(state, ty, None))
1670 }
1671 } else {
1672 (ty, encoder.ty(state, ty, None))
1673 }
1674 }
1675 Type::Interface(id) => (ty, encoder.interface(state, id)),
1676 Type::World(id) => (ty, encoder.world(state, id)),
1677 Type::Module(_) => (ty, encoder.ty(state, ty, None)),
1678 },
1679 _ => panic!("only types can be defined"),
1680 };
1681
1682 let index = state
1683 .builder()
1684 .export(name, ComponentExportKind::Type, index, None);
1685
1686 state.current.type_indexes.insert(ty, index);
1688
1689 log::debug!("definition `{name}` encoded to type index {index}");
1690 index
1691 }
1692
1693 fn import(&self, state: &mut State, name: &str, types: &Types, kind: ItemKind) -> u32 {
1694 if let ItemKind::Instance(id) = kind {
1697 if let Some(id) = &types[id].id {
1698 if let Some(index) = state.current.instances.get(id) {
1699 return *index;
1700 }
1701 }
1702 }
1703
1704 let encoder = TypeEncoder::new(types);
1706 if let ItemKind::Type(Type::Resource(id)) = kind {
1707 return encoder.import_resource(state, name, id);
1708 }
1709
1710 log::debug!(
1711 "encoding import of {kind} `{name}`",
1712 kind = kind.desc(types)
1713 );
1714
1715 let ty = encoder.ty(state, kind.ty(), None);
1717 let index = state.builder().import(
1718 name,
1719 match kind {
1720 ItemKind::Type(_) => ComponentTypeRef::Type(TypeBounds::Eq(ty)),
1721 ItemKind::Func(_) => ComponentTypeRef::Func(ty),
1722 ItemKind::Instance(_) => ComponentTypeRef::Instance(ty),
1723 ItemKind::Component(_) => ComponentTypeRef::Component(ty),
1724 ItemKind::Module(_) => ComponentTypeRef::Module(ty),
1725 ItemKind::Value(_) => ComponentTypeRef::Value(ComponentValType::Type(ty)),
1726 },
1727 );
1728
1729 log::debug!(
1730 "import `{name}` encoded to {desc} index {index}",
1731 desc = kind.desc(types)
1732 );
1733
1734 match kind {
1735 ItemKind::Type(ty) => {
1736 state.current.type_indexes.insert(ty, index);
1738 }
1739 ItemKind::Instance(id) => {
1740 if let Some(id) = &types[id].id {
1741 log::debug!(
1742 "interface `{id}` is available for aliasing as instance index {index}"
1743 );
1744 state.current.instances.insert(id.clone(), index);
1745 }
1746 }
1747 _ => {}
1748 }
1749
1750 index
1751 }
1752
1753 fn instantiation(
1754 &self,
1755 state: &mut State,
1756 index: NodeIndex,
1757 node: &Node,
1758 options: EncodeOptions,
1759 ) -> u32 {
1760 let package_id = node.package.expect("instantiation requires a package");
1761 let package = self.0.packages[package_id.index].package.as_ref().unwrap();
1762 let imports = &self.0.types[package.ty()].imports;
1763
1764 let component_index = if let Some(index) = state.packages.get(&package_id) {
1765 *index
1766 } else {
1767 let index = if options.define_components {
1768 state.builder().component_raw(None, package.bytes())
1769 } else {
1770 let encoder = TypeEncoder::new(&self.0.types);
1771 let ty = encoder.component(state, package.ty());
1772 state.builder().import(
1773 &Self::package_import_name(package),
1774 ComponentTypeRef::Component(ty),
1775 )
1776 };
1777
1778 state.packages.insert(package_id, index);
1779 index
1780 };
1781
1782 let mut arguments = Vec::with_capacity(imports.len());
1783 arguments.extend(
1784 self.0
1785 .graph
1786 .edges_directed(index, Direction::Incoming)
1787 .map(|e| {
1788 let kind = self.0.graph[e.source()].item_kind.into();
1789 let index = state.node_indexes[&e.source()];
1790 match e.weight() {
1791 Edge::Alias(_) | Edge::Dependency => {
1792 panic!("unexpected edge for an instantiation")
1793 }
1794 Edge::Argument(i) => (
1795 Cow::Borrowed(imports.get_index(*i).unwrap().0.as_str()),
1796 kind,
1797 index,
1798 ),
1799 }
1800 }),
1801 );
1802
1803 if let Some(implicit) = state.implicit_args.remove(&index) {
1804 arguments.extend(implicit.into_iter().map(|(n, k, i)| (n.into(), k, i)));
1805 }
1806
1807 log::debug!(
1808 "instantiating package `{package}` with arguments: {arguments:?}",
1809 package = package.name(),
1810 );
1811
1812 let index = state
1813 .builder()
1814 .instantiate(None, component_index, arguments);
1815
1816 log::debug!(
1817 "instantiation of package `{package}` encoded to instance index {index}",
1818 package = package.name(),
1819 );
1820
1821 index
1822 }
1823
1824 fn alias(&self, state: &mut State, node: NodeIndex) -> u32 {
1825 let (source, export) = self
1826 .0
1827 .get_alias_source(NodeId(node))
1828 .expect("alias should have a source");
1829
1830 let source_node = &self.0[source];
1831 let exports = match source_node.item_kind {
1832 ItemKind::Instance(id) => &self.0.types[id].exports,
1833 _ => panic!("expected the source of an alias to be an instance"),
1834 };
1835
1836 let kind = exports[export];
1837 let instance = state.node_indexes[&source.0];
1838
1839 log::debug!(
1840 "encoding alias for {kind} export `{export}` of instance index {instance}",
1841 kind = kind.desc(&self.0.types),
1842 );
1843
1844 let index = state.builder().alias(
1845 None,
1846 Alias::InstanceExport {
1847 instance,
1848 kind: kind.into(),
1849 name: export,
1850 },
1851 );
1852
1853 log::debug!(
1854 "alias of export `{export}` encoded to {kind} index {index}",
1855 kind = kind.desc(&self.0.types)
1856 );
1857 index
1858 }
1859
1860 fn package_import_name(package: &Package) -> String {
1861 let mut name = String::new();
1862
1863 write!(&mut name, "unlocked-dep=<{name}", name = package.name()).unwrap();
1864 if let Some(version) = package.version() {
1865 write!(&mut name, "@{{>={version}}}", version = version).unwrap();
1866 }
1867
1868 write!(&mut name, ">").unwrap();
1869 name
1870 }
1871
1872 fn encode_names(&self, state: &State, encoded: &mut ComponentBuilder) {
1873 let mut names = ComponentNameSection::new();
1874 let mut types = NameMap::new();
1875 let mut funcs = NameMap::new();
1876 let mut instances = NameMap::new();
1877 let mut components = NameMap::new();
1878 let mut modules = NameMap::new();
1879 let mut values = NameMap::new();
1880
1881 for index in self.0.graph.node_indices() {
1882 let node = &self.0.graph[index];
1883 if let Some(name) = &node.name {
1884 let map = match node.item_kind {
1885 ItemKind::Type(_) => &mut types,
1886 ItemKind::Func(_) => &mut funcs,
1887 ItemKind::Instance(_) => &mut instances,
1888 ItemKind::Component(_) => &mut components,
1889 ItemKind::Module(_) => &mut modules,
1890 ItemKind::Value(_) => &mut values,
1891 };
1892
1893 let index = state.node_indexes[&index];
1894 map.append(index, name)
1895 }
1896 }
1897
1898 if !types.is_empty() {
1899 names.types(&types);
1900 }
1901
1902 if !funcs.is_empty() {
1903 names.funcs(&funcs);
1904 }
1905
1906 if !instances.is_empty() {
1907 names.instances(&instances);
1908 }
1909
1910 if !components.is_empty() {
1911 names.components(&components);
1912 }
1913
1914 if !modules.is_empty() {
1915 names.core_modules(&modules);
1916 }
1917
1918 if !values.is_empty() {
1919 names.values(&values);
1920 }
1921
1922 if !names.is_empty() {
1923 encoded.custom_section(&names.as_custom());
1924 }
1925 }
1926}
1927
1928#[cfg(test)]
1929mod test {
1930 use super::*;
1931 use wac_types::{DefinedType, PrimitiveType, Resource, ValueType};
1932
1933 #[test]
1934 fn it_adds_a_type_definition() {
1935 let mut graph = CompositionGraph::new();
1936 let id = graph
1937 .types_mut()
1938 .add_defined_type(DefinedType::Alias(ValueType::Primitive(
1939 PrimitiveType::Bool,
1940 )));
1941 assert!(graph
1942 .define_type("foo", Type::Value(ValueType::Defined(id)))
1943 .is_ok());
1944 }
1945
1946 #[test]
1947 fn it_cannot_define_a_resource() {
1948 let mut graph = CompositionGraph::new();
1949 let id = graph.types_mut().add_resource(Resource {
1950 name: "a".to_string(),
1951 alias: None,
1952 });
1953 assert!(matches!(
1954 graph.define_type("foo", Type::Resource(id)).unwrap_err(),
1955 DefineTypeError::CannotDefineResource
1956 ));
1957 }
1958
1959 #[test]
1960 fn it_must_export_a_type_definition() {
1961 let mut graph = CompositionGraph::new();
1962 let id = graph
1963 .types_mut()
1964 .add_defined_type(DefinedType::Alias(ValueType::Primitive(PrimitiveType::S32)));
1965 let id = graph
1966 .define_type("foo", Type::Value(ValueType::Defined(id)))
1967 .unwrap();
1968 assert!(matches!(
1969 graph.unexport(id).unwrap_err(),
1970 UnexportError::MustExportDefinition
1971 ));
1972 }
1973
1974 #[test]
1975 fn it_can_remove_a_type_definition() {
1976 let mut graph = CompositionGraph::new();
1977 let ty_id = graph
1978 .types_mut()
1979 .add_defined_type(DefinedType::Alias(ValueType::Primitive(PrimitiveType::S32)));
1980 let node_id = graph
1981 .define_type("foo", Type::Value(ValueType::Defined(ty_id)))
1982 .unwrap();
1983
1984 graph.remove_node(node_id);
1987
1988 assert!(graph.get_export("foo").is_none());
1990 }
1991 #[test]
1992 fn it_cleans_up_exports_on_unregister_package() {
1993 let mut graph = CompositionGraph::new();
1994 let bytes = wat::parse_str(
1995 r#"(component
1996 (import "f" (func))
1997 (export "g" (func 0))
1998 )"#,
1999 )
2000 .unwrap();
2001
2002 let package =
2003 wac_types::Package::from_bytes("test:pkg", None, bytes, graph.types_mut()).unwrap();
2004 let pkg_id = graph.register_package(package).unwrap();
2005
2006 let inst_id = graph.instantiate(pkg_id);
2008 let alias_id = graph.alias_instance_export(inst_id, "g").unwrap();
2009 graph.export(alias_id, "g").unwrap();
2010
2011 assert!(graph.get_export("g").is_some());
2012
2013 graph.unregister_package(pkg_id);
2015 assert!(
2016 graph.get_export("g").is_none(),
2017 "exports should be cleaned up after unregister_package"
2018 );
2019 }
2020}