Skip to content

Instantly share code, notes, and snippets.

@DutchGhost
Created July 27, 2019 16:28
Show Gist options
  • Select an option

  • Save DutchGhost/04cd56b6f37c0cb4b1e5cd2d0de83f90 to your computer and use it in GitHub Desktop.

Select an option

Save DutchGhost/04cd56b6f37c0cb4b1e5cd2d0de83f90 to your computer and use it in GitHub Desktop.
use core::{
mem::{self, MaybeUninit},
ptr,
};
/// This struct is a simple wrapper around `[MaybeUninit<T>; N]`.
/// It provides some convenience methods for working with arrays that may have uninitialized items.
pub(crate) struct MaybeArray<T, const N: usize> {
array: [MaybeUninit<T>; N]
}
impl <T, const N: usize> Default for MaybeArray<T, { N }> {
#[inline(always)]
fn default() -> Self {
Self {
array: unsafe { MaybeUninit::<_>::uninit().assume_init() }
}
}
}
impl <T, const N: usize> MaybeArray<T, { N }> {
/// Returns a pointer to the element at `index`.
/// This element *may* be uninitialized.
#[inline(always)]
fn nth_ptr(&self, index: usize) -> *const T {
debug_assert!(index < N);
unsafe {
let nth_element = &*(self.array.get_unchecked(index));
nth_element.as_ptr()
}
}
/// Returns a mutable pointer to the element at `index`.
/// This element *may* be uninitialized.
#[inline(always)]
fn nth_ptr_mut(&mut self, index: usize) -> *mut T {
debug_assert!(index < N);
unsafe {
let nth_element = &mut *(self.array.get_unchecked_mut(index));
nth_element.as_mut_ptr()
}
}
/// Returns a pointer to the first element of the array.
/// This element *may* be uninitialized.
#[inline(always)]
fn first_ptr(&mut self) -> *const T {
self.nth_ptr(0)
}
/// Returns a mutable pointer to the first element of the array.
/// This element *may* be uninitialized.
#[inline(always)]
fn first_ptr_mut(&mut self) -> *mut T {
self.nth_ptr_mut(0)
}
/// Returns a pointer to the whole array.
/// There *may* be elements in the array that are uninitialized.
#[inline(always)]
const fn array_ptr(&self) -> *const [T; N] {
&self.array as *const [MaybeUninit<T>; N] as *const [T; N]
}
/// Returns a mutable pointer to the whole array.
/// There *may* be elements in the array that are uninitialized.
#[inline(always)]
fn array_ptr_mut(&mut self) -> *mut [T; N] {
&mut self.array as *mut [MaybeUninit<T>; N] as *mut [T; N]
}
/// Reads the element at `index`.
///
/// # Unsafe
/// Marked unsafe because
/// 1) `index` is *NOT* boundschecked.
/// 2) The element at `index` may be uninitialized, thus reading it is invalid.
#[inline(always)]
pub unsafe fn take(&mut self, index: usize) -> T {
ptr::read(self.nth_ptr_mut(index))
}
/// Sets the element at `index` to `value`.
///
/// # Unsafe
/// Marked unsafe because `index` is not boundchecked.
#[inline(always)]
pub unsafe fn set(&mut self, index: usize, value: T) {
ptr::write(self.nth_ptr_mut(index), value)
}
/// Transforms `this` into an array.
/// # Unsafe
/// Marked unsafe because all elements within the `MaybeArray` *MUST*
/// be initialized. If they are not, invoking this function is UB.
pub unsafe fn into_array(mut this: MaybeArray<T, N>) -> [T; N] {
// We dont have to `mem::forget(this)`,
// since the inner array contains `MaybeUninit<T>`'s,
// which will never invoke the destructor.
let array_ptr = this.array_ptr_mut();
ptr::read(array_ptr)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment