use core::{
cmp, fmt,
mem::{self, ManuallyDrop, MaybeUninit},
ops::{Deref, DerefMut},
ptr, slice,
};
pub struct ArrayBuilder<T, const N: usize> {
buf: [MaybeUninit<T>; N],
len: usize,
}
impl<T: Clone, const N: usize> Clone for ArrayBuilder<T, N> {
fn clone(&self) -> Self {
let mut new = Self::new();
new.len = self.len();
new.deref_mut().clone_from_slice(self.deref());
new
}
}
impl<T: fmt::Debug, const N: usize> fmt::Debug for ArrayBuilder<T, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ArrayBuilder")
.field("capacity", &N)
.field("length", &self.len)
.field("values", &self.deref())
.finish()
}
}
impl<T, U, const N: usize> cmp::PartialEq<ArrayBuilder<U, N>> for ArrayBuilder<T, N>
where
T: cmp::PartialEq<U>,
{
fn eq(&self, other: &ArrayBuilder<U, N>) -> bool {
self.deref() == other.deref()
}
}
impl<T: cmp::Eq, const N: usize> cmp::Eq for ArrayBuilder<T, N> {}
impl<T: cmp::PartialOrd, const N: usize> cmp::PartialOrd for ArrayBuilder<T, N> {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
self.deref().partial_cmp(other.deref())
}
}
impl<T: cmp::Ord, const N: usize> cmp::Ord for ArrayBuilder<T, N> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.deref().cmp(other.deref())
}
}
impl<T, const N: usize> Drop for ArrayBuilder<T, N> {
fn drop(&mut self) {
self.clear()
}
}
impl<T, const N: usize> Deref for ArrayBuilder<T, N> {
type Target = [T];
fn deref(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
}
}
impl<T, const N: usize> DerefMut for ArrayBuilder<T, N> {
fn deref_mut(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
}
}
impl<T, const N: usize> From<[T; N]> for ArrayBuilder<T, N> {
fn from(array: [T; N]) -> Self {
Self {
buf: unsafe { ptr::read(array.as_ptr() as *const [MaybeUninit<T>; N]) },
len: N,
}
}
}
impl<T, const N: usize> ArrayBuilder<T, N> {
const UNINIT: MaybeUninit<T> = MaybeUninit::uninit();
pub fn new() -> Self {
Self {
buf: [Self::UNINIT; N],
len: 0,
}
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_full(&self) -> bool {
self.len == N
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn clear(&mut self) {
let s: &mut [T] = self;
unsafe {
ptr::drop_in_place(s);
}
self.len = 0;
}
fn as_ptr(&self) -> *const T {
self.buf.as_ptr() as _
}
fn as_mut_ptr(&mut self) -> *mut T {
self.buf.as_mut_ptr() as _
}
pub fn push(&mut self, t: T) {
assert!(self.len < N);
unsafe {
self.push_unchecked(t);
}
}
pub fn try_push(&mut self, t: T) -> Result<(), T> {
if self.len < N {
unsafe {
self.push_unchecked(t);
}
Ok(())
} else {
Err(t)
}
}
pub unsafe fn push_unchecked(&mut self, t: T) {
ptr::write(self.as_mut_ptr().add(self.len), t);
self.len += 1;
}
pub fn pop(&mut self) -> Option<T> {
if self.len > 0 {
unsafe { Some(self.pop_unchecked()) }
} else {
None
}
}
pub unsafe fn pop_unchecked(&mut self) -> T {
self.len -= 1;
ptr::read(self.as_ptr().add(self.len))
}
pub fn build(self) -> Result<[T; N], Self> {
if self.len == N {
unsafe { Ok(self.build_unchecked()) }
} else {
Err(self)
}
}
pub unsafe fn build_unchecked(self) -> [T; N] {
let self_ = ManuallyDrop::new(self);
ptr::read(self_.as_ptr() as *const [T; N])
}
pub fn take(&mut self) -> Self {
mem::replace(self, Self::new())
}
}