use crate::{css, types::*, Color};
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Rgba {
pub r: f64,
pub g: f64,
pub b: f64,
pub alpha: f64,
}
impl Color for Rgba {
fn hex(&self) -> String {
format!("#{:08X}", u32::from(*self))
}
}
impl Eq for Rgba {}
#[allow(clippy::derive_hash_xor_eq)]
impl std::hash::Hash for Rgba {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.r.to_bits().hash(state);
self.g.to_bits().hash(state);
self.b.to_bits().hash(state);
self.alpha.to_bits().hash(state);
}
}
impl From<[u8; 4]> for Rgba {
fn from(array: [u8; 4]) -> Self {
Self {
r: array[0] as f64 / 255.0,
g: array[1] as f64 / 255.0,
b: array[2] as f64 / 255.0,
alpha: array[3] as f64 / 255.0,
}
}
}
impl From<Rgba> for [u8; 4] {
fn from(color: Rgba) -> Self {
[
(color.r * 255.0).round() as u8,
(color.g * 255.0).round() as u8,
(color.b * 255.0).round() as u8,
(color.alpha * 255.0).round() as u8,
]
}
}
impl From<u32> for Rgba {
fn from(int: u32) -> Self {
let r = (int >> 24) as u8;
let g = (int >> 16) as u8;
let b = (int >> 8) as u8;
let alpha = int as u8;
Self::from([r, g, b, alpha])
}
}
impl From<Rgba> for u32 {
fn from(color: Rgba) -> u32 {
let [r, g, b, alpha]: [u8; 4] = color.into();
((r as u32) << 24) | ((g as u32) << 16) | ((b as u32) << 8) | (alpha as u32)
}
}
impl From<[f64; 4]> for Rgba {
fn from(array: [f64; 4]) -> Self {
Self {
r: array[0],
g: array[1],
b: array[2],
alpha: array[3],
}
}
}
impl From<Rgba> for [f64; 4] {
fn from(color: Rgba) -> Self {
[color.r, color.g, color.b, color.alpha]
}
}
impl From<&str> for Rgba {
fn from(string: &str) -> Self {
let string = string.strip_prefix('#').unwrap_or(string);
const EXPECT_MSG: &str = "invalid hexadecimal string";
let Rgb { r, g, b } = Rgb::from(string);
let alpha = u8::from_str_radix(&string[6..8], 16).expect(EXPECT_MSG);
Self {
r: r as f64 / 255.0,
g: g as f64 / 255.0,
b: b as f64 / 255.0,
alpha: alpha as f64 / 255.0,
}
}
}
impl From<Rgb> for Rgba {
fn from(other: Rgb) -> Self {
Self {
r: other.r,
g: other.g,
b: other.b,
alpha: 1.0,
}
}
}
impl From<Hsv> for Rgba {
fn from(other: Hsv) -> Self {
Self::from(Rgb::from(other))
}
}
impl From<Hsl> for Rgba {
fn from(other: Hsl) -> Self {
Self::from(Rgb::from(other))
}
}
impl From<Hsva> for Rgba {
fn from(other: Hsva) -> Self {
let Rgb { r, g, b } = Rgb::from(other);
Self {
r,
g,
b,
alpha: other.alpha,
}
}
}
impl From<Hsla> for Rgba {
fn from(other: Hsla) -> Self {
let Rgb { r, g, b } = Rgb::from(other);
Self {
r,
g,
b,
alpha: other.alpha,
}
}
}
impl TryFrom<&css::CssColorNotation> for Rgba {
type Error = css::Error;
fn try_from(other: &css::CssColorNotation) -> css::Result<Self> {
match other.format {
css::CssColorType::Rgb => Ok(Self::from(Rgb::try_from(other)?)),
css::CssColorType::Rgba => {
let mut this = Self::from(Rgb::try_from(other)?);
this.alpha = css::css_number_to_float(
other.values.get(3).ok_or(css::Error::InvalidCssParams)?,
);
Ok(this)
}
_ => Err(css::Error::WrongCssFormat),
}
}
}
impl From<Rgba> for css::CssColorNotation {
fn from(other: Rgba) -> Self {
Self {
format: css::CssColorType::Rgba,
values: vec![
css::CssNumber::Float(other.r * 255.0),
css::CssNumber::Float(other.g * 255.0),
css::CssNumber::Float(other.b * 255.0),
css::CssNumber::Percent(other.alpha),
],
}
}
}
#[cfg(feature = "wgpu")]
impl From<wgpu::Color> for Rgba {
fn from(other: wgpu::Color) -> Rgba {
Rgba::from([other.r, other.g, other.b, other.a])
}
}
#[cfg(feature = "wgpu")]
impl From<Rgba> for wgpu::Color {
fn from(other: Rgba) -> wgpu::Color {
wgpu::Color {
r: other.r,
g: other.g,
b: other.b,
a: other.alpha,
}
}
}