use hex::FromHexError;
use std::{fmt::Display, io::Error, sync::LazyLock};
#[derive(Clone)]
pub struct Color {
r: u8,
g: u8,
b: u8,
hexadecimal: String,
}
impl Default for Color{
fn default() -> Self {
Color::rgb(0, 0, 0)
}
}
impl Color {
pub fn rgb(r: u8, g: u8, b: u8) -> Self {
Color {
r,
g,
b,
hexadecimal: format!("#{r:02x}{g:02x}{b:02x}"),
}
}
pub fn from_color_string(string: &str) -> Result<Self, Error> {
match string.to_lowercase().as_str() {
"red" => Ok(Color::rgb(255, 0, 0)),
"green" => Ok(Color::rgb(0, 255, 0)),
"blue" => Ok(Color::rgb(0, 0, 255)),
"white" => Ok(Color::rgb(255, 255, 255)),
"black" => Ok(Color::rgb(0, 0, 0)),
"yellow" => Ok(Color::rgb(255, 255, 0)),
"purple" => Ok(Color::rgb(255, 0, 255)),
"cyan" => Ok(Color::rgb(0, 255, 255)),
_ => Err(Error::new(
std::io::ErrorKind::InvalidInput,
format!("'{string}' is not a recognized color"),
)),
}
}
pub fn from_rgb_string(string: &str) -> Result<Self, Error> {
let mut decode: Vec<u8> = Vec::new();
for color in string
.split(|c: char| !c.is_numeric())
.filter(|s| !s.is_empty())
{
let mut num: u16 = 0;
for character in color.chars() {
num *= 10;
num += character as u16 - '0' as u16;
if num > 255 {
return Err(Error::new(
std::io::ErrorKind::InvalidInput,
format!("Value over 255 in rgb : {num} at index {}", decode.len()),
));
}
}
decode.push(num as u8);
}
if decode.len() < 3 {
return Err(Error::new(
std::io::ErrorKind::InvalidInput,
"less than 3 arguments for color definition",
));
}
Ok(Color::rgb(decode[0], decode[1], decode[2]))
}
pub fn from_hexadecimal(hexadecimal_color: &str) -> Result<Self, FromHexError> {
let mut color: String = hexadecimal_color.to_string();
if hexadecimal_color.starts_with("#") {
color = hexadecimal_color.chars().filter(|c| *c != '#').collect();
}
let decode = hex::decode(&color)?;
Ok(Color::rgb(decode[0], decode[1], decode[2]))
}
pub fn red(&self) -> u8 {
self.r
}
pub fn green(&self) -> u8 {
self.g
}
pub fn blue(&self) -> u8 {
self.b
}
pub fn hexadecimal_value(&self) -> String {
self.hexadecimal.clone()
}
pub fn inverted(&self)->Self {
Color::rgb(255-self.r, 255-self.g, 255-self.b)
}
}
impl Display for Color {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"r: {}, g: {}, b: {}, hex: {}",
self.red(),
self.green(),
self.blue(),
self.hexadecimal_value()
)
}
}