Documentation
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::cell::UnsafeCell;
use core::mem::MaybeUninit;
use core::sync::atomic::{AtomicUsize, Ordering::*};

pub struct Ring<T> {
    buffer: Box<[UnsafeCell<MaybeUninit<T>>]>,
    capacity: usize,
    mask: usize,
    head: AtomicUsize,
    tail: AtomicUsize,
    cached_head: UnsafeCell<usize>,
    cached_tail: UnsafeCell<usize>,
}

unsafe impl<T: Send> Send for Ring<T> {}
unsafe impl<T: Send> Sync for Ring<T> {}

impl<T> Ring<T> {
    pub fn new(capacity: usize) -> Self {
        assert!(capacity > 0, "capacity must be non-zero");
        assert!(capacity.is_power_of_two(), "capacity must be power of two");

        let mut buffer = Vec::with_capacity(capacity);
        for _ in 0..capacity {
            buffer.push(UnsafeCell::new(MaybeUninit::uninit()));
        }

        Self {
            buffer: buffer.into_boxed_slice(),
            capacity,
            mask: capacity - 1,
            head: AtomicUsize::new(0),
            tail: AtomicUsize::new(0),
            cached_head: UnsafeCell::new(0),
            cached_tail: UnsafeCell::new(0),
        }
    }

    /// Push item to ring buffer (producer only)
    pub fn push(&self, value: T) -> Result<(), T> {
        unsafe {
            let tail = self.tail.load(Relaxed);
            let next_tail = tail.wrapping_add(1);

            // Check cached head first to avoid cache ping-pong
            let cached_head = *self.cached_head.get();
            if next_tail.wrapping_sub(cached_head) > self.capacity {
                // Update cache and check again
                let head = self.head.load(Acquire);
                *self.cached_head.get() = head;

                if next_tail.wrapping_sub(head) > self.capacity {
                    return Err(value); // Buffer full
                }
            }

            // Write to buffer
            let index = tail & self.mask;
            (*self.buffer[index].get()).write(value);

            // Make write visible before updating tail
            self.tail.store(next_tail, Release);
            Ok(())
        }
    }

    /// Pop item from ring buffer (consumer only)
    pub fn pop(&self) -> Option<T> {
        unsafe {
            let head = self.head.load(Relaxed);

            // Check cached tail first
            let cached_tail = *self.cached_tail.get();
            if head == cached_tail {
                // Update cache and check again
                let tail = self.tail.load(Acquire);
                *self.cached_tail.get() = tail;

                if head == tail {
                    return None; // Buffer empty
                }
            }

            // Read from buffer
            let index = head & self.mask;
            let value = (*self.buffer[index].get()).assume_init_read();

            // Make read visible before updating head
            self.head.store(head.wrapping_add(1), Release);
            Some(value)
        }
    }

    /// Try push without blocking
    pub fn try_push(&self, value: T) -> Result<(), T> {
        self.push(value)
    }

    /// Try pop without blocking  
    pub fn try_pop(&self) -> Option<T> {
        self.pop()
    }

    /// Get current number of items (approximation)
    pub fn len(&self) -> usize {
        let tail = self.tail.load(Acquire);
        let head = self.head.load(Acquire);
        tail.wrapping_sub(head)
    }

    /// Get capacity
    pub fn capacity(&self) -> usize {
        self.capacity
    }

    /// Check if empty (consumer perspective)
    pub fn is_empty(&self) -> bool {
        self.head.load(Acquire) == self.tail.load(Acquire)
    }

    /// Check if full (producer perspective)
    pub fn is_full(&self) -> bool {
        let tail = self.tail.load(Acquire);
        let head = self.head.load(Acquire);
        tail.wrapping_sub(head) == self.capacity
    }
}

impl<T> Drop for Ring<T> {
    fn drop(&mut self) {
        // Drop any remaining items
        while self.pop().is_some() {}
    }
}