Skip to content

Commit

Permalink
Merge #229
Browse files Browse the repository at this point in the history
229: Implement `bytemuck::Zeroable` and `bytemuck::Pod` for every color type r=Ogeon a=gymore-io

I'm working on an experimental creative framework for Rust and I wanted to use one of `palette` types in a uniform buffer. This can be easily done through unsafe code but I think it is much cleaner to use the [`bytemuck`](https://crates.io/crates/bytemuck) crate which provide the [`Zeroable`] and [`Pod`] traits to convert types from and to raw bytes.

This pull request implements those traits for the color types defined in this crate.

# Changes

I did the whole pull request in a single commit, implementing the traits for the following types.

* `Rgb<S, T>` where `T` is `Pod`/`Zeroable`
* `Luma<S, T>` where `T` is `Pod`/`Zeroable`
* `Hsl<S, T>` where `T` is `Pod`/`Zeroable`
* `Hsluv<Wp, T>` where `T` is `Pod`/`Zeroable`
* `Hsv<S, T>` where `T` is `Pod`/`Zeroable`
* `Hwb<S, T>` where `T` is `Pod`/`Zeroable`
* `Lab<Wp, T>` where `T` is `Pod`/`Zeroable`
* `Lch<Wp, T>` where `T` is `Pod`/`Zeroable`
* `Lchuv<Wp, T>` where `T` is `Pod`/`Zeroable`
* `Xyz<Wp, T>` where `T` is `Pod`/`Zeroable`
* `Yxy<Wp, T>` where `T` is `Pod`/`Zeroable`

* `Alpha<C, T>` where `C` and `T` are `Zeroable`

* `Alpha<C<T>, T>` where `C<T>` is a color that is `Pod` and `T` is `Pod`
  eg. `Alpha<Rgb<T>, T>` is `Pod` if `T` is `Pod`

I also implemented `Zeroable` and `Pod` for the [`Packed<C>`](https://ogeon.github.io/docs/palette/master/palette/struct.Packed.html) rgba struct. This required to make it implement `Copy` regardless of whether `C` was `Copy`.

# Note

I really expect this change to be used with the `Rgba` / `Rgb` types, but I made the change for every color type for consistency.

[`Pod`]: https://docs.rs/bytemuck/1.5.1/bytemuck/trait.Pod.html
[`Zeroable`]: https://docs.rs/bytemuck/1.5.1/bytemuck/trait.Zeroable.html

Co-authored-by: Gymore <gymore.contact@gmail.com>
Co-authored-by: Erik Hedvall <Ogeon@users.noreply.github.com>
  • Loading branch information
3 people authored May 29, 2021
2 parents dcab2a7 + ddcc134 commit 0893b39
Show file tree
Hide file tree
Showing 17 changed files with 254 additions and 1 deletion.
4 changes: 4 additions & 0 deletions palette/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ version = "1"
features = ["serde_derive"]
optional = true

[dependencies.bytemuck]
version = "1"
optional = true

[dev-dependencies]
csv = "1"
lazy_static = "1"
Expand Down
21 changes: 21 additions & 0 deletions palette/src/alpha/alpha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,27 @@ where
}
}

#[cfg(feature = "bytemuck")]
unsafe impl<C, T> bytemuck::Zeroable for Alpha<C, T>
where
C: bytemuck::Zeroable,
T: bytemuck::Zeroable,
{
}

// Safety:
// It is a requirement of `Pixel<T>` that the in-memory representation of
// `C` is made of `T`s.
// Because `T` is `Pod`, `Alpha<C, T>` is `Pod` as well because no internal
// padding can be introduced during monomorphization.
#[cfg(feature = "bytemuck")]
unsafe impl<C, T> bytemuck::Pod for Alpha<C, T>
where
T: bytemuck::Pod,
C: bytemuck::Pod + Pixel<T>,
{
}

#[cfg(test)]
mod test {
use crate::encoding::Srgb;
Expand Down
18 changes: 18 additions & 0 deletions palette/src/blend/pre_alpha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,24 @@ impl<C, T: Float> DerefMut for PreAlpha<C, T> {
}
}

#[cfg(feature = "bytemuck")]
unsafe impl<C, T> bytemuck::Zeroable for PreAlpha<C, T>
where
C: bytemuck::Zeroable,
T: Float + bytemuck::Zeroable,
{
}

// Safety:
// See `Alpha<C, T>`'s implementation of `Pod`.
#[cfg(feature = "bytemuck")]
unsafe impl<C, T> bytemuck::Pod for PreAlpha<C, T>
where
C: bytemuck::Pod + Pixel<T>,
T: Float + bytemuck::Pod,
{
}

#[cfg(test)]
#[cfg(feature = "serializing")]
mod test {
Expand Down
16 changes: 16 additions & 0 deletions palette/src/hsl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,22 @@ where
}
}

#[cfg(feature = "bytemuck")]
unsafe impl<S, T> bytemuck::Zeroable for Hsl<S, T>
where
S: RgbStandard,
T: FloatComponent + bytemuck::Zeroable,
{
}

#[cfg(feature = "bytemuck")]
unsafe impl<S, T> bytemuck::Pod for Hsl<S, T>
where
S: RgbStandard,
T: FloatComponent + bytemuck::Pod,
{
}

#[cfg(test)]
mod test {
use super::Hsl;
Expand Down
16 changes: 16 additions & 0 deletions palette/src/hsluv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,22 @@ where
}
}

#[cfg(feature = "bytemuck")]
unsafe impl<Wp, T> bytemuck::Zeroable for Hsluv<Wp, T>
where
Wp: WhitePoint,
T: FloatComponent + bytemuck::Zeroable,
{
}

#[cfg(feature = "bytemuck")]
unsafe impl<Wp, T> bytemuck::Pod for Hsluv<Wp, T>
where
Wp: WhitePoint,
T: FloatComponent + bytemuck::Pod,
{
}

#[cfg(test)]
mod test {
use super::Hsluv;
Expand Down
16 changes: 16 additions & 0 deletions palette/src/hsv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,22 @@ where
}
}

#[cfg(feature = "bytemuck")]
unsafe impl<S, T> bytemuck::Zeroable for Hsv<S, T>
where
S: RgbStandard,
T: FloatComponent + bytemuck::Zeroable,
{
}

#[cfg(feature = "bytemuck")]
unsafe impl<S, T> bytemuck::Pod for Hsv<S, T>
where
S: RgbStandard,
T: FloatComponent + bytemuck::Pod,
{
}

#[cfg(test)]
mod test {
use super::Hsv;
Expand Down
5 changes: 5 additions & 0 deletions palette/src/hues.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,11 @@ macro_rules! make_hues {
$name(rng.gen() * from_f64(360.0))
}
}

#[cfg(feature = "bytemuck")]
unsafe impl<T: Float + bytemuck::Zeroable> bytemuck::Zeroable for $name<T> {}
#[cfg(feature = "bytemuck")]
unsafe impl<T: Float + bytemuck::Pod> bytemuck::Pod for $name<T> {}
)+)
}

Expand Down
16 changes: 16 additions & 0 deletions palette/src/hwb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,22 @@ where
}
}

#[cfg(feature = "bytemuck")]
unsafe impl<S, T> bytemuck::Zeroable for Hwb<S, T>
where
S: RgbStandard,
T: FloatComponent + bytemuck::Zeroable,
{
}

#[cfg(feature = "bytemuck")]
unsafe impl<S, T> bytemuck::Pod for Hwb<S, T>
where
S: RgbStandard,
T: FloatComponent + bytemuck::Pod,
{
}

#[cfg(test)]
mod test {
use super::Hwb;
Expand Down
16 changes: 16 additions & 0 deletions palette/src/lab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,22 @@ where
}
}

#[cfg(feature = "bytemuck")]
unsafe impl<Wp, T> bytemuck::Zeroable for Lab<Wp, T>
where
Wp: WhitePoint,
T: FloatComponent + bytemuck::Zeroable,
{
}

#[cfg(feature = "bytemuck")]
unsafe impl<Wp, T> bytemuck::Pod for Lab<Wp, T>
where
Wp: WhitePoint,
T: FloatComponent + bytemuck::Pod,
{
}

#[cfg(test)]
mod test {
use super::Lab;
Expand Down
16 changes: 16 additions & 0 deletions palette/src/lch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,22 @@ where
}
}

#[cfg(feature = "bytemuck")]
unsafe impl<Wp, T> bytemuck::Zeroable for Lch<Wp, T>
where
Wp: WhitePoint,
T: FloatComponent + bytemuck::Zeroable,
{
}

#[cfg(feature = "bytemuck")]
unsafe impl<Wp, T> bytemuck::Pod for Lch<Wp, T>
where
Wp: WhitePoint,
T: FloatComponent + bytemuck::Pod,
{
}

#[cfg(test)]
mod test {
use crate::white_point::D65;
Expand Down
16 changes: 16 additions & 0 deletions palette/src/lchuv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,22 @@ where
}
}

#[cfg(feature = "bytemuck")]
unsafe impl<Wp, T> bytemuck::Zeroable for Lchuv<Wp, T>
where
Wp: WhitePoint,
T: FloatComponent + bytemuck::Zeroable,
{
}

#[cfg(feature = "bytemuck")]
unsafe impl<Wp, T> bytemuck::Pod for Lchuv<Wp, T>
where
Wp: WhitePoint,
T: FloatComponent + bytemuck::Pod,
{
}

#[cfg(test)]
mod test {
use crate::white_point::D65;
Expand Down
16 changes: 16 additions & 0 deletions palette/src/luma/luma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,22 @@ where
}
}

#[cfg(feature = "bytemuck")]
unsafe impl<S, T> bytemuck::Zeroable for Luma<S, T>
where
S: LumaStandard,
T: Component + bytemuck::Zeroable,
{
}

#[cfg(feature = "bytemuck")]
unsafe impl<S, T> bytemuck::Pod for Luma<S, T>
where
S: LumaStandard,
T: Component + bytemuck::Pod,
{
}

#[cfg(test)]
mod test {
use crate::encoding::Srgb;
Expand Down
16 changes: 16 additions & 0 deletions palette/src/luv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,22 @@ where
}
}

#[cfg(feature = "bytemuck")]
unsafe impl<Wp, T> bytemuck::Zeroable for Luv<Wp, T>
where
Wp: WhitePoint,
T: FloatComponent + bytemuck::Zeroable,
{
}

#[cfg(feature = "bytemuck")]
unsafe impl<Wp, T> bytemuck::Pod for Luv<Wp, T>
where
Wp: WhitePoint,
T: FloatComponent + bytemuck::Pod,
{
}

#[cfg(test)]
mod test {
use super::Luv;
Expand Down
15 changes: 14 additions & 1 deletion palette/src/rgb/packed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ use crate::Pixel;
/// assert_eq!(colors[0].color, 0x7F0080);
/// assert_eq!(colors[1].color, 0x60BBCC);
/// ```
#[derive(Copy, Clone, Debug, PartialEq, Eq, Pixel)]
#[derive(Debug, PartialEq, Eq, Pixel)]
#[palette(palette_internal)]
#[repr(C)]
pub struct Packed<C = channels::Argb> {
Expand All @@ -72,6 +72,14 @@ pub struct Packed<C = channels::Argb> {
pub channel_order: PhantomData<C>,
}

impl<C> Copy for Packed<C> {}

impl<C> Clone for Packed<C> {
fn clone(&self) -> Self {
*self
}
}

/// Splits and combines RGB(A) types with some channel ordering. Channels may be
/// ordered as `Abgr`, `Argb`, `Bgra`, or `Rgba`.
pub trait RgbChannels {
Expand Down Expand Up @@ -159,6 +167,11 @@ where
}
}

#[cfg(feature = "bytemuck")]
unsafe impl<C> bytemuck::Zeroable for Packed<C> {}
#[cfg(feature = "bytemuck")]
unsafe impl<C: 'static> bytemuck::Pod for Packed<C> {}

#[cfg(test)]
mod test {
use crate::rgb::packed::channels::{Abgr, Argb, Bgra, Rgba};
Expand Down
16 changes: 16 additions & 0 deletions palette/src/rgb/rgb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,22 @@ where
}
}

#[cfg(feature = "bytemuck")]
unsafe impl<S, T> bytemuck::Zeroable for Rgb<S, T>
where
S: RgbStandard,
T: Component + bytemuck::Zeroable,
{
}

#[cfg(feature = "bytemuck")]
unsafe impl<S, T> bytemuck::Pod for Rgb<S, T>
where
S: RgbStandard,
T: Component + bytemuck::Pod,
{
}

#[cfg(test)]
mod test {
use core::str::FromStr;
Expand Down
16 changes: 16 additions & 0 deletions palette/src/xyz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,22 @@ where
}
}

#[cfg(feature = "bytemuck")]
unsafe impl<Wp, T> bytemuck::Zeroable for Xyz<Wp, T>
where
Wp: WhitePoint,
T: FloatComponent + bytemuck::Zeroable,
{
}

#[cfg(feature = "bytemuck")]
unsafe impl<Wp, T> bytemuck::Pod for Xyz<Wp, T>
where
Wp: WhitePoint,
T: FloatComponent + bytemuck::Pod,
{
}

#[cfg(test)]
mod test {
use super::Xyz;
Expand Down
16 changes: 16 additions & 0 deletions palette/src/yxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,22 @@ where
}
}

#[cfg(feature = "bytemuck")]
unsafe impl<Wp, T> bytemuck::Zeroable for Yxy<Wp, T>
where
Wp: WhitePoint,
T: FloatComponent + bytemuck::Zeroable,
{
}

#[cfg(feature = "bytemuck")]
unsafe impl<Wp, T> bytemuck::Pod for Yxy<Wp, T>
where
Wp: WhitePoint,
T: FloatComponent + bytemuck::Pod,
{
}

#[cfg(test)]
mod test {
use super::Yxy;
Expand Down

0 comments on commit 0893b39

Please sign in to comment.