use core::fmt::{self, Debug};
use core::mem::{ManuallyDrop, MaybeUninit};
use crate::{
array::IntoIter,
drop_flavor::{DropFlavor, MayDrop, NonDrop, as_inner, as_inner_mut, wrap},
};
use typewit::Identity;
#[repr(transparent)]
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))]
pub struct ArrayBuilder<T, const N: usize, D: DropFlavor> {
inner: D::Wrap<ArrayBuilderInner<T, N>>,
}
#[repr(C)]
pub struct ArrayBuilderInner<T, const N: usize> {
array: [MaybeUninit<T>; N],
inited: usize,
}
impl<T, const N: usize> ArrayBuilderInner<T, N> {
const fn into_builder<D: DropFlavor>(self) -> ArrayBuilder<T, N, D> {
ArrayBuilder { inner: wrap(self) }
}
}
impl<T, const N: usize> ArrayBuilder<T, N, MayDrop> {
#[inline(always)]
pub const fn of_drop<const N2: usize>() -> Self
where
Self: Identity<Type = ArrayBuilder<T, N2, MayDrop>>,
{
Self::of_any()
}
}
impl<T, const N: usize> ArrayBuilder<T, N, NonDrop> {
#[inline(always)]
pub const fn of_copy<const N2: usize>() -> Self
where
T: Copy,
Self: Identity<Type = ArrayBuilder<T, N2, NonDrop>>,
{
Self::of_any()
}
#[inline(always)]
pub const fn of_assumed_nondrop<const N2: usize>() -> Self
where
Self: Identity<Type = ArrayBuilder<T, N2, NonDrop>>,
{
Self::of_any()
}
}
impl<T, const N: usize, D: DropFlavor> ArrayBuilder<T, N, D> {
const fn of_any() -> Self {
ArrayBuilderInner {
array: crate::maybe_uninit::uninit_array(),
inited: 0,
}
.into_builder()
}
pub const fn len(&self) -> usize {
as_inner::<D, _>(&self.inner).inited
}
pub const fn is_empty(&self) -> bool {
as_inner::<D, _>(&self.inner).inited == 0
}
pub const fn is_full(&self) -> bool {
as_inner::<D, _>(&self.inner).inited == N
}
pub const fn as_slice(&self) -> &[T] {
unsafe {
let this = as_inner::<D, _>(&self.inner);
core::slice::from_raw_parts(this.array.as_ptr().cast::<T>(), this.inited)
}
}
pub const fn as_mut_slice(&mut self) -> &mut [T] {
let this = as_inner_mut::<D, _>(&mut self.inner);
unsafe { core::slice::from_raw_parts_mut(this.array.as_mut_ptr().cast::<T>(), this.inited) }
}
#[track_caller]
pub const fn push(&mut self, val: T) {
let this = as_inner_mut::<D, _>(&mut self.inner);
assert!(this.inited < N, "trying to add an element to full array");
this.array[this.inited] = MaybeUninit::new(val);
this.inited += 1;
}
#[track_caller]
pub const fn extend_from_array<const N2: usize>(&mut self, another_array: [T; N2]) {
let this = as_inner_mut::<D, _>(&mut self.inner);
let next_len = match this.inited.checked_add(N2) {
Some(x) if x <= N => x,
_ => panic!("trying to add too many elements to array"),
};
unsafe {
this.array
.as_mut_ptr()
.add(this.inited)
.cast::<[T; N2]>()
.write(another_array);
}
this.inited = next_len;
}
#[track_caller]
pub const fn extend_from_slice(&mut self, slice: &[T])
where
T: Copy,
{
let this = as_inner_mut::<D, _>(&mut self.inner);
let next_len = match this.inited.checked_add(slice.len()) {
Some(x) if x <= N => x,
_ => panic!("trying to add too many elements to array"),
};
unsafe {
this.array
.as_mut_ptr()
.cast::<T>()
.add(this.inited)
.copy_from_nonoverlapping(slice.as_ptr(), slice.len())
}
this.inited = next_len;
}
#[track_caller]
pub const fn build(self) -> [T; N] {
assert!(
self.is_full(),
"trying to unwrap a non-fully-initialized array"
);
unsafe {
let mut this = ManuallyDrop::new(self);
(&raw mut this).cast::<[T; N]>().read()
}
}
pub const fn copy(&self) -> Self
where
T: Copy,
{
ArrayBuilderInner {
..*as_inner::<D, _>(&self.inner)
}
.into_builder()
}
pub const fn into_drop(self) -> ArrayBuilder<T, N, MayDrop> {
self.into_any_flavor()
}
pub const fn into_copy(self) -> ArrayBuilder<T, N, NonDrop>
where
T: Copy,
{
self.into_any_flavor()
}
const fn into_any_flavor<D2: DropFlavor>(self) -> ArrayBuilder<T, N, D2> {
unsafe { crate::__priv_transmute!(ArrayBuilder<T, N, D>, ArrayBuilder<T, N, D2>, self) }
}
pub const fn infer_length_from_consumer<U, D2>(&self, _consumer: &IntoIter<U, N, D2>)
where
D2: DropFlavor,
{
}
}
impl<T, const N: usize> Default for ArrayBuilder<T, N, MayDrop> {
fn default() -> Self {
Self::of_drop()
}
}
impl<T: Copy, const N: usize> Default for ArrayBuilder<T, N, NonDrop> {
fn default() -> Self {
Self::of_copy()
}
}
impl<T: Debug, const N: usize, D: DropFlavor> Debug for ArrayBuilder<T, N, D> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let this = as_inner::<D, _>(&self.inner);
fmt.debug_struct("ArrayBuilder")
.field("array", &self.as_slice())
.field("uninit_len", &(N - this.inited))
.finish()
}
}
impl<T: Clone, const N: usize, D: DropFlavor> Clone for ArrayBuilder<T, N, D> {
fn clone(&self) -> Self {
let mut this = Self::of_any();
for elem in self.as_slice() {
this.push(elem.clone());
}
this
}
}
impl<T, const N: usize> Drop for ArrayBuilderInner<T, N> {
fn drop(&mut self) {
unsafe {
let inited = self.inited;
let ptr = self.array.as_mut_ptr().cast::<T>();
core::ptr::slice_from_raw_parts_mut(ptr, inited).drop_in_place();
}
}
}