wiwi/chain/array.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
use crate::prelude_std::*;
use super::{ Chain as _, ChainInner as _ };
super::decl_chain! {
generics_decl: [T, const N: usize]
generics: [T, N]
chain: ArrayChain
inner: [T; N]
}
impl<T, const N: usize> ArrayChain<T, N> {
#[inline]
pub fn new_uninit() -> ArrayChain<MaybeUninit<T>, N> {
// SAFETY: `MaybeUninit` has no initialisation requirement, so
// `[MaybeUninit<T>; N]` is always valid
unsafe { ArrayChain::from_inner(MaybeUninit::uninit().assume_init()) }
}
#[inline]
pub fn new_zeroed() -> ArrayChain<MaybeUninit<T>, N> {
// SAFETY: `MaybeUninit` has no initialisation requirement, so
// `[MaybeUninit<T>; N]` is always valid
unsafe { ArrayChain::from_inner(MaybeUninit::zeroed().assume_init()) }
}
}
impl<T, const N: usize> ArrayChain<MaybeUninit<T>, N> {
/// Assumes all slots inside the array are initialised according to `T`'s
/// requirements, and converts into an array of T
///
/// Note: this implementation is currently subpar, as it does fully copy `self`
/// into a new container using `ptr::read`. We have to do this because, at the
/// time of writing:
///
/// - `transmute` is a bit too dumb, and is not able to prove `[T; N]` and
/// `[MaybeUninit<T>; N]` are guaranteed to be equal sized, even though
/// we can see and prove it
/// - `transmute_unchecked` is like `transmute` but without that compile time
/// size check, but it is unstable, and according to a code comment will
/// almost certainly never be stabilised (reasoning is that it's too unsafe,
/// too much power to give users :p, and to hopefully find other methods for
/// doing things without it so that it isn't needed)
/// - `MaybeUninit::array_assume_init` is unstable (it internally makes use of
/// `transmute_unchecked`)
///
/// We don't know of any other option than to perform a ptr cast,
/// then read from it.
///
/// # Safety
///
/// All slots in `self` must be fully initialised with valid values of `T`.
#[inline]
pub unsafe fn assume_init(self) -> ArrayChain<T, N> {
#[expect(clippy::as_conversions, reason = "ptr cast")]
let ptr = self.as_inner() as *const [MaybeUninit<T>; N] as *const [T; N];
// SAFETY: `ptr` is obtained from `self`, performed valid cast from array
// of MaybeUninit to array of T, and caller promises that all slots in the
// array are properly initialised values of `T`. Also see doc comment on
// this function for why this is a ptr read rather than a transmute
unsafe { ptr.read().into_chain() }
}
}