gled_model/patching/
addressing.rs1use crate::collection::Collections;
6use crate::patching::Patch;
7use crate::patching::fixture::{ArtnetDMXAddress, FixtureId};
8use std::collections::{BTreeMap, BTreeSet};
9
10#[derive(Debug, Clone, Default, PartialEq, Eq)]
13pub struct Addressing {
14 addresses: BTreeMap<FixtureId, ArtnetDMXAddress>,
15 universes: Vec<u16>,
16}
17
18impl Addressing {
19 pub fn slot(&self, id: FixtureId) -> Option<(usize, ArtnetDMXAddress)> {
22 let address = *self.addresses.get(&id)?;
23 let slot = self.universes.binary_search(&address.universe()).ok()?;
24 Some((slot, address))
25 }
26
27 pub fn universes(&self) -> &[u16] {
29 &self.universes
30 }
31}
32
33impl Patch {
34 pub fn addressing(&self, collections: &Collections) -> Addressing {
36 let addresses = self.addresses(collections);
37 let universes: BTreeSet<u16> = addresses
38 .values()
39 .map(|address| address.universe())
40 .collect();
41 Addressing {
42 addresses,
43 universes: universes.into_iter().collect(),
44 }
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use crate::patching::fixture::{Fixture, LayoutPosition};
52 use crate::test_support::{collections_with, rgb_bar};
53
54 #[test]
55 fn a_fixture_s_slot_is_its_universe_s_place_among_the_universes() {
56 let (collections, ids) = collections_with(vec![rgb_bar(4, 1.0)]);
57 let mut patch = Patch::default();
58 let a = patch.add_fixture(
59 Fixture::with_definition("a", ids[0]),
60 LayoutPosition::default(),
61 );
62 let b = patch.add_fixture(
63 Fixture::with_definition("b", ids[0]),
64 LayoutPosition::default(),
65 );
66 patch.topology.ports.entry(b).or_default().universe = 5;
67
68 let addressing = patch.addressing(&collections);
69
70 assert_eq!(addressing.universes(), [0, 5]);
71 assert_eq!(addressing.slot(a).map(|(slot, _)| slot), Some(0));
72 assert_eq!(addressing.slot(b).map(|(slot, _)| slot), Some(1));
73 }
74
75 #[test]
79 fn a_fixture_wider_than_a_universe_and_its_chain_get_no_address() {
80 let (collections, ids) = collections_with(vec![
81 rgb_bar(4, 1.0),
82 rgb_bar(171, 1.0),
83 rgb_bar(22_000, 1.0),
84 ]);
85 let mut patch = Patch::default();
86 let head = patch.add_fixture(
87 Fixture::with_definition("head", ids[0]),
88 LayoutPosition::default(),
89 );
90 let wide = patch.add_fixture(
91 Fixture::with_definition("wide", ids[1]),
92 LayoutPosition::default(),
93 );
94 let tail = patch.add_fixture(
95 Fixture::with_definition("tail", ids[0]),
96 LayoutPosition::default(),
97 );
98 patch.topology.make_successor(head, wide);
99 patch.topology.make_successor(wide, tail);
100 let huge = patch.add_fixture(
101 Fixture::with_definition("huge", ids[2]),
102 LayoutPosition::default(),
103 );
104
105 let addressing = patch.addressing(&collections);
106
107 assert_eq!(
108 addressing.slot(head).map(|(_, a)| a.into_pair()),
109 Some((0, 0))
110 );
111 assert_eq!(addressing.slot(wide), None);
112 assert_eq!(addressing.slot(tail), None);
113 assert_eq!(addressing.slot(huge), None);
114 assert_eq!(addressing.universes(), [0]);
115 }
116
117 #[test]
118 fn a_fixture_without_a_definition_has_no_slot() {
119 let (collections, _) = collections_with(vec![]);
120 let mut patch = Patch::default();
121 let orphan = patch.add_fixture(Fixture::new("orphan"), LayoutPosition::default());
122
123 let addressing = patch.addressing(&collections);
124
125 assert_eq!(addressing.slot(orphan), None);
126 assert!(addressing.universes().is_empty());
127 }
128}