diff --git a/Cargo.toml b/Cargo.toml index 8952104..a13a9dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ readme = "crates-io.md" [dependencies] bytecheck = { version = "~0.6.7", optional = true, default-features = false } +bytemuck = { version = "^1.4.0", optional = true, features = ["derive"], default-features = false } [features] default = ["std"] diff --git a/src/impl_bytemuck.rs b/src/impl_bytemuck.rs new file mode 100644 index 0000000..10fcd9a --- /dev/null +++ b/src/impl_bytemuck.rs @@ -0,0 +1,63 @@ +// implementations of bytemuck Zeroable and Pod traits for BigEndian and LittleEndian variants of +// types which are themselves Zeroable and Pod. This enables use of bytemuck::cast* methods to +// safely transmute to and from these types. + +use bytemuck::{Zeroable, Pod}; +use crate::{Primitive, BigEndian, LittleEndian}; + +// SAFETY: T and T::Storage is Zeroable and Pod. LittleEndian is repr(transparent) +// this satisfies the safety contracts of Zeroable and Pod. +#[cfg(feature = "bytemuck")] +unsafe impl Zeroable for LittleEndian +where T: Primitive + Zeroable, + T::Storage: Zeroable {} +#[cfg(feature = "bytemuck")] +unsafe impl Pod for LittleEndian +where T: Primitive + Pod + Copy + 'static, + T::Storage: Pod {} + + +// SAFETY: T and T::Storage is Zeroable and Pod. BigEndian is repr(transparent) +// this satisfies the safety contracts of Zeroable and Pod. +#[cfg(feature = "bytemuck")] +unsafe impl Zeroable for BigEndian +where T: Primitive + Zeroable, + T::Storage: Zeroable {} +#[cfg(feature = "bytemuck")] +unsafe impl Pod for BigEndian +where T: Primitive + Pod + Copy + 'static, + T::Storage: Pod {} + +#[cfg(test)] +mod tests { + use crate::*; + use bytemuck::Pod; + + #[test] + fn check_impl_pod() { + fn assert_impl_pod() {} + + assert_impl_pod::(); + assert_impl_pod::(); + assert_impl_pod::(); + assert_impl_pod::(); + assert_impl_pod::(); + assert_impl_pod::(); + + assert_impl_pod::(); + assert_impl_pod::(); + assert_impl_pod::(); + assert_impl_pod::(); + assert_impl_pod::(); + assert_impl_pod::(); + + assert_impl_pod::(); + assert_impl_pod::(); + assert_impl_pod::(); + assert_impl_pod::(); + + // char is not Pod, so these types shouldn't be either + //assert_impl_pod::(); + //assert_impl_pod::(); + } +} diff --git a/src/lib.rs b/src/lib.rs index c8356fe..707aa03 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,6 +69,8 @@ mod impl_traits; #[cfg(feature = "validation")] #[macro_use] mod impl_validation; +#[cfg(feature = "bytemuck")] +mod impl_bytemuck; #[cfg(feature = "validation")] use bytecheck::{CharCheckError, CheckBytes, NonZeroCheckError}; @@ -98,6 +100,7 @@ pub unsafe trait Primitive { /// This is mostly useful for `const` conversions to big- and little-endian types in contexts where /// type inference is required. Because it's native-endian, the inner value is publicly exposed. #[derive(Clone, Copy)] +#[cfg_attr(feature = "bytemuck", derive(bytemuck::Zeroable, bytemuck::Pod))] #[repr(transparent)] pub struct NativeEndian { /// The value of the type