Something went wrong. Try again.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601use std::{ cmp::Ordering, fmt::{Display, Formatter, Result as FmtResult}, ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},};
/// A numeric component value used throughout the library.////// Wraps an `f64` and provides arithmetic operations that accept any numeric type/// via `Into<Component>` conversions. Used internally as the building block for/// color space coordinates, chromaticity values, and matrix elements.#[derive(Clone, Copy, Debug)]pub struct Component(pub(crate) f64);
impl Component { /// Creates a new component from any value convertible to `f64`. pub fn new(value: impl Into<f64>) -> Self { Self(value.into()) }
/// Creates a new component in a const context. pub const fn new_const(value: f64) -> Self { Self(value) }
/// Returns this component clamped to the given range. pub fn clamp(&self, minimum: impl Into<Self>, maximum: impl Into<Self>) -> Self { Self(self.0.clamp(minimum.into().0, maximum.into().0)) }
/// Linearly interpolates between `self` and `other` at parameter `t`. /// /// When `t` is 0.0 the result is `self`, when 1.0 the result is `other`. /// Values outside 0.0–1.0 extrapolate beyond the endpoints. pub fn lerp(self, other: impl Into<Self>, t: impl Into<Self>) -> Self { let other = other.into(); let t = t.into(); Self(self.0 + (other.0 - self.0) * t.0) }}
impl<T> Add<T> for Componentwhere T: Into<Self>,{ type Output = Self;
fn add(self, rhs: T) -> Self { Self(self.0 + rhs.into().0) }}
impl<T> AddAssign<T> for Componentwhere T: Into<Component>,{ fn add_assign(&mut self, rhs: T) { self.0 += rhs.into().0 }}
impl<T> Div<T> for Componentwhere T: Into<Self>,{ type Output = Self;
fn div(self, rhs: T) -> Self { Self(self.0 / rhs.into().0) }}
impl<T> DivAssign<T> for Componentwhere T: Into<Self>,{ fn div_assign(&mut self, rhs: T) { self.0 /= rhs.into().0 }}
#[cfg(feature = "serde")]impl<'de> serde::Deserialize<'de> for Component { fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { f64::deserialize(deserializer).map(Self) }}
impl Display for Component { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { write!(f, "{:.precision$}", self.0, precision = f.precision().unwrap_or(4)) }}
impl From<f32> for Component { fn from(value: f32) -> Self { Self(value as f64) }}
impl From<f64> for Component { fn from(value: f64) -> Self { Self(value) }}
impl From<i8> for Component { fn from(value: i8) -> Self { Self(value as f64) }}
impl From<i16> for Component { fn from(value: i16) -> Self { Self(value as f64) }}
impl From<i32> for Component { fn from(value: i32) -> Self { Self(value as f64) }}
impl From<i64> for Component { fn from(value: i64) -> Self { Self(value as f64) }}
impl From<i128> for Component { fn from(value: i128) -> Self { Self(value as f64) }}
impl From<isize> for Component { fn from(value: isize) -> Self { Self(value as f64) }}
impl From<u8> for Component { fn from(value: u8) -> Self { Self(value as f64) }}
impl From<u16> for Component { fn from(value: u16) -> Self { Self(value as f64) }}
impl From<u32> for Component { fn from(value: u32) -> Self { Self(value as f64) }}
impl From<u64> for Component { fn from(value: u64) -> Self { Self(value as f64) }}
impl From<u128> for Component { fn from(value: u128) -> Self { Self(value as f64) }}
impl From<usize> for Component { fn from(value: usize) -> Self { Self(value as f64) }}
impl<T> Mul<T> for Componentwhere T: Into<Self>,{ type Output = Self;
fn mul(self, rhs: T) -> Self { Self(self.0 * rhs.into().0) }}
impl<T> MulAssign<T> for Componentwhere T: Into<Self>,{ fn mul_assign(&mut self, rhs: T) { self.0 *= rhs.into().0; }}
impl Neg for Component { type Output = Self;
fn neg(self) -> Self { Self(-self.0) }}
impl<T> PartialEq<T> for Componentwhere T: Into<Self> + Copy,{ fn eq(&self, other: &T) -> bool { self.0 == (*other).into().0 }}
impl<T> PartialOrd<T> for Componentwhere T: Into<Self> + Copy,{ fn partial_cmp(&self, other: &T) -> Option<Ordering> { self.0.partial_cmp(&(*other).into().0) }}
#[cfg(feature = "serde")]impl serde::Serialize for Component { fn serialize<Ser: serde::Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> { self.0.serialize(serializer) }}
impl<T> Sub<T> for Componentwhere T: Into<Self>,{ type Output = Self;
fn sub(self, rhs: T) -> Self { Self(self.0 - rhs.into().0) }}
impl<T> SubAssign<T> for Componentwhere T: Into<Self>,{ fn sub_assign(&mut self, rhs: T) { self.0 -= rhs.into().0; }}/// Returns the default alpha value (1.0) for serde deserialization.#[cfg(feature = "serde")]pub(crate) fn default_alpha() -> Component { Component(1.0)}
#[cfg(test)]mod test { use super::*;
mod add { use pretty_assertions::assert_eq;
use super::*;
#[test] fn it_adds_f64() { let c = Component::new(1.0); let result = c + 0.5;
assert_eq!(result, 1.5); }
#[test] fn it_adds_integer() { let c = Component::new(1.0); let result = c + 2;
assert_eq!(result, 3.0); }
#[test] fn it_adds_component() { let a = Component::new(1.0); let b = Component::new(2.0);
assert_eq!(a + b, 3.0); } }
mod add_assign { use pretty_assertions::assert_eq;
use super::*;
#[test] fn it_adds_and_assigns() { let mut c = Component::new(1.0); c += 0.5;
assert_eq!(c, 1.5); } }
mod clamp { use pretty_assertions::assert_eq;
use super::*;
#[test] fn it_clamps_to_minimum() { let c = Component::new(-0.5);
assert_eq!(c.clamp(0.0, 1.0), 0.0); }
#[test] fn it_clamps_to_maximum() { let c = Component::new(1.5);
assert_eq!(c.clamp(0.0, 1.0), 1.0); }
#[test] fn it_returns_value_when_in_range() { let c = Component::new(0.5);
assert_eq!(c.clamp(0.0, 1.0), 0.5); }
#[test] fn it_accepts_integer_bounds() { let c = Component::new(150.0);
assert_eq!(c.clamp(0, 100), 100.0); } }
mod lerp { use pretty_assertions::assert_eq;
use super::*;
#[test] fn it_returns_start_at_zero() { let c = Component::new(3.0);
assert_eq!(c.lerp(7.0, 0.0), 3.0); }
#[test] fn it_returns_end_at_one() { let c = Component::new(3.0);
assert_eq!(c.lerp(7.0, 1.0), 7.0); }
#[test] fn it_returns_midpoint_at_half() { let c = Component::new(0.0);
assert_eq!(c.lerp(10.0, 0.5), 5.0); }
#[test] fn it_extrapolates_beyond_one() { let c = Component::new(0.0);
assert_eq!(c.lerp(10.0, 1.5), 15.0); }
#[test] fn it_extrapolates_below_zero() { let c = Component::new(0.0);
assert_eq!(c.lerp(10.0, -0.5), -5.0); }
#[test] fn it_accepts_component_arguments() { let a = Component::new(0.0); let b = Component::new(10.0); let t = Component::new(0.25);
assert_eq!(a.lerp(b, t), 2.5); } }
mod display { use pretty_assertions::assert_eq;
use super::*;
#[test] fn it_displays_with_default_precision() { let c = Component::new(1.23456789);
assert_eq!(format!("{}", c), "1.2346"); }
#[test] fn it_displays_with_custom_precision() { let c = Component::new(1.23456789);
assert_eq!(format!("{:.2}", c), "1.23"); assert_eq!(format!("{:.6}", c), "1.234568"); } }
mod div { use pretty_assertions::assert_eq;
use super::*;
#[test] fn it_divides_by_f64() { let c = Component::new(6.0); let result = c / 2.0;
assert_eq!(result, 3.0); }
#[test] fn it_divides_by_integer() { let c = Component::new(6.0); let result = c / 3;
assert_eq!(result, 2.0); } }
mod div_assign { use pretty_assertions::assert_eq;
use super::*;
#[test] fn it_divides_and_assigns() { let mut c = Component::new(6.0); c /= 2.0;
assert_eq!(c, 3.0); } }
mod mul { use pretty_assertions::assert_eq;
use super::*;
#[test] fn it_multiplies_by_f64() { let c = Component::new(2.0); let result = c * 3.0;
assert_eq!(result, 6.0); }
#[test] fn it_multiplies_by_integer() { let c = Component::new(2.0); let result = c * 3;
assert_eq!(result, 6.0); } }
mod mul_assign { use pretty_assertions::assert_eq;
use super::*;
#[test] fn it_multiplies_and_assigns() { let mut c = Component::new(2.0); c *= 3.0;
assert_eq!(c, 6.0); } }
mod neg { use pretty_assertions::assert_eq;
use super::*;
#[test] fn it_negates_positive() { let c = Component::new(1.0);
assert_eq!(-c, -1.0); }
#[test] fn it_negates_negative() { let c = Component::new(-1.0);
assert_eq!(-c, 1.0); } }
mod partial_eq { use pretty_assertions::{assert_eq, assert_ne};
use super::*;
#[test] fn it_compares_with_f64() { let c = Component::new(1.0);
assert_eq!(c, 1.0); assert_ne!(c, 2.0); }
#[test] fn it_compares_with_integer() { let c = Component::new(1.0);
assert_eq!(c, 1); assert_ne!(c, 2); }
#[test] fn it_compares_with_component() { let a = Component::new(1.0); let b = Component::new(1.0); let c = Component::new(2.0);
assert_eq!(a, b); assert_ne!(a, c); } }
mod partial_ord { use super::*;
#[test] fn it_orders_with_f64() { let c = Component::new(1.0);
assert!(c < 2.0); assert!(c > 0.0); assert!(c <= 1.0); assert!(c >= 1.0); }
#[test] fn it_orders_with_integer() { let c = Component::new(1.0);
assert!(c < 2); assert!(c > 0); }
#[test] fn it_orders_with_component() { let a = Component::new(1.0); let b = Component::new(2.0);
assert!(a < b); assert!(b > a); } }
mod sub { use pretty_assertions::assert_eq;
use super::*;
#[test] fn it_subtracts_f64() { let c = Component::new(3.0); let result = c - 1.0;
assert_eq!(result, 2.0); }
#[test] fn it_subtracts_integer() { let c = Component::new(3.0); let result = c - 1;
assert_eq!(result, 2.0); } }
mod sub_assign { use pretty_assertions::assert_eq;
use super::*;
#[test] fn it_subtracts_and_assigns() { let mut c = Component::new(3.0); c -= 1.0;
assert_eq!(c, 2.0); } }}