1use sim_kernel::{Expr, Symbol};
4
5use crate::{Edge, Graph, Node, NodeId, Port, PortMode, PortRef};
6
7#[derive(Clone, Debug)]
10pub struct InstrumentTopologySpec {
11 pub name: Symbol,
13 pub modules: Vec<InstrumentTopologyModule>,
15 pub cords: Vec<InstrumentTopologyCord>,
17 pub metadata: Vec<(Symbol, Expr)>,
19}
20
21impl InstrumentTopologySpec {
22 pub fn new(name: Symbol) -> Self {
24 Self {
25 name,
26 modules: Vec::new(),
27 cords: Vec::new(),
28 metadata: Vec::new(),
29 }
30 }
31
32 pub fn with_module(mut self, module: InstrumentTopologyModule) -> Self {
34 self.modules.push(module);
35 self
36 }
37
38 pub fn with_cord(mut self, cord: InstrumentTopologyCord) -> Self {
40 self.cords.push(cord);
41 self
42 }
43
44 pub fn with_metadata(mut self, key: Symbol, value: Expr) -> Self {
46 self.metadata.push((key, value));
47 self
48 }
49}
50
51#[derive(Clone, Debug)]
54pub struct InstrumentTopologyModule {
55 pub id: NodeId,
57 pub kind: Symbol,
59 pub inputs: Vec<InstrumentTopologyJack>,
61 pub outputs: Vec<InstrumentTopologyJack>,
63 pub settings: Vec<(Symbol, Expr)>,
65 pub raw_view: Vec<(Symbol, Expr)>,
67}
68
69impl InstrumentTopologyModule {
70 pub fn new(id: impl Into<NodeId>, kind: Symbol) -> Self {
72 Self {
73 id: id.into(),
74 kind,
75 inputs: Vec::new(),
76 outputs: Vec::new(),
77 settings: Vec::new(),
78 raw_view: Vec::new(),
79 }
80 }
81
82 pub fn with_input(mut self, jack: InstrumentTopologyJack) -> Self {
84 self.inputs.push(jack);
85 self
86 }
87
88 pub fn with_output(mut self, jack: InstrumentTopologyJack) -> Self {
90 self.outputs.push(jack);
91 self
92 }
93
94 pub fn with_setting(mut self, key: Symbol, value: Expr) -> Self {
96 self.settings.push((key, value));
97 self
98 }
99
100 pub fn with_raw(mut self, key: Symbol, value: Expr) -> Self {
102 self.raw_view.push((key, value));
103 self
104 }
105}
106
107#[derive(Clone, Debug)]
110pub struct InstrumentTopologyJack {
111 pub name: Symbol,
113 pub mode: PortMode,
115 pub required: bool,
117 pub normalled_default: Option<Expr>,
119}
120
121impl InstrumentTopologyJack {
122 pub fn value(name: impl Into<String>, required: bool) -> Self {
124 Self::new(Symbol::new(name.into()), PortMode::Value, required)
125 }
126
127 pub fn stream(name: impl Into<String>, required: bool) -> Self {
129 Self::new(Symbol::new(name.into()), PortMode::Stream, required)
130 }
131
132 pub fn new(name: Symbol, mode: PortMode, required: bool) -> Self {
134 Self {
135 name,
136 mode,
137 required,
138 normalled_default: None,
139 }
140 }
141
142 pub fn with_normalled_default(mut self, value: Expr) -> Self {
144 self.normalled_default = Some(value);
145 self
146 }
147}
148
149#[derive(Clone, Debug)]
151pub struct InstrumentTopologyCord {
152 pub from: PortRef,
154 pub to: PortRef,
156 pub max_visits: Option<u32>,
158}
159
160impl InstrumentTopologyCord {
161 pub fn new(from: PortRef, to: PortRef) -> Self {
163 Self {
164 from,
165 to,
166 max_visits: None,
167 }
168 }
169
170 pub fn with_max_visits(mut self, max_visits: u32) -> Self {
172 self.max_visits = Some(max_visits);
173 self
174 }
175}
176
177#[derive(Clone, Copy, Debug, Default)]
179pub struct InstrumentTopologyAdapter;
180
181impl InstrumentTopologyAdapter {
182 pub fn graph_from_spec(&self, spec: &InstrumentTopologySpec) -> Graph {
184 let mut graph = Graph::new(spec.name.clone());
185 graph.metadata = spec.metadata.clone();
186 graph.metadata.push((
187 Symbol::qualified("topology", "adapter"),
188 Expr::Symbol(Symbol::qualified("topology/adapter", "instrument-patch")),
189 ));
190 graph.nodes = spec.modules.iter().map(module_to_node).collect();
191 graph.edges = spec
192 .cords
193 .iter()
194 .enumerate()
195 .map(|(index, cord)| cord_to_edge(index as u32, cord))
196 .collect();
197 graph
198 }
199}
200
201fn module_to_node(module: &InstrumentTopologyModule) -> Node {
202 let mut node = Node::with_ports(
203 module.id.clone(),
204 module.kind.clone(),
205 module.inputs.iter().map(jack_to_port).collect(),
206 module.outputs.iter().map(jack_to_port).collect(),
207 );
208 if !module.settings.is_empty() {
209 node.options.push((
210 Symbol::new("settings"),
211 Expr::Map(symbol_expr_entries(&module.settings)),
212 ));
213 }
214 if !module.raw_view.is_empty() {
215 node.options.push((
216 Symbol::new("raw-view"),
217 Expr::Map(symbol_expr_entries(&module.raw_view)),
218 ));
219 }
220 let normalled = normalled_defaults(&module.inputs, &module.outputs);
221 if !normalled.is_empty() {
222 node.options
223 .push((Symbol::new("normalled-defaults"), Expr::Map(normalled)));
224 }
225 node
226}
227
228fn jack_to_port(jack: &InstrumentTopologyJack) -> Port {
229 Port::new(
230 jack.name.clone(),
231 jack.mode,
232 jack.required && jack.normalled_default.is_none(),
233 )
234}
235
236fn cord_to_edge(index: u32, cord: &InstrumentTopologyCord) -> Edge {
237 let mut edge = Edge::new(index, cord.from.clone(), cord.to.clone());
238 edge.max_visits = cord.max_visits;
239 edge
240}
241
242fn normalled_defaults(
243 inputs: &[InstrumentTopologyJack],
244 outputs: &[InstrumentTopologyJack],
245) -> Vec<(Expr, Expr)> {
246 inputs
247 .iter()
248 .chain(outputs)
249 .filter_map(|jack| {
250 jack.normalled_default
251 .as_ref()
252 .map(|value| (Expr::Symbol(jack.name.clone()), value.clone()))
253 })
254 .collect()
255}
256
257fn symbol_expr_entries(entries: &[(Symbol, Expr)]) -> Vec<(Expr, Expr)> {
258 entries
259 .iter()
260 .map(|(key, value)| (Expr::Symbol(key.clone()), value.clone()))
261 .collect()
262}