use sim_kernel::{Expr, Symbol};
use crate::{Edge, Graph, Node, NodeId, Port, PortMode, PortRef};
#[derive(Clone, Debug)]
pub struct InstrumentTopologySpec {
pub name: Symbol,
pub modules: Vec<InstrumentTopologyModule>,
pub cords: Vec<InstrumentTopologyCord>,
pub metadata: Vec<(Symbol, Expr)>,
}
impl InstrumentTopologySpec {
pub fn new(name: Symbol) -> Self {
Self {
name,
modules: Vec::new(),
cords: Vec::new(),
metadata: Vec::new(),
}
}
pub fn with_module(mut self, module: InstrumentTopologyModule) -> Self {
self.modules.push(module);
self
}
pub fn with_cord(mut self, cord: InstrumentTopologyCord) -> Self {
self.cords.push(cord);
self
}
pub fn with_metadata(mut self, key: Symbol, value: Expr) -> Self {
self.metadata.push((key, value));
self
}
}
#[derive(Clone, Debug)]
pub struct InstrumentTopologyModule {
pub id: NodeId,
pub kind: Symbol,
pub inputs: Vec<InstrumentTopologyJack>,
pub outputs: Vec<InstrumentTopologyJack>,
pub settings: Vec<(Symbol, Expr)>,
pub raw_view: Vec<(Symbol, Expr)>,
}
impl InstrumentTopologyModule {
pub fn new(id: impl Into<NodeId>, kind: Symbol) -> Self {
Self {
id: id.into(),
kind,
inputs: Vec::new(),
outputs: Vec::new(),
settings: Vec::new(),
raw_view: Vec::new(),
}
}
pub fn with_input(mut self, jack: InstrumentTopologyJack) -> Self {
self.inputs.push(jack);
self
}
pub fn with_output(mut self, jack: InstrumentTopologyJack) -> Self {
self.outputs.push(jack);
self
}
pub fn with_setting(mut self, key: Symbol, value: Expr) -> Self {
self.settings.push((key, value));
self
}
pub fn with_raw(mut self, key: Symbol, value: Expr) -> Self {
self.raw_view.push((key, value));
self
}
}
#[derive(Clone, Debug)]
pub struct InstrumentTopologyJack {
pub name: Symbol,
pub mode: PortMode,
pub required: bool,
pub normalled_default: Option<Expr>,
}
impl InstrumentTopologyJack {
pub fn value(name: impl Into<String>, required: bool) -> Self {
Self::new(Symbol::new(name.into()), PortMode::Value, required)
}
pub fn stream(name: impl Into<String>, required: bool) -> Self {
Self::new(Symbol::new(name.into()), PortMode::Stream, required)
}
pub fn new(name: Symbol, mode: PortMode, required: bool) -> Self {
Self {
name,
mode,
required,
normalled_default: None,
}
}
pub fn with_normalled_default(mut self, value: Expr) -> Self {
self.normalled_default = Some(value);
self
}
}
#[derive(Clone, Debug)]
pub struct InstrumentTopologyCord {
pub from: PortRef,
pub to: PortRef,
pub max_visits: Option<u32>,
}
impl InstrumentTopologyCord {
pub fn new(from: PortRef, to: PortRef) -> Self {
Self {
from,
to,
max_visits: None,
}
}
pub fn with_max_visits(mut self, max_visits: u32) -> Self {
self.max_visits = Some(max_visits);
self
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct InstrumentTopologyAdapter;
impl InstrumentTopologyAdapter {
pub fn graph_from_spec(&self, spec: &InstrumentTopologySpec) -> Graph {
let mut graph = Graph::new(spec.name.clone());
graph.metadata = spec.metadata.clone();
graph.metadata.push((
Symbol::qualified("topology", "adapter"),
Expr::Symbol(Symbol::qualified("topology/adapter", "instrument-patch")),
));
graph.nodes = spec.modules.iter().map(module_to_node).collect();
graph.edges = spec
.cords
.iter()
.enumerate()
.map(|(index, cord)| cord_to_edge(index as u32, cord))
.collect();
graph
}
}
fn module_to_node(module: &InstrumentTopologyModule) -> Node {
let mut node = Node::with_ports(
module.id.clone(),
module.kind.clone(),
module.inputs.iter().map(jack_to_port).collect(),
module.outputs.iter().map(jack_to_port).collect(),
);
if !module.settings.is_empty() {
node.options.push((
Symbol::new("settings"),
Expr::Map(symbol_expr_entries(&module.settings)),
));
}
if !module.raw_view.is_empty() {
node.options.push((
Symbol::new("raw-view"),
Expr::Map(symbol_expr_entries(&module.raw_view)),
));
}
let normalled = normalled_defaults(&module.inputs, &module.outputs);
if !normalled.is_empty() {
node.options
.push((Symbol::new("normalled-defaults"), Expr::Map(normalled)));
}
node
}
fn jack_to_port(jack: &InstrumentTopologyJack) -> Port {
Port::new(
jack.name.clone(),
jack.mode,
jack.required && jack.normalled_default.is_none(),
)
}
fn cord_to_edge(index: u32, cord: &InstrumentTopologyCord) -> Edge {
let mut edge = Edge::new(index, cord.from.clone(), cord.to.clone());
edge.max_visits = cord.max_visits;
edge
}
fn normalled_defaults(
inputs: &[InstrumentTopologyJack],
outputs: &[InstrumentTopologyJack],
) -> Vec<(Expr, Expr)> {
inputs
.iter()
.chain(outputs)
.filter_map(|jack| {
jack.normalled_default
.as_ref()
.map(|value| (Expr::Symbol(jack.name.clone()), value.clone()))
})
.collect()
}
fn symbol_expr_entries(entries: &[(Symbol, Expr)]) -> Vec<(Expr, Expr)> {
entries
.iter()
.map(|(key, value)| (Expr::Symbol(key.clone()), value.clone()))
.collect()
}