mod convert;
mod hsla;
mod hwba;
mod rgba;
pub use self::hsla::Hsla;
pub use self::hwba::Hwba;
pub use self::rgba::{RgbFormat, Rgba};
use crate::output::{Format, Formatted};
use std::borrow::Cow;
use std::fmt::{self, Display};
#[derive(Clone, Debug)]
pub enum Color {
Rgba(Rgba),
Hsla(Hsla),
Hwba(Hwba),
}
impl Eq for Color {}
impl PartialEq for Color {
fn eq(&self, other: &Self) -> bool {
self.cmp(other).is_eq()
}
}
impl Ord for Color {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match (self, other) {
(Color::Hsla(a), Color::Hsla(b)) => a.partial_cmp(b).unwrap(),
(Color::Hsla(a), Color::Hwba(b)) => {
a.partial_cmp(&Hsla::from(b)).unwrap()
}
(Color::Hwba(a), Color::Hsla(b)) => {
Hsla::from(a).partial_cmp(b).unwrap()
}
(a, b) => a.to_rgba().cmp(&b.to_rgba()),
}
}
}
impl PartialOrd for Color {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Color {
pub(crate) fn is_rgb(&self) -> bool {
matches!(self, Self::Rgba(_))
}
pub fn to_rgba(&self) -> Cow<Rgba> {
match self {
Self::Rgba(rgba) => Cow::Borrowed(rgba),
Self::Hsla(hsla) => Cow::Owned(Rgba::from(hsla)),
Self::Hwba(hwba) => Cow::Owned(Rgba::from(hwba)),
}
}
pub fn to_hsla(&self) -> Cow<Hsla> {
match self {
Self::Rgba(rgba) => Cow::Owned(Hsla::from(rgba)),
Self::Hsla(ref hsla) => Cow::Borrowed(hsla),
Self::Hwba(hwba) => Cow::Owned(Hsla::from(hwba)),
}
}
pub fn to_hwba(&self) -> Cow<Hwba> {
match self {
Self::Rgba(rgba) => Cow::Owned(Hwba::from(rgba)),
Self::Hsla(hsla) => Cow::Owned(Hwba::from(hsla)),
Self::Hwba(hwba) => Cow::Borrowed(hwba),
}
}
pub fn get_alpha(&self) -> f64 {
match self {
Self::Rgba(rgba) => rgba.alpha(),
Self::Hsla(hsla) => hsla.alpha(),
Self::Hwba(hwba) => hwba.alpha(),
}
}
pub fn set_alpha(&mut self, alpha: f64) {
let alpha = alpha.clamp(0., 1.);
match self {
Self::Rgba(ref mut rgba) => rgba.set_alpha(alpha),
Self::Hsla(ref mut hsla) => hsla.set_alpha(alpha),
Self::Hwba(ref mut hwba) => hwba.set_alpha(alpha),
}
}
pub fn rotate_hue(&self, val: f64) -> Self {
match self {
Self::Rgba(rgba) => {
let hsla = Hsla::from(rgba);
Hsla::new(
hsla.hue() + val,
hsla.sat(),
hsla.lum(),
hsla.alpha(),
hsla.hsla_format,
)
.into()
}
Self::Hsla(hsla) => Hsla::new(
hsla.hue() + val,
hsla.sat(),
hsla.lum(),
hsla.alpha(),
hsla.hsla_format,
)
.into(),
Self::Hwba(hwba) => Hwba::new(
hwba.hue() + val,
hwba.whiteness(),
hwba.blackness(),
hwba.alpha(),
)
.into(),
}
}
pub(crate) fn invert(&self, weight: f64) -> Self {
match self {
Color::Rgba(rgba) => rgba.invert(weight).into(),
Color::Hsla(hsla) => hsla.invert(weight).into(),
Color::Hwba(hwba) => Rgba::from(hwba).invert(weight).into(),
}
}
pub(crate) fn reset_source(&mut self) {
match self {
Self::Rgba(rgba) => rgba.reset_source(),
Self::Hsla(hsla) => hsla.reset_source(),
_ => (),
}
}
pub fn format(&self, format: Format) -> Formatted<Self> {
Formatted {
value: self,
format,
}
}
}
impl From<Rgba> for Color {
fn from(rgba: Rgba) -> Self {
Self::Rgba(rgba)
}
}
impl From<Hsla> for Color {
fn from(hsla: Hsla) -> Self {
Self::Hsla(hsla)
}
}
impl From<Hwba> for Color {
fn from(hwba: Hwba) -> Self {
Self::Hwba(hwba)
}
}
impl Display for Formatted<'_, Color> {
fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
match self.value {
Color::Rgba(rgba) => rgba.format(self.format).fmt(out),
Color::Hsla(hsla) if hsla.hsla_format => {
hsla.format(self.format).fmt(out)
}
Color::Hwba(hwba) => {
Hsla::from(hwba).format(self.format).fmt(out)
}
any => any.to_rgba().format(self.format).fmt(out),
}
}
}