use core::fmt;
pub use safety_boundary::ArrayVec;
mod safety_boundary {
use core::mem::MaybeUninit;
use crate::const_tools::cond_const;
#[derive(Copy)]
pub struct ArrayVec<T: Copy, const CAP: usize> {
len: usize,
data: [MaybeUninit<T>; CAP],
}
impl<T: Copy, const CAP: usize> ArrayVec<T, CAP> {
pub const fn new() -> Self { Self { len: 0, data: [MaybeUninit::uninit(); CAP] } }
pub const fn from_slice(slice: &[T]) -> Self {
assert!(slice.len() <= CAP);
let mut data = [MaybeUninit::uninit(); CAP];
let mut i = 0;
while i < slice.len() {
data[i] = MaybeUninit::new(slice[i]);
i += 1;
}
Self { len: slice.len(), data }
}
cond_const! {
pub const(in 1.64) fn as_slice(&self) -> &[T] {
let ptr = &self.data as *const _ as *const T;
unsafe { core::slice::from_raw_parts(ptr, self.len) }
}
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { &mut *(&mut self.data[..self.len] as *mut _ as *mut [T]) }
}
pub fn push(&mut self, element: T) {
assert!(self.len < CAP);
self.data[self.len] = MaybeUninit::new(element);
self.len += 1;
}
pub fn extend_from_slice(&mut self, slice: &[T]) {
let new_len = self.len.checked_add(slice.len()).expect("integer/buffer overflow");
assert!(new_len <= CAP, "buffer overflow");
let slice = unsafe { &*(slice as *const _ as *const [MaybeUninit<T>]) };
self.data[self.len..new_len].copy_from_slice(slice);
self.len = new_len;
}
}
}
impl<T: Copy, const CAP: usize> Default for ArrayVec<T, CAP> {
fn default() -> Self { Self::new() }
}
#[allow(clippy::non_canonical_clone_impl)]
impl<T: Copy, const CAP: usize> Clone for ArrayVec<T, CAP> {
fn clone(&self) -> Self { Self::from_slice(self) }
}
impl<T: Copy, const CAP: usize> core::ops::Deref for ArrayVec<T, CAP> {
type Target = [T];
fn deref(&self) -> &Self::Target { self.as_slice() }
}
impl<T: Copy, const CAP: usize> core::ops::DerefMut for ArrayVec<T, CAP> {
fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut_slice() }
}
impl<T: Copy + Eq, const CAP: usize> Eq for ArrayVec<T, CAP> {}
impl<T: Copy + PartialEq, const CAP1: usize, const CAP2: usize> PartialEq<ArrayVec<T, CAP2>>
for ArrayVec<T, CAP1>
{
fn eq(&self, other: &ArrayVec<T, CAP2>) -> bool { **self == **other }
}
impl<T: Copy + PartialEq, const CAP: usize> PartialEq<[T]> for ArrayVec<T, CAP> {
fn eq(&self, other: &[T]) -> bool { **self == *other }
}
impl<T: Copy + PartialEq, const CAP: usize> PartialEq<ArrayVec<T, CAP>> for [T] {
fn eq(&self, other: &ArrayVec<T, CAP>) -> bool { *self == **other }
}
impl<T: Copy + PartialEq, const CAP: usize, const LEN: usize> PartialEq<[T; LEN]>
for ArrayVec<T, CAP>
{
fn eq(&self, other: &[T; LEN]) -> bool { **self == *other }
}
impl<T: Copy + PartialEq, const CAP: usize, const LEN: usize> PartialEq<ArrayVec<T, CAP>>
for [T; LEN]
{
fn eq(&self, other: &ArrayVec<T, CAP>) -> bool { *self == **other }
}
impl<T: Copy + Ord, const CAP: usize> Ord for ArrayVec<T, CAP> {
fn cmp(&self, other: &ArrayVec<T, CAP>) -> core::cmp::Ordering { (**self).cmp(&**other) }
}
impl<T: Copy + PartialOrd, const CAP1: usize, const CAP2: usize> PartialOrd<ArrayVec<T, CAP2>>
for ArrayVec<T, CAP1>
{
fn partial_cmp(&self, other: &ArrayVec<T, CAP2>) -> Option<core::cmp::Ordering> {
(**self).partial_cmp(&**other)
}
}
impl<T: Copy + fmt::Debug, const CAP: usize> fmt::Debug for ArrayVec<T, CAP> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) }
}
impl<T: Copy + core::hash::Hash, const CAP: usize> core::hash::Hash for ArrayVec<T, CAP> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) { core::hash::Hash::hash(&**self, state) }
}
#[cfg(test)]
mod tests {
use super::ArrayVec;
#[test]
fn arrayvec_ops() {
let mut av = ArrayVec::<_, 1>::new();
assert!(av.is_empty());
av.push(42);
assert_eq!(av.len(), 1);
assert_eq!(av, [42]);
}
#[test]
#[should_panic]
fn overflow_push() {
let mut av = ArrayVec::<_, 0>::new();
av.push(42);
}
#[test]
#[should_panic]
fn overflow_extend() {
let mut av = ArrayVec::<_, 0>::new();
av.extend_from_slice(&[42]);
}
#[test]
fn extend_from_slice() {
let mut av = ArrayVec::<u8, 8>::new();
av.extend_from_slice(b"abc");
}
}