use std::fmt::Debug;
use std::marker::PhantomData;
use std::mem::{ManuallyDrop, MaybeUninit};
pub const STACK_BYTES: usize = 64;
#[repr(C)]
union AlignedStorage<A> {
data: [MaybeUninit<u8>; STACK_BYTES],
_align: ManuallyDrop<[A; 0]>,
}
pub struct StackVec<A> {
data: AlignedStorage<A>,
len: usize,
}
impl<A> Default for StackVec<A> {
fn default() -> Self {
Self::new()
}
}
impl<A> StackVec<A> {
pub const fn static_capacity() -> usize {
let size = std::mem::size_of::<A>();
if size > STACK_BYTES {
return 0;
} else if size == 0 {
return usize::MAX;
} else {
STACK_BYTES / size
}
}
pub fn capacity(&self) -> usize {
Self::static_capacity()
}
pub fn new() -> Self {
let size = std::mem::size_of::<A>();
if size > STACK_BYTES {
panic!("Type is too big to fit in a stack vec.");
}
StackVec {
data: AlignedStorage {
data: [MaybeUninit::uninit(); STACK_BYTES],
},
len: 0,
}
}
pub fn as_slice(&self) -> &[A] {
unsafe { std::slice::from_raw_parts(self.data.data.as_ptr() as *const A, self.len) }
}
pub fn as_mut_slice(&mut self) -> &mut [A] {
unsafe { std::slice::from_raw_parts_mut(self.data.data.as_mut_ptr() as *mut A, self.len) }
}
pub fn push(&mut self, value: A) {
if self.may_push() {
unsafe {
let ptr = self.data.data.as_mut_ptr() as *mut A;
std::ptr::write(ptr.add(self.len), value);
self.len += 1;
}
} else {
panic!("StackVec overflow");
}
}
pub fn pop(&mut self) -> Option<A> {
if self.len() != 0 {
self.len -= 1;
unsafe {
let ptr = self.data.data.as_ptr() as *const A;
Some(std::ptr::read(ptr.add(self.len)))
}
} else {
None
}
}
pub fn remove(&mut self, index: usize) -> A {
if index >= self.len {
panic!(
"index out of bounds: the len is {} but the index is {}",
self.len, index
);
}
unsafe {
let ptr = self.data.data.as_mut_ptr() as *mut A;
let value = std::ptr::read(ptr.add(index));
for i in index..self.len - 1 {
std::ptr::write(ptr.add(i), std::ptr::read(ptr.add(i + 1)));
}
self.len -= 1;
value
}
}
pub fn clear(&mut self) {
unsafe {
let ptr = self.data.data.as_mut_ptr() as *mut A;
for i in 0..self.len {
std::ptr::drop_in_place(ptr.add(i));
}
self.len = 0;
}
}
pub fn search(&self, query: &A) -> Option<usize>
where
A: PartialEq,
{
for i in 0..self.len {
if &self[i] == query {
return Some(i);
}
}
None
}
pub fn may_push(&self) -> bool {
self.len < self.capacity()
}
pub fn may_append(&self, other_len: usize) -> bool {
self.len.saturating_add(other_len) <= self.capacity()
}
pub fn append(&mut self, other: &mut StackVec<A>) {
if !self.may_append(other.len) {
panic!("StackVec overflow");
}
unsafe {
let self_ptr = self.data.data.as_mut_ptr() as *mut A;
let other_ptr = other.data.data.as_ptr() as *const A;
for i in 0..other.len {
std::ptr::write(self_ptr.add(self.len + i), std::ptr::read(other_ptr.add(i)));
}
self.len += other.len;
other.len = 0;
}
}
pub fn drain_all(&mut self) -> StackVecIntoIter<'_, A> {
let len = self.len;
self.len = 0;
let data = unsafe { std::ptr::read(&self.data) };
StackVecIntoIter {
data,
start: 0,
end: len,
lifetime: PhantomData,
}
}
pub fn drain_to_vec(&mut self, other: &mut Vec<A>) {
other.reserve(self.len);
let ptr = unsafe { self.data.data.as_mut_ptr() as *const A };
for i in 0..self.len {
other.push(unsafe { std::ptr::read(ptr.add(i)) });
}
self.len = 0;
}
pub fn into_vec(mut self) -> Vec<A> {
let mut vec = Vec::with_capacity(self.len);
self.drain_to_vec(&mut vec);
vec
}
pub fn iter(&self) -> std::slice::Iter<'_, A> {
self.as_slice().iter()
}
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, A> {
self.as_mut_slice().iter_mut()
}
pub fn into_iter(self) -> StackVecIntoIter<'static, A> {
let len = self.len;
let data = unsafe { std::ptr::read(&self.data) };
std::mem::forget(self);
StackVecIntoIter {
data,
start: 0,
end: len,
lifetime: PhantomData,
}
}
pub fn len(&self) -> usize {
self.len
}
}
impl<A> Drop for StackVec<A> {
fn drop(&mut self) {
unsafe {
let ptr = self.data.data.as_mut_ptr() as *mut A;
for i in 0..self.len {
std::ptr::drop_in_place(ptr.add(i));
}
}
}
}
impl<A> std::ops::Index<usize> for StackVec<A> {
type Output = A;
fn index(&self, index: usize) -> &Self::Output {
if index >= self.len {
panic!(
"index out of bounds: the len is {} but the index is {}",
self.len, index
);
}
unsafe {
let ptr = self.data.data.as_ptr() as *const A;
&*ptr.add(index)
}
}
}
impl<A> std::ops::IndexMut<usize> for StackVec<A> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
if index >= self.len {
panic!(
"index out of bounds: the len is {} but the index is {}",
self.len, index
);
}
unsafe {
let ptr = self.data.data.as_mut_ptr() as *mut A;
&mut *ptr.add(index)
}
}
}
impl<A: Debug> Debug for StackVec<A> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.iter()
.fold(&mut f.debug_list(), |acc, v| acc.entry(v))
.finish()
}
}
impl<A: PartialEq> PartialEq for StackVec<A> {
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
self.iter().zip(other.iter()).all(|(l, h)| l == h)
}
}
impl<A> std::iter::FromIterator<A> for StackVec<A> {
fn from_iter<I: IntoIterator<Item = A>>(iter: I) -> Self {
let mut output = StackVec::new();
output.extend(iter);
output
}
}
impl<A> std::iter::Extend<A> for StackVec<A> {
fn extend<I: IntoIterator<Item = A>>(&mut self, iter: I) {
let iter = iter.into_iter();
for v in iter {
self.push(v);
}
}
}
impl<A: Clone> Clone for StackVec<A> {
fn clone(&self) -> Self {
self.iter().cloned().collect()
}
}
impl<A> AsRef<[A]> for StackVec<A> {
fn as_ref(&self) -> &[A] {
self.as_slice()
}
}
impl<A, const N: usize> TryInto<[A; N]> for StackVec<A> {
type Error = StackVec<A>;
fn try_into(mut self) -> Result<[A; N], Self::Error> {
if self.len() != N {
return Err(self);
}
let mut result: [MaybeUninit<A>; N] = unsafe { MaybeUninit::uninit().assume_init() };
unsafe {
let src_ptr = self.data.data.as_ptr() as *const A;
for i in 0..N {
result[i] = MaybeUninit::new(std::ptr::read(src_ptr.add(i)));
}
self.len = 0;
}
let result = unsafe { std::mem::transmute_copy::<[MaybeUninit<A>; N], [A; N]>(&result) };
std::mem::forget(self);
Ok(result)
}
}
pub struct StackVecIntoIter<'a, A> {
data: AlignedStorage<A>,
start: usize,
end: usize,
lifetime: PhantomData<&'a u8>,
}
impl<'a, A> Iterator for StackVecIntoIter<'a, A> {
type Item = A;
fn next(&mut self) -> Option<Self::Item> {
if self.start >= self.end {
None
} else {
unsafe {
let ptr = self.data.data.as_ptr() as *const A;
let value = std::ptr::read(ptr.add(self.start));
self.start += 1;
Some(value)
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.end - self.start;
(remaining, Some(remaining))
}
}
impl<'a, A> DoubleEndedIterator for StackVecIntoIter<'a, A> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.start >= self.end {
None
} else {
self.end -= 1;
unsafe {
let ptr = self.data.data.as_ptr() as *const A;
let value = std::ptr::read(ptr.add(self.end));
Some(value)
}
}
}
}
impl<'a, A> ExactSizeIterator for StackVecIntoIter<'a, A> {}
impl<'a, A> Drop for StackVecIntoIter<'a, A> {
fn drop(&mut self) {
while self.start < self.end {
unsafe {
let ptr = self.data.data.as_ptr() as *const A;
std::ptr::drop_in_place(ptr.add(self.start) as *mut A);
self.start += 1;
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
#[derive(Debug, Clone)]
struct DropTracker {
id: usize,
counter: Arc<AtomicUsize>,
}
impl DropTracker {
fn new(id: usize, counter: Arc<AtomicUsize>) -> Self {
counter.fetch_add(1, Ordering::Relaxed);
DropTracker { id, counter }
}
}
impl Drop for DropTracker {
fn drop(&mut self) {
self.counter.fetch_sub(1, Ordering::Relaxed);
}
}
#[repr(C)]
struct Large([u64; 10]);
#[test]
fn test_basic_operations() {
let mut vec = StackVec::new();
assert_eq!(vec.len(), 0);
assert!(vec.may_push());
vec.push(42u32);
assert_eq!(vec.len(), 1);
assert_eq!(vec[0], 42);
vec.push(84);
assert_eq!(vec.len(), 2);
assert_eq!(vec.as_slice(), &[42, 84]);
}
#[test]
fn test_pop_basic() {
let mut vec = StackVec::new();
assert_eq!(vec.pop(), None::<u32>);
assert_eq!(vec.len(), 0);
vec.push(1u32);
vec.push(2u32);
vec.push(3u32);
assert_eq!(vec.len(), 3);
assert_eq!(vec.pop(), Some(3));
assert_eq!(vec.len(), 2);
assert_eq!(vec.pop(), Some(2));
assert_eq!(vec.len(), 1);
assert_eq!(vec.pop(), Some(1));
assert_eq!(vec.len(), 0);
assert_eq!(vec.pop(), None);
}
#[test]
fn test_pop_ownership() {
let counter = Arc::new(AtomicUsize::new(0));
let mut vec = StackVec::new();
vec.push(DropTracker::new(1, counter.clone()));
vec.push(DropTracker::new(2, counter.clone()));
vec.push(DropTracker::new(3, counter.clone()));
assert_eq!(counter.load(Ordering::Relaxed), 3);
{
let popped = vec.pop().unwrap();
assert_eq!(popped.id, 3);
assert_eq!(counter.load(Ordering::Relaxed), 3); } assert_eq!(counter.load(Ordering::Relaxed), 2);
let popped2 = vec.pop().unwrap();
assert_eq!(popped2.id, 2);
assert_eq!(counter.load(Ordering::Relaxed), 2);
drop(vec); assert_eq!(counter.load(Ordering::Relaxed), 1);
drop(popped2); assert_eq!(counter.load(Ordering::Relaxed), 0);
}
#[test]
fn test_push_pop_sequence() {
let mut vec = StackVec::new();
vec.push(10u32);
assert_eq!(vec.pop(), Some(10));
vec.push(20);
vec.push(30);
assert_eq!(vec.pop(), Some(30));
vec.push(40);
assert_eq!(vec.len(), 2);
assert_eq!(vec.as_slice(), &[20, 40]);
assert_eq!(vec.pop(), Some(40));
assert_eq!(vec.pop(), Some(20));
assert_eq!(vec.pop(), None);
}
#[test]
fn test_pop_lifo_order() {
let mut vec = StackVec::new();
for i in 1..=5 {
vec.push(i * 10);
}
assert_eq!(vec.pop(), Some(50));
assert_eq!(vec.pop(), Some(40));
assert_eq!(vec.pop(), Some(30));
assert_eq!(vec.pop(), Some(20));
assert_eq!(vec.pop(), Some(10));
assert_eq!(vec.pop(), None);
}
#[test]
fn test_capacity_different_sizes() {
let small_vec: StackVec<u8> = StackVec::new();
assert_eq!(small_vec.capacity(), 64);
let medium_vec: StackVec<u32> = StackVec::new();
assert_eq!(medium_vec.capacity(), 16);
let large_vec: StackVec<u64> = StackVec::new();
assert_eq!(large_vec.capacity(), 8);
}
#[test]
fn test_remove_basic() {
let mut vec = StackVec::new();
vec.push(10u32);
vec.push(20);
vec.push(30);
vec.push(40);
let removed = vec.remove(1);
assert_eq!(removed, 20);
assert_eq!(vec.len(), 3);
assert_eq!(vec.as_slice(), &[10, 30, 40]);
let removed = vec.remove(2);
assert_eq!(removed, 40);
assert_eq!(vec.len(), 2);
assert_eq!(vec.as_slice(), &[10, 30]);
let removed = vec.remove(0);
assert_eq!(removed, 10);
assert_eq!(vec.len(), 1);
assert_eq!(vec.as_slice(), &[30]);
let removed = vec.remove(0);
assert_eq!(removed, 30);
assert_eq!(vec.len(), 0);
}
#[test]
#[should_panic(expected = "index out of bounds")]
fn test_remove_out_of_bounds() {
let mut vec = StackVec::new();
vec.push(10u32);
vec.remove(1); }
#[test]
#[should_panic(expected = "index out of bounds")]
fn test_remove_empty() {
let mut vec: StackVec<u32> = StackVec::new();
vec.remove(0); }
#[test]
fn test_remove_ownership() {
let counter = Arc::new(AtomicUsize::new(0));
let mut vec = StackVec::new();
vec.push(DropTracker::new(1, counter.clone()));
vec.push(DropTracker::new(2, counter.clone()));
vec.push(DropTracker::new(3, counter.clone()));
assert_eq!(counter.load(Ordering::Relaxed), 3);
{
let removed = vec.remove(1);
assert_eq!(removed.id, 2);
assert_eq!(counter.load(Ordering::Relaxed), 3); } assert_eq!(counter.load(Ordering::Relaxed), 2);
assert_eq!(vec.len(), 2);
assert_eq!(vec[0].id, 1);
assert_eq!(vec[1].id, 3);
drop(vec);
assert_eq!(counter.load(Ordering::Relaxed), 0);
}
#[test]
fn test_search_basic() {
let mut vec = StackVec::new();
vec.push(10u32);
vec.push(20);
vec.push(30);
vec.push(20);
assert_eq!(vec.search(&10), Some(0));
assert_eq!(vec.search(&20), Some(1)); assert_eq!(vec.search(&30), Some(2));
assert_eq!(vec.search(&40), None);
}
#[test]
fn test_search_empty() {
let vec: StackVec<u32> = StackVec::new();
assert_eq!(vec.search(&10), None);
}
#[test]
fn test_search_single_element() {
let mut vec = StackVec::new();
vec.push(42u32);
assert_eq!(vec.search(&42), Some(0));
assert_eq!(vec.search(&41), None);
}
#[test]
fn test_search_custom_type() {
#[derive(PartialEq, Debug)]
struct Point {
x: i32,
y: i32,
}
let mut vec = StackVec::new();
vec.push(Point { x: 1, y: 2 });
vec.push(Point { x: 3, y: 4 });
vec.push(Point { x: 5, y: 6 });
assert_eq!(vec.search(&Point { x: 3, y: 4 }), Some(1));
assert_eq!(vec.search(&Point { x: 0, y: 0 }), None);
}
#[test]
fn test_search_after_remove() {
let mut vec = StackVec::new();
vec.push(10u32);
vec.push(20);
vec.push(30);
assert_eq!(vec.search(&30), Some(2));
vec.remove(1);
assert_eq!(vec.search(&30), Some(1));
assert_eq!(vec.search(&20), None); }
#[test]
fn test_remove_search_integration() {
let mut vec = StackVec::new();
vec.push(100u32);
vec.push(200);
vec.push(300);
vec.push(400);
vec.push(500);
if let Some(index) = vec.search(&300) {
let removed = vec.remove(index);
assert_eq!(removed, 300);
}
assert_eq!(vec.len(), 4);
assert_eq!(vec.as_slice(), &[100, 200, 400, 500]);
assert_eq!(vec.search(&300), None);
assert_eq!(vec.search(&100), Some(0));
assert_eq!(vec.search(&200), Some(1));
assert_eq!(vec.search(&400), Some(2));
assert_eq!(vec.search(&500), Some(3));
}
#[test]
fn test_drain_all_basic() {
let mut vec = StackVec::new();
vec.push(1u32);
vec.push(2);
vec.push(3);
let iter = vec.drain_all();
let collected: Vec<u32> = iter.collect();
assert_eq!(collected, vec![1, 2, 3]);
assert_eq!(vec.len(), 0); }
#[test]
fn test_drain_all_empty() {
let mut vec: StackVec<u32> = StackVec::new();
let mut iter = vec.drain_all();
assert_eq!(iter.next(), None);
drop(iter);
assert_eq!(vec.len(), 0);
}
#[test]
fn test_drain_all_ownership() {
let counter = Arc::new(AtomicUsize::new(0));
let mut vec = StackVec::new();
vec.push(DropTracker::new(1, counter.clone()));
vec.push(DropTracker::new(2, counter.clone()));
vec.push(DropTracker::new(3, counter.clone()));
assert_eq!(counter.load(Ordering::Relaxed), 3);
{
let mut iter = vec.drain_all();
assert_eq!(counter.load(Ordering::Relaxed), 3);
let first = iter.next().unwrap();
assert_eq!(first.id, 1);
drop(first);
assert_eq!(counter.load(Ordering::Relaxed), 2);
drop(iter);
assert_eq!(vec.len(), 0); }
assert_eq!(counter.load(Ordering::Relaxed), 0);
}
#[test]
fn test_drain_all_partial_consumption() {
let counter = Arc::new(AtomicUsize::new(0));
let mut vec = StackVec::new();
for i in 0..4 {
vec.push(DropTracker::new(i, counter.clone()));
}
assert_eq!(counter.load(Ordering::Relaxed), 4);
{
let mut iter = vec.drain_all();
let _ = iter.next(); let _ = iter.next(); drop(iter);
assert_eq!(vec.len(), 0);
}
assert_eq!(counter.load(Ordering::Relaxed), 0);
}
#[test]
fn test_drain_all_size_hint() {
let mut vec = StackVec::new();
vec.push(1u32);
vec.push(2);
vec.push(3);
let iter = vec.drain_all();
assert_eq!(iter.size_hint(), (3, Some(3)));
assert_eq!(iter.len(), 3); }
#[test]
fn test_drain_all_iterator_properties() {
let mut vec = StackVec::new();
for i in 1..=5 {
vec.push(i);
}
let mut iter = vec.drain_all();
assert_eq!(iter.next(), Some(1));
assert_eq!(iter.next(), Some(2));
assert_eq!(iter.size_hint(), (3, Some(3)));
let remaining: Vec<i32> = iter.collect();
assert_eq!(remaining, vec![3, 4, 5]);
}
#[test]
fn test_drain_all_single_element() {
let mut vec = StackVec::new();
vec.push(42u32);
let mut iter = vec.drain_all();
assert_eq!(iter.next(), Some(42));
assert_eq!(iter.next(), None);
drop(iter);
assert_eq!(vec.len(), 0);
}
#[test]
fn test_drain_all_after_operations() {
let mut vec = StackVec::new();
vec.push(1u32);
vec.push(2);
vec.push(3);
vec.remove(1); assert_eq!(vec.as_slice(), &[1, 3]);
let drained: Vec<u32> = vec.drain_all().collect();
assert_eq!(drained, vec![1, 3]);
assert_eq!(vec.len(), 0);
}
#[test]
fn test_ownership_and_drops() {
let counter = Arc::new(AtomicUsize::new(0));
{
let mut vec = StackVec::new();
vec.push(DropTracker::new(1, counter.clone()));
vec.push(DropTracker::new(2, counter.clone()));
assert_eq!(counter.load(Ordering::Relaxed), 2);
}
assert_eq!(counter.load(Ordering::Relaxed), 0);
}
#[test]
fn test_into_iter_ownership() {
let counter = Arc::new(AtomicUsize::new(0));
{
let mut vec = StackVec::new();
vec.push(DropTracker::new(1, counter.clone()));
vec.push(DropTracker::new(2, counter.clone()));
assert_eq!(counter.load(Ordering::Relaxed), 2);
let mut iter = vec.into_iter();
let first = iter.next().unwrap();
assert_eq!(first.id, 1);
assert_eq!(counter.load(Ordering::Relaxed), 2);
drop(first);
assert_eq!(counter.load(Ordering::Relaxed), 1);
}
assert_eq!(counter.load(Ordering::Relaxed), 0);
}
#[test]
fn test_into_iter_partial_consumption() {
let counter = Arc::new(AtomicUsize::new(0));
{
let mut vec = StackVec::new();
for i in 0..4 {
vec.push(DropTracker::new(i, counter.clone()));
}
assert_eq!(counter.load(Ordering::Relaxed), 4);
let mut iter = vec.into_iter();
let _ = iter.next(); let _ = iter.next(); }
assert_eq!(counter.load(Ordering::Relaxed), 0);
}
#[test]
fn test_append_ownership() {
let counter = Arc::new(AtomicUsize::new(0));
let mut vec1 = StackVec::new();
let mut vec2 = StackVec::new();
vec1.push(DropTracker::new(1, counter.clone()));
vec2.push(DropTracker::new(2, counter.clone()));
vec2.push(DropTracker::new(3, counter.clone()));
assert_eq!(counter.load(Ordering::Relaxed), 3);
assert_eq!(vec2.len(), 2);
vec1.append(&mut vec2);
assert_eq!(vec1.len(), 3);
assert_eq!(vec2.len(), 0);
assert_eq!(counter.load(Ordering::Relaxed), 3);
drop(vec1);
drop(vec2);
assert_eq!(counter.load(Ordering::Relaxed), 0);
}
#[test]
fn test_drain_to_vec() {
let counter: Arc<AtomicUsize> = Arc::new(AtomicUsize::new(0));
let mut stack_vec = StackVec::new();
stack_vec.push(DropTracker::new(1, counter.clone()));
stack_vec.push(DropTracker::new(2, counter.clone()));
let mut heap_vec = Vec::new();
stack_vec.drain_to_vec(&mut heap_vec);
assert_eq!(stack_vec.len(), 0);
assert_eq!(heap_vec.len(), 2);
assert_eq!(counter.load(Ordering::Relaxed), 2);
drop(heap_vec);
assert_eq!(counter.load(Ordering::Relaxed), 0);
}
#[test]
fn test_clone() {
let mut vec = StackVec::new();
vec.push(42u32);
vec.push(84);
let cloned = vec.clone();
assert_eq!(vec.as_slice(), cloned.as_slice());
vec.as_mut_slice()[0] = 999;
assert_ne!(vec[0], cloned[0]);
}
#[test]
fn test_iterators() {
let mut vec = StackVec::new();
vec.push(1u32);
vec.push(2);
vec.push(3);
let collected: Vec<_> = vec.iter().copied().collect();
assert_eq!(collected, vec![1, 2, 3]);
for item in vec.iter_mut() {
*item *= 2;
}
assert_eq!(vec.as_slice(), &[2, 4, 6]);
let into_collected: Vec<_> = vec.into_iter().collect();
assert_eq!(into_collected, vec![2, 4, 6]);
}
#[test]
fn test_double_ended_iterator() {
let mut vec = StackVec::new();
vec.push(1u32);
vec.push(2);
vec.push(3);
vec.push(4);
vec.push(5);
let mut iter = vec.into_iter();
assert_eq!(iter.next(), Some(1));
assert_eq!(iter.next_back(), Some(5));
assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next_back(), Some(4));
assert_eq!(iter.next(), Some(3));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn test_double_ended_iterator_drain_all() {
let mut vec = StackVec::new();
vec.push(10u32);
vec.push(20);
vec.push(30);
let mut iter = vec.drain_all();
assert_eq!(iter.next_back(), Some(30));
assert_eq!(iter.next(), Some(10));
assert_eq!(iter.next_back(), Some(20));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn test_double_ended_iterator_ownership() {
let counter = Arc::new(AtomicUsize::new(0));
let mut vec = StackVec::new();
vec.push(DropTracker::new(1, counter.clone()));
vec.push(DropTracker::new(2, counter.clone()));
vec.push(DropTracker::new(3, counter.clone()));
vec.push(DropTracker::new(4, counter.clone()));
assert_eq!(counter.load(Ordering::Relaxed), 4);
{
let mut iter = vec.into_iter();
let first = iter.next().unwrap();
assert_eq!(first.id, 1);
let last = iter.next_back().unwrap();
assert_eq!(last.id, 4);
drop(first);
drop(last);
assert_eq!(counter.load(Ordering::Relaxed), 2);
}
assert_eq!(counter.load(Ordering::Relaxed), 0);
}
#[test]
fn test_double_ended_iterator_single_element() {
let mut vec = StackVec::new();
vec.push(42u32);
let mut iter = vec.into_iter();
assert_eq!(iter.next_back(), Some(42));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn test_double_ended_iterator_empty() {
let vec: StackVec<u32> = StackVec::new();
let mut iter = vec.into_iter();
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn test_double_ended_iterator_size_hint() {
let mut vec = StackVec::new();
vec.push(1u32);
vec.push(2);
vec.push(3);
vec.push(4);
let mut iter = vec.into_iter();
assert_eq!(iter.size_hint(), (4, Some(4)));
iter.next();
assert_eq!(iter.size_hint(), (3, Some(3)));
iter.next_back();
assert_eq!(iter.size_hint(), (2, Some(2)));
iter.next();
iter.next();
assert_eq!(iter.size_hint(), (0, Some(0)));
}
#[test]
fn test_from_iterator() {
let vec: StackVec<u32> = (1..=5).collect();
assert_eq!(vec.len(), 5);
assert_eq!(vec.as_slice(), &[1, 2, 3, 4, 5]);
}
#[test]
fn test_extend() {
let mut vec = StackVec::new();
vec.push(1u32);
vec.extend(vec![2, 3, 4]);
assert_eq!(vec.as_slice(), &[1, 2, 3, 4]);
}
#[test]
#[should_panic(expected = "StackVec overflow")]
fn test_overflow_panic() {
let mut vec: StackVec<u64> = StackVec::new();
for i in 0..=vec.capacity() {
vec.push(i as u64);
}
}
#[test]
#[should_panic(expected = "StackVec overflow")]
fn test_append_overflow() {
let mut vec1: StackVec<u64> = StackVec::new();
let mut vec2: StackVec<u64> = StackVec::new();
for i in 0..vec1.capacity() {
vec1.push(i as u64);
}
vec2.push(999);
vec1.append(&mut vec2); }
#[test]
#[should_panic(expected = "index out of bounds")]
fn test_index_panic() {
let vec: StackVec<u32> = StackVec::new();
let _ = vec[0];
}
#[test]
fn test_debug_format() {
let mut vec = StackVec::new();
vec.push(1u32);
vec.push(2);
let debug_str = format!("{:?}", vec);
assert_eq!(debug_str, "[1, 2]");
}
#[test]
fn test_partial_eq() {
let mut vec1 = StackVec::new();
let mut vec2 = StackVec::new();
vec1.push(1u32);
vec1.push(2);
vec2.push(1u32);
vec2.push(2);
assert_eq!(vec1, vec2);
vec2.push(3);
assert_ne!(vec1, vec2);
}
#[test]
fn test_size_hint_iterator() {
let mut vec = StackVec::new();
vec.push(1u32);
vec.push(2);
vec.push(3);
let iter = vec.into_iter();
assert_eq!(iter.size_hint(), (3, Some(3)));
}
#[test]
#[should_panic(expected = "Type is too big to fit in a stack vec.")]
fn test_large_type_capacity() {
let _vec: StackVec<Large> = StackVec::new();
}
#[test]
fn test_zst_support() {
let mut vec: StackVec<()> = StackVec::new();
assert_eq!(vec.len(), 0);
assert_eq!(vec.capacity(), usize::MAX);
assert_eq!(StackVec::<()>::static_capacity(), usize::MAX);
for _ in 0..1000 {
vec.push(());
}
assert_eq!(vec.len(), 1000);
vec.pop();
assert_eq!(vec.len(), 999);
vec.clear();
assert_eq!(vec.len(), 0);
}
#[test]
fn test_zst_operations() {
let mut vec: StackVec<()> = StackVec::new();
for _ in 0..10 {
vec.push(());
}
assert_eq!(vec.iter().count(), 10);
assert_eq!(vec.into_iter().count(), 10);
let vec2: StackVec<()> = (0..5).map(|_| ()).collect();
assert_eq!(vec2.len(), 5);
}
#[repr(align(16))]
struct HighlyAligned {
data: u8,
}
#[test]
fn test_alignment_support() {
let mut vec: StackVec<HighlyAligned> = StackVec::new();
assert_eq!(vec.len(), 0);
vec.push(HighlyAligned { data: 42 });
assert_eq!(vec.len(), 1);
assert_eq!(vec[0].data, 42);
let popped = vec.pop().unwrap();
assert_eq!(popped.data, 42);
}
#[test]
fn test_static_capacity_edge_cases() {
assert_eq!(StackVec::<u8>::static_capacity(), STACK_BYTES);
assert_eq!(StackVec::<u16>::static_capacity(), STACK_BYTES / 2);
assert_eq!(StackVec::<u32>::static_capacity(), STACK_BYTES / 4);
assert_eq!(StackVec::<u64>::static_capacity(), STACK_BYTES / 8);
assert_eq!(StackVec::<()>::static_capacity(), usize::MAX);
assert_eq!(StackVec::<Large>::static_capacity(), 0);
}
#[test]
fn test_capacity_consistency() {
let vec: StackVec<u32> = StackVec::new();
assert_eq!(vec.capacity(), StackVec::<u32>::static_capacity());
let vec_zst: StackVec<()> = StackVec::new();
assert_eq!(vec_zst.capacity(), StackVec::<()>::static_capacity());
assert_eq!(vec_zst.capacity(), usize::MAX);
}
#[test]
fn test_zst_drain_operations() {
let mut vec: StackVec<()> = StackVec::new();
for _ in 0..5 {
vec.push(());
}
let drained: Vec<()> = vec.drain_all().collect();
assert_eq!(drained.len(), 5);
assert_eq!(vec.len(), 0);
for _ in 0..3 {
vec.push(());
}
let mut vec_result = Vec::new();
vec.drain_to_vec(&mut vec_result);
assert_eq!(vec_result.len(), 3);
assert_eq!(vec.len(), 0);
}
#[test]
fn test_zst_clone_and_equality() {
let mut vec1: StackVec<()> = StackVec::new();
let mut vec2: StackVec<()> = StackVec::new();
for _ in 0..3 {
vec1.push(());
vec2.push(());
}
assert_eq!(vec1, vec2);
let vec3 = vec1.clone();
assert_eq!(vec1, vec3);
assert_eq!(vec3.len(), 3);
}
#[test]
fn test_highly_aligned_operations() {
let mut vec: StackVec<HighlyAligned> = StackVec::new();
vec.push(HighlyAligned { data: 1 });
vec.push(HighlyAligned { data: 2 });
vec.push(HighlyAligned { data: 3 });
assert_eq!(vec.len(), 3);
assert_eq!(vec[0].data, 1);
assert_eq!(vec[1].data, 2);
assert_eq!(vec[2].data, 3);
let removed = vec.remove(1);
assert_eq!(removed.data, 2);
assert_eq!(vec.len(), 2);
assert_eq!(vec[1].data, 3);
let values: Vec<u8> = vec.iter().map(|x| x.data).collect();
assert_eq!(values, vec![1, 3]);
}
}