palette/cast/array.rs
1use core::mem::{transmute_copy, ManuallyDrop};
2
3#[cfg(all(feature = "alloc", not(feature = "std")))]
4use alloc::{boxed::Box, vec::Vec};
5
6pub use palette_derive::ArrayCast;
7
8use crate::ArrayExt;
9
10/// Marker trait for types that can be represented as a fixed size array.
11///
12/// A type that implements this trait is assumed to have the exact same memory
13/// layout and representation as a fixed size array. This implies a couple of
14/// useful properties:
15///
16/// * Casting between `T` and `T::Array` is free and will (or should) be
17/// optimized away.
18/// * `[T]` can be cast to and from `[T::Array]`, which can be cast to and from
19/// `[U]` where `T::Array = [U; N]` and the length is a multiple of `N`.
20///
21/// This allows a number of common and useful optimizations, including casting
22/// buffers and reusing memory. It does however come with some strict
23/// requirements and the recommendation is to use `#[derive(ArrayCast)]` which
24/// checks for them automatically.
25///
26/// # Deriving
27///
28/// `ArrayCast` can be automatically derived. The only requirements are that the
29/// type is a `struct`, that it has a `#[repr(C)]` or `#[repr(transparent)]`
30/// attribute, and that all of its fields have the same types. It stays on the
31/// conservative side and will show an error if any of those requirements are
32/// not fulfilled. If some fields have different types, but the same memory
33/// layout, or are zero-sized, they can be marked with attributes to show that
34/// their types are safe to use.
35///
36/// ## Field Attributes
37///
38/// * `#[palette_unsafe_same_layout_as = "SomeType"]`: Mark the field as having
39/// the same memory layout as `SomeType`.
40///
41/// **Safety:** corrupt data and undefined behavior may occur if this is not
42/// true!
43///
44/// * `#[palette_unsafe_zero_sized]`: Mark the field as being zero-sized, and
45/// thus not taking up any memory space. This means that it can be ignored.
46///
47/// **Safety:** corrupt data and undefined behavior may occur if this is not
48/// true!
49///
50/// ## Examples
51///
52/// Basic use:
53///
54/// ```rust
55/// use palette::cast::{self, ArrayCast};
56///
57/// #[derive(PartialEq, Debug, ArrayCast)]
58/// #[repr(C)]
59/// struct MyCmyk {
60/// cyan: f32,
61/// magenta: f32,
62/// yellow: f32,
63/// key: f32,
64/// }
65///
66/// let buffer = [0.1, 0.2, 0.3, 0.4];
67/// let color: MyCmyk = cast::from_array(buffer);
68///
69/// assert_eq!(
70/// color,
71/// MyCmyk {
72/// cyan: 0.1,
73/// magenta: 0.2,
74/// yellow: 0.3,
75/// key: 0.4,
76/// }
77/// );
78/// ```
79///
80/// Heterogenous field types:
81///
82/// ```rust
83/// use std::marker::PhantomData;
84///
85/// use palette::{cast::{self, ArrayCast}, encoding::Srgb, RgbHue};
86///
87/// #[derive(PartialEq, Debug, ArrayCast)]
88/// #[repr(C)]
89/// struct MyCoolColor<S> {
90/// #[palette(unsafe_zero_sized)]
91/// standard: PhantomData<S>,
92/// // RgbHue is a wrapper with `#[repr(C)]`, so it can safely
93/// // be converted straight from `f32`.
94/// #[palette(unsafe_same_layout_as = "f32")]
95/// hue: RgbHue<f32>,
96/// lumen: f32,
97/// chroma: f32,
98/// }
99///
100/// let buffer = [172.0, 100.0, 0.3];
101/// let color: MyCoolColor<Srgb> = cast::from_array(buffer);
102///
103/// assert_eq!(
104/// color,
105/// MyCoolColor {
106/// hue: 172.0.into(),
107/// lumen: 100.0,
108/// chroma: 0.3,
109/// standard: PhantomData,
110/// }
111/// );
112/// ```
113///
114/// ## Safety
115///
116/// * The type must be inhabited (eg: no
117/// [Infallible](std::convert::Infallible)).
118/// * The type must allow any values in the array items (eg: either no
119/// requirements or some ability to recover from invalid values).
120/// * The type must be homogeneous (eg: all fields have the same type, or are
121/// wrappers that implement `ArrayCast` with the same field type, or are zero
122/// sized).
123/// * The length of `Array` must be the sum of the number of color component
124/// fields in the type and in any possible compound fields.
125/// * The type must be `repr(C)` or `repr(transparent)`.
126/// * The type must have the same size and alignment as `Self::Array`.
127///
128/// Note also that the type is assumed to not implement `Drop`. This will
129/// rarely, if ever, be an issue. The requirements above ensures that the
130/// underlying field types stay the same and will be dropped.
131///
132/// For example:
133///
134/// * `Srgb<T>` can be cast to `[T; 3]` because it has three non-zero sized
135/// fields of type `T`.
136/// * `Alpha<Srgb<T>, T>` can be cast to `[T; 4]`, that is `3 + 1` items,
137/// because it's the sum of the three items from `Srgb` and the one extra
138/// `alpha` field.
139/// * `Alpha<Srgb<T>, U>` is not allowed because `T` and `U` are different
140/// types.
141pub unsafe trait ArrayCast: Sized {
142 /// The output type of a cast to an array.
143 type Array: ArrayExt;
144}
145
146/// Cast from a color type to an array.
147///
148/// ```
149/// use palette::{cast, Srgb};
150///
151/// let color = Srgb::new(23u8, 198, 76);
152/// assert_eq!(cast::into_array(color), [23, 198, 76]);
153/// ```
154///
155/// It's also possible to use `From` and `Into` when casting built-in types:
156///
157/// ```
158/// use palette::Srgb;
159///
160/// let color = Srgb::new(23u8, 198, 76);
161///
162/// // Colors implement `Into`:
163/// let array1: [_; 3] = color.into();
164///
165/// // Arrays implement `From`:
166/// let array2 = <[_; 3]>::from(color);
167/// ```
168#[inline]
169pub fn into_array<T>(color: T) -> T::Array
170where
171 T: ArrayCast,
172{
173 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
174
175 // Safety: The requirements of implementing `ArrayCast`, as well as the size
176 // assert, ensures that transmuting `T` into `T::Array` is safe.
177 unsafe { transmute_copy(&ManuallyDrop::new(color)) }
178}
179
180/// Cast from an array to a color type.
181///
182/// ```
183/// use palette::{cast, Srgb};
184///
185/// let array = [23, 198, 76];
186/// assert_eq!(cast::from_array::<Srgb<u8>>(array), Srgb::new(23, 198, 76));
187/// ```
188///
189/// It's also possible to use `From` and `Into` when casting built-in types:
190///
191/// ```
192/// use palette::Srgb;
193///
194/// let array = [23, 198, 76];
195///
196/// // Arrays implement `Into`:
197/// let color1: Srgb<u8> = array.into();
198///
199/// // Colors implement `From`:
200/// let color2 = Srgb::from(array);
201/// ```
202#[inline]
203pub fn from_array<T>(array: T::Array) -> T
204where
205 T: ArrayCast,
206{
207 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
208
209 // Safety: The requirements of implementing `ArrayCast`, as well as the size
210 // assert, ensures that transmuting `T::Array` into `T` is safe.
211 unsafe { transmute_copy(&ManuallyDrop::new(array)) }
212}
213
214/// Cast from a color type reference to an array reference.
215///
216/// ```
217/// use palette::{cast, Srgb};
218///
219/// let color = Srgb::new(23u8, 198, 76);
220/// assert_eq!(cast::into_array_ref(&color), &[23, 198, 76]);
221/// ```
222///
223/// It's also possible to use `From`, `Into` and `AsRef` when casting built-in
224/// types:
225///
226/// ```
227/// use palette::Srgb;
228///
229/// let color = Srgb::new(23u8, 198, 76);
230///
231/// // Colors implement `AsRef`:
232/// let array1: &[_; 3] = color.as_ref();
233///
234/// // Color references implement `Into`:
235/// let array2: &[_; 3] = (&color).into();
236//
237/// // Array references implement `From`:
238/// let array3 = <&[_; 3]>::from(&color);
239/// ```
240#[inline]
241pub fn into_array_ref<T>(value: &T) -> &T::Array
242where
243 T: ArrayCast,
244{
245 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
246 assert_eq!(
247 core::mem::align_of::<T::Array>(),
248 core::mem::align_of::<T>()
249 );
250
251 let value: *const T = value;
252
253 // Safety: The requirements of implementing `ArrayCast`, as well as the size
254 // and alignment asserts, ensures that reading `T` as `T::Array` is safe.
255 unsafe { &*value.cast::<T::Array>() }
256}
257
258/// Cast from an array reference to a color type reference.
259///
260/// ```
261/// use palette::{cast, Srgb};
262///
263/// let array = [23, 198, 76];
264/// assert_eq!(cast::from_array_ref::<Srgb<u8>>(&array), &Srgb::new(23, 198, 76));
265/// ```
266///
267/// It's also possible to use `From`, `Into` and `AsRef` when casting built-in
268/// types:
269///
270/// ```
271/// use palette::Srgb;
272///
273/// let array = [23, 198, 76];
274///
275/// // Arrays implement `AsRef`:
276/// let color1: &Srgb<u8> = array.as_ref();
277///
278/// // Array references implement `Into`:
279/// let color2: &Srgb<u8> = (&array).into();
280///
281/// // Color references implement `From`:
282/// let color3 = <&Srgb<u8>>::from(&array);
283/// ```
284#[inline]
285pub fn from_array_ref<T>(value: &T::Array) -> &T
286where
287 T: ArrayCast,
288{
289 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
290 assert_eq!(
291 core::mem::align_of::<T::Array>(),
292 core::mem::align_of::<T>()
293 );
294
295 let value: *const T::Array = value;
296
297 // Safety: The requirements of implementing `ArrayCast`, as well as the size
298 // and alignment asserts, ensures that reading `T::Array` as `T` is safe.
299 unsafe { &*value.cast::<T>() }
300}
301
302/// Cast from a mutable color type reference to a mutable array reference.
303///
304/// ```
305/// use palette::{cast, Srgb};
306///
307/// let mut color = Srgb::new(23u8, 198, 76);
308/// assert_eq!(cast::into_array_mut(&mut color), &mut [23, 198, 76]);
309/// ```
310///
311/// It's also possible to use `From`, `Into` and `AsMut` when casting built-in
312/// types:
313///
314/// ```
315/// use palette::Srgb;
316///
317/// let mut color = Srgb::new(23u8, 198, 76);
318///
319/// // Colors implement `AsMut`:
320/// let array1: &mut [_; 3] = color.as_mut();
321///
322/// // Color references implement `Into`:
323/// let array2: &mut [_; 3] = (&mut color).into();
324//
325/// // Array references implement `From`:
326/// let array3 = <&mut [_; 3]>::from(&mut color);
327/// ```
328#[inline]
329pub fn into_array_mut<T>(value: &mut T) -> &mut T::Array
330where
331 T: ArrayCast,
332{
333 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
334 assert_eq!(
335 core::mem::align_of::<T::Array>(),
336 core::mem::align_of::<T>()
337 );
338
339 let value: *mut T = value;
340
341 // Safety: The requirements of implementing `ArrayCast`, as well as the size
342 // and alignment asserts, ensures that reading `T` as `T::Array` is safe.
343 unsafe { &mut *value.cast::<T::Array>() }
344}
345
346/// Cast from a mutable array reference to a mutable color type reference.
347///
348/// ```
349/// use palette::{cast, Srgb};
350///
351/// let mut array = [23, 198, 76];
352/// assert_eq!(cast::from_array_mut::<Srgb<u8>>(&mut array), &mut Srgb::new(23, 198, 76));
353/// ```
354///
355/// It's also possible to use `From`, `Into` and `AsMut` when casting built-in
356/// types:
357///
358/// ```
359/// use palette::Srgb;
360///
361/// let mut array = [23, 198, 76];
362///
363/// // Arrays implement `AsMut`:
364/// let color1: &mut Srgb<u8> = array.as_mut();
365///
366/// // Array references implement `Into`:
367/// let color2: &mut Srgb<u8> = (&mut array).into();
368///
369/// // Color references implement `From`:
370/// let color3 = <&mut Srgb<u8>>::from(&mut array);
371/// ```
372#[inline]
373pub fn from_array_mut<T>(value: &mut T::Array) -> &mut T
374where
375 T: ArrayCast,
376{
377 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
378 assert_eq!(
379 core::mem::align_of::<T::Array>(),
380 core::mem::align_of::<T>()
381 );
382
383 let value: *mut T::Array = value;
384
385 // Safety: The requirements of implementing `ArrayCast`, as well as the size
386 // and alignment asserts, ensures that reading `T::Array` as `T` is safe.
387 unsafe { &mut *value.cast::<T>() }
388}
389
390/// Cast from an array of colors to an array of arrays.
391///
392/// ```
393/// use palette::{cast, Srgb};
394///
395/// let colors = [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)];
396/// assert_eq!(cast::into_array_array(colors), [[64, 139, 10], [93, 18, 214]])
397/// ```
398#[inline]
399pub fn into_array_array<T, const N: usize>(values: [T; N]) -> [T::Array; N]
400where
401 T: ArrayCast,
402{
403 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
404 assert_eq!(
405 core::mem::align_of::<T::Array>(),
406 core::mem::align_of::<T>()
407 );
408
409 // Safety: The requirements of implementing `ArrayCast`, as well as the size
410 // and alignment asserts, ensures that reading `T` as `T::Array` is safe.
411 // The length and memory layout of the array is the same because the size is
412 // the same.
413 unsafe { transmute_copy(&ManuallyDrop::new(values)) }
414}
415
416/// Cast from an array of colors to an array of color components.
417///
418/// ## Panics
419///
420/// It's unfortunately not able to infer the length of the component array,
421/// until generic const expressions are stabilized. In the meantime, it's going
422/// to panic if `M` isn't `N * T::Array::LENGTH`. A future version will remove
423/// the `M` parameter and make the mismatch a compiler error.
424///
425/// No `try_*` alternative is provided, since the array size can't be changed
426/// during runtime.
427///
428/// ## Examples
429///
430/// ```
431/// use palette::{cast, Srgb};
432///
433/// let colors = [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)];
434/// assert_eq!(cast::into_component_array(colors), [64, 139, 10, 93, 18, 214])
435/// ```
436///
437/// It panics when the array lengths don't match up:
438///
439/// ```should_panic
440/// use palette::{cast, Srgb};
441///
442/// let colors = [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)];
443/// assert_eq!(cast::into_component_array(colors), [64, 139, 10]) // Too short
444/// ```
445#[inline]
446pub fn into_component_array<T, const N: usize, const M: usize>(
447 values: [T; N],
448) -> [<T::Array as ArrayExt>::Item; M]
449where
450 T: ArrayCast,
451{
452 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
453 assert_eq!(
454 core::mem::align_of::<T::Array>(),
455 core::mem::align_of::<T>()
456 );
457
458 // This check can be replaced with `[<T::Array as ArrayExt>::Item; N *
459 // T::Array::LENGTH]` when generic const expressions are stabilized.
460 assert_eq!(
461 N * T::Array::LENGTH,
462 M,
463 "expected the output array to have length {}, but its length is {}",
464 N * T::Array::LENGTH,
465 M
466 );
467 assert_eq!(
468 core::mem::size_of::<[T; N]>(),
469 core::mem::size_of::<[<T::Array as ArrayExt>::Item; M]>()
470 );
471 assert_eq!(
472 core::mem::align_of::<[T; N]>(),
473 core::mem::align_of::<[<T::Array as ArrayExt>::Item; M]>()
474 );
475
476 // Safety: The requirements of implementing `ArrayCast`, as well as the size
477 // and alignment asserts, ensures that reading `T` as `T::Array` is safe.
478 // The sizes and memory layout of the arrays are also asserted to be the
479 // same.
480 unsafe { transmute_copy(&ManuallyDrop::new(values)) }
481}
482
483/// Cast from an array of arrays to an array of colors.
484///
485/// ```
486/// use palette::{cast, Srgb};
487///
488/// let arrays = [[64, 139, 10], [93, 18, 214]];
489/// assert_eq!(
490/// cast::from_array_array::<Srgb<u8>, 2>(arrays),
491/// [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)]
492/// )
493/// ```
494#[inline]
495pub fn from_array_array<T, const N: usize>(values: [T::Array; N]) -> [T; N]
496where
497 T: ArrayCast,
498{
499 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
500 assert_eq!(
501 core::mem::align_of::<T::Array>(),
502 core::mem::align_of::<T>()
503 );
504
505 // Safety: The requirements of implementing `ArrayCast`, as well as the size
506 // and alignment asserts, ensures that reading `T::Array` as `T` is safe.
507 // The length and memory layout of the array is the same because the size is
508 // the same.
509 unsafe { transmute_copy(&ManuallyDrop::new(values)) }
510}
511
512/// Cast from an array of color components to an array of colors.
513///
514/// ## Panics
515///
516/// The cast will panic if the length of the input array is not a multiple of
517/// the color's array length. This is unfortunately unavoidable until generic
518/// const expressions are stabilized.
519///
520/// No `try_*` alternative is provided, since the array size can't be changed
521/// during runtime.
522///
523/// ## Examples
524///
525/// ```
526/// use palette::{cast, Srgb};
527///
528/// let components = [64, 139, 10, 93, 18, 214];
529/// assert_eq!(
530/// cast::from_component_array::<Srgb<u8>, 6, 2>(components),
531/// [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)]
532/// );
533/// ```
534///
535/// This panics:
536///
537/// ```should_panic
538/// use palette::{cast, Srgb};
539///
540/// let components = [64, 139, 10, 93, 18]; // Not a multiple of 3
541/// assert_eq!(
542/// cast::from_component_array::<Srgb<u8>, 5, 2>(components),
543/// [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)]
544/// );
545/// ```
546#[inline]
547pub fn from_component_array<T, const N: usize, const M: usize>(
548 values: [<T::Array as ArrayExt>::Item; N],
549) -> [T; M]
550where
551 T: ArrayCast,
552{
553 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
554 assert_eq!(
555 core::mem::align_of::<T::Array>(),
556 core::mem::align_of::<T>()
557 );
558
559 // These checks can be replaced with `[<T::Array as ArrayExt>::Item; N /
560 // T::Array::LENGTH]` and a compile time check for `values.len() %
561 // T::Array::LENGTH == 0` when generic const expressions are stabilized.
562 assert_eq!(
563 N % T::Array::LENGTH,
564 0,
565 "expected the array length ({}) to be divisible by {}",
566 N,
567 T::Array::LENGTH
568 );
569 assert_eq!(
570 N / T::Array::LENGTH,
571 M,
572 "expected the output array to have length {}, but its length is {}",
573 N / T::Array::LENGTH,
574 M
575 );
576 assert_eq!(
577 core::mem::size_of::<[<T::Array as ArrayExt>::Item; N]>(),
578 core::mem::size_of::<[T; M]>()
579 );
580 assert_eq!(
581 core::mem::align_of::<[<T::Array as ArrayExt>::Item; N]>(),
582 core::mem::align_of::<[T; M]>()
583 );
584
585 // Safety: The requirements of implementing `ArrayCast`, as well as the size
586 // and alignment asserts, ensures that reading `T` as `T::Array` is safe.
587 // The sizes and memory layout of the arrays are also asserted to be the
588 // same.
589 unsafe { transmute_copy(&ManuallyDrop::new(values)) }
590}
591
592/// Cast from a slice of colors to a slice of arrays.
593///
594/// ```
595/// use palette::{cast, Srgb};
596///
597/// let colors = &[Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)];
598/// assert_eq!(cast::into_array_slice(colors), &[[64, 139, 10], [93, 18, 214]])
599/// ```
600#[inline]
601pub fn into_array_slice<T>(values: &[T]) -> &[T::Array]
602where
603 T: ArrayCast,
604{
605 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
606 assert_eq!(
607 core::mem::align_of::<T::Array>(),
608 core::mem::align_of::<T>()
609 );
610
611 // Safety: The requirements of implementing `ArrayCast`, as well as the size
612 // and alignment asserts, ensures that reading `T` as `T::Array` is safe.
613 // The length is the same because the size is the same.
614 unsafe { core::slice::from_raw_parts(values.as_ptr().cast::<T::Array>(), values.len()) }
615}
616
617/// Cast from a slice of colors to a slice of color components.
618///
619/// ```
620/// use palette::{cast, Srgb};
621///
622/// let colors = &[Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)];
623/// assert_eq!(cast::into_component_slice(colors), &[64, 139, 10, 93, 18, 214])
624/// ```
625#[inline]
626pub fn into_component_slice<T>(values: &[T]) -> &[<T::Array as ArrayExt>::Item]
627where
628 T: ArrayCast,
629{
630 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
631 assert_eq!(
632 core::mem::align_of::<T::Array>(),
633 core::mem::align_of::<T>()
634 );
635
636 let length = values.len() * T::Array::LENGTH;
637
638 // Safety: The requirements of implementing `ArrayCast`, as well as the size
639 // and alignment asserts, ensures that reading `[T]` as `[T::Array::Item]`
640 // is safe. The length is multiplied by the array length.
641 unsafe {
642 core::slice::from_raw_parts(
643 values.as_ptr().cast::<<T::Array as ArrayExt>::Item>(),
644 length,
645 )
646 }
647}
648
649/// Cast from a slice of arrays to a slice of colors.
650///
651/// ```
652/// use palette::{cast, Srgb};
653///
654/// let arrays = &[[64, 139, 10], [93, 18, 214]];
655/// assert_eq!(
656/// cast::from_array_slice::<Srgb<u8>>(arrays),
657/// &[Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)]
658/// )
659/// ```
660#[inline]
661pub fn from_array_slice<T>(values: &[T::Array]) -> &[T]
662where
663 T: ArrayCast,
664{
665 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
666 assert_eq!(
667 core::mem::align_of::<T::Array>(),
668 core::mem::align_of::<T>()
669 );
670
671 // Safety: The requirements of implementing `ArrayCast`, as well as the size
672 // and alignment asserts, ensures that reading `T::Array` as `T` is safe.
673 // The length is the same because the size is the same.
674 unsafe { core::slice::from_raw_parts(values.as_ptr().cast::<T>(), values.len()) }
675}
676
677/// The same as [`try_from_component_slice`] but panics on error.
678///
679/// ## Panics
680///
681/// The cast will panic if the length of the input slice is not a multiple of
682/// the color's array length.
683///
684/// ## Examples
685///
686/// ```
687/// use palette::{cast, Srgb};
688///
689/// let components = &[64, 139, 10, 93, 18, 214];
690/// assert_eq!(
691/// cast::from_component_slice::<Srgb<u8>>(components),
692/// &[Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)]
693/// )
694/// ```
695///
696/// This panics:
697///
698/// ```should_panic
699/// use palette::{cast, Srgb};
700///
701/// let components = &[64, 139, 10, 93, 18, 214, 0, 123]; // Not a multiple of 3
702/// cast::from_component_slice::<Srgb<u8>>(components);
703/// ```
704#[inline]
705pub fn from_component_slice<T>(values: &[<T::Array as ArrayExt>::Item]) -> &[T]
706where
707 T: ArrayCast,
708{
709 try_from_component_slice(values).unwrap()
710}
711
712/// Cast from a slice of color components to a slice of colors.
713///
714/// ## Errors
715///
716/// The cast will return an error if the length of the input slice is not a
717/// multiple of the color's array length.
718///
719/// ## Examples
720///
721/// ```
722/// use palette::{cast, Srgb};
723///
724/// let components = &[64, 139, 10, 93, 18, 214];
725/// assert_eq!(
726/// cast::try_from_component_slice::<Srgb<u8>>(components),
727/// Ok([Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)].as_ref())
728/// )
729/// ```
730///
731/// This produces an error:
732///
733/// ```
734/// use palette::{cast, Srgb};
735///
736/// let components = &[64, 139, 10, 93, 18]; // Not a multiple of 3
737/// assert!(cast::try_from_component_slice::<Srgb<u8>>(components).is_err());
738/// ```
739#[inline]
740pub fn try_from_component_slice<T>(
741 values: &[<T::Array as ArrayExt>::Item],
742) -> Result<&[T], SliceCastError>
743where
744 T: ArrayCast,
745{
746 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
747 assert_eq!(
748 core::mem::align_of::<T::Array>(),
749 core::mem::align_of::<T>()
750 );
751
752 if values.len() % T::Array::LENGTH != 0 {
753 return Err(SliceCastError);
754 }
755
756 let length = values.len() / T::Array::LENGTH;
757 let raw = values.as_ptr().cast::<T>();
758
759 // Safety: The requirements of implementing `ArrayCast`, as well as the size
760 // and alignment asserts, ensures that reading `T` as `T::Array` is safe.
761 unsafe { Ok(core::slice::from_raw_parts(raw, length)) }
762}
763
764/// Cast from a mutable slice of colors to a mutable slice of arrays.
765///
766/// ```
767/// use palette::{cast, Srgb};
768///
769/// let colors = &mut [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)];
770/// assert_eq!(
771/// cast::into_array_slice_mut(colors),
772/// &mut [[64, 139, 10], [93, 18, 214]]
773/// )
774/// ```
775#[inline]
776pub fn into_array_slice_mut<T>(values: &mut [T]) -> &mut [T::Array]
777where
778 T: ArrayCast,
779{
780 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
781 assert_eq!(
782 core::mem::align_of::<T::Array>(),
783 core::mem::align_of::<T>()
784 );
785
786 // Safety: The requirements of implementing `ArrayCast`, as well as the size
787 // and alignment asserts, ensures that reading `T` as `T::Array` is safe.
788 // The length is the same because the size is the same.
789 unsafe { core::slice::from_raw_parts_mut(values.as_mut_ptr().cast::<T::Array>(), values.len()) }
790}
791
792/// Cast from a slice of colors to a slice of color components.
793///
794/// ```
795/// use palette::{cast, Srgb};
796///
797/// let colors = &mut [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)];
798/// assert_eq!(
799/// cast::into_component_slice_mut(colors),
800/// &mut [64, 139, 10, 93, 18, 214]
801/// )
802/// ```
803#[inline]
804pub fn into_component_slice_mut<T>(values: &mut [T]) -> &mut [<T::Array as ArrayExt>::Item]
805where
806 T: ArrayCast,
807{
808 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
809 assert_eq!(
810 core::mem::align_of::<T::Array>(),
811 core::mem::align_of::<T>()
812 );
813
814 let length = values.len() * T::Array::LENGTH;
815
816 // Safety: The requirements of implementing `ArrayCast`, as well as the size
817 // and alignment asserts, ensures that reading `[T]` as `[T::Array::Item]`
818 // is safe. The length is multiplied by the array length.
819 unsafe {
820 core::slice::from_raw_parts_mut(
821 values.as_mut_ptr().cast::<<T::Array as ArrayExt>::Item>(),
822 length,
823 )
824 }
825}
826
827/// Cast from a mutable slice of arrays to a mutable slice of colors.
828///
829/// ```
830/// use palette::{cast, Srgb};
831///
832/// let arrays = &mut [[64, 139, 10], [93, 18, 214]];
833/// assert_eq!(
834/// cast::from_array_slice_mut::<Srgb<u8>>(arrays),
835/// &mut [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)]
836/// )
837/// ```
838#[inline]
839pub fn from_array_slice_mut<T>(values: &mut [T::Array]) -> &mut [T]
840where
841 T: ArrayCast,
842{
843 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
844 assert_eq!(
845 core::mem::align_of::<T::Array>(),
846 core::mem::align_of::<T>()
847 );
848
849 // Safety: The requirements of implementing `ArrayCast`, as well as the size
850 // and alignment asserts, ensures that reading `T::Array` as `T` is safe.
851 // The length is the same because the size is the same.
852 unsafe { core::slice::from_raw_parts_mut(values.as_mut_ptr().cast::<T>(), values.len()) }
853}
854
855/// The same as [`try_from_component_slice_mut`] but panics on error.
856///
857/// ## Panics
858///
859/// The cast will panic if the length of the input slice is not a multiple of
860/// the color's array length.
861///
862/// ## Examples
863///
864/// ```
865/// use palette::{cast, Srgb};
866///
867/// let components = &mut [64, 139, 10, 93, 18, 214];
868/// assert_eq!(
869/// cast::from_component_slice_mut::<Srgb<u8>>(components),
870/// &mut [Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)]
871/// )
872/// ```
873///
874/// This panics:
875///
876/// ```should_panic
877/// use palette::{cast, Srgb};
878///
879/// let components = &mut [64, 139, 10, 93, 18, 214, 0, 123]; // Not a multiple of 3
880/// cast::from_component_slice_mut::<Srgb<u8>>(components);
881/// ```
882#[inline]
883pub fn from_component_slice_mut<T>(values: &mut [<T::Array as ArrayExt>::Item]) -> &mut [T]
884where
885 T: ArrayCast,
886{
887 try_from_component_slice_mut(values).unwrap()
888}
889
890/// Cast from a mutable slice of color components to a slice of colors.
891///
892/// ## Errors
893///
894/// The cast will return an error if the length of the input slice is not a
895/// multiple of the color's array length.
896///
897/// ## Examples
898///
899/// ```
900/// use palette::{cast, Srgb};
901///
902/// let components = &mut [64, 139, 10, 93, 18, 214];
903/// assert_eq!(
904/// cast::try_from_component_slice_mut::<Srgb<u8>>(components),
905/// Ok([Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)].as_mut())
906/// )
907/// ```
908///
909/// This produces an error:
910///
911/// ```
912/// use palette::{cast, Srgb};
913///
914/// let components = &mut [64, 139, 10, 93, 18]; // Not a multiple of 3
915/// assert!(cast::try_from_component_slice_mut::<Srgb<u8>>(components).is_err());
916/// ```
917#[inline]
918pub fn try_from_component_slice_mut<T>(
919 values: &mut [<T::Array as ArrayExt>::Item],
920) -> Result<&mut [T], SliceCastError>
921where
922 T: ArrayCast,
923{
924 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
925 assert_eq!(
926 core::mem::align_of::<T::Array>(),
927 core::mem::align_of::<T>()
928 );
929
930 if values.len() % T::Array::LENGTH != 0 {
931 return Err(SliceCastError);
932 }
933
934 let length = values.len() / T::Array::LENGTH;
935 let raw = values.as_mut_ptr().cast::<T>();
936
937 // Safety: The requirements of implementing `ArrayCast`, as well as the size
938 // and alignment asserts, ensures that reading `T` as `T::Array` is safe.
939 unsafe { Ok(core::slice::from_raw_parts_mut(raw, length)) }
940}
941
942/// Cast from a boxed color type to a boxed array.
943///
944/// ```
945/// use palette::{cast, Srgb};
946///
947/// let color = Box::new(Srgb::new(23u8, 198, 76));
948/// assert_eq!(cast::into_array_box(color), Box::new([23, 198, 76]));
949/// ```
950///
951/// It's also possible to use `From` and `Into` when casting built-in types:
952///
953/// ```
954/// use palette::Srgb;
955///
956/// // Boxed colors implement `Into`:
957/// let color1 = Box::new(Srgb::new(23u8, 198, 76));
958/// let array1: Box<[_; 3]> = color1.into();
959///
960/// // Boxed arrays implement `From`:
961/// let color2 = Box::new(Srgb::new(23u8, 198, 76));
962/// let array2 = <Box<[_; 3]>>::from(color2);
963/// ```
964#[cfg(feature = "alloc")]
965#[inline]
966pub fn into_array_box<T>(value: Box<T>) -> Box<T::Array>
967where
968 T: ArrayCast,
969{
970 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
971 assert_eq!(
972 core::mem::align_of::<T::Array>(),
973 core::mem::align_of::<T>()
974 );
975
976 let raw = Box::into_raw(value);
977
978 // Safety: The requirements of implementing `ArrayCast`, as well as the size
979 // and alignment asserts, ensures that reading `T` as `T::Array` is safe.
980 unsafe { Box::from_raw(raw.cast::<T::Array>()) }
981}
982
983/// Cast from a boxed array to a boxed color type.
984///
985/// ```
986/// use palette::{cast, Srgb};
987///
988/// let array = Box::new([23, 198, 76]);
989/// assert_eq!(cast::from_array_box::<Srgb<u8>>(array), Box::new(Srgb::new(23, 198, 76)));
990/// ```
991///
992/// It's also possible to use `From` and `Into` when casting built-in types:
993///
994/// ```
995/// use palette::Srgb;
996///
997///
998/// // Boxed arrays implement `Into`:
999/// let array1 = Box::new([23, 198, 76]);
1000/// let color1: Box<Srgb<u8>> = array1.into();
1001///
1002/// // Boxed colors implement `From`:
1003/// let array2 = Box::new([23, 198, 76]);
1004/// let color2 = <Box<Srgb<u8>>>::from(array2);
1005/// ```
1006#[cfg(feature = "alloc")]
1007#[inline]
1008pub fn from_array_box<T>(value: Box<T::Array>) -> Box<T>
1009where
1010 T: ArrayCast,
1011{
1012 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
1013 assert_eq!(
1014 core::mem::align_of::<T::Array>(),
1015 core::mem::align_of::<T>()
1016 );
1017
1018 let raw = Box::into_raw(value);
1019
1020 // Safety: The requirements of implementing `ArrayCast`, as well as the size
1021 // and alignment asserts, ensures that reading `T::Array` as `T` is safe.
1022 unsafe { Box::from_raw(raw.cast::<T>()) }
1023}
1024
1025/// Cast from a boxed slice of colors to a boxed slice of arrays.
1026///
1027/// ```
1028/// use palette::{cast, Srgb};
1029///
1030/// let colors = vec![Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)].into_boxed_slice();
1031/// assert_eq!(
1032/// cast::into_array_slice_box(colors),
1033/// vec![[64, 139, 10], [93, 18, 214]].into_boxed_slice()
1034/// )
1035/// ```
1036#[cfg(feature = "alloc")]
1037#[inline]
1038pub fn into_array_slice_box<T>(values: Box<[T]>) -> Box<[T::Array]>
1039where
1040 T: ArrayCast,
1041{
1042 let raw: *mut [T::Array] = into_array_slice_mut(Box::leak(values));
1043
1044 // Safety: We know the pointer comes from a `Box` and thus has the correct lifetime.
1045 unsafe { Box::from_raw(raw) }
1046}
1047
1048/// Cast from a boxed slice of colors to a boxed slice of color components.
1049///
1050/// ```
1051/// use palette::{cast, Srgb};
1052///
1053/// let colors = vec![Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)].into_boxed_slice();
1054/// assert_eq!(
1055/// cast::into_component_slice_box(colors),
1056/// vec![64, 139, 10, 93, 18, 214].into_boxed_slice()
1057/// )
1058/// ```
1059#[cfg(feature = "alloc")]
1060#[inline]
1061pub fn into_component_slice_box<T>(values: Box<[T]>) -> Box<[<T::Array as ArrayExt>::Item]>
1062where
1063 T: ArrayCast,
1064{
1065 let raw: *mut [<T::Array as ArrayExt>::Item] = into_component_slice_mut(Box::leak(values));
1066
1067 // Safety: We know the pointer comes from a `Box` and thus has the correct lifetime.
1068 unsafe { Box::from_raw(raw) }
1069}
1070
1071/// Cast from a boxed slice of arrays to a boxed slice of colors.
1072///
1073/// ```
1074/// use palette::{cast, Srgb};
1075///
1076/// let arrays = vec![[64, 139, 10], [93, 18, 214]].into_boxed_slice();
1077/// assert_eq!(
1078/// cast::from_array_slice_box::<Srgb<u8>>(arrays),
1079/// vec![Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)].into_boxed_slice()
1080/// )
1081/// ```
1082#[cfg(feature = "alloc")]
1083#[inline]
1084pub fn from_array_slice_box<T>(values: Box<[T::Array]>) -> Box<[T]>
1085where
1086 T: ArrayCast,
1087{
1088 let raw: *mut [T] = from_array_slice_mut(Box::leak(values));
1089
1090 // Safety: We know the pointer comes from a `Box` and thus has the correct lifetime.
1091 unsafe { Box::from_raw(raw) }
1092}
1093
1094/// The same as [`try_from_component_slice_box`] but panics on error.
1095///
1096/// ## Panics
1097///
1098/// The cast will panic if the length of the input slice is not a multiple of
1099/// the color's array length.
1100///
1101/// ## Examples
1102///
1103/// ```
1104/// use palette::{cast, Srgb};
1105///
1106/// let components = vec![64, 139, 10, 93, 18, 214].into_boxed_slice();
1107/// assert_eq!(
1108/// cast::from_component_slice_box::<Srgb<u8>>(components),
1109/// vec![Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)].into_boxed_slice()
1110/// )
1111/// ```
1112///
1113/// This panics:
1114///
1115/// ```should_panic
1116/// use palette::{cast, Srgb};
1117///
1118/// // Not a multiple of 3:
1119/// let components = vec![64, 139, 10, 93, 18, 214, 0, 123].into_boxed_slice();
1120/// cast::from_component_slice_box::<Srgb<u8>>(components);
1121/// ```
1122#[cfg(feature = "alloc")]
1123#[inline]
1124pub fn from_component_slice_box<T>(values: Box<[<T::Array as ArrayExt>::Item]>) -> Box<[T]>
1125where
1126 T: ArrayCast,
1127{
1128 try_from_component_slice_box(values).unwrap()
1129}
1130
1131/// Cast from a boxed slice of color components to a boxed slice of colors.
1132///
1133/// ## Errors
1134///
1135/// The cast will return an error if the length of the input slice is not a
1136/// multiple of the color's array length.
1137///
1138/// ## Examples
1139///
1140/// ```
1141/// use palette::{cast, Srgb};
1142///
1143/// let components = vec![64, 139, 10, 93, 18, 214].into_boxed_slice();
1144/// assert_eq!(
1145/// cast::try_from_component_slice_box::<Srgb<u8>>(components),
1146/// Ok(vec![Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)].into_boxed_slice())
1147/// )
1148/// ```
1149///
1150/// This produces an error:
1151///
1152/// ```
1153/// use palette::{cast, Srgb};
1154///
1155/// // Not a multiple of 3:
1156/// let components = vec![64, 139, 10, 93, 18].into_boxed_slice();
1157///
1158/// if let Err(error) = cast::try_from_component_slice_box::<Srgb<u8>>(components) {
1159/// // We get the original values back on error:
1160/// assert_eq!(
1161/// error.values,
1162/// vec![64, 139, 10, 93, 18].into_boxed_slice()
1163/// );
1164/// } else {
1165/// unreachable!();
1166/// }
1167/// ```
1168#[cfg(feature = "alloc")]
1169#[inline]
1170pub fn try_from_component_slice_box<T>(
1171 values: Box<[<T::Array as ArrayExt>::Item]>,
1172) -> Result<Box<[T]>, BoxedSliceCastError<<T::Array as ArrayExt>::Item>>
1173where
1174 T: ArrayCast,
1175{
1176 if values.len() % T::Array::LENGTH != 0 {
1177 return Err(BoxedSliceCastError { values });
1178 }
1179
1180 let raw: *mut [T] = from_component_slice_mut(Box::leak(values));
1181
1182 // Safety: We know the pointer comes from a `Box` and thus has the correct lifetime.
1183 unsafe { Ok(Box::from_raw(raw)) }
1184}
1185
1186/// Cast from a `Vec` of colors to a `Vec` of arrays.
1187///
1188/// ```
1189/// use palette::{cast, Srgb};
1190///
1191/// let colors = vec![Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)];
1192/// assert_eq!(
1193/// cast::into_array_vec(colors),
1194/// vec![[64, 139, 10], [93, 18, 214]]
1195/// )
1196/// ```
1197#[cfg(feature = "alloc")]
1198#[inline]
1199pub fn into_array_vec<T>(values: Vec<T>) -> Vec<T::Array>
1200where
1201 T: ArrayCast,
1202{
1203 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
1204 assert_eq!(
1205 core::mem::align_of::<T::Array>(),
1206 core::mem::align_of::<T>()
1207 );
1208 let mut values = ManuallyDrop::new(values);
1209
1210 let raw = values.as_mut_ptr();
1211
1212 // Safety: The requirements of implementing `ArrayCast`, as well as the size
1213 // and alignment asserts, ensures that reading `T` as `T::Array` is safe.
1214 // Length and capacity are the same because the size is the same.
1215 unsafe { Vec::from_raw_parts(raw.cast::<T::Array>(), values.len(), values.capacity()) }
1216}
1217
1218/// Cast from a `Vec` of colors to a `Vec` of color components.
1219///
1220/// ```
1221/// use palette::{cast, Srgb};
1222///
1223/// let colors = vec![Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)];
1224/// assert_eq!(
1225/// cast::into_component_vec(colors),
1226/// vec![64, 139, 10, 93, 18, 214]
1227/// )
1228/// ```
1229#[cfg(feature = "alloc")]
1230#[inline]
1231pub fn into_component_vec<T>(values: Vec<T>) -> Vec<<T::Array as ArrayExt>::Item>
1232where
1233 T: ArrayCast,
1234{
1235 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
1236 assert_eq!(
1237 core::mem::align_of::<T::Array>(),
1238 core::mem::align_of::<T>()
1239 );
1240 let mut values = ManuallyDrop::new(values);
1241
1242 let raw = values.as_mut_ptr();
1243 let length = values.len() * T::Array::LENGTH;
1244 let capacity = values.capacity() * T::Array::LENGTH;
1245
1246 // Safety: The requirements of implementing `ArrayCast`, as well as the size
1247 // and alignment asserts, ensures that reading `T` as `T::Array` is safe.
1248 // The length and capacity are multiplied by the array length.
1249 unsafe { Vec::from_raw_parts(raw.cast::<<T::Array as ArrayExt>::Item>(), length, capacity) }
1250}
1251
1252/// Cast from a `Vec` of arrays to a `Vec` of colors.
1253///
1254/// ```
1255/// use palette::{cast, Srgb};
1256///
1257/// let arrays = vec![[64, 139, 10], [93, 18, 214]];
1258/// assert_eq!(
1259/// cast::from_array_vec::<Srgb<u8>>(arrays),
1260/// vec![Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)]
1261/// )
1262/// ```
1263#[cfg(feature = "alloc")]
1264#[inline]
1265pub fn from_array_vec<T>(values: Vec<T::Array>) -> Vec<T>
1266where
1267 T: ArrayCast,
1268{
1269 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
1270 assert_eq!(
1271 core::mem::align_of::<T::Array>(),
1272 core::mem::align_of::<T>()
1273 );
1274 let mut values = ManuallyDrop::new(values);
1275
1276 let raw = values.as_mut_ptr();
1277
1278 // Safety: The requirements of implementing `ArrayCast`, as well as the size
1279 // and alignment asserts, ensures that reading `T::Array` as `T` is safe.
1280 // Length and capacity are the same because the size is the same.
1281 unsafe { Vec::from_raw_parts(raw.cast::<T>(), values.len(), values.capacity()) }
1282}
1283
1284/// The same as [`try_from_component_vec`] but panics on error.
1285///
1286/// ## Panics
1287///
1288/// The cast will panic if the length or capacity of the input `Vec` is not a
1289/// multiple of the color's array length.
1290///
1291/// ## Examples
1292///
1293/// ```
1294/// use palette::{cast, Srgb};
1295///
1296/// let components = vec![64, 139, 10, 93, 18, 214];
1297/// assert_eq!(
1298/// cast::from_component_vec::<Srgb<u8>>(components),
1299/// vec![Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)]
1300/// )
1301/// ```
1302///
1303/// This panics due to the incorrect length:
1304///
1305/// ```should_panic
1306/// use palette::{cast, Srgb};
1307///
1308/// // Not a multiple of 3:
1309/// let components = vec![64, 139, 10, 93, 18, 214, 0, 123];
1310/// cast::from_component_vec::<Srgb<u8>>(components);
1311/// ```
1312///
1313/// This panics due to the incorrect capacity:
1314///
1315/// ```should_panic
1316/// use palette::{cast, Srgb};
1317///
1318/// let mut components = vec![64, 139, 10, 93, 18, 214];
1319/// components.reserve_exact(2); // Not a multiple of 3
1320/// cast::from_component_vec::<Srgb<u8>>(components);
1321/// ```
1322#[cfg(feature = "alloc")]
1323#[inline]
1324pub fn from_component_vec<T>(values: Vec<<T::Array as ArrayExt>::Item>) -> Vec<T>
1325where
1326 T: ArrayCast,
1327{
1328 try_from_component_vec(values).unwrap()
1329}
1330
1331/// Cast from a `Vec` of color components to a `Vec` of colors.
1332///
1333/// ## Errors
1334///
1335/// The cast will return an error if the length or capacity of the input `Vec`
1336/// is not a multiple of the color's array length.
1337///
1338/// ## Examples
1339///
1340/// ```
1341/// use palette::{cast, Srgb};
1342///
1343/// let components = vec![64, 139, 10, 93, 18, 214];
1344/// assert_eq!(
1345/// cast::try_from_component_vec::<Srgb<u8>>(components),
1346/// Ok(vec![Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)])
1347/// )
1348/// ```
1349///
1350/// This produces an error due to the incorrect length:
1351///
1352/// ```
1353/// use palette::{cast, Srgb};
1354///
1355/// // Not a multiple of 3:
1356/// let components = vec![64, 139, 10, 93, 18];
1357///
1358/// if let Err(error) = cast::try_from_component_vec::<Srgb<u8>>(components) {
1359/// // We get the original values back on error:
1360/// assert_eq!(error.values, vec![64, 139, 10, 93, 18]);
1361/// } else {
1362/// unreachable!();
1363/// }
1364/// ```
1365///
1366/// This produces an error due to the incorrect capacity:
1367///
1368/// ```
1369/// use palette::{cast, Srgb};
1370///
1371/// let mut components = vec![64, 139, 10, 93, 18, 214];
1372/// components.reserve_exact(2); // Not a multiple of 3
1373///
1374/// if let Err(error) = cast::try_from_component_vec::<Srgb<u8>>(components) {
1375/// // We get the original values back on error:
1376/// assert_eq!(error.values, vec![64, 139, 10, 93, 18, 214]);
1377/// assert_eq!(error.values.capacity(), 8);
1378/// } else {
1379/// unreachable!();
1380/// }
1381/// ```
1382#[cfg(feature = "alloc")]
1383#[inline]
1384pub fn try_from_component_vec<T>(
1385 values: Vec<<T::Array as ArrayExt>::Item>,
1386) -> Result<Vec<T>, VecCastError<<T::Array as ArrayExt>::Item>>
1387where
1388 T: ArrayCast,
1389{
1390 assert_eq!(core::mem::size_of::<T::Array>(), core::mem::size_of::<T>());
1391 assert_eq!(
1392 core::mem::align_of::<T::Array>(),
1393 core::mem::align_of::<T>()
1394 );
1395
1396 if values.len() % T::Array::LENGTH != 0 {
1397 return Err(VecCastError {
1398 values,
1399 kind: VecCastErrorKind::LengthMismatch,
1400 });
1401 }
1402
1403 if values.capacity() % T::Array::LENGTH != 0 {
1404 return Err(VecCastError {
1405 values,
1406 kind: VecCastErrorKind::CapacityMismatch,
1407 });
1408 }
1409
1410 let mut values = ManuallyDrop::new(values);
1411
1412 let raw = values.as_mut_ptr();
1413 let length = values.len() / T::Array::LENGTH;
1414 let capacity = values.capacity() / T::Array::LENGTH;
1415
1416 // Safety: The requirements of implementing `ArrayCast`, as well as the size
1417 // and alignment asserts, ensures that reading `T` as `T::Array` is safe.
1418 // The length and capacity are multiplies of the array length.
1419 unsafe { Ok(Vec::from_raw_parts(raw.cast::<T>(), length, capacity)) }
1420}
1421
1422/// Map values of color A to values of color B without creating a new `Vec`.
1423///
1424/// This uses the guarantees of [`ArrayCast`] to reuse the allocation.
1425#[cfg(feature = "alloc")]
1426#[inline]
1427pub fn map_vec_in_place<A, B, F>(values: Vec<A>, mut map: F) -> Vec<B>
1428where
1429 A: ArrayCast,
1430 B: ArrayCast<Array = A::Array>,
1431 F: FnMut(A) -> B,
1432{
1433 // We are checking `B` in advance, to stop the program before any work is
1434 // done. `A` is checked when converting to arrays.
1435 assert_eq!(core::mem::size_of::<B::Array>(), core::mem::size_of::<B>());
1436 assert_eq!(
1437 core::mem::align_of::<B::Array>(),
1438 core::mem::align_of::<B>()
1439 );
1440
1441 let mut values = ManuallyDrop::new(into_array_vec(values));
1442
1443 for item in &mut *values {
1444 // Safety: We will put a new value back below, and `values` will not be dropped on panic.
1445 let input = unsafe { core::ptr::read(item) };
1446
1447 let output = into_array::<B>(map(from_array::<A>(input)));
1448
1449 // Safety: `output` is derived from the original value, so this is putting it back into place.
1450 unsafe { core::ptr::write(item, output) };
1451 }
1452
1453 from_array_vec(ManuallyDrop::into_inner(values))
1454}
1455
1456/// Map values of color A to values of color B without creating a new `Box<[B]>`.
1457///
1458/// This uses the guarantees of [`ArrayCast`] to reuse the allocation.
1459#[cfg(feature = "alloc")]
1460#[inline]
1461pub fn map_slice_box_in_place<A, B, F>(values: Box<[A]>, mut map: F) -> Box<[B]>
1462where
1463 A: ArrayCast,
1464 B: ArrayCast<Array = A::Array>,
1465 F: FnMut(A) -> B,
1466{
1467 // We are checking `B` in advance, to stop the program before any work is
1468 // done. `A` is checked when converting to arrays.
1469 assert_eq!(core::mem::size_of::<B::Array>(), core::mem::size_of::<B>());
1470 assert_eq!(
1471 core::mem::align_of::<B::Array>(),
1472 core::mem::align_of::<B>()
1473 );
1474
1475 let mut values = ManuallyDrop::new(into_array_slice_box(values));
1476
1477 for item in &mut **values {
1478 // Safety: We will put a new value back below, and `values` will not be dropped on panic.
1479 let input = unsafe { core::ptr::read(item) };
1480
1481 let output = into_array::<B>(map(from_array::<A>(input)));
1482
1483 // Safety: `output` is derived from the original value, so this is putting it back into place.
1484 unsafe { core::ptr::write(item, output) };
1485 }
1486
1487 from_array_slice_box(ManuallyDrop::into_inner(values))
1488}
1489
1490/// The error type returned when casting a slice of components fails.
1491#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1492pub struct SliceCastError;
1493
1494impl core::fmt::Display for SliceCastError {
1495 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1496 f.write_str("could not convert component slice to colors")
1497 }
1498}
1499
1500#[cfg(feature = "std")]
1501impl std::error::Error for SliceCastError {}
1502
1503/// The error type returned when casting a boxed slice of components fails.
1504#[derive(Clone, PartialEq, Eq)]
1505#[cfg(feature = "alloc")]
1506pub struct BoxedSliceCastError<T> {
1507 /// The original values.
1508 pub values: Box<[T]>,
1509}
1510
1511#[cfg(feature = "alloc")]
1512impl<T> core::fmt::Debug for BoxedSliceCastError<T> {
1513 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1514 f.debug_struct("BoxedSliceCastError").finish()
1515 }
1516}
1517
1518#[cfg(feature = "alloc")]
1519impl<T> core::fmt::Display for BoxedSliceCastError<T> {
1520 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1521 f.write_str("could not convert boxed component slice to colors")
1522 }
1523}
1524
1525#[cfg(feature = "std")]
1526impl<T> std::error::Error for BoxedSliceCastError<T> {}
1527
1528/// The error type returned when casting a `Vec` of components fails.
1529#[derive(Clone, PartialEq, Eq)]
1530#[cfg(feature = "alloc")]
1531pub struct VecCastError<T> {
1532 /// The type of error that occurred.
1533 pub kind: VecCastErrorKind,
1534
1535 /// The original values.
1536 pub values: Vec<T>,
1537}
1538
1539#[cfg(feature = "alloc")]
1540impl<T> core::fmt::Debug for VecCastError<T> {
1541 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1542 f.debug_struct("VecCastError")
1543 .field("kind", &self.kind)
1544 .finish()
1545 }
1546}
1547
1548#[cfg(feature = "alloc")]
1549impl<T> core::fmt::Display for VecCastError<T> {
1550 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1551 f.write_str("could not convert component vector to colors")
1552 }
1553}
1554
1555#[cfg(feature = "std")]
1556impl<T> std::error::Error for VecCastError<T> {}
1557
1558/// The type of error that is returned when casting a `Vec` of components.
1559#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1560#[cfg(feature = "alloc")]
1561pub enum VecCastErrorKind {
1562 /// The type of error returned when the length of a `Vec` didn't match the
1563 /// requirements.
1564 LengthMismatch,
1565
1566 /// The type of error returned when the capacity of a `Vec` didn't match the
1567 /// requirements.
1568 CapacityMismatch,
1569}
1570
1571#[cfg(test)]
1572mod test {
1573 #[cfg(feature = "alloc")]
1574 use crate::{LinSrgb, Srgb};
1575
1576 #[cfg(feature = "alloc")]
1577 #[test]
1578 fn array_vec_len_cap() {
1579 let mut original = vec![
1580 Srgb::new(255u8, 0, 0),
1581 Srgb::new(0, 255, 0),
1582 Srgb::new(0, 0, 255),
1583 ];
1584 original.reserve_exact(5); // Bringing it to 8
1585
1586 let colors_arrays = super::into_array_vec(original);
1587 assert_eq!(colors_arrays.len(), 3);
1588 assert_eq!(colors_arrays.capacity(), 8);
1589
1590 let colors = super::from_array_vec::<Srgb<_>>(colors_arrays);
1591 assert_eq!(colors.len(), 3);
1592 assert_eq!(colors.capacity(), 8);
1593
1594 let colors_components = super::into_component_vec(colors);
1595 assert_eq!(colors_components.len(), 9);
1596 assert_eq!(colors_components.capacity(), 24);
1597
1598 let colors = super::from_component_vec::<Srgb<_>>(colors_components);
1599 assert_eq!(colors.len(), 3);
1600 assert_eq!(colors.capacity(), 8);
1601 }
1602
1603 #[cfg(feature = "alloc")]
1604 #[test]
1605 fn map_vec_in_place() {
1606 fn do_things(rgb: Srgb) -> LinSrgb {
1607 let mut linear = rgb.into_linear();
1608 core::mem::swap(&mut linear.red, &mut linear.blue);
1609 linear
1610 }
1611
1612 let values = vec![Srgb::new(0.8, 1.0, 0.2), Srgb::new(0.9, 0.1, 0.3)];
1613 let result = super::map_vec_in_place(values, do_things);
1614 assert_eq!(
1615 result,
1616 vec![
1617 do_things(Srgb::new(0.8, 1.0, 0.2)),
1618 do_things(Srgb::new(0.9, 0.1, 0.3))
1619 ]
1620 )
1621 }
1622
1623 #[cfg(feature = "alloc")]
1624 #[test]
1625 fn map_slice_box_in_place() {
1626 fn do_things(rgb: Srgb) -> LinSrgb {
1627 let mut linear = rgb.into_linear();
1628 core::mem::swap(&mut linear.red, &mut linear.blue);
1629 linear
1630 }
1631
1632 let values = vec![Srgb::new(0.8, 1.0, 0.2), Srgb::new(0.9, 0.1, 0.3)].into_boxed_slice();
1633 let result = super::map_slice_box_in_place(values, do_things);
1634 assert_eq!(
1635 result,
1636 vec![
1637 do_things(Srgb::new(0.8, 1.0, 0.2)),
1638 do_things(Srgb::new(0.9, 0.1, 0.3))
1639 ]
1640 .into_boxed_slice()
1641 )
1642 }
1643}