palette/cast/
as_components_traits.rs

1use core::fmt::Debug;
2
3use super::{
4    into_component_slice, into_component_slice_mut, try_from_component_slice,
5    try_from_component_slice_mut, ArrayCast, SliceCastError,
6};
7
8/// Trait for casting a reference to a collection of colors into a reference to
9/// a collection of color components without copying.
10///
11/// This trait is meant as a more convenient alternative to the free functions
12/// in [`cast`][crate::cast], to allow method chaining among other things.
13///
14/// ## Examples
15///
16/// ```
17/// use palette::{cast::AsComponents, Srgb};
18///
19/// let array: [_; 2] = [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)];
20/// let slice: &[_] = &[Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)];
21/// let vec: Vec<_> = vec![Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)];
22///
23/// assert_eq!(array.as_components(), &[64, 139, 10, 93, 18, 214]);
24/// assert_eq!(slice.as_components(), &[64, 139, 10, 93, 18, 214]);
25/// assert_eq!(vec.as_components(), &[64, 139, 10, 93, 18, 214]);
26/// ```
27pub trait AsComponents<C: ?Sized> {
28    /// Cast this collection of colors into a collection of color components.
29    fn as_components(&self) -> &C;
30}
31
32/// Trait for casting a mutable reference to a collection of colors into a
33/// mutable reference to a collection of color components without copying.
34///
35/// This trait is meant as a more convenient alternative to the free functions
36/// in [`cast`][crate::cast], to allow method chaining among other things.
37///
38/// ## Examples
39///
40/// ```
41/// use palette::{cast::AsComponentsMut, Srgb};
42///
43/// let mut array: [_; 2] = [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)];
44/// let slice_mut: &mut [_] = &mut [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)];
45/// let mut vec: Vec<_> = vec![Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)];
46///
47/// assert_eq!(array.as_components_mut(), &mut [64, 139, 10, 93, 18, 214]);
48/// assert_eq!(slice_mut.as_components_mut(), &mut [64, 139, 10, 93, 18, 214]);
49/// assert_eq!(vec.as_components_mut(), &mut [64, 139, 10, 93, 18, 214]);
50/// ```
51pub trait AsComponentsMut<C: ?Sized> {
52    /// Cast this collection of colors into a mutable collection of color
53    /// components.
54    fn as_components_mut(&mut self) -> &mut C;
55}
56
57macro_rules! impl_as_components {
58    ($($owning:ty $(where ($($ty_input:tt)+))?),*) => {
59        $(
60            impl<'a, T, C, const N: usize $(, $($ty_input)+)?> AsComponents<[T]> for $owning
61            where
62                C: ArrayCast<Array = [T; N]>,
63            {
64                #[inline]
65                fn as_components(&self) -> &[T] {
66                    into_component_slice(self.as_ref())
67                }
68            }
69
70            impl<'a, T, C, const N: usize $(, $($ty_input)+)?> AsComponentsMut<[T]> for $owning
71            where
72                C: ArrayCast<Array = [T; N]>,
73            {
74                #[inline]
75                fn as_components_mut(&mut self) -> &mut [T] {
76                    into_component_slice_mut(self.as_mut())
77                }
78            }
79        )*
80    };
81}
82
83impl_as_components!([C], [C; M] where (const M: usize));
84
85#[cfg(feature = "alloc")]
86impl_as_components!(alloc::boxed::Box<[C]>, alloc::vec::Vec<C>);
87
88/// Trait for trying to cast a reference to collection of color components into
89/// a reference to collection of colors without copying.
90///
91/// This trait is meant as a more convenient alternative to the free functions
92/// in [`cast`][crate::cast], to allow method chaining among other things.
93///
94/// ## Errors
95///
96/// The cast will return an error if the cast fails, such as when the length of
97/// the input is not a multiple of the color's array length.
98///
99/// ## Examples
100///
101/// ```
102/// use palette::{cast::TryComponentsAs, Srgb};
103///
104/// let array: [_; 6] = [64, 139, 10, 93, 18, 214];
105/// let slice: &[_] = &[64, 139, 10, 93, 18, 214];
106/// let vec: Vec<_> = vec![64, 139, 10, 93, 18, 214];
107///
108/// let colors: Result<&[Srgb<u8>], _> = array.try_components_as();
109/// assert_eq!(colors, Ok(&[Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)][..]));
110///
111/// let colors: Result<&[Srgb<u8>], _> = slice.try_components_as();
112/// assert_eq!(colors, Ok(&[Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)][..]));
113///
114/// let colors: Result<&[Srgb<u8>], _> = vec.try_components_as();
115/// assert_eq!(colors, Ok(&[Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)][..]));
116/// ```
117///
118/// This produces an error:
119///
120/// ```
121/// use palette::{cast::TryComponentsAs, Srgb};
122///
123/// let components = [64, 139, 10, 93, 18]; // Not a multiple of 3
124/// let colors: Result<&[Srgb<u8>], _> = components.try_components_as();
125/// assert!(colors.is_err());
126/// ```
127pub trait TryComponentsAs<C: ?Sized> {
128    /// The error for when `try_components_as` fails to cast.
129    type Error;
130
131    /// Try to cast this collection of color components into a reference to a
132    /// collection of colors.
133    ///
134    /// Return an error if the conversion can't be done, such as when the number
135    /// of items in `self` isn't a multiple of the number of components in the
136    /// color type.
137    fn try_components_as(&self) -> Result<&C, Self::Error>;
138}
139
140/// Trait for trying to cast a mutable reference to collection of color
141/// components into a mutable reference to collection of colors without copying.
142///
143/// This trait is meant as a more convenient alternative to the free functions
144/// in [`cast`][crate::cast], to allow method chaining among other things.
145///
146/// ## Errors
147///
148/// The cast will return an error if the cast fails, such as when the length of
149/// the input is not a multiple of the color's array length.
150///
151/// ## Examples
152///
153/// ```
154/// use palette::{cast::TryComponentsAsMut, Srgb};
155///
156/// let mut array: [_; 6] = [64, 139, 10, 93, 18, 214];
157/// let slice_mut: &mut [_] = &mut [64, 139, 10, 93, 18, 214];
158/// let mut vec: Vec<_> = vec![64, 139, 10, 93, 18, 214];
159///
160/// let colors: Result<&mut [Srgb<u8>], _> = array.try_components_as_mut();
161/// assert_eq!(colors, Ok(&mut [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)][..]));
162///
163/// let colors: Result<&mut [Srgb<u8>], _> = slice_mut.try_components_as_mut();
164/// assert_eq!(colors, Ok(&mut [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)][..]));
165///
166/// let colors: Result<&mut [Srgb<u8>], _> = vec.try_components_as_mut();
167/// assert_eq!(colors, Ok(&mut [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)][..]));
168/// ```
169///
170/// This produces an error:
171///
172/// ```
173/// use palette::{cast::TryComponentsAsMut, Srgb};
174///
175/// let mut components = [64, 139, 10, 93, 18]; // Not a multiple of 3
176/// let colors: Result<&mut [Srgb<u8>], _> = components.try_components_as_mut();
177/// assert!(colors.is_err());
178/// ```
179pub trait TryComponentsAsMut<C: ?Sized> {
180    /// The error for when `try_components_as_mut` fails to cast.
181    type Error;
182
183    /// Try to cast this collection of color components into a mutable reference
184    /// to a collection of colors.
185    ///
186    /// Return an error if the conversion can't be done, such as when the number
187    /// of items in `self` isn't a multiple of the number of components in the
188    /// color type.
189    fn try_components_as_mut(&mut self) -> Result<&mut C, Self::Error>;
190}
191
192macro_rules! impl_try_components_as {
193    ($($owning:ty $(where ($($ty_input:tt)+))?),*) => {
194        $(
195            impl<'a, T, C, const N: usize $(, $($ty_input)+)?> TryComponentsAs<[C]> for $owning
196            where
197                C: ArrayCast<Array = [T; N]>,
198            {
199                type Error = SliceCastError;
200
201                #[inline]
202                fn try_components_as(&self) -> Result<&[C], Self::Error> {
203                    try_from_component_slice(self.as_ref())
204                }
205            }
206
207            impl<'a, T, C, const N: usize $(, $($ty_input)+)?> TryComponentsAsMut<[C]> for $owning
208            where
209                C: ArrayCast<Array = [T; N]>,
210            {
211                type Error = SliceCastError;
212
213                #[inline]
214                fn try_components_as_mut(&mut self) -> Result<&mut [C], Self::Error> {
215                    try_from_component_slice_mut(self.as_mut())
216                }
217            }
218        )*
219    };
220}
221
222impl_try_components_as!([T], [T; M] where (const M: usize));
223
224#[cfg(feature = "alloc")]
225impl_try_components_as!(alloc::boxed::Box<[T]>, alloc::vec::Vec<T>);
226
227/// Trait for casting a reference to collection of color components into a
228/// reference to collection of colors without copying.
229///
230/// This trait is meant as a more convenient alternative to the free functions
231/// in [`cast`][crate::cast], to allow method chaining among other things.
232///
233/// ## Panics
234///
235/// The cast will panic if the cast fails, such as when the length of the input
236/// is not a multiple of the color's array length.
237///
238/// ## Examples
239///
240/// ```
241/// use palette::{cast::ComponentsAs, Srgb};
242///
243/// let array: [_; 6] = [64, 139, 10, 93, 18, 214];
244/// let slice: &[_] = &[64, 139, 10, 93, 18, 214];
245/// let vec: Vec<_> = vec![64, 139, 10, 93, 18, 214];
246///
247/// let colors: &[Srgb<u8>] = array.components_as();
248/// assert_eq!(colors, &[Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)]);
249///
250/// let colors: &[Srgb<u8>] = slice.components_as();
251/// assert_eq!(colors, &[Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)]);
252///
253/// let colors: &[Srgb<u8>] = vec.components_as();
254/// assert_eq!(colors, &[Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)]);
255/// ```
256///
257/// This panics:
258///
259/// ```should_panic
260/// use palette::{cast::ComponentsAs, Srgb};
261///
262/// let components = [64, 139, 10, 93, 18, 214, 0, 123]; // Not a multiple of 3
263/// let colors: &[Srgb<u8>] = components.components_as();
264/// ```
265pub trait ComponentsAs<C: ?Sized> {
266    /// Cast this collection of color components into a reference to a
267    /// collection of colors.
268    ///
269    /// ## Panics
270    /// If the conversion can't be done, such as when the number of items in
271    /// `self` isn't a multiple of the number of components in the color type.
272    fn components_as(&self) -> &C;
273}
274
275impl<T, C> ComponentsAs<C> for T
276where
277    T: TryComponentsAs<C> + ?Sized,
278    T::Error: Debug,
279    C: ?Sized,
280{
281    fn components_as(&self) -> &C {
282        self.try_components_as().unwrap()
283    }
284}
285
286/// Trait for casting a mutable reference to collection of color components into
287/// a mutable reference to collection of colors without copying.
288///
289/// This trait is meant as a more convenient alternative to the free functions
290/// in [`cast`][crate::cast], to allow method chaining among other things.
291///
292/// ## Panics
293///
294/// The cast will panic if the cast fails, such as when the length of the input
295/// is not a multiple of the color's array length.
296///
297/// ## Examples
298///
299/// ```
300/// use palette::{cast::ComponentsAsMut, Srgb};
301///
302/// let mut array: [_; 6] = [64, 139, 10, 93, 18, 214];
303/// let slice_mut: &mut [_] = &mut [64, 139, 10, 93, 18, 214];
304/// let mut vec: Vec<_> = vec![64, 139, 10, 93, 18, 214];
305///
306/// let colors: &mut [Srgb<u8>] = array.components_as_mut();
307/// assert_eq!(colors, &mut [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)]);
308///
309/// let colors: &mut [Srgb<u8>] = slice_mut.components_as_mut();
310/// assert_eq!(colors, &mut [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)]);
311///
312/// let colors: &mut [Srgb<u8>] = vec.components_as_mut();
313/// assert_eq!(colors, &mut [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)]);
314/// ```
315///
316/// This panics:
317///
318/// ```should_panic
319/// use palette::{cast::ComponentsAsMut, Srgb};
320///
321/// let mut components = [64, 139, 10, 93, 18, 214, 0, 123]; // Not a multiple of 3
322/// let colors: &mut [Srgb<u8>] = components.components_as_mut();
323/// ```
324pub trait ComponentsAsMut<C: ?Sized> {
325    /// Cast this collection of color components into a mutable reference to a
326    /// collection of colors.
327    ///
328    /// ## Panics
329    /// If the conversion can't be done, such as when the number of items in
330    /// `self` isn't a multiple of the number of components in the color type.
331    fn components_as_mut(&mut self) -> &mut C;
332}
333
334impl<T, C> ComponentsAsMut<C> for T
335where
336    T: TryComponentsAsMut<C> + ?Sized,
337    T::Error: Debug,
338    C: ?Sized,
339{
340    fn components_as_mut(&mut self) -> &mut C {
341        self.try_components_as_mut().unwrap()
342    }
343}
344
345#[cfg(test)]
346mod test {
347    use crate::Srgb;
348
349    use super::{
350        AsComponents, AsComponentsMut, ComponentsAs, ComponentsAsMut, TryComponentsAs,
351        TryComponentsAsMut,
352    };
353
354    #[test]
355    fn as_components() {
356        let slice: &[Srgb<u8>] = &[Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)];
357        let slice_mut: &mut [Srgb<u8>] = &mut [Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)];
358        let mut slice_box: Box<[Srgb<u8>]> =
359            vec![Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)].into_boxed_slice();
360        let mut vec: Vec<Srgb<u8>> = vec![Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)];
361        let mut array: [Srgb<u8>; 2] = [Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)];
362
363        let _: &[u8] = slice.as_components();
364        let _: &[u8] = slice_box.as_components();
365        let _: &[u8] = vec.as_components();
366        let _: &[u8] = array.as_components();
367
368        let _: &mut [u8] = slice_mut.as_components_mut();
369        let _: &mut [u8] = slice_box.as_components_mut();
370        let _: &mut [u8] = vec.as_components_mut();
371        let _: &mut [u8] = array.as_components_mut();
372    }
373
374    #[test]
375    fn try_components_as() {
376        let slice: &[u8] = &[1, 2, 3, 4, 5, 6];
377        let slice_mut: &mut [u8] = &mut [1, 2, 3, 4, 5, 6];
378        let mut slice_box: Box<[u8]> = vec![1, 2, 3, 4, 5, 6].into_boxed_slice();
379        let mut vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6];
380        let mut array: [u8; 6] = [1, 2, 3, 4, 5, 6];
381
382        let _: &[Srgb<u8>] = slice.try_components_as().unwrap();
383        let _: &[Srgb<u8>] = slice_box.try_components_as().unwrap();
384        let _: &[Srgb<u8>] = vec.try_components_as().unwrap();
385        let _: &[Srgb<u8>] = array.try_components_as().unwrap();
386
387        let _: &mut [Srgb<u8>] = slice_mut.try_components_as_mut().unwrap();
388        let _: &mut [Srgb<u8>] = slice_box.try_components_as_mut().unwrap();
389        let _: &mut [Srgb<u8>] = vec.try_components_as_mut().unwrap();
390        let _: &mut [Srgb<u8>] = array.try_components_as_mut().unwrap();
391    }
392
393    #[test]
394    fn components_as() {
395        let slice: &[u8] = &[1, 2, 3, 4, 5, 6];
396        let slice_mut: &mut [u8] = &mut [1, 2, 3, 4, 5, 6];
397        let mut slice_box: Box<[u8]> = vec![1, 2, 3, 4, 5, 6].into_boxed_slice();
398        let mut vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6];
399        let mut array: [u8; 6] = [1, 2, 3, 4, 5, 6];
400
401        let _: &[Srgb<u8>] = slice.components_as();
402        let _: &[Srgb<u8>] = slice_box.components_as();
403        let _: &[Srgb<u8>] = vec.components_as();
404        let _: &[Srgb<u8>] = array.components_as();
405
406        let _: &mut [Srgb<u8>] = slice_mut.components_as_mut();
407        let _: &mut [Srgb<u8>] = slice_box.components_as_mut();
408        let _: &mut [Srgb<u8>] = vec.components_as_mut();
409        let _: &mut [Srgb<u8>] = array.components_as_mut();
410    }
411}