use alloc::boxed::Box;
use alloc::vec::Vec;
use core::fmt::Debug;
use core::iter::FusedIterator;
use core::mem::{ManuallyDrop, MaybeUninit};
use core::panic::{RefUnwindSafe, UnwindSafe};
use core::ptr::NonNull;
use core::{ptr, slice};
use super::utils::{IsZST, split_range_bound, zst_init};
pub struct ArrayVec<T, const N: usize> {
len: usize,
data: [MaybeUninit<T>; N],
}
unsafe impl<T: Sync, const N: usize> Sync for ArrayVec<T, N> {}
unsafe impl<T: Send, const N: usize> Send for ArrayVec<T, N> {}
impl<T, const N: usize> UnwindSafe for ArrayVec<T, N> where T: UnwindSafe {}
impl<T, const N: usize> RefUnwindSafe for ArrayVec<T, N> where T: RefUnwindSafe {}
impl<T, const N: usize> Default for ArrayVec<T, N> {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl<T, const N: usize> Drop for ArrayVec<T, N> {
fn drop(&mut self) {
if core::mem::needs_drop::<T>() {
self.clear();
}
}
}
impl<T, const N: usize> ArrayVec<T, N> {
#[inline(always)]
pub const fn capacity(&self) -> usize {
N
}
#[inline(always)]
pub const fn len(&self) -> usize {
self.len
}
#[inline(always)]
pub const fn is_empty(&self) -> bool {
self.len == 0
}
#[inline(always)]
pub const fn is_full(&self) -> bool {
self.len == N
}
#[inline(always)]
pub const fn as_ptr(&self) -> *const T {
&raw const self.data as *const T
}
#[inline(always)]
pub const fn as_mut_ptr(&mut self) -> *mut T {
&raw mut self.data as *mut T
}
#[inline]
pub const fn as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
}
#[inline]
pub const fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
}
#[inline(always)]
pub const unsafe fn set_len(&mut self, new_len: usize) {
debug_assert!(new_len <= N);
self.len = new_len
}
#[inline]
pub fn clear(&mut self) {
if core::mem::needs_drop::<T>() {
unsafe {
let slice: &mut [T] = self.as_mut_slice();
ptr::drop_in_place::<[T]>(slice);
}
}
self.len = 0;
}
#[inline]
pub fn truncate(&mut self, len: usize) {
if self.len > len {
if core::mem::needs_drop::<T>() {
unsafe {
let data = self.as_mut_ptr().add(len);
let len = self.len - len;
let to_drop = ptr::slice_from_raw_parts_mut(data, len);
ptr::drop_in_place::<[T]>(to_drop);
}
}
self.len = len;
}
}
}
impl<T, const N: usize> ArrayVec<T, N> {
#[must_use]
#[inline(always)]
pub const fn new() -> Self {
Self {
data: unsafe { MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init() },
len: 0,
}
}
#[inline]
#[must_use]
pub const fn from_slice(slice: &[T]) -> Self
where
T: Copy,
{
let length = slice.len();
assert!(length <= N, "length overflow");
let mut vec = Self::new();
if !T::IS_ZST {
unsafe {
let src = slice.as_ptr();
let dst = vec.as_mut_ptr();
ptr::copy_nonoverlapping(src, dst, length);
}
}
vec.len = length;
vec
}
#[inline]
pub fn into_vec(mut self) -> Vec<T> {
let mut vec: Vec<T> = Vec::with_capacity(self.len);
unsafe {
ptr::copy_nonoverlapping(self.as_ptr(), vec.as_mut_ptr(), self.len);
vec.set_len(self.len);
self.len = 0;
}
vec
}
#[inline]
pub fn into_boxed_slice(self) -> Box<[T]> {
self.into_vec().into_boxed_slice()
}
#[inline]
pub const fn push(&mut self, value: T) {
assert!(!self.is_full(), "length overflow during `push`");
unsafe {
self.push_unchecked(value);
}
}
#[inline]
pub const fn try_push(&mut self, value: T) -> Result<(), T> {
if self.is_full() {
Err(value)
} else {
unsafe {
self.push_unchecked(value);
}
Ok(())
}
}
#[inline(always)]
pub const unsafe fn push_unchecked(&mut self, value: T) {
let len: usize = self.len;
if T::IS_ZST {
::core::mem::forget(value);
} else {
unsafe {
ptr::write(self.as_mut_ptr().add(len), value);
}
}
self.len = len + 1;
}
#[inline(always)]
pub const fn pop(&mut self) -> Option<T> {
if self.len == 0 {
crate::utils::cold_path();
None
} else {
unsafe {
self.len -= 1;
core::hint::assert_unchecked(self.len < self.capacity());
if T::IS_ZST {
Some(zst_init())
} else {
Some(ptr::read(self.as_ptr().add(self.len)))
}
}
}
}
#[inline]
pub fn pop_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option<T> {
if self.len == 0 {
crate::utils::cold_path();
None
} else {
unsafe {
let ptr = self.as_mut_ptr().add(self.len - 1);
if predicate(&mut *ptr) {
self.len -= 1;
Some(ptr::read(ptr))
} else {
None
}
}
}
}
#[inline]
pub const fn insert(&mut self, index: usize, element: T) {
assert!(index <= self.len, "insertion index should be <= len");
assert!(self.len < N, "length overflow during `insert`");
if T::IS_ZST {
::core::mem::forget(element);
} else {
unsafe {
let ptr = self.as_mut_ptr().add(index);
if index < self.len {
ptr::copy(ptr, ptr.add(1), self.len - index);
}
ptr::write(ptr, element);
}
}
self.len += 1;
}
#[inline]
pub const fn remove(&mut self, index: usize) -> T {
assert!(index < self.len, "removal index should be < len");
unsafe {
let value: T;
if T::IS_ZST {
value = zst_init();
} else {
let ptr = self.as_mut_ptr().add(index);
value = ptr::read(ptr);
ptr::copy(ptr.add(1), ptr, self.len - index - 1);
}
self.len -= 1;
value
}
}
#[inline]
pub const fn swap_remove(&mut self, index: usize) -> T {
assert!(index < self.len, "removal index should be < len");
unsafe {
let value: T;
if T::IS_ZST {
value = zst_init();
} else {
let base_ptr = self.as_mut_ptr();
value = ptr::read(base_ptr.add(index));
ptr::copy(base_ptr.add(self.len - 1), base_ptr.add(index), 1);
}
self.len -= 1;
value
}
}
pub fn append<const P: usize>(&mut self, other: &mut ArrayVec<T, P>) {
assert!(other.len <= N - self.len, "length overflow during `append`");
unsafe {
let slice = other.as_slice();
let count = slice.len();
if !T::IS_ZST {
let len = self.len();
let dst = self.as_mut_ptr().add(len);
ptr::copy_nonoverlapping::<T>(slice.as_ptr(), dst, count);
}
self.len += count;
other.len = 0;
}
}
pub fn resize_with<F: FnMut() -> T>(&mut self, new_len: usize, mut f: F) {
assert!(new_len <= N, "length overflow during `resize_with`");
let len = self.len();
if new_len > len {
let ptr = self.as_mut_ptr();
(len..new_len).for_each(|idx| unsafe {
ptr::write(ptr.add(idx), f());
});
self.len = new_len;
} else {
self.truncate(new_len);
}
}
pub fn retain_mut<F: FnMut(&mut T) -> bool>(&mut self, mut f: F) {
let mut count = 0usize;
let base_ptr = self.as_mut_ptr();
for index in 0..self.len {
unsafe {
let dst = base_ptr.add(index);
if f(&mut *dst) {
ptr::copy(dst, base_ptr.add(count), 1);
count += 1;
} else {
ptr::drop_in_place(dst);
}
}
}
self.len = count;
}
#[inline]
pub fn retain<F: FnMut(&T) -> bool>(&mut self, mut f: F) {
self.retain_mut(|v| f(v));
}
pub fn dedup_by<F: FnMut(&mut T, &mut T) -> bool>(&mut self, mut same_bucket: F) {
if self.len <= 1 {
return;
}
let ptr = self.as_mut_ptr();
let mut left = 0usize;
unsafe {
let mut p_l = ptr.add(left);
for right in 1..self.len {
let p_r = ptr.add(right);
if !same_bucket(&mut *p_r, &mut *p_l) {
left += 1;
p_l = ptr.add(left);
if right != left {
ptr::swap(p_r, p_l);
}
}
}
}
self.truncate(left + 1);
}
#[inline]
pub fn dedup_by_key<F, K>(&mut self, mut key: F)
where
F: FnMut(&mut T) -> K,
K: PartialEq,
{
self.dedup_by(|a, b| key(a) == key(b));
}
#[inline]
pub const fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
unsafe { slice::from_raw_parts_mut(self.data.as_mut_ptr().add(self.len), N - self.len) }
}
}
super::utils::impl_common_traits!(ArrayVec<T, N>);
impl<T, U, const N: usize> PartialEq<ArrayVec<U, N>> for ArrayVec<T, N>
where
T: PartialEq<U>,
{
#[inline]
fn eq(&self, other: &ArrayVec<U, N>) -> bool {
PartialEq::eq(self.as_slice(), other.as_slice())
}
}
impl<T: PartialEq, const N: usize> ArrayVec<T, N> {
#[inline]
pub fn dedup(&mut self) {
self.dedup_by(|x, y| PartialEq::eq(x, y));
}
}
impl<T: Clone, const N: usize> Clone for ArrayVec<T, N> {
fn clone(&self) -> Self {
let mut vec = Self::new();
for item in self.as_slice() {
unsafe { vec.push_unchecked(item.clone()) };
}
vec
}
fn clone_from(&mut self, source: &Self) {
self.clear();
for item in source.as_slice() {
unsafe { self.push_unchecked(item.clone()) };
}
}
}
impl<'a, T: 'a + Clone, const N: usize> Extend<&'a T> for ArrayVec<T, N> {
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
for item in iter {
self.push(item.clone());
}
}
}
impl<T, const N: usize> Extend<T> for ArrayVec<T, N> {
#[inline]
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
for item in iter {
self.push(item);
}
}
}
impl<T, const N: usize> FromIterator<T> for ArrayVec<T, N> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut vec = Self::new();
for item in iter {
vec.push(item);
}
vec
}
}
impl<T, const N: usize> From<ArrayVec<T, N>> for Vec<T> {
fn from(v: ArrayVec<T, N>) -> Vec<T> {
v.into_vec()
}
}
impl<T, const N: usize> From<ArrayVec<T, N>> for Box<[T]> {
fn from(v: ArrayVec<T, N>) -> Box<[T]> {
v.into_vec().into_boxed_slice()
}
}
impl<T, const N: usize, const P: usize> TryFrom<ArrayVec<T, N>> for [T; P] {
type Error = ArrayVec<T, N>;
fn try_from(mut vec: ArrayVec<T, N>) -> Result<[T; P], ArrayVec<T, N>> {
if vec.len() != P {
return Err(vec);
}
let src = vec.as_ptr();
unsafe { vec.set_len(0) };
let array = unsafe { ptr::read(src as *const [T; P]) };
Ok(array)
}
}
impl<T, const N: usize> From<[T; N]> for ArrayVec<T, N> {
fn from(array: [T; N]) -> Self {
let array = ManuallyDrop::new(array);
let mut vec = <ArrayVec<T, N>>::new();
let dst = &raw mut vec.data;
let src = &raw const *array as *const [MaybeUninit<T>; N];
unsafe {
ptr::copy_nonoverlapping(src, dst, 1);
vec.set_len(N);
}
vec
}
}
pub struct IntoIter<T, const N: usize> {
vec: ManuallyDrop<ArrayVec<T, N>>,
index: usize,
}
unsafe impl<T: Send, const N: usize> Send for IntoIter<T, N> {}
unsafe impl<T: Sync, const N: usize> Sync for IntoIter<T, N> {}
impl<T, const N: usize> IntoIterator for ArrayVec<T, N> {
type Item = T;
type IntoIter = IntoIter<T, N>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
IntoIter {
vec: ManuallyDrop::new(self),
index: 0,
}
}
}
impl<T, const N: usize> Iterator for IntoIter<T, N> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.vec.len() {
self.index += 1;
unsafe { Some(ptr::read(self.vec.as_ptr().add(self.index - 1))) }
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let v = self.vec.len() - self.index;
(v, Some(v))
}
}
impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
let len = self.vec.len();
if self.index < len {
unsafe {
self.vec.set_len(len - 1);
}
unsafe { Some(ptr::read(self.vec.as_ptr().add(len - 1))) }
} else {
None
}
}
}
impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> {
#[inline]
fn len(&self) -> usize {
self.vec.len() - self.index
}
}
impl<T, const N: usize> FusedIterator for IntoIter<T, N> {}
impl<T: Debug, const N: usize> Debug for IntoIter<T, N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("IntoIter")
.field(&self.vec.as_slice())
.finish()
}
}
impl<T, const N: usize> Drop for IntoIter<T, N> {
fn drop(&mut self) {
if self.index < self.vec.len {
unsafe {
ptr::drop_in_place(ptr::slice_from_raw_parts_mut(
self.vec.as_mut_ptr().add(self.index),
self.vec.len - self.index,
));
}
}
}
}
impl<T, const N: usize> Default for IntoIter<T, N> {
fn default() -> Self {
Self {
vec: ManuallyDrop::new(ArrayVec::new()),
index: 0,
}
}
}
pub struct Drain<'a, T: 'a, const N: usize> {
tail_start: usize,
tail_len: usize,
iter: slice::Iter<'a, T>,
vec: NonNull<ArrayVec<T, N>>,
}
impl<T, const N: usize> ArrayVec<T, N> {
pub fn drain<R: core::ops::RangeBounds<usize>>(&mut self, range: R) -> Drain<'_, T, N> {
let len = self.len();
let (start, end) = split_range_bound(&range, len);
unsafe {
self.set_len(start);
let data = self.as_ptr().add(start);
let range_slice = slice::from_raw_parts(data, end - start);
Drain {
tail_start: end,
tail_len: len - end,
iter: range_slice.iter(),
vec: NonNull::new_unchecked(self as *mut _),
}
}
}
}
impl<T: Debug, const N: usize> Debug for Drain<'_, T, N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Drain").field(&self.iter.as_slice()).finish()
}
}
impl<T, const N: usize> Iterator for Drain<'_, T, N> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<T> {
self.iter
.next()
.map(|reference| unsafe { ptr::read(reference) })
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<T, const N: usize> DoubleEndedIterator for Drain<'_, T, N> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.iter
.next_back()
.map(|reference| unsafe { ptr::read(reference) })
}
}
impl<T, const N: usize> ExactSizeIterator for Drain<'_, T, N> {
#[inline]
fn len(&self) -> usize {
self.iter.len()
}
}
impl<T, const N: usize> FusedIterator for Drain<'_, T, N> {}
impl<'a, T: 'a, const N: usize> Drop for Drain<'a, T, N> {
fn drop(&mut self) {
struct DropGuard<'r, 'a, T, const N: usize>(&'r mut Drain<'a, T, N>);
impl<'r, 'a, T, const N: usize> Drop for DropGuard<'r, 'a, T, N> {
fn drop(&mut self) {
if self.0.tail_len > 0 {
unsafe {
let source_vec = self.0.vec.as_mut();
let start = source_vec.len();
let tail = self.0.tail_start;
if tail != start {
let base = source_vec.as_mut_ptr();
let src = base.add(tail);
let dst = base.add(start);
ptr::copy(src, dst, self.0.tail_len);
}
source_vec.set_len(start + self.0.tail_len);
}
}
}
}
let iter = core::mem::take(&mut self.iter);
let drop_len = iter.len();
let mut vec = self.vec;
if T::IS_ZST {
unsafe {
let vec = vec.as_mut();
let old_len = vec.len();
vec.set_len(old_len + drop_len + self.tail_len);
vec.truncate(old_len + self.tail_len);
}
return;
}
let _guard = DropGuard(self);
if drop_len == 0 {
return;
}
let drop_ptr = iter.as_slice().as_ptr();
unsafe {
let vec_ptr = vec.as_mut().as_mut_ptr();
let drop_offset = drop_ptr.offset_from_unsigned(vec_ptr);
let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len);
ptr::drop_in_place(to_drop);
}
}
}
pub struct ExtractIf<'a, T, F: FnMut(&mut T) -> bool, const N: usize> {
vec: &'a mut ArrayVec<T, N>,
idx: usize,
end: usize,
del: usize,
old_len: usize,
pred: F,
}
impl<T, const N: usize> ArrayVec<T, N> {
pub fn extract_if<F, R>(&mut self, range: R, filter: F) -> ExtractIf<'_, T, F, N>
where
F: FnMut(&mut T) -> bool,
R: core::ops::RangeBounds<usize>,
{
let old_len = self.len();
let (start, end) = split_range_bound(&range, old_len);
unsafe {
self.set_len(0);
}
ExtractIf {
vec: self,
idx: start,
del: 0,
end,
old_len,
pred: filter,
}
}
}
impl<T, F: FnMut(&mut T) -> bool, const N: usize> Iterator for ExtractIf<'_, T, F, N> {
type Item = T;
fn next(&mut self) -> Option<T> {
while self.idx < self.end {
let i = self.idx;
let cur = unsafe { &mut *self.vec.as_mut_ptr().add(i) };
let drained = (self.pred)(cur);
self.idx += 1;
if drained {
self.del += 1;
return Some(unsafe { ptr::read(cur) });
} else if self.del > 0 {
unsafe {
let hole_slot = self.vec.as_mut_ptr().add(i - self.del);
ptr::copy_nonoverlapping(cur, hole_slot, 1);
}
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.end - self.idx))
}
}
impl<T, F: FnMut(&mut T) -> bool, const N: usize> Drop for ExtractIf<'_, T, F, N> {
fn drop(&mut self) {
if !T::IS_ZST && self.del > 0 {
unsafe {
let base = self.vec.as_mut_ptr();
ptr::copy(
base.add(self.idx),
base.add(self.idx - self.del),
self.old_len - self.idx,
);
}
}
unsafe {
self.vec.set_len(self.old_len - self.del);
}
}
}
impl<T: Debug, F: FnMut(&mut T) -> bool, const N: usize> Debug for ExtractIf<'_, T, F, N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let peek = if self.idx < self.end {
self.vec.get(self.idx)
} else {
None
};
f.debug_struct("ExtractIf")
.field("peek", &peek)
.finish_non_exhaustive()
}
}
#[cfg(test)]
mod tests {
use super::ArrayVec;
use core::sync::atomic::{AtomicUsize, Ordering};
macro_rules! define_tracker {
() => {
static DROPS: AtomicUsize = AtomicUsize::new(0);
struct Tracker;
impl Drop for Tracker {
fn drop(&mut self) {
DROPS.fetch_add(1, Ordering::SeqCst);
}
}
};
}
#[test]
fn drop_zst() {
define_tracker!();
DROPS.store(0, Ordering::SeqCst);
let mut vec = ArrayVec::<Tracker, 8>::new();
vec.push(Tracker);
vec.push(Tracker);
vec.push(Tracker);
vec.push(Tracker);
vec.push(Tracker);
{
let mut drain = vec.drain(1..4);
let one = drain.next_back().unwrap();
drop(one);
assert_eq!(DROPS.load(Ordering::SeqCst), 1);
}
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
drop(vec);
assert_eq!(DROPS.load(Ordering::SeqCst), 5);
}
#[test]
fn drop_vec() {
define_tracker!();
DROPS.store(0, Ordering::SeqCst);
{
let mut vec = ArrayVec::<Tracker, 4>::new();
vec.push(Tracker);
vec.push(Tracker);
vec.push(Tracker);
assert_eq!(DROPS.load(Ordering::SeqCst), 0);
}
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
}
#[test]
fn drop_pop_remove() {
define_tracker!();
DROPS.store(0, Ordering::SeqCst);
let mut vec = ArrayVec::<Tracker, 4>::new();
vec.push(Tracker);
vec.push(Tracker);
vec.push(Tracker);
let popped = vec.pop().unwrap();
assert_eq!(DROPS.load(Ordering::SeqCst), 0);
drop(popped);
assert_eq!(DROPS.load(Ordering::SeqCst), 1);
let removed = vec.remove(0);
assert_eq!(DROPS.load(Ordering::SeqCst), 1);
drop(removed);
assert_eq!(DROPS.load(Ordering::SeqCst), 2);
drop(vec);
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
}
#[test]
fn drop_into_iter() {
define_tracker!();
DROPS.store(0, Ordering::SeqCst);
let mut vec = ArrayVec::<Tracker, 4>::new();
vec.push(Tracker);
vec.push(Tracker);
vec.push(Tracker);
let mut iter = vec.into_iter();
let first = iter.next().unwrap();
drop(first);
assert_eq!(DROPS.load(Ordering::SeqCst), 1);
drop(iter);
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
}
#[test]
fn drop_drain() {
define_tracker!();
DROPS.store(0, Ordering::SeqCst);
let mut vec = ArrayVec::<Tracker, 8>::new();
vec.push(Tracker);
vec.push(Tracker);
vec.push(Tracker);
vec.push(Tracker);
vec.push(Tracker);
{
let mut drain = vec.drain(1..4);
let first = drain.next().unwrap();
drop(first);
assert_eq!(DROPS.load(Ordering::SeqCst), 1);
}
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
drop(vec);
assert_eq!(DROPS.load(Ordering::SeqCst), 5);
}
#[test]
fn drop_extract_if() {
static DROPS: AtomicUsize = AtomicUsize::new(0);
struct Tracker {
id: usize,
}
impl Drop for Tracker {
fn drop(&mut self) {
DROPS.fetch_add(1, Ordering::SeqCst);
}
}
DROPS.store(0, Ordering::SeqCst);
let mut vec = ArrayVec::<Tracker, 8>::new();
for id in 0..6 {
vec.push(Tracker { id });
}
let removed: ArrayVec<Tracker, 8> = vec.extract_if(.., |t| t.id % 2 == 0).collect();
assert_eq!(DROPS.load(Ordering::SeqCst), 0);
drop(removed);
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
drop(vec);
assert_eq!(DROPS.load(Ordering::SeqCst), 6);
}
}