Thanks to visit codestin.com
Credit goes to docs.rs

uapi/
pod.rs

1use crate::*;
2use std::{
3    marker::PhantomData,
4    mem,
5    mem::{ManuallyDrop, MaybeUninit},
6    ops::Deref,
7    slice,
8};
9
10/// Marker trait for Pod types
11///
12/// This is not a general Pod type and only supposed to be used for interaction with this
13/// crate.
14///
15/// See also the crate documentation.
16///
17/// # Safety
18///
19/// For all sized types `T: Pod`, transmuting any array of type `[u8; size_of::<T>()]` to
20/// `T` must produce a valid value.
21///
22/// For all types `T: Pod`, overwriting the contents of `t: &mut T` with any array of type
23/// `[u8; size_of_val(t)]` must produce a valid value.
24pub unsafe trait Pod {}
25
26/// Returns an instance of `T` whose object representation is `0` in all non-padding bytes
27pub fn pod_zeroed<T: Pod>() -> T {
28    unsafe { mem::zeroed() }
29}
30
31/// Converts `u` to `T`
32///
33/// `u` and `T` must have the same size.
34pub fn pod_read<T: Pod, U: Packed + ?Sized>(u: &U) -> Result<T> {
35    let mut t = pod_zeroed();
36    pod_write(u, &mut t)?;
37    Ok(t)
38}
39
40/// Converts `u` into an iterator of `T`
41///
42/// The size of `u` must be a multiple of the size of `T`
43pub fn pod_iter<'a, T: Pod + 'a, U: Packed + ?Sized>(
44    u: &'a U,
45) -> Result<impl Iterator<Item = T> + 'a> {
46    if mem::size_of::<T>() != 0 && mem::size_of_val(u) % mem::size_of::<T>() != 0 {
47        einval()
48    } else {
49        Ok(Iter {
50            buf: as_bytes(u),
51            _pd: PhantomData,
52        })
53    }
54}
55
56struct Iter<'a, T> {
57    buf: &'a [u8],
58    _pd: PhantomData<fn() -> T>,
59}
60
61impl<'a, T: Pod> Iterator for Iter<'a, T> {
62    type Item = T;
63
64    fn next(&mut self) -> Option<Self::Item> {
65        if self.buf.is_empty() {
66            None
67        } else {
68            let t = pod_read_init(self.buf).unwrap();
69            self.buf = &self.buf[mem::size_of::<T>()..];
70            Some(t)
71        }
72    }
73}
74
75/// Converts an initial port of `u` to `T`
76///
77/// The size of `u` must be equal to or larger than the size of `T`.
78pub fn pod_read_init<T: Pod, U: Packed + ?Sized>(u: &U) -> Result<T> {
79    let mut t = pod_zeroed();
80    pod_write_common_prefix(u, &mut t)?;
81    Ok(t)
82}
83
84/// Writes `u` to `t`
85///
86/// `u` and `t` must have the same size.
87pub fn pod_write<T: Pod + ?Sized, U: Packed + ?Sized>(u: &U, t: &mut T) -> Result<()> {
88    if mem::size_of_val(t) != mem::size_of_val(u) {
89        einval()
90    } else {
91        pod_write_common_prefix(u, t)
92    }
93}
94
95/// Writes an initial portion of `u` to `t`
96///
97/// The size of `u` must be equal to or larger than the size of `t`.
98fn pod_write_common_prefix<T: Pod + ?Sized, U: Packed + ?Sized>(
99    u: &U,
100    t: &mut T,
101) -> Result<()> {
102    if mem::size_of_val(t) > mem::size_of_val(u) {
103        einval()
104    } else {
105        unsafe {
106            let dst = t as *mut _ as *mut u8;
107            let src = u as *const _ as *const u8;
108            std::ptr::copy_nonoverlapping(src, dst, mem::size_of_val(t));
109        }
110        Ok(())
111    }
112}
113
114unsafe impl<T: Pod> Pod for [T] {
115}
116
117unsafe impl<T: Pod, const N: usize> Pod for [T; N] {
118}
119
120// TODO: https://github.com/rust-lang/rust/pull/79135
121// unsafe impl<T: Pod, const N: usize> Pod for [T; N] {
122// }
123
124unsafe impl<T> Pod for *const T {
125}
126
127unsafe impl<T> Pod for *mut T {
128}
129
130unsafe impl<T> Pod for MaybeUninit<T> {
131}
132
133macro_rules! imp_pod {
134    ($($path:path)*) => {
135        $(unsafe impl Pod for $path {})*
136    }
137}
138
139imp_pod! {
140    u8
141    u16
142    u32
143    u64
144    u128
145    usize
146    i8
147    i16
148    i32
149    i64
150    i128
151    isize
152
153    f32
154    f64
155
156    c::sockaddr
157    c::sockaddr_storage
158    c::sockaddr_un
159    c::sockaddr_in
160    c::sockaddr_in6
161
162    c::msghdr
163    c::cmsghdr
164
165    c::in6_pktinfo
166
167    c::siginfo_t
168    c::flock
169    c::timespec
170    c::timeval
171    c::linger
172
173    OwnedFd
174    Fd
175}
176
177#[cfg(not(any(target_os = "macos", target_os = "openbsd")))]
178imp_pod! {
179    c::sigset_t
180}
181
182#[cfg(target_os = "linux")]
183imp_pod! {
184    c::sockaddr_alg
185    c::sockaddr_nl
186    c::sockaddr_ll
187    c::sockaddr_vm
188    c::signalfd_siginfo
189    c::nlmsghdr
190    c::nlattr
191    c::ifinfomsg
192    c::input_event
193    c::open_how
194    c::sched_attr
195    c::sched_param
196    c::genlmsghdr
197    c::nlmsgerr
198    c::itimerspec
199    c::itimerval
200    c::epoll_event
201}
202
203#[cfg(not(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd")))]
204imp_pod! {
205    c::ucred
206    c::in_pktinfo
207    c::ip_mreq
208    c::ip_mreqn
209}
210
211/// Marker trait for types without padding
212///
213/// # Safety
214///
215/// Types that implement this must not have padding bytes
216pub unsafe trait Packed {}
217
218unsafe impl<T: Packed> Packed for [T] {
219}
220
221unsafe impl<T: Packed, const N: usize> Packed for [T; N] {
222}
223
224// TODO: https://github.com/rust-lang/rust/pull/79135
225// unsafe impl<T: Packed, const N: usize> Packed for [T; N] {
226// }
227
228unsafe impl<T> Packed for *const T {
229}
230
231unsafe impl<T> Packed for *mut T {
232}
233
234macro_rules! imp_packed {
235    ($($path:path)*) => {
236        $(unsafe impl Packed for $path {})*
237    }
238}
239
240imp_packed! {
241    u8
242    u16
243    u32
244    u64
245    u128
246    usize
247    i8
248    i16
249    i32
250    i64
251    i128
252    isize
253
254    f32
255    f64
256
257    OwnedFd
258    Fd
259}
260
261/// Returns the object representation of `t`
262pub fn as_bytes<T: Packed + ?Sized>(t: &T) -> &[u8] {
263    unsafe {
264        let ptr = t as *const _ as *const u8;
265        slice::from_raw_parts(ptr, mem::size_of_val(t))
266    }
267}
268
269/// Returns the mutable object representation of `t`
270pub fn as_bytes_mut<T: Pod + Packed + ?Sized>(t: &mut T) -> &mut [u8] {
271    unsafe {
272        let ptr = t as *mut _ as *mut u8;
273        slice::from_raw_parts_mut(ptr, mem::size_of_val(t))
274    }
275}
276
277/// Transparent wrapper that asserts that a type is `Pod`
278#[repr(transparent)]
279#[derive(Copy)]
280pub struct AssertPod<T: ?Sized>(ManuallyDrop<T>);
281
282impl<T: ?Sized> AssertPod<T> {
283    /// Wraps a `&mut T`
284    ///
285    /// # Safety
286    ///
287    /// `T` must follow the `Pod` contract.
288    pub unsafe fn new(t: &mut T) -> &mut Self {
289        &mut *(t as *mut T as *mut AssertPod<T>)
290    }
291}
292
293impl<T: Copy> Clone for AssertPod<T> {
294    fn clone(&self) -> Self {
295        *self
296    }
297}
298
299impl<T> AssertPod<T> {
300    /// Unwraps the contained object
301    ///
302    /// # Safety
303    ///
304    /// `T` must follow the `Pod` contract.
305    pub unsafe fn unwrap(self) -> T {
306        ManuallyDrop::into_inner(self.0)
307    }
308}
309
310unsafe impl<T: ?Sized> Pod for AssertPod<T> {
311}
312
313/// Transparent wrapper that asserts that a type is `Packed`
314#[repr(transparent)]
315#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
316pub struct AssertPacked<T: ?Sized>(T);
317
318impl<T: ?Sized> AssertPacked<T> {
319    /// Wraps a `&T`
320    ///
321    /// # Safety
322    ///
323    /// `T` must follow the `Packed` contract.
324    pub unsafe fn new(t: &T) -> &Self {
325        &*(t as *const T as *const AssertPacked<T>)
326    }
327}
328
329unsafe impl<T: ?Sized> Packed for AssertPacked<T> {
330}
331
332impl<T: ?Sized> Deref for AssertPacked<T> {
333    type Target = T;
334
335    fn deref(&self) -> &Self::Target {
336        &self.0
337    }
338}
339
340/// Asserts that `T` is `Pod`
341///
342/// # Safety
343///
344/// `T` must follow the `Pod` contract.
345pub unsafe fn assert_pod<T: ?Sized>(t: &mut T) -> &mut AssertPod<T> {
346    AssertPod::new(t)
347}
348
349/// Asserts that `T` is `Packed`
350///
351/// # Safety
352///
353/// `T` must follow the `Packed` contract.
354pub unsafe fn assert_packed<T: ?Sized>(t: &T) -> &AssertPacked<T> {
355    AssertPacked::new(t)
356}