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),
}
}
pub fn push(&self, value: T) -> Result<(), T> {
unsafe {
let tail = self.tail.load(Relaxed);
let next_tail = tail.wrapping_add(1);
let cached_head = *self.cached_head.get();
if next_tail.wrapping_sub(cached_head) > self.capacity {
let head = self.head.load(Acquire);
*self.cached_head.get() = head;
if next_tail.wrapping_sub(head) > self.capacity {
return Err(value); }
}
let index = tail & self.mask;
(*self.buffer[index].get()).write(value);
self.tail.store(next_tail, Release);
Ok(())
}
}
pub fn pop(&self) -> Option<T> {
unsafe {
let head = self.head.load(Relaxed);
let cached_tail = *self.cached_tail.get();
if head == cached_tail {
let tail = self.tail.load(Acquire);
*self.cached_tail.get() = tail;
if head == tail {
return None; }
}
let index = head & self.mask;
let value = (*self.buffer[index].get()).assume_init_read();
self.head.store(head.wrapping_add(1), Release);
Some(value)
}
}
pub fn try_push(&self, value: T) -> Result<(), T> {
self.push(value)
}
pub fn try_pop(&self) -> Option<T> {
self.pop()
}
pub fn len(&self) -> usize {
let tail = self.tail.load(Acquire);
let head = self.head.load(Acquire);
tail.wrapping_sub(head)
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn is_empty(&self) -> bool {
self.head.load(Acquire) == self.tail.load(Acquire)
}
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) {
while self.pop().is_some() {}
}
}