#![doc=include_str!("../README.md")]
use alloc::handle_alloc_error;
use core::fmt::{self, Debug, Display};
use core::hash::Hash;
use core::ops::{Deref, DerefMut};
use std::alloc::{self, Layout};
use std::convert::TryFrom;
use std::ptr::NonNull;
use std::{mem, ptr};
pub struct FixedCapacityVec<T, const N: usize> {
data: NonNull<T>,
len: usize,
}
macro_rules! impl_traits_if_T { { $( $trait:path $(, $unsafe:tt )?; )* } => { $(
$( $unsafe )? impl<T: $trait, const N: usize> $trait for FixedCapacityVec<T, N> {}
)* } }
impl_traits_if_T! {
Send, unsafe;
Sync, unsafe;
std::panic::UnwindSafe;
std::panic::RefUnwindSafe;
}
impl<T, const N: usize> FixedCapacityVec<T, N> {
#[inline]
pub fn new() -> Self {
let data = if Self::NZST {
unsafe {
let data: *mut u8 = alloc::alloc(Self::LAYOUT);
let data: *mut T = data as _;
let data: NonNull<T> =
NonNull::new(data).unwrap_or_else(|| handle_alloc_error(Self::LAYOUT));
data
}
} else {
NonNull::dangling()
};
FixedCapacityVec { data, len: 0 }
}
const LAYOUT: Layout = { Layout::new::<[T; N]>() };
const NZST: bool = { Self::LAYOUT.size() != 0 };
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn is_full(&self) -> bool {
self.len == N
}
#[inline]
pub fn push(&mut self, item: T) {
self.try_push_or_discard(item).unwrap();
}
#[inline]
pub fn pop(&mut self) -> Option<T> {
self.len = self.len.checked_sub(1)?;
let item = unsafe {
self.data.as_ptr().add(self.len).read()
};
Some(item)
}
#[inline]
fn slice(&self) -> NonNull<[T]> {
let p = self.data.as_ptr(); let p = ptr::slice_from_raw_parts(p, self.len); unsafe { NonNull::new(p as _).unwrap_unchecked() } }
#[inline]
unsafe fn from_raw_parts(data: NonNull<T>, length: usize) -> Self {
Self { data, len: length }
}
#[inline]
fn into_raw_parts(self) -> (NonNull<T>, usize) {
let data = self.data;
let len = self.len;
mem::forget(self);
(data, len)
}
}
macro_rules! define_try_push { {
$( # $attr:tt )*
$vis:vis fn $fn:ident($item:ident) -> Result<, $Error:ty> { or Err($err:expr) }
} => {
impl<T, const N: usize> FixedCapacityVec<T, N> {
$( # $attr )*
$vis fn $fn(&mut self, $item: T) -> Result<(), $Error> {
if self.len >= N {
return Err($err);
}
unsafe {
if Self::NZST {
self.data.as_ptr().add(self.len).write($item);
}
self.len += 1;
}
Ok(())
}
}
} }
define_try_push! {
#[inline]
pub fn try_push_or_discard(item) -> Result<, FullError> { or Err(FullError) }
}
define_try_push! {
#[inline]
pub fn try_push(item) -> Result<, T> { or Err(item) }
}
impl<T, const N: usize> Drop for FixedCapacityVec<T, N> {
#[inline]
fn drop(&mut self) {
unsafe {
if mem::needs_drop::<T>() {
let data: NonNull<[T]> = self.slice();
ptr::drop_in_place(data.as_ptr());
}
if Self::NZST {
alloc::dealloc(self.data.as_ptr() as _, Self::LAYOUT);
}
}
}
}
impl<T, const N: usize> Deref for FixedCapacityVec<T, N> {
type Target = [T];
#[inline]
fn deref(&self) -> &[T] {
unsafe {
self.slice().as_ref()
}
}
}
impl<T, const N: usize> DerefMut for FixedCapacityVec<T, N> {
#[inline]
fn deref_mut(&mut self) -> &mut [T] {
unsafe {
self.slice().as_mut()
}
}
}
impl<T, const N: usize> TryFrom<FixedCapacityVec<T, N>> for Box<[T; N]> {
type Error = FixedCapacityVec<T, N>;
#[inline]
fn try_from(v: FixedCapacityVec<T, N>) -> Result<Box<[T; N]>, FixedCapacityVec<T, N>> {
if v.len == N {
Ok(unsafe {
let data: *mut [T; N] = v.data.as_ptr() as _;
mem::forget(v);
let data: Box<[T; N]> = Box::from_raw(data);
data
})
} else {
Err(v)
}
}
}
impl<T, const N: usize> From<Box<[T; N]>> for FixedCapacityVec<T, N> {
#[inline]
fn from(b: Box<[T; N]>) -> FixedCapacityVec<T, N> {
let b: *mut [T; N] = Box::into_raw(b);
let b: *mut T = b as _;
let b: NonNull<T> = unsafe { NonNull::new(b).unwrap_unchecked() };
unsafe { FixedCapacityVec::from_raw_parts(b, N) }
}
}
impl<T, const N: usize> From<FixedCapacityVec<T, N>> for Vec<T> {
#[inline]
fn from(v: FixedCapacityVec<T, N>) -> Vec<T> {
unsafe {
let (data, len) = v.into_raw_parts();
let data: *mut T = data.as_ptr();
let vec: Vec<T> = Vec::from_raw_parts(data, len, N);
vec
}
}
}
impl<T, const N: usize> TryFrom<Vec<T>> for FixedCapacityVec<T, N> {
type Error = Vec<T>;
#[inline]
fn try_from(mut vec: Vec<T>) -> Result<FixedCapacityVec<T, N>, Vec<T>> {
if vec.capacity() == N || Layout::new::<T>().size() == 0 {
Ok(unsafe {
let data: *mut T = vec.as_mut_ptr();
let data: NonNull<T> = NonNull::new(data).unwrap_unchecked();
let len = vec.len();
mem::forget(vec);
Self::from_raw_parts(data, len)
})
} else {
Err(vec)
}
}
}
mod safe;
pub use safe::*;
#[cfg(test)]
mod test;
#[cfg(not(feature = "minimal-1"))]
compile_error! { "You must enable at least one fixed-capacity-vec crate feature!" }