1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
//! ## `Tolerance` and `DeltaEq` traits
//!
//! This module deals with comparing two colors by [`DeltaE`] within a certain [`Tolerance`].
//!
//! See also: [`assert_delta_eq`]
//!
//! ### Implementing `Tolerance` and `DeltaEq`
//!
//! ```
//! use deltae::*;
//!
//! struct MyTolerance(f32);
//!
//! impl Tolerance for MyTolerance {
//! fn tolerance(self) -> f32 {
//! self.0
//! }
//! }
//!
//! #[derive(Copy, Clone)]
//! struct MyLab(f32, f32, f32);
//!
//! // Types that implement Into<Lab> also implement the Delta trait
//! impl From<MyLab> for LabValue {
//! fn from(mylab: MyLab) -> LabValue {
//! LabValue {
//! l: mylab.0,
//! a: mylab.1,
//! b: mylab.2,
//! }
//! }
//! }
//!
//! impl<D: Delta + Copy> DeltaEq<D> for MyLab {}
//!
//! let mylab = MyLab(89.73, 1.88, -6.96);
//! let lab = LabValue::new(89.73, 1.88, -6.96).unwrap();
//! let de2000 = mylab.delta(lab, DEMethod::DE2000);
//! assert!(mylab.delta_eq(&lab, DE1976, 0.0));
//! ```
use crate::*;
/// Trait to determine whether two values are within a certain tolerance of [`DeltaE`]. Types that
/// implement Into<[`LabValue`]> implicitly implement [`Delta`]. Types that implement [`Delta`] and
/// [`Copy`] may also implement DeltaEq for other types that also implement [`Delta`] and [`Copy`].
/// ```
/// use deltae::*;
///
/// #[derive(Copy, Clone)]
/// struct MyLab(f32, f32, f32);
///
/// // Types that implement Into<Lab> implicitly implement the Delta trait
/// impl From<MyLab> for LabValue {
/// fn from(mylab: MyLab) -> LabValue {
/// LabValue {
/// l: mylab.0,
/// a: mylab.1,
/// b: mylab.2,
/// }
/// }
/// }
///
/// // Types that implement Delta and Copy may also implement DeltaEq for other types that also
/// // implement Delta and Copy
/// impl<D: Delta + Copy> DeltaEq<D> for MyLab {}
///
/// let mylab = MyLab(89.73, 1.88, -6.96);
/// let lab = LabValue::new(89.73, 1.88, -6.96).unwrap();
/// let de2000 = mylab.delta(lab, DEMethod::DE2000);
/// assert!(mylab.delta_eq(&lab, DE1976, 0.0));
/// ```
pub trait DeltaEq<D: Delta + Copy>: Delta + Copy {
/// Return true if the value is less than or equal to the [`Tolerance`]
fn delta_eq<T: Tolerance>(&self, other: D, method: DEMethod, tolerance: T) -> bool {
self.delta(other, method).value() <= &tolerance.tolerance()
}
}
/// Convenience macro for asserting two values are equivalent within a tolerance
/// ```
/// use deltae::*;
///
/// let lab0 = LabValue::new(50.0, 0.0, 0.0).unwrap();
/// let lab1 = LabValue::new(50.1, 0.1, 0.1).unwrap();
///
/// // Assert that the difference between lab0 and lab1 is less than 1.0 DE2000
/// assert_delta_eq!(lab0, lab1, DE2000, 1.0);
/// ```
#[macro_export]
macro_rules! assert_delta_eq {
($reference:expr, $sample:expr, $method:expr, $tolerance:expr) => {
assert!($reference.delta_eq($sample, $method, $tolerance))
};
($reference:expr, $sample:expr, $method:expr, $tolerance:expr, $($message:tt)*) => {
assert!($reference.delta_eq($sample, $method, $tolerance), $($message)*)
};
}
/// Convenience macro for asserting two values are equivalent within a tolerance
/// ```
/// use deltae::*;
///
/// let lab0 = LabValue::new(50.0, 0.0, 0.0).unwrap();
/// let lab1 = LabValue::new(50.1, 1.0, 1.0).unwrap();
///
/// // Assert that the difference between lab0 and lab1 is greater than 1.0 DE2000
/// assert_delta_ne!(lab0, lab1, DE2000, 1.0);
/// ```
#[macro_export]
macro_rules! assert_delta_ne {
($reference:expr, $sample:expr, $method:expr, $tolerance:expr) => {
assert!(!$reference.delta_eq($sample, $method, $tolerance))
};
($reference:expr, $sample:expr, $method:expr, $tolerance:expr, $($message:tt)*) => {
assert!(!$reference.delta_eq($sample, $method, $tolerance), $($message)*)
};
}
/// Trait to define a tolerance value for the [`DeltaEq`] trait
pub trait Tolerance {
/// Return a tolerance value
fn tolerance(self) -> f32;
}
impl Tolerance for f32 {
fn tolerance(self) -> f32 {
self
}
}
impl Tolerance for f64 {
fn tolerance(self) -> f32 {
self as f32
}
}
impl Tolerance for DeltaE {
fn tolerance(self) -> f32 {
self.value
}
}
macro_rules! impl_delta_eq {
($t:ty) => {
impl<D: Delta + Copy> DeltaEq<D> for $t {}
}
}
impl_delta_eq!(LabValue);
impl_delta_eq!(LchValue);
impl_delta_eq!(XyzValue);