Skip to content

Commit c89f46a

Browse files
committed
Librarify the plug command
Signed-off-by: Brian H <brian.hardock@fermyon.com>
1 parent 1096a5b commit c89f46a

File tree

3 files changed

+98
-59
lines changed

3 files changed

+98
-59
lines changed

crates/wac-graph/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939

4040
pub(crate) mod encoding;
4141
mod graph;
42+
mod plug;
4243

4344
pub use graph::*;
45+
pub use plug::*;
4446
pub use wac_types as types;

crates/wac-graph/src/plug.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use crate::{types::SubtypeChecker, CompositionGraph, PackageId};
2+
use thiserror::Error;
3+
4+
/// Represents an error that can occur when plugging components together.
5+
#[derive(Debug, Error)]
6+
pub enum PlugError {
7+
/// The socket component had no matching imports for the plugs that were provided
8+
#[error("the socket component had no matching imports for the plugs that were provided")]
9+
NoPlugHappened,
10+
/// An error occurred when building the composition graph
11+
#[error("an error occurred when building the composition graph")]
12+
GraphError {
13+
/// The underlying graph error
14+
#[source]
15+
source: anyhow::Error,
16+
},
17+
}
18+
19+
/// Take the exports of the plug components and plug them into the socket component.
20+
///
21+
/// Note that the `PackageId`s in `plugs` and `socket` must be registered with the `graph`
22+
/// before calling this function.
23+
pub 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+
// Instantiate the plug component
46+
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+
// Check we've actually done any plugging.
61+
if graph
62+
.get_instantiation_arguments(socket_instantiation)
63+
.next()
64+
.is_none()
65+
{
66+
return Err(PlugError::NoPlugHappened);
67+
}
68+
69+
// Export all exports from the socket component.
70+
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+
}

src/commands/plug.rs

Lines changed: 10 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use std::{
66
use anyhow::{bail, Context as _, Error, Result};
77
use clap::Args;
88
use std::str::FromStr;
9-
use wac_graph::{CompositionGraph, EncodeOptions, NodeId, PackageId};
10-
use wac_types::{Package, SubtypeChecker};
9+
use wac_graph::{CompositionGraph, EncodeOptions};
10+
use wac_types::Package;
1111

1212
#[cfg(feature = "registry")]
1313
use warg_client::FileSystemClient;
@@ -151,7 +151,6 @@ impl PlugCommand {
151151

152152
let socket = Package::from_bytes("socket", None, socket, graph.types_mut())?;
153153
let socket = graph.register_package(socket)?;
154-
let socket_instantiation = graph.instantiate(socket);
155154

156155
// Collect the plugs by their names
157156
let mut plugs_by_name = std::collections::HashMap::<_, Vec<_>>::new();
@@ -169,6 +168,8 @@ impl PlugCommand {
169168
plugs_by_name.entry(name).or_default().push(plug);
170169
}
171170

171+
let mut plug_packages = Vec::new();
172+
172173
// Plug each plug into the socket.
173174
for (name, plug_refs) in plugs_by_name {
174175
for (i, plug_ref) in plug_refs.iter().enumerate() {
@@ -221,37 +222,23 @@ impl PlugCommand {
221222
use core::fmt::Write;
222223
write!(&mut name, "{i}").unwrap();
223224
}
224-
plug_into_socket(&name, &path, socket, socket_instantiation, &mut graph)?;
225+
226+
let plug_package = Package::from_file(&name, None, &path, graph.types_mut())?;
227+
let package_id = graph.register_package(plug_package)?;
228+
plug_packages.push(package_id);
225229
}
226230
}
227231

228-
// Check we've actually done any plugging.
229-
if graph
230-
.get_instantiation_arguments(socket_instantiation)
231-
.next()
232-
.is_none()
233-
{
234-
bail!("the socket component had no matching imports for the plugs that were provided")
235-
}
232+
wac_graph::plug(&mut graph, plug_packages, socket)?;
236233

237-
// Export all exports from the socket component.
238-
for name in graph.types()[graph[socket].ty()]
239-
.exports
240-
.keys()
241-
.cloned()
242-
.collect::<Vec<_>>()
243-
{
244-
let export = graph.alias_instance_export(socket_instantiation, &name)?;
245-
graph.export(export, &name)?;
246-
}
234+
let mut bytes = graph.encode(EncodeOptions::default())?;
247235

248236
let binary_output_to_terminal =
249237
!self.wat && self.output.is_none() && std::io::stdout().is_terminal();
250238
if binary_output_to_terminal {
251239
bail!("cannot print binary wasm output to a terminal; pass the `-t` flag to print the text format instead");
252240
}
253241

254-
let mut bytes = graph.encode(EncodeOptions::default())?;
255242
if self.wat {
256243
bytes = wasmprinter::print_bytes(&bytes)
257244
.context("failed to convert binary wasm output to text")?
@@ -278,39 +265,3 @@ impl PlugCommand {
278265
Ok(())
279266
}
280267
}
281-
282-
/// Take the exports of the plug component and plug them into the socket component.
283-
fn plug_into_socket(
284-
name: &str,
285-
plug_path: &std::path::Path,
286-
socket: PackageId,
287-
socket_instantiation: NodeId,
288-
graph: &mut CompositionGraph,
289-
) -> Result<(), anyhow::Error> {
290-
let plug = Package::from_file(name, None, plug_path, graph.types_mut())?;
291-
let plug = graph.register_package(plug)?;
292-
293-
let mut plugs = Vec::new();
294-
let mut cache = Default::default();
295-
let mut checker = SubtypeChecker::new(&mut cache);
296-
for (name, plug_ty) in &graph.types()[graph[plug].ty()].exports {
297-
if let Some(socket_ty) = graph.types()[graph[socket].ty()].imports.get(name) {
298-
if checker
299-
.is_subtype(*plug_ty, graph.types(), *socket_ty, graph.types())
300-
.is_ok()
301-
{
302-
plugs.push(name.clone());
303-
}
304-
}
305-
}
306-
307-
// Instantiate the plug component
308-
let mut plug_instantiation = None;
309-
for plug_name in plugs {
310-
log::debug!("using export `{plug_name}` for plug");
311-
let plug_instantiation = *plug_instantiation.get_or_insert_with(|| graph.instantiate(plug));
312-
let export = graph.alias_instance_export(plug_instantiation, &plug_name)?;
313-
graph.set_instantiation_argument(socket_instantiation, &plug_name, export)?;
314-
}
315-
Ok(())
316-
}

0 commit comments

Comments
 (0)