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}