logo
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
use super::*;

impl From<(u8, u8, u8)> for Color {
    fn from(c: (u8, u8, u8)) -> Self {
        Self::new(c.0, c.1, c.2, 255)
    }
}

impl From<[u8; 3]> for Color {
    fn from(c: [u8; 3]) -> Self {
        Self::new(c[0], c[1], c[2], 255)
    }
}

impl From<(u8, u8, u8, u8)> for Color {
    fn from(c: (u8, u8, u8, u8)) -> Self {
        Self::new(c.0, c.1, c.2, c.3)
    }
}

impl From<[u8; 4]> for Color {
    fn from(c: [u8; 4]) -> Self {
        Self::new(c[0], c[1], c[2], c[3])
    }
}

impl From<(f32, f32, f32)> for Color {
    fn from(c: (f32, f32, f32)) -> Self {
        Self::new((c.0 * 255.0) as u8, (c.1 * 255.0) as u8, (c.2 * 255.0) as u8, 255)
    }
}

impl From<(f32, f32, f32, f32)> for Color {
    fn from(c: (f32, f32, f32, f32)) -> Self {
        Self::new((c.0 * 255.0) as u8, (c.1 * 255.0) as u8, (c.2 * 255.0) as u8, (c.3 * 255.0) as u8)
    }
}

impl From<Color> for u32 {
    fn from(c: Color) -> Self {
        let (r, g, b, a) = c.view();
        u32::from_le_bytes([r, g, b, a])
    }
}

impl From<u32> for Color {
    fn from(c: u32) -> Self {
        let [r, g, b, a] = c.to_le_bytes();
        Self::new(r, g, b, a)
    }
}

fn hex_digit(c: &u8) -> Result<u8> {
    match c {
        b'0'..=b'9' => Ok(c - b'0'),
        b'A'..=b'F' => Ok(c - b'A' + 10),
        b'a'..=b'f' => Ok(c - b'a' + 10),
        _ => parse_error!("{} does not a valid hex character", c),
    }
}

impl FromStr for Color {
    type Err = GraphicsError;

    fn from_str(s: &str) -> Result<Self> {
        if !s.starts_with("#") {
            return parse_error!("{} does not a valid hex color string", s);
        }
        let this = match &s[1..].as_bytes() {
            [c1, c2] => {
                let c = hex_digit(c1)? * 16 + hex_digit(c2)?;
                Color::new(c, c, c, 255)
            }
            [r, g, b] => Color::new(
                //
                hex_digit(r)? * 17,
                hex_digit(g)? * 17,
                hex_digit(b)? * 17,
                255,
            ),
            [r, g, b, a] => Color::new(
                //
                hex_digit(r)? * 17,
                hex_digit(g)? * 17,
                hex_digit(b)? * 17,
                hex_digit(a)? * 17,
            ),
            [r1, r2, g1, g2, b1, b2] => Color::new(
                hex_digit(r1)? * 16 + hex_digit(r2)?,
                hex_digit(g1)? * 16 + hex_digit(g2)?,
                hex_digit(b1)? * 16 + hex_digit(b2)?,
                255,
            ),
            [r1, r2, g1, g2, b1, b2, a1, a2] => Color::new(
                hex_digit(r1)? * 16 + hex_digit(r2)?,
                hex_digit(g1)? * 16 + hex_digit(g2)?,
                hex_digit(b1)? * 16 + hex_digit(b2)?,
                hex_digit(a1)? * 16 + hex_digit(a2)?,
            ),
            _ => return parse_error!("Hex color string length must be 2, 3, 4, 6, 8."),
        };
        Ok(this)
    }
}