p_chan/
macros.rs

1/// Declare a newtype channel wrapper.
2///
3/// ```
4/// p_chan::channel!(
5///     (Ch8, p_chan::unsigned::Ch8),
6///     doc = "8-bit channel",
7/// );
8/// ```
9#[macro_export]
10macro_rules! channel {
11    (($ty: ident, $inner: ty), $attr: meta $(,)?) => {
12        #[$attr]
13        #[derive(
14            Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default,
15        )]
16        #[repr(transparent)]
17        pub struct $ty($inner);
18
19        impl $ty {
20            fn __() {
21                struct Impl<T>(core::marker::PhantomData<fn() -> T>)
22                where
23                    T: $crate::bytemuck::Pod + $crate::bytemuck::Zeroable;
24
25                const INNER: Impl<$inner> = Impl(core::marker::PhantomData);
26            }
27        }
28
29        impl From<$inner> for $ty {
30            fn from(value: $inner) -> Self {
31                Self(value)
32            }
33        }
34
35        impl From<$ty> for $inner {
36            fn from(chan: $ty) -> Self {
37                chan.0
38            }
39        }
40
41        #[allow(unsafe_code)]
42        unsafe impl $crate::bytemuck::Zeroable for $ty {}
43
44        #[allow(unsafe_code)]
45        unsafe impl $crate::bytemuck::Pod for $ty {}
46    };
47}
48
49/// Declare a channel group type.
50///
51/// ```
52/// p_chan::group!(
53///     (Pixel),
54///     doc = "A pixel, made up of individual color channels",
55/// );
56///
57/// p_chan::group!(
58///     (Frame),
59///     doc = "An audio frame, made up of individual speaker channels",
60/// );
61/// ```
62#[macro_export]
63macro_rules! group {
64    (($ty: ident), $attr: meta $(,)?) => {
65        #[$attr]
66        #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
67        #[repr(transparent)]
68        pub struct $ty<Chan, const CH: usize>([Chan; CH]);
69
70        impl<Chan, const CH: usize> Default for $ty<Chan, CH>
71        where
72            Chan: Default + Copy,
73        {
74            fn default() -> Self {
75                Self([Chan::default(); CH])
76            }
77        }
78
79        #[allow(unsafe_code)]
80        unsafe impl<Chan, const CH: usize> $crate::bytemuck::Zeroable
81            for $ty<Chan, CH>
82        where
83            Chan: $crate::bytemuck::Zeroable,
84        {
85        }
86
87        #[allow(unsafe_code)]
88        unsafe impl<Chan, const CH: usize> $crate::bytemuck::Pod
89            for $ty<Chan, CH>
90        where
91            Chan: $crate::bytemuck::Pod,
92        {
93        }
94    };
95}
96
97macro_rules! ch_int {
98    (
99        ($ty: ident, $p: ty, $b: ty, $normalize: path, $midpoint: item),
100        $docs: meta $(,)?
101    ) => {
102        #[$docs]
103        #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
104        #[repr(transparent)]
105        pub struct $ty($p);
106
107        impl core::fmt::Debug for $ty {
108            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
109            {
110                core::fmt::Debug::fmt(&self.0, f)
111            }
112        }
113
114        impl core::fmt::Display for $ty {
115            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
116            {
117                core::fmt::Display::fmt(&self.0, f)
118            }
119        }
120
121        impl From<$p> for $ty {
122            fn from(value: $p) -> Self {
123                Self::new(value)
124            }
125        }
126
127        impl From<$ty> for $p {
128            fn from(chan: $ty) -> Self {
129                chan.0
130            }
131        }
132
133        impl $ty {
134            /// Maximum value
135            pub const MAX: Self = Self::new($normalize(<$p>::MAX));
136            /// Middle value
137            pub const MID: Self = Self::MAX.midpoint(Self::MIN);
138            /// Minimum value
139            pub const MIN: Self = Self::new($normalize(<$p>::MIN));
140
141            /// Create a new channel value.
142            pub const fn new(value: $p) -> Self {
143                Self($normalize(value))
144            }
145
146            /// Get the inner primitive channel value.
147            pub const fn into_inner(self) -> $p {
148                self.0
149            }
150
151            $midpoint
152
153            /// Returns `max` if `self` is greater than `max`, and `min` if
154            /// `self` is less than `min`. Otherwise this returns `self`.
155            ///
156            /// # Panics
157            ///
158            /// Panics if `min > max`.
159            pub const fn clamp(self, min: Self, max: Self) -> Self {
160                let (mut this, min, max) = (self.0, min.0, max.0);
161
162                assert!(min <= max, "min > max");
163
164                if this < min {
165                    this = min;
166                }
167
168                if this > max {
169                    this = max;
170                }
171
172                Self(this)
173            }
174
175            pub(crate) const fn int_multiply(&mut self, rhs: Self) {
176                let this = self.into_inner() as $b;
177                let rhs = rhs.into_inner() as $b;
178                let min = Self::MIN.into_inner() as $b;
179                let max = Self::MAX.into_inner() as $b;
180                let mut res = (this * rhs) / max;
181
182                if res < min {
183                    res = min;
184                }
185
186                if res > max {
187                    res = max;
188                }
189
190                *self = Self(res as $p);
191            }
192        }
193
194        impl core::ops::Add for $ty {
195            type Output = Self;
196
197            #[inline(always)]
198            fn add(self, rhs: Self) -> Self {
199                crate::ops::Sum([self, rhs]).add()
200            }
201        }
202
203        impl core::ops::AddAssign for $ty {
204            #[inline(always)]
205            fn add_assign(&mut self, rhs: Self) {
206                *self = *self + rhs;
207            }
208        }
209
210        impl core::ops::Sub for $ty {
211            type Output = Self;
212
213            #[inline(always)]
214            fn sub(self, rhs: Self) -> Self {
215                crate::ops::Difference(self, [rhs]).sub()
216            }
217        }
218
219        impl core::ops::SubAssign for $ty {
220            #[inline(always)]
221            fn sub_assign(&mut self, rhs: Self) {
222                *self = *self - rhs;
223            }
224        }
225
226        impl core::ops::Neg for $ty {
227            type Output = Self;
228
229            #[inline(always)]
230            fn neg(self) -> Self {
231                crate::ops::Negation(self).neg()
232            }
233        }
234
235        impl core::ops::Not for $ty {
236            type Output = Self;
237
238            #[inline(always)]
239            fn not(self) -> Self {
240                crate::ops::Inversion(self).inv()
241            }
242        }
243
244        impl core::ops::Mul for $ty {
245            type Output = Self;
246
247            #[inline(always)]
248            fn mul(mut self, rhs: Self) -> Self {
249                self.int_multiply(rhs);
250                self
251            }
252        }
253
254        impl core::ops::MulAssign for $ty {
255            #[inline(always)]
256            fn mul_assign(&mut self, rhs: Self) {
257                *self = *self * rhs;
258            }
259        }
260
261        #[allow(unsafe_code)]
262        unsafe impl bytemuck::Zeroable for $ty {}
263
264        #[allow(unsafe_code)]
265        unsafe impl bytemuck::Pod for $ty {}
266    };
267}
268
269macro_rules! ch_float {
270    (
271        ($ty: ident, $p: ty, $normalize: path, $min: literal, $mid: literal),
272        $docs: meta $(,)?
273    ) => {
274        #[$docs]
275        #[derive(Copy, Clone, Default)]
276        #[repr(transparent)]
277        pub struct $ty($p);
278
279        impl core::hash::Hash for $ty {
280            fn hash<H>(&self, state: &mut H)
281            where
282                H: core::hash::Hasher,
283            {
284                self.0.to_bits().hash(state)
285            }
286        }
287
288        impl core::cmp::PartialEq for $ty {
289            fn eq(&self, other: &Self) -> bool {
290                $normalize(self.into_inner()) == $normalize(other.into_inner())
291            }
292        }
293
294        impl core::cmp::Ord for $ty {
295            fn cmp(&self, other: &Self) -> core::cmp::Ordering {
296                $normalize(self.into_inner())
297                    .partial_cmp(&$normalize(other.into_inner()))
298                    .unwrap()
299            }
300        }
301
302        impl core::cmp::Eq for $ty {}
303
304        impl core::cmp::PartialOrd for $ty {
305            fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
306                Some(self.cmp(other))
307            }
308        }
309
310        impl core::fmt::Debug for $ty {
311            fn fmt(
312                &self,
313                f: &mut core::fmt::Formatter<'_>,
314            ) -> core::fmt::Result {
315                self.0.fmt(f)
316            }
317        }
318
319        impl core::fmt::Display for $ty {
320            fn fmt(
321                &self,
322                f: &mut core::fmt::Formatter<'_>,
323            ) -> core::fmt::Result {
324                self.0.fmt(f)
325            }
326        }
327
328        impl From<$p> for $ty {
329            fn from(value: $p) -> Self {
330                Self::new(value)
331            }
332        }
333
334        impl From<$ty> for $p {
335            fn from(chan: $ty) -> Self {
336                chan.0
337            }
338        }
339
340        impl $ty {
341            /// Maximum value
342            pub const MAX: Self = Self::new(1.0);
343            /// Middle value
344            pub const MID: Self = Self::new($mid);
345            /// Minimum value
346            pub const MIN: Self = Self::new($min);
347
348            /// Create a new channel value.
349            pub const fn new(value: $p) -> Self {
350                Self($normalize(value))
351            }
352
353            /// Get the inner primitive channel value.
354            pub const fn into_inner(self) -> $p {
355                self.0
356            }
357
358            /// Calculates the middle point of `self` and `rhs` (clamped).
359            ///
360            /// `midpoint(a, b)` is `(a + b) / 2`.
361            pub const fn midpoint(self, rhs: Self) -> Self {
362                // Overflow is impossible since maximum value is 1 (would need
363                // to be over (float::MAX / 2.0)
364                Self($normalize((self.0 + rhs.0) / 2.0))
365            }
366
367            /// Returns `max` if `self` is greater than `max`, and `min` if
368            /// `self` is less than `min`. Otherwise this returns `self`.
369            ///
370            /// # Panics
371            ///
372            /// Panics if `min > max`.
373            pub const fn clamp(self, min: Self, max: Self) -> Self {
374                Self(self.0.clamp(min.0, max.0))
375            }
376        }
377
378        impl core::ops::Add for $ty {
379            type Output = Self;
380
381            #[inline(always)]
382            fn add(self, rhs: Self) -> Self {
383                crate::ops::Sum([self, rhs]).add()
384            }
385        }
386
387        impl core::ops::AddAssign for $ty {
388            #[inline(always)]
389            fn add_assign(&mut self, rhs: Self) {
390                *self = *self + rhs;
391            }
392        }
393
394        impl core::ops::Sub for $ty {
395            type Output = Self;
396
397            #[inline(always)]
398            fn sub(self, rhs: Self) -> Self {
399                crate::ops::Difference(self, [rhs]).sub()
400            }
401        }
402
403        impl core::ops::SubAssign for $ty {
404            #[inline(always)]
405            fn sub_assign(&mut self, rhs: Self) {
406                *self = *self - rhs;
407            }
408        }
409
410        impl core::ops::Neg for $ty {
411            type Output = Self;
412
413            #[inline(always)]
414            fn neg(self) -> Self {
415                crate::ops::Negation(self).neg()
416            }
417        }
418
419        impl core::ops::Not for $ty {
420            type Output = Self;
421
422            #[inline(always)]
423            fn not(self) -> Self {
424                crate::ops::Inversion(self).inv()
425            }
426        }
427
428        impl core::ops::Mul for $ty {
429            type Output = Self;
430
431            #[inline(always)]
432            fn mul(self, rhs: Self) -> Self {
433                crate::ops::Product([self, rhs]).mul()
434            }
435        }
436
437        impl core::ops::MulAssign for $ty {
438            #[inline(always)]
439            fn mul_assign(&mut self, rhs: Self) {
440                *self = *self * rhs;
441            }
442        }
443
444        #[allow(unsafe_code)]
445        unsafe impl bytemuck::Zeroable for $ty {}
446
447        #[allow(unsafe_code)]
448        unsafe impl bytemuck::Pod for $ty {}
449    };
450}
451
452macro_rules! conversion {
453    ($from:ty, $into:ty) => {
454        impl From<$from> for $into {
455            fn from(value: $from) -> $into {
456                Conversion::<$from, $into>::conv(value)
457            }
458        }
459    };
460}