From 2691083fa864200830bf9dce7fc890f594e3e402 Mon Sep 17 00:00:00 2001 From: Kornel Date: Sun, 14 Jun 2020 13:26:38 +0100 Subject: [PATCH] Use Plain trait for ComponentBytes soundness --- Cargo.toml | 1 + src/alt.rs | 8 ++++++-- src/internal/pixel.rs | 13 ++++++++++++- src/internal/rgb.rs | 6 +++++- src/internal/rgba.rs | 12 +++++++++++- src/lib.rs | 6 ++++++ 6 files changed, 41 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index eeb20cc..5099b22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ travis-ci = { repository = "kornelski/rust-rgb" } [dependencies] serde = { version = "1.0", optional = true, features = ["derive"] } +plain = "0.2.3" [dev-dependencies] serde_json = "1.0" diff --git a/src/alt.rs b/src/alt.rs index 34e0dd5..a585f2c 100644 --- a/src/alt.rs +++ b/src/alt.rs @@ -1,3 +1,4 @@ +use plain::Plain; use crate::internal::pixel::*; use core::mem; use core::ops; @@ -113,6 +114,9 @@ pub struct GrayAlpha( pub AlphaComponentType, ); +unsafe impl Plain for Gray where T: Plain {} +unsafe impl Plain for GrayAlpha where T: Plain, A: Plain {} + /// 8-bit gray pub type GRAY8 = Gray; @@ -219,7 +223,7 @@ impl ComponentSlice for [GrayAlpha] { } } -impl ComponentBytes for [GrayAlpha] {} +impl ComponentBytes for [GrayAlpha] {} impl ComponentSlice for Gray { #[inline(always)] @@ -252,7 +256,7 @@ impl ComponentSlice for [Gray] { } } -impl ComponentBytes for [Gray] {} +impl ComponentBytes for [Gray] {} /// Assumes 255 is opaque impl From> for GrayAlpha { diff --git a/src/internal/pixel.rs b/src/internal/pixel.rs index 143dc1c..6b052c5 100644 --- a/src/internal/pixel.rs +++ b/src/internal/pixel.rs @@ -1,3 +1,4 @@ +use plain::Plain; use core; /// Casting the struct to slices of its components @@ -14,7 +15,17 @@ pub trait ComponentSlice { } /// Casting a slice of `RGB/A` values to a slice of `u8` -pub trait ComponentBytes where Self: ComponentSlice { +/// +/// If instead of `RGB8` you use `RGB`, and you want to cast from/to that custom type, +/// implement the `Plain` trait for it: +/// +/// ```rust +/// # struct MyCustomType; +/// unsafe impl rgb::plain::Plain for MyCustomType {} +/// ``` +/// +/// Plain types are not allowed to contain struct padding, booleans, chars, enums, references or pointers. +pub trait ComponentBytes where Self: ComponentSlice { /// The components interpreted as raw bytes, in machine's native endian. In `RGB` bytes of the red component are first. #[inline] fn as_bytes(&self) -> &[u8] { diff --git a/src/internal/rgb.rs b/src/internal/rgb.rs index d74f42c..1ae9371 100644 --- a/src/internal/rgb.rs +++ b/src/internal/rgb.rs @@ -1,3 +1,4 @@ +use plain::Plain; use super::pixel::*; use crate::alt::BGR; use crate::alt::BGRA; @@ -25,6 +26,9 @@ impl BGR { } } +unsafe impl Plain for RGB where T: Plain {} +unsafe impl Plain for BGR where T: Plain {} + macro_rules! impl_rgb { ($RGB:ident, $RGBA:ident) => { impl $RGB { @@ -101,7 +105,7 @@ macro_rules! impl_rgb { } } - impl ComponentBytes for [$RGB] {} + impl ComponentBytes for [$RGB] {} } } diff --git a/src/internal/rgba.rs b/src/internal/rgba.rs index 77669ed..92d3b54 100644 --- a/src/internal/rgba.rs +++ b/src/internal/rgba.rs @@ -43,6 +43,9 @@ impl BGRA { } } +unsafe impl plain::Plain for RGBA where T: plain::Plain, A: plain::Plain {} +unsafe impl plain::Plain for BGRA where T: plain::Plain, A: plain::Plain {} + #[cfg(feature = "argb")] impl ARGB { #[inline(always)] @@ -87,6 +90,11 @@ impl ABGR { } } +#[cfg(feature = "argb")] +unsafe impl plain::Plain for ARGB where T: plain::Plain, A: plain::Plain {} +#[cfg(feature = "argb")] +unsafe impl plain::Plain for ABGR where T: plain::Plain, A: plain::Plain {} + macro_rules! impl_rgba { ($RGBA:ident) => { impl $RGBA { @@ -188,7 +196,7 @@ macro_rules! impl_rgba { } } - impl ComponentBytes for [$RGBA] {} + impl ComponentBytes for [$RGBA] {} } } @@ -364,6 +372,8 @@ fn abgr_test() { #[allow(deprecated)] fn bgra_test() { let neg = BGRA::new(1, 2, 3i32, 1000).map(|x| -x); + let _ = neg.as_slice(); + let _ = [neg].as_bytes(); assert_eq!(neg.r, -1); assert_eq!(neg.bgr().r, -1); assert_eq!(neg.g, -2); diff --git a/src/lib.rs b/src/lib.rs index 02dc6e1..3c3e5fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,6 +47,12 @@ mod internal { /// BGR might be useful for some Windows or OpenGL APIs. pub mod alt; +/// Re-export from `plain` crate +pub mod plain { + // wrapped in mod to prevent `use rgb::*` picking it + pub use plain::Plain; +} + pub use crate::internal::convert::*; pub use crate::internal::ops::*; pub use crate::internal::pixel::*;