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
use core::fmt;
use crate::IsWithinBounds;
use super::FromColorUnclamped;
/// The error type for a color conversion that converted a color into a color
/// with invalid values.
#[derive(Debug)]
pub struct OutOfBounds<T> {
color: T,
}
impl<T> OutOfBounds<T> {
/// Create a new error wrapping a color
#[inline]
fn new(color: T) -> Self {
OutOfBounds { color }
}
/// Consume this error and return the wrapped color
#[inline]
pub fn color(self) -> T {
self.color
}
}
#[cfg(feature = "std")]
impl<T: fmt::Debug> std::error::Error for OutOfBounds<T> {
fn description(&self) -> &str {
"color conversion is out of bounds"
}
}
impl<T> fmt::Display for OutOfBounds<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "color conversion is out of bounds")
}
}
/// A trait for fallible conversion of one color from another.
///
/// `U: TryFromColor<T>` is implemented for every type `U: FromColorUnclamped<T> + Clamp`.
///
/// See [`FromColor`](crate::convert::FromColor) for a lossy version of this trait.
/// See [`FromColorUnclamped`](crate::convert::FromColorUnclamped) for a lossless version.
///
/// See the [`convert`](crate::convert) module for how to implement `FromColorUnclamped` for
/// custom colors.
pub trait TryFromColor<T>: Sized {
/// Convert from T, returning ok if the color is inside of its defined
/// range, otherwise an `OutOfBounds` error is returned which contains
/// the unclamped color.
///
///```
/// use palette::convert::TryFromColor;
/// use palette::{Hsl, Srgb};
///
/// let rgb = match Srgb::try_from_color(Hsl::new(150.0, 1.0, 1.1)) {
/// Ok(color) => color,
/// Err(err) => {
/// println!("Color is out of bounds");
/// err.color()
/// }
/// };
/// ```
fn try_from_color(t: T) -> Result<Self, OutOfBounds<Self>>;
}
impl<T, U> TryFromColor<T> for U
where
U: FromColorUnclamped<T> + IsWithinBounds<Mask = bool>,
{
#[inline]
fn try_from_color(t: T) -> Result<Self, OutOfBounds<Self>> {
let this = Self::from_color_unclamped(t);
if this.is_within_bounds() {
Ok(this)
} else {
Err(OutOfBounds::new(this))
}
}
}
/// A trait for fallible conversion of a color into another.
///
/// `U: TryIntoColor<T>` is implemented for every type `T: TryFromColor<U>`.
///
/// See [`TryFromColor`](crate::convert::TryFromColor) for more details.
pub trait TryIntoColor<T>: Sized {
/// Convert into T, returning ok if the color is inside of its defined
/// range, otherwise an `OutOfBounds` error is returned which contains
/// the unclamped color.
///
///```
/// use palette::convert::TryIntoColor;
/// use palette::{Hsl, Srgb};
///
/// let rgb: Srgb = match Hsl::new(150.0, 1.0, 1.1).try_into_color() {
/// Ok(color) => color,
/// Err(err) => {
/// println!("Color is out of bounds");
/// err.color()
/// }
/// };
/// ```
fn try_into_color(self) -> Result<T, OutOfBounds<T>>;
}
impl<T, U> TryIntoColor<U> for T
where
U: TryFromColor<T>,
{
#[inline]
fn try_into_color(self) -> Result<U, OutOfBounds<U>> {
U::try_from_color(self)
}
}