sim-lib-topology 0.1.0

Data-driven topology engine.
Documentation
use sim_kernel::Symbol;
use sim_lib_stream_core::{BridgeLatency, DomainBridgeKind, LatencyClass};

use super::{Graph, Node, PortRef, sym, test_cx};
use crate::{
    Edge, PlacementNodeProfile, PlacementRefusalReason, SiteMap, SiteProfile, place, place_graph,
};

#[test]
fn all_local_map_places_without_bridges() {
    let mut cx = test_cx();
    let graph = fx_graph();
    let report = place(&mut cx, &graph, &all_audio_site_map()).expect("place graph");

    assert!(report.is_accepted());
    assert_eq!(report.placed.len(), 3);
    assert!(
        report
            .placed
            .iter()
            .all(|node| node.site.as_symbol() == &Symbol::new("audio"))
    );
    assert!(report.bridges.is_empty());
    assert_eq!(report.latency.len(), 1);
    assert_eq!(report.latency[0].node.as_symbol(), &Symbol::new("out"));
    assert_eq!(report.latency[0].latency, BridgeLatency::frames(16));
}

#[test]
fn offloaded_fx_map_inserts_latency_comp_bridges() {
    let mut cx = test_cx();
    let compiled = crate::compile_graph(&mut cx, &fx_graph()).expect("compiled graph");
    let report = place_graph(&compiled, &offloaded_fx_site_map());

    assert!(report.is_accepted());
    assert_eq!(report.bridges.len(), 2);
    assert!(
        report
            .bridges
            .iter()
            .all(|bridge| bridge.kind() == DomainBridgeKind::LatencyCompDelay)
    );
    assert_eq!(report.bridges[0].from.as_symbol(), &Symbol::new("in"));
    assert_eq!(report.bridges[0].to.as_symbol(), &Symbol::new("fx"));
    assert_eq!(report.bridges[1].from.as_symbol(), &Symbol::new("fx"));
    assert_eq!(report.bridges[1].to.as_symbol(), &Symbol::new("out"));
    assert_eq!(report.latency[0].latency, BridgeLatency::frames(64));
}

#[test]
fn illegal_realtime_remote_map_is_refused_as_data() {
    let mut cx = test_cx();
    let graph = fx_graph();
    let report = place(&mut cx, &graph, &illegal_realtime_site_map()).expect("place graph");

    assert!(!report.is_accepted());
    assert!(report.refusals.iter().any(|refusal| {
        refusal.node.as_symbol() == &Symbol::new("fx")
            && refusal.site.as_symbol() == &Symbol::new("worker")
            && refusal.reason == PlacementRefusalReason::RealtimePinViolation
    }));
}

#[test]
fn site_latency_class_mismatch_is_refused_as_data() {
    let mut cx = test_cx();
    let graph = fx_graph();
    let report = place(&mut cx, &graph, &unsupported_latency_site_map()).expect("place graph");

    assert!(!report.is_accepted());
    assert!(report.refusals.iter().any(|refusal| {
        refusal.node.as_symbol() == &Symbol::new("fx")
            && refusal.reason == PlacementRefusalReason::UnsupportedLatencyClass
    }));
}

fn fx_graph() -> Graph {
    let mut graph = Graph::minimal("placement-fx");
    let mut fx = Node::named("fx", "call");
    fx.target = Some(sym("gain"));
    graph.nodes = vec![Node::named("in", "in"), fx, Node::named("out", "out")];
    graph.edges = vec![
        Edge::new(0, PortRef::output("in"), PortRef::input("fx")),
        Edge::new(1, PortRef::output("fx"), PortRef::input("out")),
    ];
    graph
}

fn all_audio_site_map() -> SiteMap {
    SiteMap::new(SiteProfile::audio_clock("audio"))
        .with_node_profile("in", block_profile())
        .with_node_profile(
            "fx",
            block_profile().with_latency(BridgeLatency::frames(16)),
        )
        .with_node_profile("out", block_profile())
}

fn offloaded_fx_site_map() -> SiteMap {
    SiteMap::new(SiteProfile::audio_clock("audio"))
        .with_site(SiteProfile::local_worker("worker"))
        .assign_node("fx", "worker")
        .with_node_profile("in", block_profile())
        .with_node_profile(
            "fx",
            block_profile().with_latency(BridgeLatency::frames(64)),
        )
        .with_node_profile("out", block_profile())
}

fn illegal_realtime_site_map() -> SiteMap {
    SiteMap::new(SiteProfile::audio_clock("audio"))
        .with_site(SiteProfile::local_worker("worker"))
        .assign_node("fx", "worker")
        .with_node_profile("in", block_profile())
        .with_node_profile("fx", PlacementNodeProfile::sample_exact(Some(48_000), true))
        .with_node_profile("out", block_profile())
}

fn unsupported_latency_site_map() -> SiteMap {
    SiteMap::new(SiteProfile::audio_clock("audio"))
        .with_site(SiteProfile::local_worker("worker"))
        .assign_node("fx", "worker")
        .with_node_profile("in", block_profile())
        .with_node_profile(
            "fx",
            PlacementNodeProfile::new(
                sim_lib_stream_core::RateContract::new(
                    sim_lib_stream_core::ClockDomain::Job,
                    LatencyClass::RemoteCollaboration,
                    None,
                ),
                false,
            ),
        )
        .with_node_profile("out", block_profile())
}

fn block_profile() -> PlacementNodeProfile {
    PlacementNodeProfile::block_local()
}