use crate::dot::DotString;
use std::borrow::Cow;
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Color<'a> {
RGB {
red: u8,
green: u8,
blue: u8,
},
RGBA {
red: u8,
green: u8,
blue: u8,
alpha: u8,
},
HSV {
hue: f32,
saturation: f32,
value: f32,
},
Named(&'a str),
}
impl<'a> DotString<'a> for Color<'a> {
fn dot_string(&self) -> Cow<'a, str> {
match self {
Color::RGB { red, green, blue } => {
format!("#{:02x?}{:02x?}{:02x?}", red, green, blue).into()
}
Color::RGBA {
red,
green,
blue,
alpha,
} => {
format!("#{:02x?}{:02x?}{:02x?}{:02x?}", red, green, blue, alpha).into()
}
Color::HSV {
hue,
saturation,
value,
} => format!("{} {} {}", hue, saturation, value).into(),
Color::Named(color) => (*color).into(),
}
}
}
pub struct WeightedColor<'a> {
pub color: Color<'a>,
pub weight: Option<f32>,
}
impl<'a> DotString<'a> for WeightedColor<'a> {
fn dot_string(&self) -> Cow<'a, str> {
let mut dot_string = self.color.dot_string().to_string();
if let Some(weight) = &self.weight {
dot_string.push_str(format!(";{}", weight).as_str());
}
dot_string.into()
}
}
pub struct ColorList<'a> {
pub colors: Vec<WeightedColor<'a>>,
}
impl<'a> DotString<'a> for ColorList<'a> {
fn dot_string(&self) -> Cow<'a, str> {
let mut dot_string = String::new();
let mut iter = self.colors.iter();
let first = iter.next();
if first.is_none() {
return dot_string.into();
}
dot_string.push_str(&first.unwrap().dot_string());
for weighted_color in iter {
dot_string.push_str(":");
dot_string.push_str(&weighted_color.dot_string())
}
dot_string.into()
}
}
pub trait IntoWeightedColor<'a> {
fn into_weighted_color(self) -> WeightedColor<'a>;
}
impl<'a> IntoWeightedColor<'a> for &(Color<'a>, Option<f32>) {
fn into_weighted_color(self) -> WeightedColor<'a> {
let (s, t) = *self;
WeightedColor {
color: s,
weight: t,
}
}
}
#[cfg(test)]
mod test {
use crate::attributes::{Color, ColorList, WeightedColor};
use crate::DotString;
#[test]
fn colorlist_dot_string() {
let yellow = WeightedColor {
color: Color::Named("yellow"),
weight: Some(0.3),
};
let blue = WeightedColor {
color: Color::Named("blue"),
weight: None,
};
let color_list = ColorList {
colors: vec![yellow, blue],
};
let dot_string = color_list.dot_string();
assert_eq!("yellow;0.3:blue", dot_string);
}
#[test]
fn color_rbg_dot_string() {
let color = Color::RGB {
red: 160,
green: 82,
blue: 45,
};
assert_eq!("#a0522d", color.dot_string());
}
#[test]
fn color_rbga_dot_string() {
let color = Color::RGBA {
red: 160,
green: 82,
blue: 45,
alpha: 10,
};
assert_eq!("#a0522d0a", color.dot_string());
}
#[test]
fn color_hsv_dot_string() {
let color = Color::HSV {
hue: 0.051,
saturation: 0.718,
value: 0.627,
};
assert_eq!("0.051 0.718 0.627", color.dot_string());
}
}