1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use core::ops::{Deref, DerefMut};

use num_traits::FromPrimitive;

use crate::{color::rgb::Rgb, Pixel};

/// Grayscale pixel
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct Gray<T>(pub [T; 1]);

impl<T> From<[T; 1]> for Gray<T> {
    fn from(value: [T; 1]) -> Self {
        Gray(value)
    }
}

impl<T> Deref for Gray<T> {
    type Target = [T; 1];

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T> DerefMut for Gray<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl<T> Pixel for Gray<T> {
    const CHANNELS: u8 = 1;
}

impl<T, U, const R: usize, const G: usize, const B: usize> From<Rgb<U, R, G, B>> for Gray<T>
where
    T: Copy + FromPrimitive,
    U: Copy + Into<f32>,
{
    fn from(rgb: Rgb<U, R, G, B>) -> Self {
        // rec601 luma
        let y =
            T::from_f32(0.2126 * rgb[R].into() + 0.7152 * rgb[G].into() + 0.0722 * rgb[B].into())
                .expect("could not convert from f32 to T");

        Gray([y])
    }
}

impl<T, const R: usize, const G: usize, const B: usize> From<Gray<T>> for Rgb<T, R, G, B>
where
    T: Copy,
{
    fn from(gray: Gray<T>) -> Self {
        Rgb([gray[0], gray[0], gray[0]])
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn channels() {
        assert_eq!(Gray::<u8>::CHANNELS, 1);
    }

    #[test]
    fn index_mut() {
        let pix: Gray<u8> = Gray { 0: [1] };

        assert_eq!(pix[0], 1);
    }
}