use std::{
marker::PhantomData,
mem::ManuallyDrop,
ops::{Deref, DerefMut},
ptr::NonNull,
};
use super::{StackCapacity, StackCommon};
pub struct Stack<T> {
cursor: NonNull<T>,
start: NonNull<T>,
end: NonNull<T>,
_marker: PhantomData<T>,
}
impl<T> Default for Stack<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> StackCapacity<T> for Stack<T> {}
impl<T> StackCommon<T> for Stack<T> {
#[inline]
fn start(&self) -> NonNull<T> {
self.start
}
#[inline]
fn end(&self) -> NonNull<T> {
self.end
}
#[inline]
fn cursor(&self) -> NonNull<T> {
self.cursor
}
#[inline]
fn set_start(&mut self, start: NonNull<T>) {
self.start = start;
}
#[inline]
fn set_end(&mut self, end: NonNull<T>) {
self.end = end;
}
#[inline]
fn set_cursor(&mut self, cursor: NonNull<T>) {
self.cursor = cursor;
}
fn len(&self) -> usize {
unsafe { self.cursor_offset() }
}
}
impl<T> Stack<T> {
pub const MAX_CAPACITY: usize = <Self as StackCapacity<T>>::MAX_CAPACITY;
#[inline]
pub const fn new() -> Self {
const { assert!(size_of::<T>() > 0, "Zero sized types are not supported") };
let dangling = NonNull::dangling();
Self { cursor: dangling, start: dangling, end: dangling, _marker: PhantomData }
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
if capacity == 0 {
Self::new()
} else {
assert!(
capacity <= Self::MAX_CAPACITY,
"`capacity` must not exceed `Self::MAX_CAPACITY`"
);
unsafe { Self::with_capacity_unchecked(capacity) }
}
}
#[inline]
pub unsafe fn with_capacity_unchecked(capacity: usize) -> Self {
debug_assert!(capacity > 0);
debug_assert!(capacity <= Self::MAX_CAPACITY);
let capacity_bytes = capacity * size_of::<T>();
unsafe { Self::new_with_capacity_bytes_unchecked(capacity_bytes) }
}
#[inline]
unsafe fn new_with_capacity_bytes_unchecked(capacity_bytes: usize) -> Self {
const { assert!(size_of::<T>() > 0, "Zero sized types are not supported") };
let (start, end) = unsafe { Self::allocate(capacity_bytes) };
Self { cursor: start, start, end, _marker: PhantomData }
}
#[inline]
pub fn last(&self) -> Option<&T> {
#[expect(clippy::if_not_else)]
if !self.is_empty() {
Some(unsafe { self.last_unchecked() })
} else {
None
}
}
#[inline]
pub unsafe fn last_unchecked(&self) -> &T {
debug_assert!(self.end > self.start);
debug_assert!(self.cursor > self.start);
debug_assert!(self.cursor <= self.end);
unsafe { self.cursor.sub(1).as_ref() }
}
#[inline]
pub fn last_mut(&mut self) -> Option<&mut T> {
#[expect(clippy::if_not_else)]
if !self.is_empty() {
Some(unsafe { self.last_unchecked_mut() })
} else {
None
}
}
#[inline]
pub unsafe fn last_unchecked_mut(&mut self) -> &mut T {
debug_assert!(self.end > self.start);
debug_assert!(self.cursor > self.start);
debug_assert!(self.cursor <= self.end);
unsafe { self.cursor.sub(1).as_mut() }
}
#[inline]
pub fn push(&mut self, value: T) {
if self.cursor == self.end {
unsafe { self.push_slow(value) };
} else {
unsafe { self.cursor.as_ptr().write(value) };
self.cursor = unsafe { self.cursor.add(1) };
}
}
#[cold]
#[inline(never)]
unsafe fn push_slow(&mut self, value: T) {
#[expect(clippy::if_not_else)]
if self.end != self.start {
unsafe { self.grow() };
} else {
let (start, end) = unsafe { Self::allocate(Self::DEFAULT_CAPACITY_BYTES) };
self.start = start;
self.cursor = start;
self.end = end;
}
unsafe { self.cursor.as_ptr().write(value) }
self.cursor = unsafe { self.cursor.add(1) };
}
#[inline]
pub fn pop(&mut self) -> Option<T> {
#[expect(clippy::if_not_else)]
if !self.is_empty() {
Some(unsafe { self.pop_unchecked() })
} else {
None
}
}
#[inline]
pub unsafe fn pop_unchecked(&mut self) -> T {
debug_assert!(self.end > self.start);
debug_assert!(self.cursor > self.start);
debug_assert!(self.cursor <= self.end);
self.cursor = unsafe { self.cursor.sub(1) };
unsafe { self.cursor.read() }
}
#[inline]
pub fn clear(&mut self) {
if self.is_empty() {
return;
}
debug_assert!(self.end > self.start);
unsafe { self.drop_contents() };
self.cursor = self.start;
}
#[inline]
pub fn len(&self) -> usize {
<Self as StackCommon<T>>::len(self)
}
#[inline]
pub fn is_empty(&self) -> bool {
self.cursor == self.start
}
#[inline]
pub fn capacity(&self) -> usize {
<Self as StackCommon<T>>::capacity(self)
}
#[inline]
pub fn as_slice(&self) -> &[T] {
<Self as StackCommon<T>>::as_slice(self)
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
<Self as StackCommon<T>>::as_mut_slice(self)
}
#[inline] pub fn into_vec(self) -> Vec<T> {
debug_assert!(self.len() <= self.capacity());
let stack = ManuallyDrop::new(self);
unsafe { Vec::from_raw_parts(stack.start.as_ptr(), stack.len(), stack.capacity()) }
}
}
impl<T> Drop for Stack<T> {
fn drop(&mut self) {
if self.end == self.start {
return;
}
if !self.is_empty() {
unsafe { self.drop_contents() };
}
unsafe { self.deallocate() };
}
}
impl<T> Deref for Stack<T> {
type Target = [T];
#[inline]
fn deref(&self) -> &[T] {
self.as_slice()
}
}
impl<T> DerefMut for Stack<T> {
#[inline]
fn deref_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<T> From<Vec<T>> for Stack<T> {
#[inline] fn from(vec: Vec<T>) -> Self {
const { assert!(size_of::<T>() > 0, "Zero sized types are not supported") };
let mut vec = ManuallyDrop::new(vec);
let ptr = unsafe { NonNull::new_unchecked(vec.as_mut_ptr()) };
unsafe {
Self {
cursor: ptr.add(vec.len()),
start: ptr,
end: ptr.add(vec.capacity()),
_marker: PhantomData,
}
}
}
}
impl<T> From<Stack<T>> for Vec<T> {
#[inline]
fn from(stack: Stack<T>) -> Self {
stack.into_vec()
}
}
impl<T> FromIterator<T> for Stack<T> {
#[inline] fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let vec = Vec::from_iter(iter);
Self::from(vec)
}
}
unsafe impl<T: Send> Send for Stack<T> {}
unsafe impl<T: Sync> Sync for Stack<T> {}
#[cfg(test)]
mod tests {
use super::*;
macro_rules! assert_len_cap_last {
($stack:ident, $len:expr, $capacity:expr, $last:expr) => {
assert_eq!($stack.len(), $len);
assert_eq!($stack.capacity(), $capacity);
assert_eq!($stack.last(), $last);
};
}
#[test]
fn new() {
let stack = Stack::<bool>::new();
assert_len_cap_last!(stack, 0, 0, None);
assert_eq!(stack.capacity_bytes(), 0);
let stack = Stack::<u64>::new();
assert_len_cap_last!(stack, 0, 0, None);
assert_eq!(stack.capacity_bytes(), 0);
let stack = Stack::<[u8; 1024]>::new();
assert_len_cap_last!(stack, 0, 0, None);
assert_eq!(stack.capacity_bytes(), 0);
let stack = Stack::<[u8; 1025]>::new();
assert_len_cap_last!(stack, 0, 0, None);
assert_eq!(stack.capacity_bytes(), 0);
}
#[test]
fn with_capacity() {
let stack = Stack::<u64>::with_capacity(16);
assert_len_cap_last!(stack, 0, 16, None);
assert_eq!(stack.capacity_bytes(), 128);
}
#[test]
fn with_capacity_zero() {
let stack = Stack::<u64>::with_capacity(0);
assert_len_cap_last!(stack, 0, 0, None);
}
#[test]
fn from_vec() {
let vec = vec![10_u64, 20, 30];
let stack = Stack::from(vec);
assert_len_cap_last!(stack, 3, 3, Some(&30));
}
#[test]
fn from_empty_vec() {
let vec: Vec<u64> = vec![];
let stack = Stack::from(vec);
assert_len_cap_last!(stack, 0, 0, None);
}
#[test]
fn from_iterator() {
let arr = [10_u64, 20, 30];
let stack = Stack::from_iter(arr);
assert_len_cap_last!(stack, 3, 3, Some(&30));
}
#[test]
fn collect_iterator() {
let arr = [10_u64, 20, 30];
let stack = arr.into_iter().collect::<Stack<_>>();
assert_len_cap_last!(stack, 3, 3, Some(&30));
}
#[test]
fn from_empty_iterator() {
let arr: [u64; 0] = [];
#[expect(clippy::from_iter_instead_of_collect)]
let stack = Stack::from_iter(arr.iter());
assert_len_cap_last!(stack, 0, 0, None);
}
#[test]
fn collect_empty_iterator() {
let arr: [u64; 0] = [];
let stack = arr.into_iter().collect::<Stack<_>>();
assert_len_cap_last!(stack, 0, 0, None);
}
#[test]
fn into_vec() {
let stack = Stack::from(vec![10_u64, 20, 30]);
assert_len_cap_last!(stack, 3, 3, Some(&30));
let vec = stack.into_vec();
assert_eq!(vec, vec![10, 20, 30]);
assert_eq!(vec.capacity(), 3);
}
#[test]
fn into_empty_vec() {
let stack = Stack::<u64>::new();
assert_len_cap_last!(stack, 0, 0, None);
let vec = stack.into_vec();
assert_eq!(vec, vec![]);
assert_eq!(vec.capacity(), 0);
}
#[test]
fn into_vec_via_from_trait() {
let stack = Stack::from(vec![10_u64, 20, 30]);
assert_len_cap_last!(stack, 3, 3, Some(&30));
let vec = Vec::from(stack);
assert_eq!(vec, vec![10, 20, 30]);
assert_eq!(vec.capacity(), 3);
}
#[test]
fn into_empty_vec_via_from_trait() {
let stack = Stack::<u64>::new();
assert_len_cap_last!(stack, 0, 0, None);
let vec = Vec::from(stack);
assert_eq!(vec, vec![]);
assert_eq!(vec.capacity(), 0);
}
#[test]
fn push_then_pop() {
let mut stack = Stack::<u64>::new();
assert_len_cap_last!(stack, 0, 0, None);
assert_eq!(stack.capacity_bytes(), 0);
stack.push(10);
assert_len_cap_last!(stack, 1, 4, Some(&10));
assert_eq!(stack.capacity_bytes(), 32);
stack.push(20);
assert_len_cap_last!(stack, 2, 4, Some(&20));
stack.push(30);
assert_len_cap_last!(stack, 3, 4, Some(&30));
stack.push(40);
assert_len_cap_last!(stack, 4, 4, Some(&40));
assert_eq!(stack.capacity_bytes(), 32);
stack.push(50);
assert_len_cap_last!(stack, 5, 8, Some(&50));
assert_eq!(stack.capacity_bytes(), 64);
stack.push(60);
assert_len_cap_last!(stack, 6, 8, Some(&60));
stack.push(70);
assert_len_cap_last!(stack, 7, 8, Some(&70));
stack.push(80);
assert_len_cap_last!(stack, 8, 8, Some(&80));
assert_eq!(stack.capacity_bytes(), 64);
stack.push(90);
assert_len_cap_last!(stack, 9, 16, Some(&90));
assert_eq!(stack.capacity_bytes(), 128);
assert_eq!(stack.pop(), Some(90));
assert_len_cap_last!(stack, 8, 16, Some(&80));
assert_eq!(stack.pop(), Some(80));
assert_len_cap_last!(stack, 7, 16, Some(&70));
assert_eq!(stack.pop(), Some(70));
assert_len_cap_last!(stack, 6, 16, Some(&60));
assert_eq!(stack.pop(), Some(60));
assert_len_cap_last!(stack, 5, 16, Some(&50));
assert_eq!(stack.pop(), Some(50));
assert_len_cap_last!(stack, 4, 16, Some(&40));
assert_eq!(stack.pop(), Some(40));
assert_len_cap_last!(stack, 3, 16, Some(&30));
assert_eq!(stack.pop(), Some(30));
assert_len_cap_last!(stack, 2, 16, Some(&20));
assert_eq!(stack.pop(), Some(20));
assert_len_cap_last!(stack, 1, 16, Some(&10));
assert_eq!(stack.pop(), Some(10));
assert_len_cap_last!(stack, 0, 16, None);
assert_eq!(stack.pop(), None);
assert_eq!(stack.capacity_bytes(), 128);
}
#[test]
fn push_and_pop_mixed() {
let mut stack = Stack::<u64>::new();
assert_len_cap_last!(stack, 0, 0, None);
assert_eq!(stack.capacity_bytes(), 0);
stack.push(10);
assert_len_cap_last!(stack, 1, 4, Some(&10));
assert_eq!(stack.capacity_bytes(), 32);
stack.push(20);
assert_len_cap_last!(stack, 2, 4, Some(&20));
stack.push(30);
assert_len_cap_last!(stack, 3, 4, Some(&30));
assert_eq!(stack.pop(), Some(30));
assert_len_cap_last!(stack, 2, 4, Some(&20));
stack.push(31);
assert_len_cap_last!(stack, 3, 4, Some(&31));
stack.push(40);
assert_len_cap_last!(stack, 4, 4, Some(&40));
assert_eq!(stack.capacity_bytes(), 32);
assert_eq!(stack.pop(), Some(40));
assert_len_cap_last!(stack, 3, 4, Some(&31));
assert_eq!(stack.capacity_bytes(), 32);
stack.push(41);
assert_len_cap_last!(stack, 4, 4, Some(&41));
assert_eq!(stack.capacity_bytes(), 32);
stack.push(50);
assert_len_cap_last!(stack, 5, 8, Some(&50));
assert_eq!(stack.capacity_bytes(), 64);
assert_eq!(stack.pop(), Some(50));
assert_len_cap_last!(stack, 4, 8, Some(&41));
assert_eq!(stack.pop(), Some(41));
assert_len_cap_last!(stack, 3, 8, Some(&31));
assert_eq!(stack.pop(), Some(31));
assert_len_cap_last!(stack, 2, 8, Some(&20));
stack.push(32);
assert_len_cap_last!(stack, 3, 8, Some(&32));
assert_eq!(stack.pop(), Some(32));
assert_len_cap_last!(stack, 2, 8, Some(&20));
assert_eq!(stack.pop(), Some(20));
assert_len_cap_last!(stack, 1, 8, Some(&10));
assert_eq!(stack.pop(), Some(10));
assert_len_cap_last!(stack, 0, 8, None);
assert_eq!(stack.pop(), None);
assert_eq!(stack.pop(), None);
assert_eq!(stack.capacity_bytes(), 64);
stack.push(11);
assert_len_cap_last!(stack, 1, 8, Some(&11));
assert_eq!(stack.pop(), Some(11));
assert_len_cap_last!(stack, 0, 8, None);
assert_eq!(stack.pop(), None);
assert_eq!(stack.pop(), None);
assert_eq!(stack.capacity_bytes(), 64);
}
#[test]
fn last_mut() {
let mut stack = Stack::<u64>::new();
assert_len_cap_last!(stack, 0, 0, None);
assert_eq!(stack.last_mut(), None);
stack.push(10);
assert_len_cap_last!(stack, 1, 4, Some(&10));
*stack.last_mut().unwrap() = 11;
assert_len_cap_last!(stack, 1, 4, Some(&11));
*stack.last_mut().unwrap() = 12;
assert_len_cap_last!(stack, 1, 4, Some(&12));
stack.push(20);
assert_len_cap_last!(stack, 2, 4, Some(&20));
*stack.last_mut().unwrap() = 21;
assert_len_cap_last!(stack, 2, 4, Some(&21));
*stack.last_mut().unwrap() = 22;
assert_len_cap_last!(stack, 2, 4, Some(&22));
}
#[test]
fn clear() {
let mut stack = Stack::<u64>::new();
assert_len_cap_last!(stack, 0, 0, None);
stack.clear();
assert_len_cap_last!(stack, 0, 0, None);
stack.push(10);
assert_len_cap_last!(stack, 1, 4, Some(&10));
stack.clear();
assert_len_cap_last!(stack, 0, 4, None);
}
#[test]
#[expect(clippy::items_after_statements)]
fn drop() {
use std::sync::{Mutex, OnceLock};
static DROPS: OnceLock<Mutex<Vec<u32>>> = OnceLock::new();
DROPS.get_or_init(|| Mutex::new(vec![]));
fn drops() -> Vec<u32> {
std::mem::take(DROPS.get().unwrap().lock().unwrap().as_mut())
}
#[derive(PartialEq, Debug)]
struct Droppy(u32);
impl Drop for Droppy {
fn drop(&mut self) {
DROPS.get().unwrap().lock().unwrap().push(self.0);
}
}
{
let mut stack = Stack::new();
stack.push(Droppy(10));
stack.push(Droppy(20));
stack.push(Droppy(30));
assert_eq!(stack.len(), 3);
assert_eq!(stack.capacity(), 4);
stack.pop();
assert_eq!(drops(), &[30]);
assert!(drops().is_empty());
stack.push(Droppy(31));
stack.push(Droppy(40));
stack.push(Droppy(50));
assert_eq!(stack.len(), 5);
assert_eq!(stack.capacity(), 8);
assert!(drops().is_empty());
}
assert_eq!(drops(), &[10, 20, 31, 40, 50]);
}
#[test]
fn send_sync() {
use std::rc::Rc;
use crate::types::implements;
assert!(implements!(Stack<u32>: Send));
assert!(implements!(Stack<u32>: Sync));
assert!(implements!(Stack<Rc<u32>>: !Send));
assert!(implements!(Stack<Rc<u32>>: !Sync));
}
}