1#[derive(Clone, Debug, Eq, PartialEq)]
2pub struct Colour {
3 pub red: u8,
4 pub green: u8,
5 pub blue: u8,
6}
7
8impl Colour {
9 pub fn from(string: &str) -> Result<Colour, crate::Error> {
10 let values: Vec<&str> = string.trim_matches(',').split(',').collect();
11
12 if values.len() != 3 {
13 return Err(crate::Error::Colour);
14 }
15
16 let red: u8 = values[0].parse().unwrap_or(0);
17 let green: u8 = values[1].parse().unwrap_or(0);
18 let blue: u8 = values[2].parse().unwrap_or(0);
19
20 Ok(Colour { red, green, blue })
21 }
22
23 pub fn from_hex(hex: &str) -> Result<Colour, crate::Error> {
24 let hex = hex.to_lowercase().trim_start_matches('#').to_string();
25 let rgb = data_encoding::HEXLOWER.decode(hex.as_bytes()).unwrap();
26
27 Ok(Colour { red: rgb[0], green: rgb[1], blue: rgb[2], })
28 }
29}
30
31impl ToString for Colour {
32 fn to_string(&self) -> String {
33 format!("{},{},{}", self.red, self.green, self.blue)
34 }
35}
36
37#[cfg(test)]
38mod test {
39 use crate::Colour;
40
41 #[test]
42 fn colour_from_string() {
43 assert_eq!(
44 Colour::from("0,255,0").unwrap(),
45 Colour { red: 0, green: 255, blue: 0 }
46 );
47 }
48
49 #[test]
50 fn colour_to_string() {
51 assert_eq!(Colour { red: 22, green: 33, blue: 44, }.to_string(), "22,33,44".to_string());
52 }
53
54 #[test]
55 fn colour_missing_value() {
56 assert!(Colour::from("0,0").is_err());
57 }
58
59 #[test]
60 fn colour_ambiguous_value() {
61 assert!(Colour::from("0,0,").is_err());
62 }
63
64 #[test]
65 fn colour_extraneous_value() {
66 assert!(Colour::from("0,0,0,0").is_err());
67 }
68
69 #[test]
70 fn colour_from_hex() {
71 let output = Colour::from_hex("#ffff00").unwrap();
72 let expected = Colour { red: 255, green: 255, blue: 0 };
73 assert_eq!(output, expected);
74 }
75
76 #[test]
77 fn colour_from_hex_upper() {
78 let output = Colour::from_hex("#ABCDEF").unwrap();
79 let expected = Colour { red: 171, green: 205, blue: 239 };
80 assert_eq!(output, expected);
81 }
82}