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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use crate::utils::conversion;
use std::str::FromStr;

#[derive(Debug, PartialEq)]
pub enum Color {
    Rgb(u8, u8, u8),
    Hsv(u8, u8, u8),
    Hex(String),
    Hsl(u8, u8, u8),
    Rgba(u8, u8, u8, f64),
    Lab(f64, f64, f64),
    Unknown,
}

impl From<&str> for Color {
    fn from(str: &str) -> Self {
        match str {
            str if str.starts_with("#") => Self::Hex(str.to_string()),
            str if str.starts_with("rgba") => Color::parse_rgba(str),
            str if str.starts_with("rgb") => Color::parse_rgb(str),
            str if str.starts_with("hsv") => todo!(),
            str if str.starts_with("hsl") => todo!(),
            _ => Self::Unknown,
        }
    }
}

impl IntoIterator for Color {
    type Item = f64;
    type IntoIter = std::vec::IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        match self {
            Self::Rgb(r, g, b) => vec![r as f64, g as f64, b as f64].into_iter(),
            Self::Hsv(_, _, _) => todo!(),
            Self::Hex(_) => todo!(),
            Self::Hsl(_, _, _) => todo!(),
            Self::Rgba(r, g, b, a) => vec![r as f64, g as f64, b as f64, a].into_iter(),
            Self::Lab(l, a, b) => vec![l, a, b].into_iter(),
            Self::Unknown => todo!(),
        }
    }
}

impl Color {
    pub fn get_mode(self, mode: &str) -> Self {
        match mode {
            "hex" => match self {
                Self::Hex(..) => self,
                Self::Rgb(..) => conversion::hex::rgb2hex(self),
                _ => todo!(),
            },
            "rgb" => match self {
                Self::Rgb(..) => self,
                Self::Hex(..) => conversion::hex::hex2rgb(self),
                Self::Lab(..) => conversion::lab::lab2rgb(self),
                _ => todo!(),
            },
            "lab" => match self {
                Self::Lab(..) => self,
                Self::Rgb(..) => conversion::lab::rgb2lab(self),
                _ => todo!(),
            },
            _ => todo!(),
        }
    }
}

impl Color {
    fn parse_rgb(str: &str) -> Self {
        let v_u8: Vec<u8> = str
            .trim()
            .replace(" ", "")
            .replace("rgb(", "")
            .replace(")", "")
            .split(",")
            .map(|s| s.parse().unwrap())
            .collect();
        Self::Rgb(v_u8[0], v_u8[1], v_u8[2])
    }
    fn parse_rgba(str: &str) -> Self {
        let v: Vec<String> = str
            .trim()
            .replace(" ", "")
            .replace("rgba(", "")
            .replace(")", "")
            .split(",")
            .map(|s| s.to_string())
            .collect();
        let (r, g, b) = (
            v[0].parse().unwrap(),
            v[1].parse().unwrap(),
            v[2].parse().unwrap(),
        );
        let alpha = f64::from_str(v[3].as_str()).unwrap();
        Self::Rgba(r, g, b, alpha)
    }
}

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

    #[test]
    fn test_color_from_str() {
        let hex_color = Color::from("#abcdef");
        assert_eq!(hex_color, Color::Hex(String::from("#abcdef")));

        let rgb_color = Color::from("rgb(255, 255, 255)");
        assert_eq!(rgb_color, Color::Rgb(255, 255, 255));

        let rgba_color = Color::from("rgba(255, 255, 255, 0.6)");
        assert_eq!(rgba_color, Color::Rgba(255, 255, 255, 0.6));
    }
}