use core::cmp::Ordering;
use core::fmt;
use core::iter::FusedIterator;
use core::mem::MaybeUninit;
use core::ops::{Deref, DerefMut, RangeBounds};
use core::ptr;
use core::slice;
#[repr(C)]
pub(crate) struct InlineVec<T, const N: usize> {
len: u16,
data: [MaybeUninit<T>; N],
}
unsafe impl<T: Send, const N: usize> Send for InlineVec<T, N> {}
unsafe impl<T: Sync, const N: usize> Sync for InlineVec<T, N> {}
impl<T, const N: usize> InlineVec<T, N> {
#[inline]
pub(crate) const fn new() -> Self {
const {
assert!(N <= u16::MAX as usize, "InlineVec capacity exceeds u16::MAX");
}
Self {
len: 0,
data: [const { MaybeUninit::uninit() }; N],
}
}
#[inline]
pub(crate) fn len(&self) -> usize {
self.len as usize
}
#[inline]
pub(crate) fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
#[allow(dead_code)] pub(crate) fn capacity(&self) -> usize {
N
}
#[inline]
pub(crate) fn as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.data.as_ptr() as *const T, self.len as usize) }
}
#[inline]
pub(crate) fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self.data.as_mut_ptr() as *mut T, self.len as usize) }
}
#[inline]
#[allow(dead_code)] pub(crate) fn as_ptr(&self) -> *const T {
self.data.as_ptr() as *const T
}
#[inline]
#[allow(dead_code)] pub(crate) fn as_mut_ptr(&mut self) -> *mut T {
self.data.as_mut_ptr() as *mut T
}
#[inline]
pub(crate) fn get(&self, idx: usize) -> Option<&T> {
self.as_slice().get(idx)
}
#[inline]
pub(crate) unsafe fn get_unchecked(&self, idx: usize) -> &T {
unsafe { &*self.data.as_ptr().add(idx).cast::<T>() }
}
#[inline]
pub(crate) unsafe fn get_unchecked_mut(&mut self, idx: usize) -> &mut T {
unsafe { &mut *self.data.as_mut_ptr().add(idx).cast::<T>() }
}
#[inline]
pub(crate) fn push(&mut self, value: T) {
debug_assert!((self.len as usize) < N, "InlineVec capacity exceeded");
unsafe {
self.data.as_mut_ptr().add(self.len as usize).write(MaybeUninit::new(value));
}
self.len += 1;
}
#[inline]
pub(crate) fn pop(&mut self) -> Option<T> {
if self.len == 0 {
return None;
}
self.len -= 1;
Some(unsafe { self.data.as_ptr().add(self.len as usize).read().assume_init() })
}
#[inline]
pub(crate) fn insert(&mut self, pos: usize, value: T) {
let len = self.len as usize;
assert!(pos <= len, "InlineVec::insert index out of bounds");
debug_assert!(len < N, "InlineVec capacity exceeded");
if pos == len {
unsafe {
self.data.as_mut_ptr().add(pos).write(MaybeUninit::new(value));
}
self.len += 1;
return;
}
unsafe {
let base = self.data.as_mut_ptr();
ptr::copy(base.add(pos), base.add(pos + 1), len - pos);
base.add(pos).write(MaybeUninit::new(value));
}
self.len += 1;
}
#[inline]
pub(crate) fn remove(&mut self, pos: usize) -> T {
let len = self.len as usize;
assert!(pos < len, "InlineVec::remove index out of bounds");
unsafe {
let base = self.data.as_mut_ptr();
let value = base.add(pos).read().assume_init();
ptr::copy(base.add(pos + 1), base.add(pos), len - pos - 1);
self.len -= 1;
value
}
}
#[inline]
pub(crate) fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
for value in iter {
self.push(value);
}
}
#[inline]
pub(crate) fn iter(&self) -> slice::Iter<'_, T> {
self.as_slice().iter()
}
#[inline]
#[allow(dead_code)] pub(crate) fn iter_mut(&mut self) -> slice::IterMut<'_, T> {
self.as_mut_slice().iter_mut()
}
pub(crate) fn drain<R: RangeBounds<usize>>(&mut self, range: R) -> Drain<'_, T, N> {
use core::ops::Bound::*;
let len = self.len as usize;
let start = match range.start_bound() {
Included(&n) => n,
Excluded(&n) => n + 1,
Unbounded => 0,
};
let end = match range.end_bound() {
Included(&n) => n + 1,
Excluded(&n) => n,
Unbounded => len,
};
assert!(start <= end, "InlineVec::drain start > end");
assert!(end <= len, "InlineVec::drain end > len");
self.len = start as u16;
Drain {
vec: self,
start,
next_idx: start,
end,
original_len: len,
}
}
#[inline]
#[allow(dead_code)] pub(crate) unsafe fn raw_len(this: *const Self) -> u16 {
unsafe { ptr::read(ptr::addr_of!((*this).len)) }
}
#[inline]
#[allow(dead_code)] pub(crate) unsafe fn raw_data_ptr(this: *const Self) -> *const T {
unsafe { ptr::addr_of!((*this).data) as *const T }
}
}
impl<T, const N: usize> Default for InlineVec<T, N> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<T, const N: usize> Drop for InlineVec<T, N> {
fn drop(&mut self) {
unsafe {
let slice =
slice::from_raw_parts_mut(self.data.as_mut_ptr() as *mut T, self.len as usize);
ptr::drop_in_place(slice);
}
}
}
impl<T, const N: usize> Deref for InlineVec<T, N> {
type Target = [T];
#[inline]
fn deref(&self) -> &[T] {
self.as_slice()
}
}
impl<T, const N: usize> DerefMut for InlineVec<T, N> {
#[inline]
fn deref_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<T, const N: usize, I: slice::SliceIndex<[T]>> core::ops::Index<I> for InlineVec<T, N> {
type Output = I::Output;
#[inline]
fn index(&self, idx: I) -> &Self::Output {
core::ops::Index::index(self.as_slice(), idx)
}
}
impl<T, const N: usize, I: slice::SliceIndex<[T]>> core::ops::IndexMut<I> for InlineVec<T, N> {
#[inline]
fn index_mut(&mut self, idx: I) -> &mut Self::Output {
core::ops::IndexMut::index_mut(self.as_mut_slice(), idx)
}
}
impl<T: fmt::Debug, const N: usize> fmt::Debug for InlineVec<T, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl<T: Clone, const N: usize> Clone for InlineVec<T, N> {
fn clone(&self) -> Self {
let mut new = Self::new();
for v in self.iter() {
new.push(v.clone());
}
new
}
}
impl<T: PartialEq, const N: usize> PartialEq for InlineVec<T, N> {
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl<T: Eq, const N: usize> Eq for InlineVec<T, N> {}
impl<T: PartialOrd, const N: usize> PartialOrd for InlineVec<T, N> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.as_slice().partial_cmp(other.as_slice())
}
}
impl<T: Ord, const N: usize> Ord for InlineVec<T, N> {
fn cmp(&self, other: &Self) -> Ordering {
self.as_slice().cmp(other.as_slice())
}
}
impl<'a, T, const N: usize> IntoIterator for &'a InlineVec<T, N> {
type Item = &'a T;
type IntoIter = slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T, const N: usize> IntoIterator for &'a mut InlineVec<T, N> {
type Item = &'a mut T;
type IntoIter = slice::IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
pub(crate) struct Drain<'a, T, const N: usize> {
vec: &'a mut InlineVec<T, N>,
start: usize,
next_idx: usize,
end: usize,
original_len: usize,
}
impl<'a, T, const N: usize> Iterator for Drain<'a, T, N> {
type Item = T;
fn next(&mut self) -> Option<T> {
if self.next_idx >= self.end {
return None;
}
let idx = self.next_idx;
self.next_idx += 1;
Some(unsafe { self.vec.data.as_ptr().add(idx).read().assume_init() })
}
fn size_hint(&self) -> (usize, Option<usize>) {
let rem = self.end - self.next_idx;
(rem, Some(rem))
}
}
impl<'a, T, const N: usize> ExactSizeIterator for Drain<'a, T, N> {}
impl<'a, T, const N: usize> FusedIterator for Drain<'a, T, N> {}
impl<'a, T, const N: usize> Drop for Drain<'a, T, N> {
fn drop(&mut self) {
for i in self.next_idx..self.end {
unsafe {
let _ = self.vec.data.as_ptr().add(i).read().assume_init();
}
}
let tail_len = self.original_len - self.end;
if tail_len > 0 && self.start != self.end {
unsafe {
let base = self.vec.data.as_mut_ptr();
ptr::copy(base.add(self.end), base.add(self.start), tail_len);
}
}
self.vec.len = (self.start + tail_len) as u16;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn push_pop_len() {
let mut v: InlineVec<u32, 4> = InlineVec::new();
assert_eq!(v.len(), 0);
assert!(v.is_empty());
v.push(1);
v.push(2);
v.push(3);
assert_eq!(v.len(), 3);
assert_eq!(v.as_slice(), &[1, 2, 3]);
assert_eq!(v.pop(), Some(3));
assert_eq!(v.pop(), Some(2));
assert_eq!(v.pop(), Some(1));
assert_eq!(v.pop(), None);
}
#[test]
fn insert_remove() {
let mut v: InlineVec<u32, 8> = InlineVec::new();
v.extend([10, 20, 30, 40]);
v.insert(2, 25);
assert_eq!(v.as_slice(), &[10, 20, 25, 30, 40]);
assert_eq!(v.remove(1), 20);
assert_eq!(v.as_slice(), &[10, 25, 30, 40]);
assert_eq!(v.remove(0), 10);
assert_eq!(v.as_slice(), &[25, 30, 40]);
}
#[test]
fn insert_at_end() {
let mut v: InlineVec<u32, 4> = InlineVec::new();
v.push(1);
v.insert(1, 2);
assert_eq!(v.as_slice(), &[1, 2]);
}
#[test]
fn drain_middle() {
let mut v: InlineVec<u32, 8> = InlineVec::new();
v.extend([1, 2, 3, 4, 5]);
let drained: Vec<u32> = v.drain(1..4).collect();
assert_eq!(drained, vec![2, 3, 4]);
assert_eq!(v.as_slice(), &[1, 5]);
}
#[test]
fn drain_full() {
let mut v: InlineVec<u32, 8> = InlineVec::new();
v.extend([1, 2, 3, 4, 5]);
let drained: Vec<u32> = v.drain(..).collect();
assert_eq!(drained, vec![1, 2, 3, 4, 5]);
assert!(v.is_empty());
}
#[test]
fn drain_unconsumed_drops_elements_and_shifts() {
use std::sync::atomic::{AtomicUsize, Ordering};
static DROPPED: AtomicUsize = AtomicUsize::new(0);
struct DropCounter(u32);
impl Drop for DropCounter {
fn drop(&mut self) {
DROPPED.fetch_add(1, Ordering::Relaxed);
}
}
DROPPED.store(0, Ordering::Relaxed);
let mut v: InlineVec<DropCounter, 8> = InlineVec::new();
v.push(DropCounter(1));
v.push(DropCounter(2));
v.push(DropCounter(3));
v.push(DropCounter(4));
{
let mut iter = v.drain(1..3);
let _ = iter.next(); } assert_eq!(v.len(), 2);
assert_eq!(v.as_slice()[0].0, 1);
assert_eq!(v.as_slice()[1].0, 4);
assert_eq!(DROPPED.load(Ordering::Relaxed), 2);
drop(v);
assert_eq!(DROPPED.load(Ordering::Relaxed), 4);
}
#[test]
fn deref_slice_apis() {
let mut v: InlineVec<u32, 8> = InlineVec::new();
v.extend([5, 3, 1, 4, 2]);
assert_eq!(v.iter().copied().min(), Some(1));
assert_eq!(v[0], 5);
v[0] = 9;
assert_eq!(v.as_slice(), &[9, 3, 1, 4, 2]);
}
#[test]
fn drop_runs_for_initialised_elements_only() {
use std::sync::atomic::{AtomicUsize, Ordering};
static DROPPED: AtomicUsize = AtomicUsize::new(0);
struct DropCounter;
impl Drop for DropCounter {
fn drop(&mut self) {
DROPPED.fetch_add(1, Ordering::Relaxed);
}
}
DROPPED.store(0, Ordering::Relaxed);
{
let mut v: InlineVec<DropCounter, 16> = InlineVec::new();
v.push(DropCounter);
v.push(DropCounter);
v.push(DropCounter);
}
assert_eq!(DROPPED.load(Ordering::Relaxed), 3);
}
#[test]
fn raw_accessors_match_safe_accessors() {
let mut v: InlineVec<u32, 8> = InlineVec::new();
v.extend([10, 20, 30]);
let raw_len = unsafe { InlineVec::raw_len(&v as *const _) };
assert_eq!(raw_len, 3);
unsafe {
let data: *const u32 = InlineVec::raw_data_ptr(&v as *const _);
assert_eq!(ptr::read(data.add(0)), 10);
assert_eq!(ptr::read(data.add(1)), 20);
assert_eq!(ptr::read(data.add(2)), 30);
}
}
}