// SPDX-License-Identifier: MPL-2.0 use core::mem::offset_of; use padding_struct::padding_struct; /// Test basic padding functionality #[test] fn basic_padding() { #[repr(C)] #[padding_struct] struct TestStruct { a: u8, b: u32, c: u16, } // Verify reference struct exists let _ref_struct = __TestStruct__ { a: 1, b: 2, c: 3 }; // Verify padded struct let padded = TestStruct { a: 1, __pad1: [0; { offset_of!(__TestStruct__, b) - offset_of!(__TestStruct__, a) - size_of::() }], b: 2, __pad2: [0; { offset_of!(__TestStruct__, c) - offset_of!(__TestStruct__, b) - size_of::() }], c: 3, __pad3: [0; { size_of::<__TestStruct__>() - offset_of!(__TestStruct__, c) - size_of::() }], }; assert_eq!(padded.a, 1); assert_eq!(padded.b, 2); assert_eq!(padded.c, 3); } /// Test single field struct #[test] fn single_field() { #[repr(C)] #[padding_struct] struct SingleField { value: u64, } let single = SingleField { value: 42, __pad1: [0; { size_of::<__SingleField__>() - offset_of!(__SingleField__, value) - size_of::() }], }; assert_eq!(single.value, 42); } /// Test multiple fields struct #[test] fn multiple_fields() { #[repr(C)] #[padding_struct] struct MultiField { a: u8, b: u16, c: u32, d: u64, } let multi = MultiField { a: 1, __pad1: [0; { offset_of!(__MultiField__, b) - offset_of!(__MultiField__, a) - size_of::() }], b: 2, __pad2: [0; { offset_of!(__MultiField__, c) - offset_of!(__MultiField__, b) - size_of::() }], c: 3, __pad3: [0; { offset_of!(__MultiField__, d) - offset_of!(__MultiField__, c) - size_of::() }], d: 4, __pad4: [0; { size_of::<__MultiField__>() - offset_of!(__MultiField__, d) - size_of::() }], }; assert_eq!(multi.a, 1); assert_eq!(multi.b, 2); assert_eq!(multi.c, 3); assert_eq!(multi.d, 4); } /// Test struct with field documentation #[test] fn with_field_docs() { #[repr(C)] #[padding_struct] struct Documented { /// First field first: u8, /// Second field second: u32, } let doc = Documented { first: 10, __pad1: [0; { offset_of!(__Documented__, second) - offset_of!(__Documented__, first) - size_of::() }], second: 20, __pad2: [0; { size_of::<__Documented__>() - offset_of!(__Documented__, second) - size_of::() }], }; assert_eq!(doc.first, 10); assert_eq!(doc.second, 20); } /// Verify that field offsets are consistent between reference and padded structs #[test] fn offset_consistency() { #[repr(C)] #[padding_struct] struct OffsetTest { a: u8, b: u32, } // Reference struct offsets let ref_a_offset = offset_of!(__OffsetTest__, a); let ref_b_offset = offset_of!(__OffsetTest__, b); // Padded struct offsets should be the same let padded_a_offset = offset_of!(OffsetTest, a); let padded_b_offset = offset_of!(OffsetTest, b); assert_eq!(ref_a_offset, padded_a_offset); assert_eq!(ref_b_offset, padded_b_offset); } /// Test that padding is zero-filled #[test] fn padding_zero_filled() { #[repr(C)] #[padding_struct] struct ZeroPadded { a: u8, b: u32, } let zero_pad = ZeroPadded { a: 255, __pad1: [0; { offset_of!(__ZeroPadded__, b) - offset_of!(__ZeroPadded__, a) - size_of::() }], b: 0xFFFFFFFF, __pad2: [0; { size_of::<__ZeroPadded__>() - offset_of!(__ZeroPadded__, b) - size_of::() }], }; // Verify padding is all zeros for byte in &zero_pad.__pad1 { assert_eq!(*byte, 0); } for byte in &zero_pad.__pad2 { assert_eq!(*byte, 0); } } /// Test that padded struct can derive zerocopy traits #[test] fn zerocopy_derive() { use zerocopy::*; #[repr(C)] #[padding_struct] #[derive(Clone, Copy, FromBytes, IntoBytes, Immutable, KnownLayout)] struct ZerocopyStruct { a: u8, b: u32, c: u16, } // Test Zeroable let zeroed = ZerocopyStruct::new_zeroed(); assert_eq!(zeroed.a, 0); assert_eq!(zeroed.b, 0); assert_eq!(zeroed.c, 0); // Test Pod - cast from bytes let bytes = [1u8, 0, 0, 0, 0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD, 0, 0]; let from_bytes: &ZerocopyStruct = FromBytes::ref_from_bytes(&bytes[..size_of::()]).unwrap(); assert_eq!(from_bytes.a, 1); assert_eq!(from_bytes.b, 0x78563412); assert_eq!(from_bytes.c, 0xCDAB); // Test Pod - cast to bytes let test_struct = ZerocopyStruct { a: 42, __pad1: [0; { offset_of!(__ZerocopyStruct__, b) - offset_of!(__ZerocopyStruct__, a) - size_of::() }], b: 0xDEADBEEF, __pad2: [0; { offset_of!(__ZerocopyStruct__, c) - offset_of!(__ZerocopyStruct__, b) - size_of::() }], c: 0x1234, __pad3: [0; { size_of::<__ZerocopyStruct__>() - offset_of!(__ZerocopyStruct__, c) - size_of::() }], }; let as_bytes: &[u8] = test_struct.as_bytes(); assert_eq!(as_bytes[0], 42); } /// Test that repr attributes (align, packed, etc.) are preserved in ref struct #[test] fn repr_align_preserved() { #[repr(C, align(16))] #[padding_struct] struct AlignedStruct { a: u8, b: u32, } // Verify alignment is correct assert_eq!(align_of::(), 16); assert_eq!(align_of::<__AlignedStruct__>(), 16); let aligned = AlignedStruct { a: 1, __pad1: [0; { offset_of!(__AlignedStruct__, b) - offset_of!(__AlignedStruct__, a) - size_of::() }], b: 2, __pad2: [0; { size_of::<__AlignedStruct__>() - offset_of!(__AlignedStruct__, b) - size_of::() }], }; assert_eq!(aligned.a, 1); assert_eq!(aligned.b, 2); } /// Test that size and alignment match between ref struct and padded struct #[test] fn size_align_match() { #[repr(C, align(8))] #[padding_struct] struct TestStruct { a: u8, b: u16, c: u32, } // The compile-time check ensures these are equal assert_eq!(size_of::(), size_of::<__TestStruct__>()); assert_eq!(align_of::(), align_of::<__TestStruct__>()); }