1use bitvec::{array::BitArray, slice::IterOnes};
2
3use crate::AudioGraphError;
4
5include!(concat!(env!("OUT_DIR"), "/constants.rs"));
6
7const WORDS: usize = (MAX_CHANNELS - 1) / 64 + 1;
8
9pub type ChannelSelection = ChannelSelectionImpl<MAX_CHANNELS, WORDS>;
18
19#[derive(Clone)]
20pub struct ChannelSelectionImpl<const NUM_CHANNELS: usize, const WORDS: usize> {
21 bits: BitArray<[u64; WORDS]>,
22}
23
24impl<const NUM_CHANNELS: usize, const WORDS: usize> Default
25 for ChannelSelectionImpl<NUM_CHANNELS, WORDS>
26{
27 fn default() -> Self {
29 Self::new(NUM_CHANNELS)
30 }
31}
32
33impl<const NUM_CHANNELS: usize, const WORDS: usize> ChannelSelectionImpl<NUM_CHANNELS, WORDS> {
34 pub fn new(num_connected: usize) -> Self {
36 let mut bits = BitArray::ZERO;
37 let count = num_connected.min(NUM_CHANNELS);
38 bits[..count].fill(true);
39 Self { bits }
40 }
41
42 pub fn from_indices(indices: &[usize]) -> Self {
49 let mut selection = ChannelSelectionImpl::new(0);
50 for &index in indices {
51 selection
52 .connect(index)
53 .expect("Channel index is out of bounds");
54 }
55 selection
56 }
57
58 pub fn connect(&mut self, channel: usize) -> Result<(), AudioGraphError> {
60 if channel >= NUM_CHANNELS {
61 return Err("Channel index is out of bounds");
62 }
63
64 self.bits.set(channel, true);
65 Ok(())
66 }
67
68 pub fn disconnect(&mut self, channel: usize) -> Result<(), AudioGraphError> {
69 if channel >= NUM_CHANNELS {
70 return Err("Channel index is out of bounds");
71 }
72
73 self.bits.set(channel, false);
74 Ok(())
75 }
76
77 pub fn is_connected(&self, channel: usize) -> bool {
79 if channel < NUM_CHANNELS {
80 self.bits[channel]
81 } else {
82 false
83 }
84 }
85
86 pub fn iter(&self) -> IterOnes<'_, u64, bitvec::order::Lsb0> {
88 self.bits.iter_ones()
89 }
90
91 pub fn clamp(&mut self, max_channels: usize) {
93 self.bits.split_at_mut(max_channels).1.fill(false);
94 }
95
96 pub fn index_of_last_connected(&self) -> Option<usize> {
98 self.bits.last_one()
99 }
100
101 pub fn combine(&mut self, other: &Self) {
103 self.bits |= other.bits;
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn test_channel_selection_creation() {
113 let selection = ChannelSelection::new(3);
114 assert!(selection.is_connected(0));
115 assert!(selection.is_connected(1));
116 assert!(selection.is_connected(2));
117 assert!(!selection.is_connected(3));
118 assert!(!selection.is_connected(63));
119 assert!(!selection.is_connected(64));
120 }
121
122 #[test]
123 fn test_channel_selection_clamping() {
124 let mut selection = ChannelSelection::new(5);
125 selection.clamp(3);
126 assert!(selection.is_connected(0));
127 assert!(selection.is_connected(1));
128 assert!(selection.is_connected(2));
129 assert!(!selection.is_connected(3));
130 assert!(!selection.is_connected(4));
131 }
132}