palette/convert/
try_from_into_color.rs

1use core::fmt;
2
3use crate::IsWithinBounds;
4
5use super::FromColorUnclamped;
6
7/// The error type for a color conversion that converted a color into a color
8/// with invalid values.
9#[derive(Debug)]
10pub struct OutOfBounds<T> {
11    color: T,
12}
13
14impl<T> OutOfBounds<T> {
15    /// Create a new error wrapping a color
16    #[inline]
17    fn new(color: T) -> Self {
18        OutOfBounds { color }
19    }
20
21    /// Consume this error and return the wrapped color
22    #[inline]
23    pub fn color(self) -> T {
24        self.color
25    }
26}
27
28#[cfg(feature = "std")]
29impl<T: fmt::Debug> std::error::Error for OutOfBounds<T> {
30    fn description(&self) -> &str {
31        "color conversion is out of bounds"
32    }
33}
34
35impl<T> fmt::Display for OutOfBounds<T> {
36    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
37        write!(fmt, "color conversion is out of bounds")
38    }
39}
40
41/// A trait for fallible conversion of one color from another.
42///
43/// `U: TryFromColor<T>` is implemented for every type `U: FromColorUnclamped<T> + Clamp`.
44///
45/// See [`FromColor`](crate::convert::FromColor) for a lossy version of this trait.
46/// See [`FromColorUnclamped`](crate::convert::FromColorUnclamped) for a lossless version.
47///
48/// See the [`convert`](crate::convert) module for how to implement `FromColorUnclamped` for
49/// custom colors.
50pub trait TryFromColor<T>: Sized {
51    /// Convert from T, returning ok if the color is inside of its defined
52    /// range, otherwise an `OutOfBounds` error is returned which contains
53    /// the unclamped color.
54    ///
55    ///```
56    /// use palette::convert::TryFromColor;
57    /// use palette::{Hsl, Srgb};
58    ///
59    /// let rgb = match Srgb::try_from_color(Hsl::new(150.0, 1.0, 1.1)) {
60    ///     Ok(color) => color,
61    ///     Err(err) => {
62    ///         println!("Color is out of bounds");
63    ///         err.color()
64    ///     }
65    /// };
66    /// ```
67    fn try_from_color(t: T) -> Result<Self, OutOfBounds<Self>>;
68}
69
70impl<T, U> TryFromColor<T> for U
71where
72    U: FromColorUnclamped<T> + IsWithinBounds<Mask = bool>,
73{
74    #[inline]
75    fn try_from_color(t: T) -> Result<Self, OutOfBounds<Self>> {
76        let this = Self::from_color_unclamped(t);
77        if this.is_within_bounds() {
78            Ok(this)
79        } else {
80            Err(OutOfBounds::new(this))
81        }
82    }
83}
84
85/// A trait for fallible conversion of a color into another.
86///
87/// `U: TryIntoColor<T>` is implemented for every type `T: TryFromColor<U>`.
88///
89/// See [`TryFromColor`](crate::convert::TryFromColor) for more details.
90pub trait TryIntoColor<T>: Sized {
91    /// Convert into T, returning ok if the color is inside of its defined
92    /// range, otherwise an `OutOfBounds` error is returned which contains
93    /// the unclamped color.
94    ///
95    ///```
96    /// use palette::convert::TryIntoColor;
97    /// use palette::{Hsl, Srgb};
98    ///
99    /// let rgb: Srgb = match Hsl::new(150.0, 1.0, 1.1).try_into_color() {
100    ///     Ok(color) => color,
101    ///     Err(err) => {
102    ///         println!("Color is out of bounds");
103    ///         err.color()
104    ///     }
105    /// };
106    /// ```
107    fn try_into_color(self) -> Result<T, OutOfBounds<T>>;
108}
109
110impl<T, U> TryIntoColor<U> for T
111where
112    U: TryFromColor<T>,
113{
114    #[inline]
115    fn try_into_color(self) -> Result<U, OutOfBounds<U>> {
116        U::try_from_color(self)
117    }
118}