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
#[derive(Clone, Debug, Eq, PartialEq)] pub struct Colour { pub red: u8, pub green: u8, pub blue: u8, } impl Colour { pub fn from(string: &str) -> Result<Colour, crate::Error> { let values: Vec<&str> = string.trim_matches(',').split(',').collect(); if values.len() != 3 { return Err(crate::Error::Colour); } let red: u8 = values[0].parse().unwrap_or(0); let green: u8 = values[1].parse().unwrap_or(0); let blue: u8 = values[2].parse().unwrap_or(0); Ok(Colour { red, green, blue }) } pub fn from_hex(hex: &str) -> Result<Colour, crate::Error> { let hex = hex.to_lowercase().trim_start_matches('#').to_string(); let rgb = data_encoding::HEXLOWER.decode(hex.as_bytes()).unwrap(); Ok(Colour { red: rgb[0], green: rgb[1], blue: rgb[2], }) } } impl ToString for Colour { fn to_string(&self) -> String { format!("{},{},{}", self.red, self.green, self.blue) } } #[cfg(test)] mod test { use crate::Colour; #[test] fn colour_from_string() { assert_eq!( Colour::from("0,255,0").unwrap(), Colour { red: 0, green: 255, blue: 0 } ); } #[test] fn colour_to_string() { assert_eq!(Colour { red: 22, green: 33, blue: 44, }.to_string(), "22,33,44".to_string()); } #[test] fn colour_missing_value() { assert!(Colour::from("0,0").is_err()); } #[test] fn colour_ambiguous_value() { assert!(Colour::from("0,0,").is_err()); } #[test] fn colour_extraneous_value() { assert!(Colour::from("0,0,0,0").is_err()); } #[test] fn colour_from_hex() { let output = Colour::from_hex("#ffff00").unwrap(); let expected = Colour { red: 255, green: 255, blue: 0 }; assert_eq!(output, expected); } #[test] fn colour_from_hex_upper() { let output = Colour::from_hex("#ABCDEF").unwrap(); let expected = Colour { red: 171, green: 205, blue: 239 }; assert_eq!(output, expected); } }