use std::convert::TryFrom;
use super::{space::*, Color, ColorSpace, ParseError};
impl TryFrom<(ColorSpace, &[f64])> for Color {
type Error = ParseError;
fn try_from((space, vals): (ColorSpace, &[f64])) -> Result<Self, Self::Error> {
let required_args = space.num_components();
if vals.len() != required_args {
return Err(ParseError::NumberOfComponents {
expected: required_args,
got: vals.len(),
});
}
match space {
ColorSpace::Rgb => Color::try_from(Rgb::new(vals[0], vals[1], vals[2])),
ColorSpace::Cmy => Color::try_from(Cmy::new(vals[0], vals[1], vals[2])),
ColorSpace::Cmyk => Color::try_from(Cmyk::new(vals[0], vals[1], vals[2], vals[3])),
ColorSpace::Hsv => Color::try_from(Hsv::new(vals[0], vals[1], vals[2])),
ColorSpace::Hsl => Color::try_from(Hsl::new(vals[0], vals[1], vals[2])),
ColorSpace::Lch => Color::try_from(Lch::new(vals[0], vals[1], vals[2])),
ColorSpace::Luv => Color::try_from(Luv::new(vals[0], vals[1], vals[2])),
ColorSpace::Lab => Color::try_from(Lab::new(vals[0], vals[1], vals[2])),
ColorSpace::HunterLab => Color::try_from(HunterLab::new(vals[0], vals[1], vals[2])),
ColorSpace::Xyz => Color::try_from(Xyz::new(vals[0], vals[1], vals[2])),
ColorSpace::Yxy => Color::try_from(Yxy::new(vals[0], vals[1], vals[2])),
ColorSpace::Gray => Color::try_from(Gray::new(vals[0])),
}
}
}
pub(crate) fn color_from_components_unchecked(space: ColorSpace, vals: &[f64]) -> Color {
let required_args = space.num_components();
if vals.len() != required_args {
Err::<(), _>(ParseError::NumberOfComponents {
expected: required_args,
got: vals.len(),
})
.unwrap();
}
match space {
ColorSpace::Rgb => Color::Rgb(Rgb::new(vals[0], vals[1], vals[2])),
ColorSpace::Cmy => Color::Cmy(Cmy::new(vals[0], vals[1], vals[2])),
ColorSpace::Cmyk => Color::Cmyk(Cmyk::new(vals[0], vals[1], vals[2], vals[3])),
ColorSpace::Hsv => Color::Hsv(Hsv::new(vals[0], vals[1], vals[2])),
ColorSpace::Hsl => Color::Hsl(Hsl::new(vals[0], vals[1], vals[2])),
ColorSpace::Lch => Color::Lch(Lch::new(vals[0], vals[1], vals[2])),
ColorSpace::Luv => Color::Luv(Luv::new(vals[0], vals[1], vals[2])),
ColorSpace::Lab => Color::Lab(Lab::new(vals[0], vals[1], vals[2])),
ColorSpace::HunterLab => Color::HunterLab(HunterLab::new(vals[0], vals[1], vals[2])),
ColorSpace::Xyz => Color::Xyz(Xyz::new(vals[0], vals[1], vals[2])),
ColorSpace::Yxy => Color::Yxy(Yxy::new(vals[0], vals[1], vals[2])),
ColorSpace::Gray => Color::Gray(Gray::new(vals[0])),
}
}
macro_rules! try_from_color {
($ty:ident -> $( $component:ident : $min:literal to $max:literal );* $(;)?) => {
impl TryFrom<$ty> for Color {
type Error = ParseError;
fn try_from(value: $ty) -> Result<Self, Self::Error> {
$(
min_max(stringify!($component), $min, $max, value.$component)?;
)*
Ok(Self::$ty(value))
}
}
};
}
try_from_color! { Rgb ->
r: 0.0 to 255.0;
g: 0.0 to 255.0;
b: 0.0 to 255.0;
}
try_from_color! { Cmy ->
c: 0.0 to 1.0;
m: 0.0 to 1.0;
y: 0.0 to 1.0;
}
try_from_color! { Cmyk ->
c: 0.0 to 1.0;
m: 0.0 to 1.0;
y: 0.0 to 1.0;
k: 0.0 to 1.0;
}
try_from_color! { Hsv ->
h: -360.0 to 360.0;
s: 0.0 to 1.0;
v: 0.0 to 1.0;
}
try_from_color! { Hsl ->
h: -360.0 to 360.0;
s: 0.0 to 1.0;
l: 0.0 to 1.0;
}
try_from_color! { Lch ->
l: 0.0 to 100.0;
c: 0.0 to 100.0;
h: -360.0 to 360.0;
}
try_from_color! { Luv ->
l: 0.0 to 100.0;
u: -134.0 to 220.0;
v: -140.0 to 122.0;
}
try_from_color! { Lab ->
l: 0.0 to 100.0;
}
try_from_color! { HunterLab ->
l: 0.0 to 100.0;
}
try_from_color! { Xyz ->
}
try_from_color! { Yxy ->
}
try_from_color! { Gray ->
l: 0.0 to 1.0;
}
fn min_max(component: &'static str, min: f64, max: f64, got: f64) -> Result<(), ParseError> {
if got < min || got > max {
if min == 0.0 && got < min {
Err(ParseError::Negative { component, got })
} else {
Err(ParseError::OutOfRange {
component,
min,
max,
got,
})
}
} else {
Ok(())
}
}
macro_rules! from_color_for {
($t:ty) => {
impl From<Color> for $t {
fn from(c: Color) -> Self {
match c {
Color::Rgb(c) => c.into(),
Color::Cmy(c) => c.into(),
Color::Cmyk(c) => c.into(),
Color::Hsv(c) => c.into(),
Color::Hsl(c) => c.into(),
Color::Lch(c) => c.into(),
Color::Luv(c) => c.into(),
Color::Lab(c) => c.into(),
Color::HunterLab(c) => c.into(),
Color::Xyz(c) => c.into(),
Color::Yxy(c) => c.into(),
Color::Gray(c) => c.into(),
}
}
}
};
}
from_color_for!(Rgb);
from_color_for!(Cmy);
from_color_for!(Cmyk);
from_color_for!(Hsv);
from_color_for!(Hsl);
from_color_for!(Lch);
from_color_for!(Luv);
from_color_for!(Lab);
from_color_for!(HunterLab);
from_color_for!(Xyz);
from_color_for!(Yxy);
from_color_for!(Gray);