briny 0.4.1

Low-level enforcement of memory layout integrity
Documentation
use briny::raw::{cast, from_bytes, slice_from_bytes, to_bytes};
use briny::traits::{Pod, RawConvert, StableLayout};

#[test]
fn to_bytes_roundtrip_fuzz() {
    #[repr(packed)]
    #[derive(Copy, Clone, Debug, PartialEq)]
    struct Pair {
        a: u32,
        b: u64,
    }

    unsafe impl StableLayout for Pair {}
    unsafe impl RawConvert for Pair {}
    unsafe impl Pod for Pair {}

    let inputs: &[Pair] = &[
        Pair { a: 0, b: 0 },
        Pair {
            a: u32::MAX,
            b: u64::MAX,
        },
        Pair {
            a: 0x12345678,
            b: 0xCAFEBABEDEADBEEF,
        },
        Pair { a: 1, b: 2 },
        Pair {
            a: 0xFFFF_FFFF,
            b: 0,
        },
    ];

    for input in inputs {
        let bytes = to_bytes(input);
        let output = from_bytes::<Pair>(bytes).unwrap();
        assert_eq!(&output, input);
    }
}

#[test]
fn slice_from_bytes_misaligned_fuzz() {
    use core::mem::{align_of, size_of};

    #[repr(C)]
    #[derive(Copy, Clone, Debug)]
    struct Word(u32);

    unsafe impl StableLayout for Word {}
    unsafe impl RawConvert for Word {}
    unsafe impl Pod for Word {}

    #[repr(align(4))]
    struct Align4([u8; 64]);

    let alignment = align_of::<Word>();
    let size = size_of::<Word>() * 10;

    let a = Align4([0u8; 64]);
    for offset in 0..=16 {
        let slice = &a.0[offset..offset + size];
        let result = slice_from_bytes::<Word>(slice);

        if offset % alignment == 0 {
            assert!(result.is_ok(), "offset {offset} should be aligned");
        } else {
            assert!(
                result.is_err(),
                "offset {offset} should be rejected as misaligned"
            );
        }
    }
}

#[test]
fn cast_struct_edge_fuzz() {
    #[repr(C, align(4))]
    #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
    struct FourBytes {
        a: u8,
        b: u8,
        c: u8,
        d: u8,
    }

    unsafe impl StableLayout for FourBytes {}
    unsafe impl RawConvert for FourBytes {}
    unsafe impl Pod for FourBytes {}

    const _: () = {
        assert!(size_of::<FourBytes>() == size_of::<u32>());
        assert!(align_of::<FourBytes>() == align_of::<u32>());
    };

    for a in 0u8..=10 {
        for b in 0u8..=10 {
            for c in 0u8..=10 {
                for d in 0u8..=10 {
                    let orig = FourBytes { a, b, c, d };
                    let casted: u32 = cast(&orig);
                    let back: FourBytes = cast(&casted);
                    assert_eq!(orig, back);
                }
            }
        }
    }
}

#[test]
fn roundtrip_cast_fuzz() {
    #[repr(C, align(4))]
    #[derive(Copy, Clone, Debug, PartialEq, Default)]
    struct A {
        x: u16,
        y: u16,
    }

    unsafe impl RawConvert for A {}
    unsafe impl StableLayout for A {}
    unsafe impl Pod for A {}

    #[repr(C, align(4))]
    #[derive(Copy, Clone, Debug, PartialEq, Default)]
    struct B(u32);

    unsafe impl RawConvert for B {}
    unsafe impl StableLayout for B {}
    unsafe impl Pod for B {}

    const _: () = {
        assert!(size_of::<A>() == size_of::<B>());
        assert!(align_of::<A>() >= align_of::<B>());
    };

    for v in 0u32..100 {
        let b = B(v);
        let a = cast::<B, A>(&b);
        let b2 = cast::<A, B>(&a);
        assert_eq!(b, b2, "roundtrip failed for value {v}");
    }
}