use core::{
borrow::{Borrow, BorrowMut},
fmt,
marker::PhantomData,
mem::MaybeUninit,
ops,
ptr::{self, NonNull},
slice::{self, from_raw_parts_mut},
};
pub struct InlineVec<T, const N: usize> {
elements: [MaybeUninit<T>; N],
len: usize,
}
impl<T, const N: usize> Drop for InlineVec<T, N> {
fn drop(&mut self) {
self.clear()
}
}
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> {
pub fn new() -> Self {
Self {
elements: unsafe { MaybeUninit::uninit().assume_init() },
len: 0,
}
}
pub fn clear(&mut self) {
for i in 0..self.len {
unsafe {
self.elements[i].as_mut_ptr().drop_in_place();
}
}
self.len = 0;
}
pub fn as_mut_ptr(&mut self) -> *mut T {
self.elements.as_mut_ptr().cast()
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
}
pub fn as_ptr(&self) -> *const T {
self.elements.as_ptr().cast()
}
pub fn as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
}
pub const fn capacity(&self) -> usize {
N
}
pub fn reserve(&mut self, additional: usize) {
if N - self.len < additional {
Self::out_of_space();
}
}
#[cold]
fn out_of_space() -> ! {
panic!(
"reserve requested more capacity than the InlineVec has available"
);
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn len(&self) -> usize {
self.len
}
pub fn extend_from_slice(&mut self, other: &[T]) {
if !other.is_empty() {
self.reserve(other.len());
unsafe {
core::ptr::copy_nonoverlapping(
other.as_ptr(),
self.as_mut_ptr().add(self.len()),
other.len(),
);
}
self.len += other.len();
}
}
pub fn pop(&mut self) -> Option<T> {
if self.len == 0 {
None
} else {
unsafe {
self.len -= 1;
Some(self.as_ptr().add(self.len()).read())
}
}
}
pub unsafe fn push_unchecked(&mut self, value: T) {
unsafe {
self.as_mut_ptr().add(self.len).write(value);
self.len += 1;
}
}
pub fn push(&mut self, value: T) {
if self.len == N {
Self::out_of_space()
} else {
unsafe {
self.push_unchecked(value);
}
}
}
pub fn reserve_exact(&mut self, additional: usize) {
self.reserve(additional);
}
pub unsafe fn set_len(&mut self, new_len: usize) {
debug_assert!(new_len <= self.capacity());
self.len = new_len;
}
pub fn drain(&mut self) -> Drain<'_, T, N> {
let remaining = self.len();
unsafe {
self.set_len(0);
}
Drain {
current: unsafe { NonNull::new_unchecked(self.as_mut_ptr()) },
remaining,
_phantom: PhantomData,
}
}
}
impl<T, const N: usize> InlineVec<MaybeUninit<T>, N> {
pub fn assume_init(self) -> InlineVec<T, N> {
let mut elements = unsafe {
MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init()
};
unsafe {
ptr::copy_nonoverlapping(
self.elements.as_ptr().cast(),
elements.as_mut_ptr(),
N,
);
}
InlineVec {
elements,
len: self.len,
}
}
}
impl<T, const N: usize> AsMut<[T]> for InlineVec<T, N> {
fn as_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<T, const N: usize> AsRef<[T]> for InlineVec<T, N> {
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}
impl<T, const N: usize> Borrow<[T]> for InlineVec<T, N> {
fn borrow(&self) -> &[T] {
self.as_slice()
}
}
impl<T, const N: usize> BorrowMut<[T]> for InlineVec<T, N> {
fn borrow_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<T: fmt::Debug, const N: usize> fmt::Debug for InlineVec<T, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_slice().fmt(f)
}
}
impl<T, const N: usize> Default for InlineVec<T, N> {
fn default() -> Self {
Self::new()
}
}
impl<T, const N: usize> ops::Deref for InlineVec<T, N> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl<T, const N: usize> ops::DerefMut for InlineVec<T, N> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice()
}
}
impl<T, I: slice::SliceIndex<[T]>, const N: usize> ops::Index<I>
for InlineVec<T, N>
{
type Output = <I as slice::SliceIndex<[T]>>::Output;
fn index(&self, index: I) -> &Self::Output {
&self.as_slice()[index]
}
}
impl<T, I: slice::SliceIndex<[T]>, const N: usize> ops::IndexMut<I>
for InlineVec<T, N>
{
fn index_mut(&mut self, index: I) -> &mut Self::Output {
&mut self.as_mut_slice()[index]
}
}
pub struct Drain<'a, T: 'a, const N: usize> {
current: NonNull<T>,
remaining: usize,
_phantom: PhantomData<&'a mut InlineVec<T, N>>,
}
impl<T: fmt::Debug, const N: usize> fmt::Debug for Drain<'_, T, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Drain").field(&self.as_slice()).finish()
}
}
impl<T, const N: usize> Drain<'_, T, N> {
pub fn as_slice(&self) -> &[T] {
unsafe { from_raw_parts_mut(self.current.as_ptr(), self.remaining) }
}
}
impl<T, const N: usize> AsRef<[T]> for Drain<'_, T, N> {
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}
impl<T, const N: usize> Iterator for Drain<'_, T, N> {
type Item = T;
fn next(&mut self) -> Option<T> {
if self.remaining > 0 {
self.remaining -= 1;
let result = unsafe { self.current.as_ptr().read() };
self.current =
unsafe { NonNull::new_unchecked(self.current.as_ptr().add(1)) };
Some(result)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl<T, const N: usize> DoubleEndedIterator for Drain<'_, T, N> {
fn next_back(&mut self) -> Option<T> {
if self.remaining > 0 {
self.remaining -= 1;
unsafe { Some(self.current.as_ptr().add(self.remaining).read()) }
} else {
None
}
}
}
impl<T, const N: usize> Drop for Drain<'_, T, N> {
fn drop(&mut self) {
for i in 0..self.remaining {
unsafe {
self.current.as_ptr().add(i).drop_in_place();
}
}
}
}
impl<T, const N: usize> ExactSizeIterator for Drain<'_, T, N> {}
impl<T, const N: usize> core::iter::FusedIterator for Drain<'_, T, N> {}
#[cfg(test)]
mod tests {
use crate::util::InlineVec;
#[test]
fn drain() {
let mut vec = InlineVec::<_, 8>::new();
for i in 0..100 {
vec.push(i);
if vec.len() == vec.capacity() {
for j in vec.drain() {
let _ = j;
}
}
}
}
}