use std::{
    marker::PhantomData,
    mem::ManuallyDrop,
    ops::{Deref, DerefMut},
    ptr::NonNull,
};

use super::{StackCapacity, StackCommon};

/// A simple stack.
///
/// If a non-empty stack is viable for your use case, prefer [`NonEmptyStack`], which is cheaper for
/// all operations.
///
/// [`NonEmptyStack`] is usually the better choice, unless either:
///
/// 1. The stack will likely never have anything pushed to it.
///    [`NonEmptyStack::new`] always allocates, whereas [`Stack::new`] does not.
///    So if stack usually starts empty and remains empty, [`Stack`] will avoid an allocation.
///    This is the same as how [`Vec`] does not allocate until you push a value into it.
///
/// 2. The type the stack holds is large or expensive to construct, so there's a high cost in having to
///    create an initial dummy value (which [`NonEmptyStack`] requires, but [`Stack`] doesn't).
///
/// To simplify implementation, zero size types are not supported (`Stack<()>`).
///
/// ## Design
/// Designed for maximally efficient [`push`], [`pop`], and reading/writing the last value on stack
/// ([`last`] / [`last_mut`]). Although, unlike [`NonEmptyStack`], [`last`] and [`last_mut`] are
/// fallible, and not branchless. So [`Stack::last`] and [`Stack::last_mut`] are a bit more expensive
/// than [`NonEmptyStack`]'s equivalents.
///
/// The alternative would likely be to use a [`Vec`]. But `Vec` is optimized for indexing into at
/// arbitrary positions, not for `push` and `pop`. `Vec` stores `len` and `capacity` as integers,
/// so requires pointer maths on every operation: `let entry_ptr = base_ptr + index * size_of::<T>();`.
///
/// In comparison, [`Stack`] uses a `cursor` pointer, so avoids these calculations.
/// This is similar to how [`std`'s slice iterators] work.
///
/// [`push`]: Stack::push
/// [`pop`]: Stack::pop
/// [`last`]: Stack::last
/// [`last_mut`]: Stack::last_mut
/// [`NonEmptyStack`]: super::NonEmptyStack
/// [`NonEmptyStack::new`]: super::NonEmptyStack::new
/// [`std`'s slice iterators]: std::slice::Iter
pub struct Stack<T> {
    /// Pointer to *after* last entry on stack
    cursor: NonNull<T>,
    /// Pointer to start of allocation containing stack
    start: NonNull<T>,
    /// Pointer to end of allocation containing stack
    end: NonNull<T>,
    /// Inform compiler that `Stack<T>` owns `T`s
    _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 {
        // SAFETY: `self.start` and `self.cursor` are both derived from same pointer.
        // `self.cursor` is always >= `self.start`.
        // Distance between pointers is always a multiple of `size_of::<T>()`.
        unsafe { self.cursor_offset() }
    }
}

impl<T> Stack<T> {
    /// Maximum capacity.
    ///
    /// Effectively unlimited on 64-bit systems.
    pub const MAX_CAPACITY: usize = <Self as StackCapacity<T>>::MAX_CAPACITY;

    /// Create new empty `Stack`.
    ///
    /// # Panics
    /// Panics if `T` is a zero-sized type.
    #[inline]
    pub const fn new() -> Self {
        // ZSTs are not supported for simplicity
        const { assert!(size_of::<T>() > 0, "Zero sized types are not supported") };

        // Create stack with equal `start` and `end`
        let dangling = NonNull::dangling();
        Self { cursor: dangling, start: dangling, end: dangling, _marker: PhantomData }
    }

    /// Create new `Stack` with pre-allocated capacity for `capacity` entries.
    ///
    /// # Panics
    /// Panics if any of these requirements are not satisfied:
    /// * `T` must not be a zero-sized type.
    /// * `capacity` must not exceed [`Self::MAX_CAPACITY`].
    #[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`"
            );
            // SAFETY: Assertion above ensures `capacity` satisfies requirements
            unsafe { Self::with_capacity_unchecked(capacity) }
        }
    }

    /// Create new `Stack` with pre-allocated capacity for `capacity` entries, without checks.
    ///
    /// `capacity` cannot be 0.
    ///
    /// # Panics
    /// Panics if `T` is a zero-sized type.
    ///
    /// # SAFETY
    ///
    /// * `capacity` must not be 0.
    /// * `capacity` must not exceed [`Self::MAX_CAPACITY`].
    #[inline]
    pub unsafe fn with_capacity_unchecked(capacity: usize) -> Self {
        debug_assert!(capacity > 0);
        debug_assert!(capacity <= Self::MAX_CAPACITY);

        // Cannot overflow if `capacity <= MAX_CAPACITY`
        let capacity_bytes = capacity * size_of::<T>();

        // SAFETY: Safety invariants which caller must satisfy guarantee that `capacity_bytes`
        // satisfies requirements
        unsafe { Self::new_with_capacity_bytes_unchecked(capacity_bytes) }
    }

    /// Create new `Stack` with provided capacity in bytes, without checks.
    ///
    /// # Panics
    /// Panics if `T` is a zero-sized type.
    ///
    /// # SAFETY
    /// * `capacity_bytes` must not be 0.
    /// * `capacity_bytes` must be a multiple of `size_of::<T>()`.
    /// * `capacity_bytes` must not exceed [`Self::MAX_CAPACITY_BYTES`].
    #[inline]
    unsafe fn new_with_capacity_bytes_unchecked(capacity_bytes: usize) -> Self {
        // ZSTs are not supported for simplicity
        const { assert!(size_of::<T>() > 0, "Zero sized types are not supported") };

        // SAFETY: Caller guarantees `capacity_bytes` satisfies requirements
        let (start, end) = unsafe { Self::allocate(capacity_bytes) };

        // `cursor` is positioned at start
        Self { cursor: start, start, end, _marker: PhantomData }
    }

    // Note: There is no need to implement `first` and `first_mut` methods.
    // `NonEmptyStack` can make those methods infallible, but `Stack` can't because `Stack` can be empty.
    // `std`'s `first` and `first_mut` methods available via `Deref` / `DerefMut` to a `&[T]` / `&mut[T]`
    // are just as efficient as a hand-written version.
    // https://godbolt.org/z/rjb1dzob1

    /// Get reference to last value on stack.
    #[inline]
    pub fn last(&self) -> Option<&T> {
        #[expect(clippy::if_not_else)]
        if !self.is_empty() {
            // SAFETY: Stack is not empty
            Some(unsafe { self.last_unchecked() })
        } else {
            None
        }
    }

    /// Get reference to last value on stack, without checking stack isn't empty.
    ///
    /// # SAFETY
    ///
    /// * Stack must not be empty.
    #[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);

        // SAFETY: All methods ensure `self.cursor` is always in bounds, is aligned for `T`,
        // and `self.current.sub(1)` points to a valid initialized `T`, if stack is not empty.
        // Caller guarantees stack is not empty.
        unsafe { self.cursor.sub(1).as_ref() }
    }

    /// Get mutable reference to last value on stack.
    #[inline]
    pub fn last_mut(&mut self) -> Option<&mut T> {
        #[expect(clippy::if_not_else)]
        if !self.is_empty() {
            // SAFETY: Stack is not empty
            Some(unsafe { self.last_unchecked_mut() })
        } else {
            None
        }
    }

    /// Get mutable reference to last value on stack, without checking stack isn't empty.
    ///
    /// # SAFETY
    ///
    /// * Stack must not be empty.
    #[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);

        // SAFETY: All methods ensure `self.cursor` is always in bounds, is aligned for `T`,
        // and `self.current.sub(1)` points to a valid initialized `T`, if stack is not empty.
        // Caller guarantees stack is not empty.
        unsafe { self.cursor.sub(1).as_mut() }
    }

    /// Push value to stack.
    ///
    /// # Panics
    /// Panics if stack is already filled to maximum capacity.
    #[inline]
    pub fn push(&mut self, value: T) {
        // The distance between `self.cursor` and `self.end` is always a multiple of `size_of::<T>()`,
        // so `==` check is sufficient to detect when full to capacity.
        if self.cursor == self.end {
            // Needs to grow
            // SAFETY: Stack is full to capacity
            unsafe { self.push_slow(value) };
        } else {
            // SAFETY: Cursor is not at end, so `self.cursor` is in bounds for writing
            unsafe { self.cursor.as_ptr().write(value) };
            // SAFETY: Cursor is not at end, so advancing by a `T` cannot be out of bounds
            self.cursor = unsafe { self.cursor.add(1) };
        }
    }

    /// Push value to stack when stack is full to capacity.
    ///
    /// This is the slow branch of `push`, which is rarely taken, so marked as `#[cold]` and
    /// `#[inline(never)]` to make `push` as small as possible, so it can be inlined.
    ///
    /// # Panics
    /// Panics if stack is already at maximum capacity.
    ///
    /// # SAFETY
    /// Stack must be full to capacity. i.e. `self.cursor == self.end`.
    #[cold]
    #[inline(never)]
    unsafe fn push_slow(&mut self, value: T) {
        #[expect(clippy::if_not_else)]
        if self.end != self.start {
            // Stack was already allocated. Grow capacity.
            // SAFETY: Checked above that is already allocated.
            unsafe { self.grow() };
        } else {
            // Stack was not allocated yet.
            // SAFETY: `DEFAULT_CAPACITY_BYTES` satisfies requirements.
            let (start, end) = unsafe { Self::allocate(Self::DEFAULT_CAPACITY_BYTES) };
            self.start = start;
            self.cursor = start;
            self.end = end;
        }

        // Write value + increment cursor.
        // SAFETY: We just allocated additional capacity, so `self.cursor` is in bounds.
        // `self.cursor` is aligned for `T`.
        unsafe { self.cursor.as_ptr().write(value) }
        // SAFETY: Cursor is not at end, so advancing by a `T` cannot be out of bounds
        self.cursor = unsafe { self.cursor.add(1) };
    }

    /// Pop value from stack.
    #[inline]
    pub fn pop(&mut self) -> Option<T> {
        #[expect(clippy::if_not_else)]
        if !self.is_empty() {
            // SAFETY: Just checked stack is not empty
            Some(unsafe { self.pop_unchecked() })
        } else {
            None
        }
    }

    /// Pop value from stack, without checking that stack isn't empty.
    ///
    /// # SAFETY
    ///
    /// * Stack must not be empty.
    #[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);

        // SAFETY: Caller guarantees stack is not empty, so subtracting 1 cannot be out of bounds
        self.cursor = unsafe { self.cursor.sub(1) };
        // SAFETY: All methods ensure `self.cursor` is always in bounds, is aligned for `T`,
        // and points to a valid initialized `T`, if stack is not empty.
        // Caller guarantees stack was not empty.
        unsafe { self.cursor.read() }
    }

    /// Clear the stack, removing all values.
    ///
    /// Note that this method has no effect on the allocated capacity
    /// of the stack.
    #[inline]
    pub fn clear(&mut self) {
        if self.is_empty() {
            return;
        }

        debug_assert!(self.end > self.start);

        // SAFETY: Checked above that stack is not empty, so stack is allocated.
        // Stack contains `self.len()` initialized entries, starting at `self.start`
        unsafe { self.drop_contents() };
        // Move cursor back to start. This is equivalent to setting len to 0
        self.cursor = self.start;
    }

    /// Get number of entries on stack.
    #[inline]
    pub fn len(&self) -> usize {
        <Self as StackCommon<T>>::len(self)
    }

    /// Get if stack is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.cursor == self.start
    }

    /// Get capacity.
    #[inline]
    pub fn capacity(&self) -> usize {
        <Self as StackCommon<T>>::capacity(self)
    }

    /// Get contents of stack as a slice `&[T]`.
    #[inline]
    pub fn as_slice(&self) -> &[T] {
        <Self as StackCommon<T>>::as_slice(self)
    }

    /// Get contents of stack as a mutable slice `&mut [T]`.
    #[inline]
    pub fn as_mut_slice(&mut self) -> &mut [T] {
        <Self as StackCommon<T>>::as_mut_slice(self)
    }

    /// Convert [`Stack`] into a [`Vec`].
    ///
    /// This is a cheap conversion. The `Vec` takes over ownership of the `Stack`'s allocation.
    /// No allocation occurs, and no data is copied.
    #[inline] // This method is just a few arithmetic operations
    pub fn into_vec(self) -> Vec<T> {
        debug_assert!(self.len() <= self.capacity());

        // Wrap `self` in `ManuallyDrop` to prevent it from being dropped
        let stack = ManuallyDrop::new(self);

        // SAFETY:
        // T is not zero-sized. It's impossible to create a `Stack<T>` with a ZST `T`.
        //
        // If the `Stack` has allocated:
        // * `start` is the pointer is was allocated with.
        // * `start` is aligned for `T`.
        // * `size_of::<T>() * capacity` is equal to the size of the allocation which backs the `Stack`.
        // * This is the size the allocation was originally allocated with.
        // * `len <= capacity`
        // * The first `len` values are properly initialized values of type `T`.
        //
        // If the `Stack` has not allocated
        // * `start` is a dangling pointer, aligned for `T`.
        //
        // In short, `Stack` manages it's allocation exactly the same way as `Vec`,
        // so it's safe to convert between the two.
        unsafe { Vec::from_raw_parts(stack.start.as_ptr(), stack.len(), stack.capacity()) }
    }
}

impl<T> Drop for Stack<T> {
    fn drop(&mut self) {
        // Nothing to drop if stack never allocated
        if self.end == self.start {
            return;
        }

        if !self.is_empty() {
            // SAFETY: Checked above that stack is allocated.
            // Stack contains `self.len()` initialized entries, starting at `self.start`
            unsafe { self.drop_contents() };
        }

        // Drop the memory
        // SAFETY: Checked above that stack is allocated.
        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> {
    /// Convert a [`Vec`] into a [`Stack`].
    ///
    /// This is a cheap conversion. The `Stack` takes over ownership of the `Vec`'s allocation.
    /// No allocation occurs, and no data is copied.
    #[inline] // This method is just a few arithmetic operations
    fn from(vec: Vec<T>) -> Self {
        // ZSTs are not supported for simplicity
        const { assert!(size_of::<T>() > 0, "Zero sized types are not supported") };

        // Wrap `vec` in `ManuallyDrop` to prevent it from being dropped
        let mut vec = ManuallyDrop::new(vec);

        // SAFETY: `Vec`'s pointer is always non-null, even when the `Vec` has not allocated
        // (in that case, it's a dangling pointer)
        let ptr = unsafe { NonNull::new_unchecked(vec.as_mut_ptr()) };

        // SAFETY:
        // We ensured that `T` is not zero-sized above.
        //
        // If the `Vec` has allocated, then `ptr` is valid.
        // `ptr + len` for an allocated `Vec` is always in bounds of the `Vec`'s allocation,
        // and `ptr + capacity` is always the end of the `Vec`'s allocation.
        //
        // If the `Vec` has not allocated, then `ptr` is a dangling pointer, and `len` and `capacity` are 0.
        // Adding 0 to an invalid pointer is legal.
        //
        // Therefore these `add` operations are sound.
        //
        // The `Stack` takes ownership of the allocation, and will deallocate it correctly when dropped.
        unsafe {
            Self {
                cursor: ptr.add(vec.len()),
                start: ptr,
                end: ptr.add(vec.capacity()),
                _marker: PhantomData,
            }
        }
    }
}

impl<T> From<Stack<T>> for Vec<T> {
    /// Convert a [`Stack`] into a [`Vec`].
    ///
    /// This is a cheap conversion. The `Vec` takes over ownership of the `Stack`'s allocation.
    /// No allocation occurs, and no data is copied.
    #[inline]
    fn from(stack: Stack<T>) -> Self {
        stack.into_vec()
    }
}

impl<T> FromIterator<T> for Stack<T> {
    /// Create a [`Stack`] from an iterator.
    #[inline] // It mostly just delegates to `Vec::from_iter`
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
        // Collect into a `Vec` first, because `Vec` has specialized implementations of `from_iter`
        // for various kinds of iterators, which we cannot replicate in stable Rust
        let vec = Vec::from_iter(iter);
        Self::from(vec)
    }
}

// SAFETY: `Stack<T>` can be `Send` / `Sync` if `T` is `Send` / `Sync`.
// It does not use interior mutability, and is essentially the same as `Vec<T>`,
// which implements `Send` / `Sync` in the same way.
unsafe impl<T: Send> Send for Stack<T> {}
// SAFETY: See above.
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]);
    }
}
