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}