use crate::collection::Collections;
use crate::patching::Patch;
use crate::patching::fixture::{ArtnetDMXAddress, FixtureId};
use std::collections::{BTreeMap, BTreeSet};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Addressing {
addresses: BTreeMap<FixtureId, ArtnetDMXAddress>,
universes: Vec<u16>,
}
impl Addressing {
pub fn slot(&self, id: FixtureId) -> Option<(usize, ArtnetDMXAddress)> {
let address = *self.addresses.get(&id)?;
let slot = self.universes.binary_search(&address.universe()).ok()?;
Some((slot, address))
}
pub fn universes(&self) -> &[u16] {
&self.universes
}
}
impl Patch {
pub fn addressing(&self, collections: &Collections) -> Addressing {
let addresses = self.addresses(collections);
let universes: BTreeSet<u16> = addresses
.values()
.map(|address| address.universe())
.collect();
Addressing {
addresses,
universes: universes.into_iter().collect(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::patching::fixture::{Fixture, LayoutPosition};
use crate::test_support::{collections_with, rgb_bar};
#[test]
fn a_fixture_s_slot_is_its_universe_s_place_among_the_universes() {
let (collections, ids) = collections_with(vec![rgb_bar(4, 1.0)]);
let mut patch = Patch::default();
let a = patch.add_fixture(
Fixture::with_definition("a", ids[0]),
LayoutPosition::default(),
);
let b = patch.add_fixture(
Fixture::with_definition("b", ids[0]),
LayoutPosition::default(),
);
patch.topology.ports.entry(b).or_default().universe = 5;
let addressing = patch.addressing(&collections);
assert_eq!(addressing.universes(), [0, 5]);
assert_eq!(addressing.slot(a).map(|(slot, _)| slot), Some(0));
assert_eq!(addressing.slot(b).map(|(slot, _)| slot), Some(1));
}
#[test]
fn a_fixture_wider_than_a_universe_and_its_chain_get_no_address() {
let (collections, ids) = collections_with(vec![
rgb_bar(4, 1.0),
rgb_bar(171, 1.0),
rgb_bar(22_000, 1.0),
]);
let mut patch = Patch::default();
let head = patch.add_fixture(
Fixture::with_definition("head", ids[0]),
LayoutPosition::default(),
);
let wide = patch.add_fixture(
Fixture::with_definition("wide", ids[1]),
LayoutPosition::default(),
);
let tail = patch.add_fixture(
Fixture::with_definition("tail", ids[0]),
LayoutPosition::default(),
);
patch.topology.make_successor(head, wide);
patch.topology.make_successor(wide, tail);
let huge = patch.add_fixture(
Fixture::with_definition("huge", ids[2]),
LayoutPosition::default(),
);
let addressing = patch.addressing(&collections);
assert_eq!(
addressing.slot(head).map(|(_, a)| a.into_pair()),
Some((0, 0))
);
assert_eq!(addressing.slot(wide), None);
assert_eq!(addressing.slot(tail), None);
assert_eq!(addressing.slot(huge), None);
assert_eq!(addressing.universes(), [0]);
}
#[test]
fn a_fixture_without_a_definition_has_no_slot() {
let (collections, _) = collections_with(vec![]);
let mut patch = Patch::default();
let orphan = patch.add_fixture(Fixture::new("orphan"), LayoutPosition::default());
let addressing = patch.addressing(&collections);
assert_eq!(addressing.slot(orphan), None);
assert!(addressing.universes().is_empty());
}
}