use num_traits::Float;
use std::fmt::{Display, Formatter, Result as FmtResult};
use crate::{
config::PRINT_BLOCK,
error::{
ColourParsingError, Result, component_to_u8, format_terminal_color, parse_hex_component, safe_constant,
u8_to_component, validate_interpolation_factor, validate_unit_component,
},
spaces::{GreyAlpha, Hsl, HslAlpha, Hsv, HsvAlpha, Lab, LabAlpha, Rgb, RgbAlpha, Srgb, SrgbAlpha, Xyz, XyzAlpha},
traits::{Colour, Convert},
};
#[derive(Debug, Clone, Copy)]
pub struct Grey<T: Float + Send + Sync> {
grey: T,
}
impl<T: Float + Send + Sync> Grey<T> {
pub fn new(grey: T) -> Result<Self> {
validate_unit_component(grey, "grey")?;
Ok(Self { grey })
}
pub const fn grey(&self) -> T {
self.grey
}
pub fn set_grey(&mut self, grey: T) -> Result<()> {
validate_unit_component(grey, "grey")?;
self.grey = grey;
Ok(())
}
}
impl<T: Float + Send + Sync> Colour<T, 1> for Grey<T> {
fn from_hex(hex: &str) -> Result<Self> {
let hex = hex.trim();
let components = hex
.strip_prefix('#')
.ok_or_else(|| ColourParsingError::MissingHexPrefix(hex.to_string()))?;
let grey = match components.len() {
1 => {
let value = parse_hex_component(components, "grey")?;
let expanded = value * 17;
u8_to_component(expanded, safe_constant(255.0)?)?
}
2 => {
let value = parse_hex_component(components, "grey")?;
u8_to_component(value, safe_constant(255.0)?)?
}
_ => {
return Err(ColourParsingError::InvalidHexLength {
actual: components.len(),
}
.into());
}
};
Self::new(grey)
}
fn to_hex(&self) -> Result<String> {
let scale = safe_constant(255.0)?;
let grey = component_to_u8(self.grey, "grey", scale)?;
Ok(format!("#{grey:02X}"))
}
fn from_bytes(bytes: [u8; 1]) -> Result<Self> {
let scale = safe_constant(255.0)?;
let value = u8_to_component(bytes[0], scale)?;
Self::new(value)
}
fn to_bytes(self) -> Result<[u8; 1]> {
let scale = safe_constant(255.0)?;
let value = component_to_u8(self.grey, "grey", scale)?;
Ok([value])
}
fn lerp(lhs: &Self, rhs: &Self, t: T) -> Result<Self> {
validate_interpolation_factor(t)?;
Self::new(lhs.grey() * (T::one() - t) + rhs.grey() * t)
}
}
impl<T: Float + Send + Sync> Convert<T> for Grey<T> {
fn to_grey(&self) -> Result<Self> {
Ok(*self)
}
fn to_grey_alpha(&self) -> Result<GreyAlpha<T>> {
GreyAlpha::new(self.grey, T::one())
}
fn to_hsl(&self) -> Result<Hsl<T>> {
Hsl::new(T::zero(), T::zero(), self.grey)
}
fn to_hsl_alpha(&self) -> Result<HslAlpha<T>> {
HslAlpha::new(T::zero(), T::zero(), self.grey, T::one())
}
fn to_hsv(&self) -> Result<Hsv<T>> {
Hsv::new(T::zero(), T::zero(), self.grey)
}
fn to_hsv_alpha(&self) -> Result<HsvAlpha<T>> {
HsvAlpha::new(T::zero(), T::zero(), self.grey, T::one())
}
fn to_lab(&self) -> Result<Lab<T>> {
self.to_xyz()?.to_lab()
}
fn to_lab_alpha(&self) -> Result<LabAlpha<T>> {
let lab = self.to_lab()?;
LabAlpha::new(lab.lightness(), lab.a_star(), lab.b_star(), T::one())
}
fn to_rgb(&self) -> Result<Rgb<T>> {
Rgb::new(self.grey, self.grey, self.grey)
}
fn to_rgb_alpha(&self) -> Result<RgbAlpha<T>> {
RgbAlpha::new(self.grey, self.grey, self.grey, T::one())
}
fn to_srgb(&self) -> Result<Srgb<T>> {
let sg = Srgb::gamma_encode(self.grey)?;
Srgb::new(sg, sg, sg)
}
fn to_srgb_alpha(&self) -> Result<SrgbAlpha<T>> {
let sg = Srgb::gamma_encode(self.grey)?;
SrgbAlpha::new(sg, sg, sg, T::one())
}
fn to_xyz(&self) -> Result<Xyz<T>> {
let white = Xyz::<T>::d65_reference_white()?;
let x = white.x() * self.grey();
let y = self.grey(); let z = white.z() * self.grey();
Xyz::new(x, y, z)
}
fn to_xyz_alpha(&self) -> Result<XyzAlpha<T>> {
let xyz = self.to_xyz()?;
XyzAlpha::new(xyz.x(), xyz.y(), xyz.z(), T::one())
}
}
impl<T: Float + Send + Sync> Display for Grey<T> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> FmtResult {
let color_string = format_terminal_color(self.grey, self.grey, self.grey, PRINT_BLOCK)?;
write!(fmt, "{color_string}")
}
}