as_bytes/
lib.rs

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