Skip to main content

libc/
types.rs

1//! Platform-agnostic support types.
2
3#[cfg(feature = "extra_traits")]
4use core::hash::Hash;
5use core::mem::MaybeUninit;
6
7use crate::prelude::*;
8
9/// A transparent wrapper over `MaybeUninit<T>` to represent uninitialized padding
10/// while providing `Default`.
11// This is restricted to `Copy` types since that's a loose indicator that zeros is actually
12// a valid bitpattern. There is no technical reason this is required, though, so it could be
13// lifted in the future if it becomes a problem.
14#[allow(dead_code)]
15#[repr(transparent)]
16#[derive(Clone, Copy)]
17pub(crate) struct Padding<T: Copy>(MaybeUninit<T>);
18
19impl<T: Copy> Default for Padding<T> {
20    fn default() -> Self {
21        Self(MaybeUninit::zeroed())
22    }
23}
24
25impl<T: Copy> Padding<T> {
26    /// Create a `Padding` initialized with the given value.
27    #[allow(dead_code)]
28    pub(crate) const fn new(val: T) -> Self {
29        Self(MaybeUninit::new(val))
30    }
31}
32
33impl<T: Copy> fmt::Debug for Padding<T> {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        // Taken from `MaybeUninit`'s debug implementation
36        // NB: there is no `.pad_fmt` so we can't use a simpler `format_args!("Padding<{..}>").
37        let full_name = core::any::type_name::<Self>();
38        let prefix_len = full_name.find("Padding").unwrap();
39        f.pad(&full_name[prefix_len..])
40    }
41}
42
43/// Do nothing when hashing to ignore the existence of padding fields.
44#[cfg(feature = "extra_traits")]
45impl<T: Copy> Hash for Padding<T> {
46    fn hash<H: hash::Hasher>(&self, _state: &mut H) {}
47}
48
49/// Padding fields are all equal, regardless of what is inside them, so they do not affect anything.
50#[cfg(feature = "extra_traits")]
51impl<T: Copy> PartialEq for Padding<T> {
52    fn eq(&self, _other: &Self) -> bool {
53        true
54    }
55}
56
57/// Mark that `Padding` implements `Eq` so that it can be used in types that implement it.
58#[cfg(feature = "extra_traits")]
59impl<T: Copy> Eq for Padding<T> {}
60
61/// The default repr type used for C style enums in Rust.
62#[cfg(target_env = "msvc")]
63#[allow(unused)]
64pub(crate) type CEnumRepr = c_int;
65#[cfg(not(target_env = "msvc"))]
66#[allow(unused)]
67pub(crate) type CEnumRepr = c_uint;
68
69/// Used to avoid `overflowing_literals` when the value is in-range for the unsigned number but
70/// out-of-range for signed.
71#[allow(unused)]
72pub(crate) const fn u16_cast_short(x: u16) -> c_short {
73    assert!(size_of::<u16>() <= size_of::<c_short>()); // Should always be true
74    x as i16
75}
76
77/// Used to avoid `overflowing_literals` when the value is in-range for the unsigned number but
78/// out-of-range for signed.
79#[allow(unused)]
80pub(crate) const fn u32_cast_int(x: u32) -> c_int {
81    // May not be true on 16-bit platforms, but should be everywhere this is used.
82    assert!(size_of::<u32>() <= size_of::<c_int>());
83    x as i32
84}
85
86/// Used to avoid `overflowing_literals` when the value is in-range for the unsigned number but
87/// out-of-range for signed.
88#[allow(unused)]
89pub(crate) const fn u32_cast_long(x: u32) -> c_long {
90    assert!(size_of::<u32>() <= size_of::<c_long>()); // Should always be true
91    x as c_long
92}
93
94/// Checked casting from `unsigned long` to `int`.
95#[allow(unused)]
96pub(crate) const fn ulong_cast_int(x: c_ulong) -> c_int {
97    assert!(x <= (c_int::MAX as c_ulong));
98    x as c_int
99}
100
101/// Checked casting from `unsigned long` to `unsigned int`.
102#[allow(unused)]
103pub(crate) const fn ulong_cast_uint(x: c_ulong) -> c_uint {
104    assert!(x <= (c_uint::MAX as c_ulong));
105    x as c_uint
106}
107
108/// Used to avoid `overflowing_literals` when the value is in-range for the unsigned number but
109/// out-of-range for signed.
110#[allow(unused)]
111#[cfg(any(target_os = "linux", target_os = "android", target_os = "l4re"))]
112pub(crate) const fn u32_cast_ioctl(x: u32) -> crate::Ioctl {
113    assert!(size_of::<u32>() <= size_of::<crate::Ioctl>()); // Should always be true
114    x as crate::Ioctl
115}
116
117#[allow(unused)]
118pub(crate) const fn u8_slice_cast_char_slice(x: &[u8]) -> &[c_char] {
119    assert!(size_of::<u8>() == size_of::<c_char>());
120    // SAFETY: same repr, possibly just a sign cast
121    unsafe { mem::transmute::<&[u8], &[c_char]>(x) }
122}
123
124/// Replace bytes in an array with those from a slice. This is a polyfill for `[T]::copy_from_slice`
125/// in `const`.
126// FIXME(msrv): we can switch to `copy_from_slice` in 1.87.
127#[must_use]
128#[allow(dead_code)]
129pub const fn replace_array_items<T: Copy, const N: usize>(
130    mut dst: [T; N],
131    src: &[T],
132    start: usize,
133) -> [T; N] {
134    let mut i = 0;
135    while i < src.len() {
136        dst[i + start] = src[i];
137        i += 1;
138    }
139    dst
140}