convolve2d/subpixels.rs
1use core::ops::{Add, Mul};
2
3/// A collection of subpixels that should make working with multi-channeled images more convenient.
4///
5/// This struct implements both `Add` and `Mul`, so that it can be used as the data type for a
6/// [`Matrix`](crate::Matrix)
7///
8/// Instead of needing to divide the Red, Green, and Blue channels out so that each has its own
9/// image `Matrix`, using `SubPixels` gives you the ability to perform all three convolutions at
10/// once.
11///
12/// # Example
13/// ```
14/// # use convolve2d::SubPixels;
15/// let sp1 = SubPixels([1, 2, 3]);
16/// let sp2 = SubPixels([4, 5, 6]);
17///
18/// assert_eq!(sp1 * 2, SubPixels([2, 4, 6]));
19/// assert_eq!(sp1 + sp2, SubPixels([5, 7, 9]));
20/// ```
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct SubPixels<T: Copy, const N: usize>(pub [T; N]);
23
24impl<T: Copy, const N: usize> SubPixels<T, N> {
25 /// Perform an infallible type conversion
26 ///
27 /// # Example
28 /// ```
29 /// # use convolve2d::SubPixels;
30 /// let pixel: SubPixels<u8, 3> = SubPixels([1, 2, 3]);
31 /// assert_eq!(pixel.convert::<f64>(), SubPixels([1.0, 2.0, 3.0]));
32 /// ```
33 pub fn convert<U: From<T> + Copy + Default>(self) -> SubPixels<U, N> {
34 let mut arr = [U::default(); N];
35 for (a, n) in arr.iter_mut().zip(self.0) {
36 *a = U::from(n);
37 }
38 SubPixels(arr)
39 }
40
41 /// Perform a fallible type conversion
42 ///
43 /// # Example
44 /// ```
45 /// # use convolve2d::SubPixels;
46 /// let pixel: SubPixels<u32, 3> = SubPixels([1, 2, 3]);
47 /// assert_eq!(pixel.try_convert::<u8>(), Ok(SubPixels([1, 2, 3])));
48 /// ```
49 pub fn try_convert<U: TryFrom<T> + Copy + Default>(self) -> Result<SubPixels<U, N>, U::Error> {
50 let mut arr = [U::default(); N];
51 for (a, n) in arr.iter_mut().zip(self.0) {
52 *a = U::try_from(n)?;
53 }
54 Ok(SubPixels(arr))
55 }
56
57 /// Perform a map operation, applying the provided function to each subpixel.
58 ///
59 /// # Example
60 /// ```
61 /// # use convolve2d::SubPixels;
62 /// let pixel = SubPixels([1, 2, 3]);
63 /// assert_eq!(pixel.map(|x| x + 1), SubPixels([2, 3, 4]));
64 /// ```
65 pub fn map<F, O>(self, operation: F) -> SubPixels<O, N>
66 where
67 F: Fn(T) -> O,
68 O: Default + Copy,
69 {
70 let mut arr = [O::default(); N];
71 for (i, x) in self.0.into_iter().enumerate() {
72 arr[i] = operation(x);
73 }
74 SubPixels(arr)
75 }
76}
77
78impl<T: Copy, const N: usize> From<[T; N]> for SubPixels<T, N> {
79 fn from(other: [T; N]) -> Self {
80 Self(other)
81 }
82}
83
84impl<T: Add<Output = T> + Copy, const N: usize> Add for SubPixels<T, N> {
85 type Output = Self;
86
87 fn add(mut self, rhs: Self) -> Self::Output {
88 for (i, x) in rhs.0.into_iter().enumerate() {
89 self.0[i] = self.0[i] + x;
90 }
91 self
92 }
93}
94
95impl<T, C, O, const N: usize> Mul<C> for SubPixels<T, N>
96where
97 C: Copy,
98 T: Mul<C, Output = O> + Copy,
99 O: Default + Copy,
100{
101 type Output = SubPixels<O, N>;
102
103 fn mul(self, rhs: C) -> Self::Output {
104 let mut arr = [O::default(); N];
105 self.0
106 .into_iter()
107 .map(|a| a * rhs)
108 .enumerate()
109 .for_each(|(i, v)| arr[i] = v);
110 SubPixels(arr)
111 }
112}
113
114impl<T: Copy + Default, const N: usize> Default for SubPixels<T, N> {
115 fn default() -> Self {
116 Self([T::default(); N])
117 }
118}