| #![allow(dead_code)] | |
| use bytemuck::{ | |
| AnyBitPattern, CheckedBitPattern, Contiguous, NoUninit, Pod, | |
| TransparentWrapper, Zeroable, | |
| }; | |
| use std::marker::{PhantomData, PhantomPinned}; | |
| #[derive(Copy, Clone, Pod, Zeroable)] | |
| #[repr(C)] | |
| struct Test { | |
| a: u16, | |
| b: u16, | |
| } | |
| #[derive(Pod, Zeroable)] | |
| #[repr(C, packed)] | |
| struct GenericPackedStruct<T: Pod> { | |
| a: u32, | |
| b: T, | |
| c: u32, | |
| } | |
| impl<T: Pod> Clone for GenericPackedStruct<T> { | |
| fn clone(&self) -> Self { | |
| *self | |
| } | |
| } | |
| impl<T: Pod> Copy for GenericPackedStruct<T> {} | |
| #[derive(Pod, Zeroable)] | |
| #[repr(C, packed(1))] | |
| struct GenericPackedStructExplicitPackedAlignment<T: Pod> { | |
| a: u32, | |
| b: T, | |
| c: u32, | |
| } | |
| impl<T: Pod> Clone for GenericPackedStructExplicitPackedAlignment<T> { | |
| fn clone(&self) -> Self { | |
| *self | |
| } | |
| } | |
| impl<T: Pod> Copy for GenericPackedStructExplicitPackedAlignment<T> {} | |
| #[derive(Zeroable)] | |
| struct ZeroGeneric<T: bytemuck::Zeroable> { | |
| a: T, | |
| } | |
| #[derive(TransparentWrapper)] | |
| #[repr(transparent)] | |
| struct TransparentSingle { | |
| a: u16, | |
| } | |
| #[derive(TransparentWrapper)] | |
| #[repr(transparent)] | |
| #[transparent(u16)] | |
| struct TransparentWithZeroSized<T> { | |
| a: u16, | |
| b: PhantomData<T>, | |
| } | |
| struct MyZst<T>(PhantomData<T>, [u8; 0], PhantomPinned); | |
| unsafe impl<T> Zeroable for MyZst<T> {} | |
| #[derive(TransparentWrapper)] | |
| #[repr(transparent)] | |
| #[transparent(u16)] | |
| struct TransparentTupleWithCustomZeroSized<T>(u16, MyZst<T>); | |
| #[repr(u8)] | |
| #[derive(Clone, Copy, Contiguous)] | |
| enum ContiguousWithValues { | |
| A = 0, | |
| B = 1, | |
| C = 2, | |
| D = 3, | |
| E = 4, | |
| } | |
| #[repr(i8)] | |
| #[derive(Clone, Copy, Contiguous)] | |
| enum ContiguousWithImplicitValues { | |
| A = -10, | |
| B, | |
| C, | |
| D, | |
| E, | |
| } | |
| #[derive(Copy, Clone, NoUninit)] | |
| #[repr(C)] | |
| struct NoUninitTest { | |
| a: u16, | |
| b: u16, | |
| } | |
| #[derive(Copy, Clone, AnyBitPattern)] | |
| #[repr(C)] | |
| union UnionTestAnyBitPattern { | |
| a: u8, | |
| b: u16, | |
| } | |
| #[repr(u8)] | |
| #[derive(Debug, Clone, Copy, NoUninit, CheckedBitPattern, PartialEq, Eq)] | |
| enum CheckedBitPatternEnumWithValues { | |
| A = 0, | |
| B = 1, | |
| C = 2, | |
| D = 3, | |
| E = 4, | |
| } | |
| #[repr(i8)] | |
| #[derive(Clone, Copy, NoUninit, CheckedBitPattern)] | |
| enum CheckedBitPatternEnumWithImplicitValues { | |
| A = -10, | |
| B, | |
| C, | |
| D, | |
| E, | |
| } | |
| #[repr(u8)] | |
| #[derive(Debug, Clone, Copy, NoUninit, CheckedBitPattern, PartialEq, Eq)] | |
| enum CheckedBitPatternEnumNonContiguous { | |
| A = 1, | |
| B = 8, | |
| C = 2, | |
| D = 3, | |
| E = 56, | |
| } | |
| #[repr(u8)] | |
| #[derive(Debug, Clone, Copy, NoUninit, CheckedBitPattern, PartialEq, Eq)] | |
| enum CheckedBitPatternEnumByteLit { | |
| A = b'A', | |
| B = b'B', | |
| C = b'C', | |
| D = b'D', | |
| E = b'E', | |
| } | |
| #[derive(Debug, Copy, Clone, NoUninit, CheckedBitPattern, PartialEq, Eq)] | |
| #[repr(C)] | |
| struct CheckedBitPatternStruct { | |
| a: u8, | |
| b: CheckedBitPatternEnumNonContiguous, | |
| } | |
| #[derive(Debug, Copy, Clone, AnyBitPattern, PartialEq, Eq)] | |
| #[repr(C)] | |
| struct AnyBitPatternTest<A: AnyBitPattern, B: AnyBitPattern> { | |
| a: A, | |
| b: B, | |
| } | |
| #[test] | |
| fn fails_cast_contiguous() { | |
| let can_cast = CheckedBitPatternEnumWithValues::is_valid_bit_pattern(&5); | |
| assert!(!can_cast); | |
| } | |
| #[test] | |
| fn passes_cast_contiguous() { | |
| let res = | |
| bytemuck::checked::from_bytes::<CheckedBitPatternEnumWithValues>(&[2u8]); | |
| assert_eq!(*res, CheckedBitPatternEnumWithValues::C); | |
| } | |
| #[test] | |
| fn fails_cast_noncontiguous() { | |
| let can_cast = CheckedBitPatternEnumNonContiguous::is_valid_bit_pattern(&4); | |
| assert!(!can_cast); | |
| } | |
| #[test] | |
| fn passes_cast_noncontiguous() { | |
| let res = | |
| bytemuck::checked::from_bytes::<CheckedBitPatternEnumNonContiguous>(&[ | |
| 56u8, | |
| ]); | |
| assert_eq!(*res, CheckedBitPatternEnumNonContiguous::E); | |
| } | |
| #[test] | |
| fn fails_cast_bytelit() { | |
| let can_cast = CheckedBitPatternEnumByteLit::is_valid_bit_pattern(&b'a'); | |
| assert!(!can_cast); | |
| } | |
| #[test] | |
| fn passes_cast_bytelit() { | |
| let res = | |
| bytemuck::checked::cast_slice::<u8, CheckedBitPatternEnumByteLit>(b"CAB"); | |
| assert_eq!( | |
| res, | |
| [ | |
| CheckedBitPatternEnumByteLit::C, | |
| CheckedBitPatternEnumByteLit::A, | |
| CheckedBitPatternEnumByteLit::B | |
| ] | |
| ); | |
| } | |
| #[test] | |
| fn fails_cast_struct() { | |
| let pod = [0u8, 24u8]; | |
| let res = bytemuck::checked::try_from_bytes::<CheckedBitPatternStruct>(&pod); | |
| assert!(res.is_err()); | |
| } | |
| #[test] | |
| fn passes_cast_struct() { | |
| let pod = [0u8, 8u8]; | |
| let res = bytemuck::checked::from_bytes::<CheckedBitPatternStruct>(&pod); | |
| assert_eq!( | |
| *res, | |
| CheckedBitPatternStruct { a: 0, b: CheckedBitPatternEnumNonContiguous::B } | |
| ); | |
| } | |
| #[test] | |
| fn anybitpattern_implies_zeroable() { | |
| let test = AnyBitPatternTest::<isize, usize>::zeroed(); | |
| assert_eq!(test, AnyBitPatternTest { a: 0isize, b: 0usize }); | |
| } | |
| #[test] | |
| fn checkedbitpattern_try_pod_read_unaligned() { | |
| let pod = [0u8]; | |
| let res = bytemuck::checked::try_pod_read_unaligned::< | |
| CheckedBitPatternEnumWithValues, | |
| >(&pod); | |
| assert!(res.is_ok()); | |
| let pod = [5u8]; | |
| let res = bytemuck::checked::try_pod_read_unaligned::< | |
| CheckedBitPatternEnumWithValues, | |
| >(&pod); | |
| assert!(res.is_err()); | |
| } | |
| #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] | |
| #[repr(C, align(16))] | |
| struct Issue127 {} |