#![no_std]
#![feature(
associated_type_bounds,
const_fn,
const_fn_union,
const_generics,
const_mut_refs,
maybe_uninit_extra,
maybe_uninit_ref,
maybe_uninit_slice_assume_init,
track_caller,
untagged_unions
)]
#![allow(incomplete_features)]
#[cfg(test)]
mod tests;
#[cfg(test)]
#[macro_use]
extern crate std;
use core::{
cmp,
fmt::{self, Debug, Formatter},
mem::{ManuallyDrop, MaybeUninit},
ops::{Bound, Range, RangeBounds},
ptr,
slice::{self, SliceIndex},
};
fn to_range(range: impl RangeBounds<usize>, len: usize) -> Range<usize> {
let start = match range.start_bound() {
Bound::Included(&n) => n,
Bound::Excluded(&n) => n + 1,
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(&n) => n + 1,
Bound::Excluded(&n) => n,
Bound::Unbounded => len,
};
start..end
}
pub struct ConstBuffer<T, const N: usize>([MaybeUninit<T>; N]);
impl<T, const N: usize> ConstBuffer<T, N> {
#[inline]
const fn from_maybe_uninit_array(maybe_uninit: MaybeUninit<[T; N]>) -> Self {
union Transmute<T, const N: usize> {
maybe_uninit: MaybeUninit<[T; N]>,
array: ManuallyDrop<[MaybeUninit<T>; N]>,
}
let array = unsafe { Transmute { maybe_uninit }.array };
Self(ManuallyDrop::into_inner(array))
}
#[inline]
pub const fn from_array(array: [T; N]) -> Self {
Self::from_maybe_uninit_array(MaybeUninit::new(array))
}
#[inline]
pub const fn new() -> Self {
Self::from_maybe_uninit_array(MaybeUninit::<[T; N]>::uninit())
}
#[inline]
pub fn zeroed() -> Self {
Self::from_maybe_uninit_array(MaybeUninit::<[T; N]>::zeroed())
}
#[inline]
pub const fn as_ptr(&self) -> *const T {
self.0.as_ptr().cast()
}
#[inline]
pub const fn as_mut_ptr(&mut self) -> *mut T {
(&mut self.0 as *mut [MaybeUninit<T>; N]).cast()
}
#[inline]
#[track_caller]
pub unsafe fn read(&self, index: usize) -> T {
debug_assert!(index < N);
self.0.get_unchecked(index).read()
}
#[inline]
#[track_caller]
pub unsafe fn write(&mut self, index: usize, value: T) -> &mut T {
debug_assert!(index < N);
self.0.get_unchecked_mut(index).write(value)
}
#[inline]
#[track_caller]
pub unsafe fn get<'a, I>(&'a self, index: I) -> &I::Output
where I: BufferIndex<'a, T> {
index.get(self)
}
#[inline]
#[track_caller]
pub unsafe fn get_mut<'a, I>(&'a mut self, index: I) -> &mut I::Output
where I: BufferIndex<'a, T> {
index.get_mut(self)
}
#[inline]
#[track_caller]
pub unsafe fn swap(&mut self, i: usize, j: usize) {
debug_assert!(i < N && j < N);
ptr::swap(self.as_mut_ptr().add(i), self.as_mut_ptr().add(j));
}
#[inline]
#[track_caller]
pub unsafe fn swap_nonoverlapping(&mut self, i: usize, j: usize) {
debug_assert!(i < N && j < N && i != j);
ptr::swap_nonoverlapping(self.as_mut_ptr().add(i), self.as_mut_ptr().add(j), 1);
}
#[inline]
pub fn resize<const M: usize>(&self) -> ConstBuffer<T, M> {
let mut new = ConstBuffer::new();
unsafe { self.0.as_ptr().copy_to_nonoverlapping(new.0.as_mut_ptr(), cmp::min(N, M)) };
new
}
#[inline]
#[track_caller]
pub unsafe fn copy_within<R>(&mut self, src: R, dest: usize)
where R: RangeBounds<usize> {
let src = to_range(src, N);
debug_assert!(src.start <= src.end && src.end <= N && dest + src.len() <= N);
self.0.as_ptr().add(src.start).copy_to(self.0.as_mut_ptr().add(dest), src.len());
}
#[inline]
#[track_caller]
pub unsafe fn copy_within_nonoverlapping<R>(&mut self, src: R, dest: usize)
where R: RangeBounds<usize> {
let src = to_range(src, N);
debug_assert!(src.start <= src.end && src.end <= N && dest + src.len() <= N);
debug_assert!(
src.len() <= cmp::max(src.start, dest) - cmp::min(src.start, dest),
"attempt to copy to overlapping memory"
);
self.as_ptr().add(src.start).copy_to_nonoverlapping(self.as_mut_ptr().add(dest), src.len())
}
#[inline]
#[track_caller]
pub unsafe fn copy_from_slice(&mut self, index: usize, slice: &[T]) {
debug_assert!(index + slice.len() <= N);
slice.as_ptr().copy_to_nonoverlapping(self.as_mut_ptr().add(index), slice.len());
}
#[inline]
#[track_caller]
pub unsafe fn clone_from_slice(&mut self, index: usize, slice: &[T])
where T: Clone {
debug_assert!(index + slice.len() <= N);
(index..).zip(slice).for_each(|(i, x)| {
self.write(i, x.clone());
});
}
#[inline]
pub fn as_maybe_uninit_slice(&self) -> &[MaybeUninit<T>] {
unsafe { slice::from_raw_parts(self.0.as_ptr(), N) }
}
#[inline]
pub fn as_maybe_uninit_mut_slice(&mut self) -> &mut [MaybeUninit<T>] {
unsafe { slice::from_raw_parts_mut(self.0.as_mut_ptr(), N) }
}
}
impl<T, const N: usize> Default for ConstBuffer<T, N> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<T, const N: usize> Clone for ConstBuffer<T, N> {
#[inline]
fn clone(&self) -> Self {
self.resize()
}
#[inline]
fn clone_from(&mut self, source: &Self) {
unsafe { source.0.as_ptr().copy_to_nonoverlapping(self.0.as_mut_ptr(), N) };
}
}
impl<T, const N: usize> Debug for ConstBuffer<T, N> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.pad(core::any::type_name::<Self>())
}
}
impl<T, const N: usize> From<[T; N]> for ConstBuffer<T, N> {
#[inline]
fn from(array: [T; N]) -> Self {
Self::from_array(array)
}
}
impl<T, const N: usize> From<[MaybeUninit<T>; N]> for ConstBuffer<T, N> {
#[inline]
fn from(array: [MaybeUninit<T>; N]) -> Self {
Self(array)
}
}
impl<T, const N: usize> From<MaybeUninit<[T; N]>> for ConstBuffer<T, N> {
#[inline]
fn from(maybe_uninit: MaybeUninit<[T; N]>) -> Self {
Self::from_maybe_uninit_array(maybe_uninit)
}
}
pub trait BufferIndex<'a, T> {
type Output: ?Sized;
unsafe fn get<const N: usize>(self, buffer: &'a ConstBuffer<T, N>) -> &'a Self::Output;
unsafe fn get_mut<const N: usize>(
self,
buffer: &'a mut ConstBuffer<T, N>,
) -> &'a mut Self::Output;
}
impl<'a, T, O: ?Sized, I> BufferIndex<'a, T> for I
where I: SliceIndex<[MaybeUninit<T>], Output: UninitWrapper<Output = O> + 'a> + Clone
{
type Output = O;
unsafe fn get<const N: usize>(self, buffer: &'a ConstBuffer<T, N>) -> &'a Self::Output {
debug_assert!(buffer.0.get(self.clone()).is_some());
buffer.0.get_unchecked(self).get()
}
unsafe fn get_mut<const N: usize>(
self,
buffer: &'a mut ConstBuffer<T, N>,
) -> &'a mut Self::Output
{
debug_assert!(buffer.0.get(self.clone()).is_some());
buffer.0.get_unchecked_mut(self).get_mut()
}
}
pub trait UninitWrapper {
type Output: ?Sized;
unsafe fn get(&self) -> &Self::Output;
unsafe fn get_mut(&mut self) -> &mut Self::Output;
}
impl<T> UninitWrapper for MaybeUninit<T> {
type Output = T;
unsafe fn get(&self) -> &Self::Output {
self.get_ref()
}
unsafe fn get_mut(&mut self) -> &mut Self::Output {
self.get_mut()
}
}
impl<T> UninitWrapper for [MaybeUninit<T>] {
type Output = [T];
unsafe fn get(&self) -> &Self::Output {
MaybeUninit::slice_get_ref(self)
}
unsafe fn get_mut(&mut self) -> &mut Self::Output {
MaybeUninit::slice_get_mut(self)
}
}