1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//! A tiny crate, which provides slices to the memory which backs an instance of a struct.
//!
//! ```
//! use as_bytes::AsBytes;
//! let i = u32::MAX;
//! let bytes = unsafe { i.as_bytes() };
//! assert_eq!(bytes, [255, 255, 255, 255]);
//! ```
//! You can use this to peek at structure layout.
//! One usecase is for testing sending structs sent the wire.
//! The below examples demonstrate two different packing attributes on the same structure.
//! ```
//! # #[repr(packed)]
//! # #[allow(dead_code)] // unread fields
//! # struct ReprPacked {
//! #     a: usize,
//! #     b: u8,
//! #     c: usize,
//! # }
//! # use as_bytes::AsBytes;
//!
//! let packed = ReprPacked {
//!     a: usize::MAX,
//!     b: 0u8,
//!     c: usize::MAX,
//! };
//! let bytes = unsafe { packed.as_bytes() };
//! assert_eq!(
//!     bytes,
//!     [255, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 255]
//! );
//! ```
//!
//! ```
//! # #[repr(C)]
//! # struct ReprC {
//! #     a: usize,
//! #     b: u8,
//! #     c: usize,
//! # }
//! # use as_bytes::AsBytes;
//!
//! let packed = ReprC {
//!     a: usize::MAX,
//!     b: 0u8,
//!     c: usize::MAX,
//! };
//! let bytes = unsafe { packed.as_bytes() };
//! assert_eq!(
//!     bytes,
//!     [
//!         255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255
//!     ]
//! );
//! ```

/// Return a slice of the memory that contains the struct
pub trait AsBytes {
    unsafe fn as_bytes(&self) -> &[u8] {
        let ptr = self as *const _ as *const u8;
        let len = std::mem::size_of_val(self);
        std::slice::from_raw_parts(ptr, len)
    }
    unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
        let ptr = self as *mut _ as *mut u8;
        let len = std::mem::size_of_val(self);
        std::slice::from_raw_parts_mut(ptr, len)
    }
}

impl<T> AsBytes for T {}

#[cfg(test)]
mod tests {
    use crate::AsBytes;

    #[test]
    fn test_u32() {
        let i = u32::MAX;
        let bytes = unsafe { i.as_bytes() };
        assert_eq!(bytes, [255, 255, 255, 255]);
    }

    #[repr(packed)]
    #[allow(dead_code)] // unread fields
    struct ReprPacked {
        a: usize,
        b: u8,
        c: usize,
    }

    #[test]
    fn test_repr_packed_struct() {
        let packed = ReprPacked {
            a: usize::MAX,
            b: 0u8,
            c: usize::MAX,
        };
        let bytes = unsafe { packed.as_bytes() };
        assert_eq!(
            bytes,
            [255, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 255]
        )
    }

    #[repr(C)]
    struct ReprC {
        a: usize,
        b: u8,
        c: usize,
    }

    #[test]
    fn test_repr_c_struct() {
        let packed = ReprC {
            a: usize::MAX,
            b: 0u8,
            c: usize::MAX,
        };
        let bytes = unsafe { packed.as_bytes() };
        assert_eq!(
            bytes,
            [
                255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255,
                255, 255, 255, 255
            ]
        )
    }
}