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}