use crate::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Rgb(u32);
impl Rgb {
#[must_use]
pub const fn from_hex(value: u32) -> Self {
Self(value & 0x00FF_FFFF)
}
pub fn parse_hex(input: &str) -> Result<Self, Error> {
let Some(hex) = input.strip_prefix('#') else {
return Err(Error::InvalidHexColor {
input: input.to_owned(),
});
};
if hex.len() != 6 || !hex.bytes().all(|byte| byte.is_ascii_hexdigit()) {
return Err(Error::InvalidHexColor {
input: input.to_owned(),
});
}
u32::from_str_radix(hex, 16)
.map(Self::from_hex)
.map_err(|_| Error::InvalidHexColor {
input: input.to_owned(),
})
}
#[must_use]
pub const fn r(self) -> u8 {
self.0.to_be_bytes()[1]
}
#[must_use]
pub const fn g(self) -> u8 {
self.0.to_be_bytes()[2]
}
#[must_use]
pub const fn b(self) -> u8 {
self.0.to_be_bytes()[3]
}
#[must_use]
pub const fn to_u32(self) -> u32 {
self.0
}
#[must_use]
pub fn to_hex_string(self) -> String {
format!("#{:06X}", self.0)
}
#[must_use]
pub const fn with_alpha_u8(self, alpha: u8) -> Rgba {
Rgba::from_rgb_alpha(self, alpha)
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
pub fn with_alpha(self, alpha: f32) -> Result<Rgba, Error> {
if !alpha.is_finite() || !(0.0..=1.0).contains(&alpha) {
return Err(Error::InvalidAlpha { alpha });
}
Ok(self.with_alpha_u8((alpha * 255.0).round() as u8))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Rgba(u32);
impl Rgba {
#[must_use]
pub const fn from_hex(value: u32) -> Self {
Self(value)
}
#[must_use]
pub const fn from_rgb_alpha(rgb: Rgb, alpha: u8) -> Self {
Self((rgb.to_u32() << 8) | alpha as u32)
}
pub fn parse_hex(input: &str) -> Result<Self, Error> {
let Some(hex) = input.strip_prefix('#') else {
return Err(Error::InvalidHexColor {
input: input.to_owned(),
});
};
if hex.len() != 8 || !hex.bytes().all(|byte| byte.is_ascii_hexdigit()) {
return Err(Error::InvalidHexColor {
input: input.to_owned(),
});
}
u32::from_str_radix(hex, 16)
.map(Self::from_hex)
.map_err(|_| Error::InvalidHexColor {
input: input.to_owned(),
})
}
#[must_use]
pub const fn r(self) -> u8 {
self.0.to_be_bytes()[0]
}
#[must_use]
pub const fn g(self) -> u8 {
self.0.to_be_bytes()[1]
}
#[must_use]
pub const fn b(self) -> u8 {
self.0.to_be_bytes()[2]
}
#[must_use]
pub const fn a(self) -> u8 {
self.0.to_be_bytes()[3]
}
#[must_use]
pub const fn to_u32(self) -> u32 {
self.0
}
#[must_use]
pub fn to_hex_string(self) -> String {
format!("#{:08X}", self.0)
}
}