1use crate::{types::SubtypeChecker, CompositionGraph, PackageId};
2use thiserror::Error;
3
4#[derive(Debug, Error)]
6pub enum PlugError {
7 #[error("the socket component had no matching imports for the plugs that were provided")]
9 NoPlugHappened,
10 #[error("an error occurred when building the composition graph")]
12 GraphError {
13 #[source]
15 source: anyhow::Error,
16 },
17}
18
19pub fn plug(
24 graph: &mut CompositionGraph,
25 plugs: Vec<PackageId>,
26 socket: PackageId,
27) -> Result<(), PlugError> {
28 let socket_instantiation = graph.instantiate(socket);
29
30 for plug in plugs {
31 let mut plug_exports = Vec::new();
32 let mut cache = Default::default();
33 let mut checker = SubtypeChecker::new(&mut cache);
34 for (name, plug_ty) in &graph.types()[graph[plug].ty()].exports {
35 if let Some(socket_ty) = graph.types()[graph[socket].ty()].imports.get(name) {
36 if checker
37 .is_subtype(*plug_ty, graph.types(), *socket_ty, graph.types())
38 .is_ok()
39 {
40 plug_exports.push(name.clone());
41 }
42 }
43 }
44
45 let mut plug_instantiation = None;
47 for plug_name in plug_exports {
48 log::debug!("using export `{plug_name}` for plug");
49 let plug_instantiation =
50 *plug_instantiation.get_or_insert_with(|| graph.instantiate(plug));
51 let export = graph
52 .alias_instance_export(plug_instantiation, &plug_name)
53 .map_err(|err| PlugError::GraphError { source: err.into() })?;
54 graph
55 .set_instantiation_argument(socket_instantiation, &plug_name, export)
56 .map_err(|err| PlugError::GraphError { source: err.into() })?;
57 }
58 }
59
60 if graph
62 .get_instantiation_arguments(socket_instantiation)
63 .next()
64 .is_none()
65 {
66 return Err(PlugError::NoPlugHappened);
67 }
68
69 for name in graph.types()[graph[socket].ty()]
71 .exports
72 .keys()
73 .cloned()
74 .collect::<Vec<_>>()
75 {
76 let export = graph
77 .alias_instance_export(socket_instantiation, &name)
78 .map_err(|err| PlugError::GraphError { source: err.into() })?;
79
80 graph
81 .export(export, &name)
82 .map_err(|err| PlugError::GraphError { source: err.into() })?;
83 }
84
85 Ok(())
86}