clack_common/process/constant_mask.rs
1use std::fmt::{Debug, Formatter};
2use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign};
3
4/// A hint that indicates which channels of an audio port are constant.
5///
6/// Channels are defined as constant when all of their samples have the exact same value. This
7/// however doesn't mean they are _silent_: the value could be different from `0`.
8///
9/// This type is internally by a 64-bit bitmask, as per the CLAP specification, hence its name. This
10/// also means a constant mask can only hold constant hints for up to 64 channels: information about
11/// any extra channels is lost, and this implementation considers those channels to never be
12/// constant.
13///
14/// # Example
15///
16/// ```
17/// use clack_common::process::ConstantMask;
18///
19/// let mut constant_mask = ConstantMask::from_bits(0b101);
20///
21/// assert!(constant_mask.is_channel_constant(0));
22/// assert!(!constant_mask.is_channel_constant(1));
23/// assert!(constant_mask.is_channel_constant(2));
24///
25/// constant_mask.set_channel_constant(1, true);
26/// assert!(constant_mask.is_channel_constant(1));
27/// assert_eq!(0b111, constant_mask.to_bits());
28///
29/// ```
30#[derive(Copy, Clone, Eq, PartialEq)]
31#[repr(transparent)]
32pub struct ConstantMask(u64);
33
34impl ConstantMask {
35 /// The capacity, in bits, of a [`ConstantMask`].
36 ///
37 /// This is how many channels can be represented in a [`ConstantMask`].
38 pub const CAPACITY: u8 = 64;
39
40 /// A [`ConstantMask`] that represents all 64 possible channels as being fully constant.
41 /// This constant mask has all its bits set to `1`.
42 pub const FULLY_CONSTANT: ConstantMask = ConstantMask(u64::MAX);
43 /// A [`ConstantMask`] that represents all 64 possible channels as being fully dynamic.
44 /// This constant mask has all its bits set to `0`.
45 pub const FULLY_DYNAMIC: ConstantMask = ConstantMask(0);
46
47 /// Creates a new constant mask from its inner bitmask representation.
48 #[inline]
49 pub const fn from_bits(bits: u64) -> Self {
50 ConstantMask(bits)
51 }
52
53 /// Gets the constant mask's inner bitmask representation.
54 #[inline]
55 pub const fn to_bits(&self) -> u64 {
56 self.0
57 }
58
59 /// Returns an iterator over the constant status of each channel in this constant mask.
60 ///
61 /// # Example
62 ///
63 /// ```
64 /// use clack_common::process::ConstantMask;
65 ///
66 /// let mut iter = ConstantMask::from_bits(0b101).iter();
67 ///
68 /// assert_eq!(Some(true), iter.next());
69 /// assert_eq!(Some(false), iter.next());
70 /// assert_eq!(Some(true), iter.next());
71 /// assert_eq!(Some(false), iter.next());
72 /// assert_eq!(Some(false), iter.next());
73 /// ```
74 #[inline]
75 pub const fn iter(&self) -> ConstantMaskIter {
76 ConstantMaskIter(self.0)
77 }
78
79 /// Returns `true` if the channel at the given index is constant, `false` otherwise.
80 ///
81 /// This function will always return `false` when given any index over `63`.
82 #[inline]
83 pub const fn is_channel_constant(&self, channel_index: u64) -> bool {
84 if channel_index > 63 {
85 return false;
86 }
87
88 (self.0 & (1 << channel_index)) != 0
89 }
90
91 /// Sets whether the channel at the given index is constant.
92 ///
93 /// This function does nothing when given any index over `63`.
94 #[inline]
95 pub const fn set_channel_constant(&mut self, channel_index: u64, value: bool) {
96 if channel_index > 63 {
97 return;
98 }
99
100 if value {
101 self.0 |= 1 << channel_index
102 } else {
103 self.0 &= !(1 << channel_index)
104 }
105 }
106}
107
108impl Debug for ConstantMask {
109 #[inline]
110 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
111 core::fmt::Binary::fmt(&self.0, f)
112 }
113}
114
115impl Default for ConstantMask {
116 /// Returns an empty constant mask, i.e. one where every channel is considered dynamic.
117 #[inline]
118 fn default() -> Self {
119 ConstantMask::FULLY_DYNAMIC
120 }
121}
122
123impl IntoIterator for ConstantMask {
124 type Item = bool;
125 type IntoIter = ConstantMaskIter;
126
127 #[inline]
128 fn into_iter(self) -> Self::IntoIter {
129 self.iter()
130 }
131}
132
133impl IntoIterator for &ConstantMask {
134 type Item = bool;
135 type IntoIter = ConstantMaskIter;
136
137 #[inline]
138 fn into_iter(self) -> Self::IntoIter {
139 self.iter()
140 }
141}
142
143impl IntoIterator for &mut ConstantMask {
144 type Item = bool;
145 type IntoIter = ConstantMaskIter;
146
147 #[inline]
148 fn into_iter(self) -> Self::IntoIter {
149 self.iter()
150 }
151}
152
153impl BitAnd for ConstantMask {
154 type Output = ConstantMask;
155
156 #[inline]
157 fn bitand(self, rhs: Self) -> Self::Output {
158 ConstantMask(self.0 & rhs.0)
159 }
160}
161
162impl BitOr for ConstantMask {
163 type Output = ConstantMask;
164
165 #[inline]
166 fn bitor(self, rhs: Self) -> Self::Output {
167 ConstantMask(self.0 | rhs.0)
168 }
169}
170
171impl BitXor for ConstantMask {
172 type Output = ConstantMask;
173
174 #[inline]
175 fn bitxor(self, rhs: Self) -> Self::Output {
176 ConstantMask(self.0 ^ rhs.0)
177 }
178}
179
180impl BitAndAssign for ConstantMask {
181 #[inline]
182 fn bitand_assign(&mut self, rhs: Self) {
183 self.0 &= rhs.0
184 }
185}
186
187impl BitOrAssign for ConstantMask {
188 #[inline]
189 fn bitor_assign(&mut self, rhs: Self) {
190 self.0 |= rhs.0
191 }
192}
193
194impl BitXorAssign for ConstantMask {
195 #[inline]
196 fn bitxor_assign(&mut self, rhs: Self) {
197 self.0 ^= rhs.0
198 }
199}
200
201/// An iterator over the constant status of each channel in a [`ConstantMask`].
202///
203/// This iterator is infinite: once all channels have been iterated over, it will return `false`
204/// continuously. Use it alongside a limiting iterator adapter, such as [`zip`](Iterator::zip) or
205/// [`take`](Iterator::take).
206///
207/// # Example
208///
209/// ```
210/// use clack_common::process::ConstantMask;
211///
212/// let mut iter = ConstantMask::from_bits(0b101).iter();
213///
214/// assert_eq!(Some(true), iter.next());
215/// assert_eq!(Some(false), iter.next());
216/// assert_eq!(Some(true), iter.next());
217/// assert_eq!(Some(false), iter.next());
218/// assert_eq!(Some(false), iter.next());
219/// ```
220#[derive(Copy, Clone)]
221pub struct ConstantMaskIter(u64);
222
223impl Iterator for ConstantMaskIter {
224 type Item = bool;
225
226 #[inline]
227 fn next(&mut self) -> Option<Self::Item> {
228 let is_constant = self.0 & 1 != 0;
229 self.0 >>= 1;
230 Some(is_constant)
231 }
232
233 #[inline]
234 fn size_hint(&self) -> (usize, Option<usize>) {
235 (usize::MAX, None)
236 }
237
238 #[inline]
239 fn nth(&mut self, n: usize) -> Option<bool> {
240 self.0 >>= n;
241
242 self.next()
243 }
244}