1//! Utilities for working with POD (Plain Old Data)
23#![no_std]
4// https://github.com/rust-lang/rfcs/blob/master/text/2585-unsafe-block-in-unsafe-fn.md
5#![deny(unsafe_op_in_unsafe_fn)]
67use core::mem::MaybeUninit;
89/// Marker trait that the given type is Plain Old Data; i.e. that it is safe to
10/// interpret any pattern of bits as a value of this type.
11///
12/// This is notably *not* true for many Rust types. e.g. interpreting the integer
13/// value `2` as a rust `bool` is undefined behavior.
14///
15/// We require `Copy` to also rule out anything that implements `Drop`.
16///
17/// References are inherently non-Pod, so we can require a 'static lifetime.
18///
19/// This is very *similar* in concept to `bytemuck::AnyBitPattern`. However,
20/// unlike `AnyBitPattern`, this trait does not say anything about how the type
21/// can be safely shared. e.g. while `bytemuck::AnyBitPattern` disallows pointer
22/// types, [`Pod`] does not.
23///
24/// # Safety
25///
26/// - Any pattern of bits must be a valid value of the given type.
27/// - The type must not contain an [`UnsafeCell`](core::cell::UnsafeCell), or any other structure
28/// that contains an `UnsafeCell` (for example [`Cell`](core::cell::Cell)). Otherwise the following
29/// code would have UB:
30/// ```ignore
31/// let x = Cell::new(0);
32/// let y = as_u8_slice(&x);
33/// x.set(1);
34/// ```
35pub unsafe trait Pod: Copy + 'static {}
3637/// Convert to a slice of raw bytes.
38///
39/// Some bytes may be uninitialized if T has padding.
40pub fn to_u8_slice<T>(slice: &[T]) -> &[MaybeUninit<u8>]
41where
42T: Pod,
43{
44// SAFETY: Any value and alignment is safe for u8.
45unsafe {
46 core::slice::from_raw_parts(
47 slice.as_ptr() as *const MaybeUninit<u8>,
48 slice.len() * core::mem::size_of::<MaybeUninit<T>>(),
49 )
50 }
51}
5253/// Cast as a slice of raw bytes.
54///
55/// Some bytes may be uninitialized if T has padding.
56pub fn as_u8_slice<T>(x: &T) -> &[MaybeUninit<u8>]
57where
58T: Pod,
59{
60 to_u8_slice(core::slice::from_ref(x))
61}
6263/// Convert to a mut slice of raw bytes.
64///
65/// Some bytes may be uninialized if T has padding.
66///
67/// # Safety
68///
69/// Uninitialized bytes (e.g. [`MaybeUninit::uninit`]) must not be written
70/// into the returned slice, which would invalidate the source `slice`.
71pub unsafe fn to_u8_slice_mut<T>(slice: &mut [T]) -> &mut [MaybeUninit<u8>]
72where
73T: Pod,
74{
75// SAFETY: Any value and alignment is safe for u8.
76unsafe {
77 core::slice::from_raw_parts_mut(
78 slice.as_mut_ptr() as *mut MaybeUninit<u8>,
79 slice.len() * core::mem::size_of::<MaybeUninit<T>>(),
80 )
81 }
82}
8384/// Cast as a mut slice of raw bytes.
85///
86/// Some bytes may be uninitialized if T has padding.
87///
88/// # Safety
89///
90/// See [`to_u8_slice_mut`].
91pub unsafe fn as_u8_slice_mut<T>(x: &mut T) -> &mut [MaybeUninit<u8>]
92where
93T: Pod,
94{
95unsafe { to_u8_slice_mut(core::slice::from_mut(x)) }
96}
9798/// Create a value of type `T`, with contents initialized to 0s.
99pub fn zeroed<T>() -> T
100where
101T: Pod,
102{
103// SAFETY: Any value is legal for Pod.
104unsafe { core::mem::zeroed() }
105}
106107/// Wrapper type to support associated compile-time size checks
108struct PodTransmute<const N: usize, T> {
109 _t: core::marker::PhantomData<T>,
110}
111112impl<const N: usize, T: Pod> PodTransmute<N, T> {
113const CHECK: () = assert!(N == core::mem::size_of::<T>());
114#[inline(always)]
115fn transmute_array(x: &[u8; N]) -> T {
116// this should perform a compile-time check
117#[allow(clippy::let_unit_value)]
118let _ = Self::CHECK;
119120// this should perform a runtime check in case the above compile-time check didn't run, but
121 // should be compiled out if the compile-time check did run
122assert_eq!(N, core::mem::size_of::<T>());
123124// It'd be nice to use `transmute` here, and take the array by value,
125 // but there's no way to convince the type system that the input and output
126 // sizes are guaranteed to be equal. So, we use `transmute_copy` which
127 // doesn't require this to be statically guaranteed.
128unsafe { core::mem::transmute_copy(x) }
129 }
130}
131132/// Interpret the bytes of `x` as a value of type `T`.
133pub fn from_array<const N: usize, T: Pod>(x: &[u8; N]) -> T {
134 PodTransmute::transmute_array(x)
135}
136137// Integer primitives
138unsafe impl Pod for u8 {}
139unsafe impl Pod for u16 {}
140unsafe impl Pod for u32 {}
141unsafe impl Pod for u64 {}
142unsafe impl Pod for i8 {}
143unsafe impl Pod for i16 {}
144unsafe impl Pod for i32 {}
145unsafe impl Pod for i64 {}
146unsafe impl Pod for isize {}
147unsafe impl Pod for usize {}
148149// No! Values other than 0 or 1 are invalid.
150// impl !Pod for bool {}
151152// No! `char` must be a valid unicode value.
153// impl !Pod for char {}
154155unsafe impl<T> Pod for core::mem::MaybeUninit<T> where T: Pod {}
156unsafe impl<T, const N: usize> Pod for [T; N] where T: Pod {}
157158// libc types
159unsafe impl Pod for libc::Dl_info {}
160unsafe impl Pod for libc::Elf32_Chdr {}
161unsafe impl Pod for libc::Elf32_Ehdr {}
162unsafe impl Pod for libc::Elf32_Phdr {}
163unsafe impl Pod for libc::Elf32_Shdr {}
164unsafe impl Pod for libc::Elf32_Sym {}
165unsafe impl Pod for libc::Elf64_Chdr {}
166unsafe impl Pod for libc::Elf64_Ehdr {}
167unsafe impl Pod for libc::Elf64_Phdr {}
168unsafe impl Pod for libc::Elf64_Shdr {}
169unsafe impl Pod for libc::Elf64_Sym {}
170unsafe impl Pod for libc::__c_anonymous_sockaddr_can_j1939 {}
171unsafe impl Pod for libc::__c_anonymous_sockaddr_can_tp {}
172unsafe impl Pod for libc::__exit_status {}
173unsafe impl Pod for libc::__timeval {}
174unsafe impl Pod for libc::_libc_fpstate {}
175unsafe impl Pod for libc::_libc_fpxreg {}
176unsafe impl Pod for libc::_libc_xmmreg {}
177unsafe impl Pod for libc::addrinfo {}
178//unsafe impl Pod for libc::af_alg_i {}
179unsafe impl Pod for libc::aiocb {}
180unsafe impl Pod for libc::arpd_request {}
181unsafe impl Pod for libc::arphdr {}
182unsafe impl Pod for libc::arpreq {}
183unsafe impl Pod for libc::arpreq_old {}
184unsafe impl Pod for libc::can_filter {}
185unsafe impl Pod for libc::can_frame {}
186unsafe impl Pod for libc::canfd_frame {}
187unsafe impl Pod for libc::cmsghdr {}
188unsafe impl Pod for libc::cpu_set_t {}
189unsafe impl Pod for libc::dirent {}
190unsafe impl Pod for libc::dirent64 {}
191unsafe impl Pod for libc::dl_phdr_info {}
192unsafe impl Pod for libc::dqblk {}
193unsafe impl Pod for libc::epoll_event {}
194unsafe impl Pod for libc::fanotify_event_metadata {}
195unsafe impl Pod for libc::fanotify_response {}
196unsafe impl Pod for libc::fd_set {}
197unsafe impl Pod for libc::ff_condition_effect {}
198unsafe impl Pod for libc::ff_constant_effect {}
199unsafe impl Pod for libc::ff_effect {}
200unsafe impl Pod for libc::ff_envelope {}
201unsafe impl Pod for libc::ff_periodic_effect {}
202unsafe impl Pod for libc::ff_ramp_effect {}
203unsafe impl Pod for libc::ff_replay {}
204unsafe impl Pod for libc::ff_rumble_effect {}
205unsafe impl Pod for libc::ff_trigger {}
206unsafe impl Pod for libc::flock {}
207unsafe impl Pod for libc::flock64 {}
208unsafe impl Pod for libc::fsid_t {}
209unsafe impl Pod for libc::genlmsghdr {}
210unsafe impl Pod for libc::glob64_t {}
211unsafe impl Pod for libc::glob_t {}
212unsafe impl Pod for libc::group {}
213unsafe impl Pod for libc::hostent {}
214unsafe impl Pod for libc::if_nameindex {}
215unsafe impl Pod for libc::ifaddrs {}
216unsafe impl Pod for libc::in6_addr {}
217unsafe impl Pod for libc::in6_pktinfo {}
218unsafe impl Pod for libc::in6_rtmsg {}
219unsafe impl Pod for libc::in_addr {}
220unsafe impl Pod for libc::in_pktinfo {}
221unsafe impl Pod for libc::inotify_event {}
222unsafe impl Pod for libc::input_absinfo {}
223unsafe impl Pod for libc::input_event {}
224unsafe impl Pod for libc::input_id {}
225unsafe impl Pod for libc::input_keymap_entry {}
226unsafe impl Pod for libc::input_mask {}
227unsafe impl Pod for libc::iovec {}
228unsafe impl Pod for libc::ip_mreq {}
229unsafe impl Pod for libc::ip_mreq_source {}
230unsafe impl Pod for libc::ip_mreqn {}
231unsafe impl Pod for libc::ipc_perm {}
232unsafe impl Pod for libc::ipv6_mreq {}
233unsafe impl Pod for libc::itimerspec {}
234unsafe impl Pod for libc::itimerval {}
235unsafe impl Pod for libc::lconv {}
236unsafe impl Pod for libc::linger {}
237unsafe impl Pod for libc::mallinfo {}
238unsafe impl Pod for libc::max_align_t {}
239unsafe impl Pod for libc::mcontext_t {}
240unsafe impl Pod for libc::mmsghdr {}
241unsafe impl Pod for libc::mntent {}
242unsafe impl Pod for libc::mq_attr {}
243unsafe impl Pod for libc::msghdr {}
244unsafe impl Pod for libc::msginfo {}
245unsafe impl Pod for libc::msqid_ds {}
246unsafe impl Pod for libc::nl_mmap_hdr {}
247unsafe impl Pod for libc::nl_mmap_req {}
248unsafe impl Pod for libc::nl_pktinfo {}
249unsafe impl Pod for libc::nlattr {}
250unsafe impl Pod for libc::nlmsgerr {}
251unsafe impl Pod for libc::nlmsghdr {}
252unsafe impl Pod for libc::ntptimeval {}
253unsafe impl Pod for libc::packet_mreq {}
254unsafe impl Pod for libc::passwd {}
255unsafe impl Pod for libc::pollfd {}
256unsafe impl Pod for libc::posix_spawn_file_actions_t {}
257unsafe impl Pod for libc::posix_spawnattr_t {}
258unsafe impl Pod for libc::protoent {}
259unsafe impl Pod for libc::pthread_attr_t {}
260unsafe impl Pod for libc::pthread_cond_t {}
261unsafe impl Pod for libc::pthread_condattr_t {}
262unsafe impl Pod for libc::pthread_mutex_t {}
263unsafe impl Pod for libc::pthread_mutexattr_t {}
264unsafe impl Pod for libc::pthread_rwlock_t {}
265unsafe impl Pod for libc::pthread_rwlockattr_t {}
266unsafe impl Pod for libc::regex_t {}
267unsafe impl Pod for libc::regmatch_t {}
268unsafe impl Pod for libc::rlimit {}
269unsafe impl Pod for libc::rlimit64 {}
270unsafe impl Pod for libc::rtentry {}
271unsafe impl Pod for libc::rusage {}
272unsafe impl Pod for libc::sched_param {}
273unsafe impl Pod for libc::sem_t {}
274unsafe impl Pod for libc::sembuf {}
275unsafe impl Pod for libc::servent {}
276unsafe impl Pod for libc::shmid_ds {}
277unsafe impl Pod for libc::sigaction {}
278unsafe impl Pod for libc::sigevent {}
279unsafe impl Pod for libc::siginfo_t {}
280unsafe impl Pod for libc::signalfd_siginfo {}
281unsafe impl Pod for libc::sigset_t {}
282unsafe impl Pod for libc::sigval {}
283unsafe impl Pod for libc::sock_extended_err {}
284unsafe impl Pod for libc::sockaddr {}
285unsafe impl Pod for libc::sockaddr_alg {}
286unsafe impl Pod for libc::sockaddr_can {}
287unsafe impl Pod for libc::sockaddr_in {}
288unsafe impl Pod for libc::sockaddr_in6 {}
289unsafe impl Pod for libc::sockaddr_ll {}
290unsafe impl Pod for libc::sockaddr_nl {}
291unsafe impl Pod for libc::sockaddr_storage {}
292unsafe impl Pod for libc::sockaddr_un {}
293unsafe impl Pod for libc::sockaddr_vm {}
294unsafe impl Pod for libc::spwd {}
295unsafe impl Pod for libc::stack_t {}
296unsafe impl Pod for libc::stat {}
297unsafe impl Pod for libc::stat64 {}
298unsafe impl Pod for libc::statfs {}
299unsafe impl Pod for libc::statfs64 {}
300unsafe impl Pod for libc::statvfs {}
301unsafe impl Pod for libc::statvfs64 {}
302unsafe impl Pod for libc::statx {}
303unsafe impl Pod for libc::statx_timestamp {}
304unsafe impl Pod for libc::sysinfo {}
305unsafe impl Pod for libc::termios {}
306unsafe impl Pod for libc::termios2 {}
307unsafe impl Pod for libc::timespec {}
308unsafe impl Pod for libc::timeval {}
309unsafe impl Pod for libc::timex {}
310unsafe impl Pod for libc::tm {}
311unsafe impl Pod for libc::tms {}
312unsafe impl Pod for libc::ucontext_t {}
313unsafe impl Pod for libc::ucred {}
314unsafe impl Pod for libc::uinput_abs_setup {}
315unsafe impl Pod for libc::uinput_ff_erase {}
316unsafe impl Pod for libc::uinput_ff_upload {}
317unsafe impl Pod for libc::uinput_setup {}
318unsafe impl Pod for libc::uinput_user_dev {}
319unsafe impl Pod for libc::user {}
320unsafe impl Pod for libc::user_fpregs_struct {}
321unsafe impl Pod for libc::user_regs_struct {}
322unsafe impl Pod for libc::utimbuf {}
323unsafe impl Pod for libc::utmpx {}
324unsafe impl Pod for libc::utsname {}
325unsafe impl Pod for libc::winsize {}
326unsafe impl Pod for libc::clone_args {}