swap_buffer_queue/
utils.rs

1use core::{
2    mem,
3    mem::MaybeUninit,
4    ops::{Deref, DerefMut},
5    slice,
6};
7
8pub(crate) fn init_array<T, const N: usize>(default: impl Fn() -> T) -> [T; N] {
9    // SAFETY: common MaybeUninit pattern, used in unstable `MaybeUninit::uninit_array`
10    let mut array: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
11    for elem in &mut array {
12        elem.write(default());
13    }
14    // SAFETY: all elements have been initialized
15    // I used `std::mem::transmute_copy` because `transmute` doesn't work here
16    // see https://users.rust-lang.org/t/transmuting-a-generic-array/45645
17    unsafe { mem::transmute_copy(&array) }
18}
19
20/// A hack for const-expression-sized array, as discussed here:
21/// https://users.rust-lang.org/t/is-slice-from-raw-parts-unsound-in-case-of-a-repr-c-struct-with-consecutive-arrays/88368
22#[repr(C)]
23pub(crate) struct ArrayWithHeaderAndTrailer<
24    T,
25    const HEADER_SIZE: usize,
26    const N: usize,
27    const TRAILER_SIZE: usize,
28> {
29    header: [T; HEADER_SIZE],
30    array: [T; N],
31    trailer: [T; TRAILER_SIZE],
32}
33
34impl<T, const HEADER_SIZE: usize, const N: usize, const TRAILER_SIZE: usize> Deref
35    for ArrayWithHeaderAndTrailer<T, HEADER_SIZE, N, TRAILER_SIZE>
36{
37    type Target = [T];
38    fn deref(&self) -> &Self::Target {
39        // SAFETY: see struct documentation
40        unsafe {
41            slice::from_raw_parts(self as *const _ as *const T, HEADER_SIZE + N + TRAILER_SIZE)
42        }
43    }
44}
45
46impl<T, const HEADER_SIZE: usize, const N: usize, const TRAILER_SIZE: usize> DerefMut
47    for ArrayWithHeaderAndTrailer<T, HEADER_SIZE, N, TRAILER_SIZE>
48{
49    fn deref_mut(&mut self) -> &mut Self::Target {
50        // SAFETY: see struct documentation
51        unsafe {
52            slice::from_raw_parts_mut(self as *mut _ as *mut T, HEADER_SIZE + N + TRAILER_SIZE)
53        }
54    }
55}
56
57impl<T, const HEADER_SIZE: usize, const N: usize, const TRAILER_SIZE: usize>
58    ArrayWithHeaderAndTrailer<T, HEADER_SIZE, N, TRAILER_SIZE>
59{
60    pub(crate) fn new(default: impl Fn() -> T) -> Self {
61        Self {
62            header: init_array(&default),
63            array: init_array(&default),
64            trailer: init_array(&default),
65        }
66    }
67}
68
69impl<T, const HEADER_SIZE: usize, const N: usize, const TRAILER_SIZE: usize> Default
70    for ArrayWithHeaderAndTrailer<T, HEADER_SIZE, N, TRAILER_SIZE>
71where
72    T: Default + Clone,
73{
74    fn default() -> Self {
75        Self::new(T::default)
76    }
77}