palette::cast

Trait ArrayCast

source
pub unsafe trait ArrayCast: Sized {
    type Array: ArrayExt;
}
Expand description

Marker trait for types that can be represented as a fixed size array.

A type that implements this trait is assumed to have the exact same memory layout and representation as a fixed size array. This implies a couple of useful properties:

  • Casting between T and T::Array is free and will (or should) be optimized away.
  • [T] can be cast to and from [T::Array], which can be cast to and from [U] where T::Array = [U; N] and the length is a multiple of N.

This allows a number of common and useful optimizations, including casting buffers and reusing memory. It does however come with some strict requirements and the recommendation is to use #[derive(ArrayCast)] which checks for them automatically.

§Deriving

ArrayCast can be automatically derived. The only requirements are that the type is a struct, that it has a #[repr(C)] or #[repr(transparent)] attribute, and that all of its fields have the same types. It stays on the conservative side and will show an error if any of those requirements are not fulfilled. If some fields have different types, but the same memory layout, or are zero-sized, they can be marked with attributes to show that their types are safe to use.

§Field Attributes

  • #[palette_unsafe_same_layout_as = "SomeType"]: Mark the field as having the same memory layout as SomeType.

    Safety: corrupt data and undefined behavior may occur if this is not true!

  • #[palette_unsafe_zero_sized]: Mark the field as being zero-sized, and thus not taking up any memory space. This means that it can be ignored.

    Safety: corrupt data and undefined behavior may occur if this is not true!

§Examples

Basic use:

use palette::cast::{self, ArrayCast};

#[derive(PartialEq, Debug, ArrayCast)]
#[repr(C)]
struct MyCmyk {
    cyan: f32,
    magenta: f32,
    yellow: f32,
    key: f32,
}

let buffer = [0.1, 0.2, 0.3, 0.4];
let color: MyCmyk = cast::from_array(buffer);

assert_eq!(
    color,
    MyCmyk {
        cyan: 0.1,
        magenta: 0.2,
        yellow: 0.3,
        key: 0.4,
    }
);

Heterogenous field types:

use std::marker::PhantomData;

use palette::{cast::{self, ArrayCast}, encoding::Srgb, RgbHue};

#[derive(PartialEq, Debug, ArrayCast)]
#[repr(C)]
struct MyCoolColor<S> {
    #[palette(unsafe_zero_sized)]
    standard: PhantomData<S>,
    // RgbHue is a wrapper with `#[repr(C)]`, so it can safely
    // be converted straight from `f32`.
    #[palette(unsafe_same_layout_as = "f32")]
    hue: RgbHue<f32>,
    lumen: f32,
    chroma: f32,
}

let buffer = [172.0, 100.0, 0.3];
let color: MyCoolColor<Srgb> = cast::from_array(buffer);

assert_eq!(
    color,
    MyCoolColor {
        hue: 172.0.into(),
        lumen: 100.0,
        chroma: 0.3,
        standard: PhantomData,
    }
);

§Safety

  • The type must be inhabited (eg: no Infallible).
  • The type must allow any values in the array items (eg: either no requirements or some ability to recover from invalid values).
  • The type must be homogeneous (eg: all fields have the same type, or are wrappers that implement ArrayCast with the same field type, or are zero sized).
  • The length of Array must be the sum of the number of color component fields in the type and in any possible compound fields.
  • The type must be repr(C) or repr(transparent).
  • The type must have the same size and alignment as Self::Array.

Note also that the type is assumed to not implement Drop. This will rarely, if ever, be an issue. The requirements above ensures that the underlying field types stay the same and will be dropped.

For example:

  • Srgb<T> can be cast to [T; 3] because it has three non-zero sized fields of type T.
  • Alpha<Srgb<T>, T> can be cast to [T; 4], that is 3 + 1 items, because it’s the sum of the three items from Srgb and the one extra alpha field.
  • Alpha<Srgb<T>, U> is not allowed because T and U are different types.

Required Associated Types§

source

type Array: ArrayExt

The output type of a cast to an array.

Object Safety§

This trait is not object safe.

Implementors§

source§

impl<C> ArrayCast for Alpha<C, <<C as ArrayCast>::Array as ArrayExt>::Item>
where C: ArrayCast, C::Array: NextArray,

source§

impl<C, T> ArrayCast for PreAlpha<C>
where C: ArrayCast + Premultiply<Scalar = T>, C::Array: NextArray + ArrayExt<Item = T>,

source§

impl<O, T, const N: usize> ArrayCast for Packed<O, [T; N]>

source§

impl<S, T> ArrayCast for Luma<S, T>

source§

impl<S, T> ArrayCast for Rgb<S, T>

source§

impl<S, T> ArrayCast for Hsl<S, T>

source§

impl<S, T> ArrayCast for Hsv<S, T>

source§

impl<S, T> ArrayCast for Hwb<S, T>

source§

impl<T> ArrayCast for Cam16Jch<T>

source§

impl<T> ArrayCast for Cam16Jmh<T>

source§

impl<T> ArrayCast for Cam16Jsh<T>

source§

impl<T> ArrayCast for Cam16Qch<T>

source§

impl<T> ArrayCast for Cam16Qmh<T>

source§

impl<T> ArrayCast for Cam16Qsh<T>

source§

impl<T> ArrayCast for Cam16UcsJab<T>

source§

impl<T> ArrayCast for Cam16UcsJmh<T>

source§

impl<T> ArrayCast for Okhsl<T>

source§

impl<T> ArrayCast for Okhsv<T>

source§

impl<T> ArrayCast for Okhwb<T>

source§

impl<T> ArrayCast for Oklab<T>

source§

impl<T> ArrayCast for Oklch<T>

source§

impl<Wp, T> ArrayCast for Hsluv<Wp, T>

source§

impl<Wp, T> ArrayCast for Lab<Wp, T>

source§

impl<Wp, T> ArrayCast for Lch<Wp, T>

source§

impl<Wp, T> ArrayCast for Lchuv<Wp, T>

source§

impl<Wp, T> ArrayCast for Luv<Wp, T>

source§

impl<Wp, T> ArrayCast for Xyz<Wp, T>

source§

impl<Wp, T> ArrayCast for Yxy<Wp, T>