#![no_std]
use core::mem::MaybeUninit;
use core::sync::atomic::{AtomicUsize, Ordering};
use core::{ptr, slice};
use util::*;
pub struct Ring<T, const N: usize> {
buf: MaybeUninit<[T; N]>,
start: AtomicUsize,
end: AtomicUsize,
pub ops: [AtomicMemoryRing; N],
}
impl<T, const N: usize> Default for Ring<T, N> {
fn default() -> Self {
Self::new()
}
}
impl<T, const N: usize> Ring<T, N> {
const CAPACITY: usize = N;
const WRAP_MAX: usize = MemoryRing::max_idx(Self::CAPACITY);
#[allow(clippy::declare_interior_mutable_const)]
const INIT_STATE: AtomicMemoryRing = AtomicMemoryRing::new(MemoryRing::INIT);
pub const fn new() -> Self {
Ring {
buf: MaybeUninit::uninit(),
start: AtomicUsize::new(0),
end: AtomicUsize::new(0),
ops: [Self::INIT_STATE; N],
}
}
fn ptr(&self) -> *mut T {
self.buf.as_ptr() as *mut T
}
pub const fn capacity(&self) -> usize {
Self::CAPACITY
}
fn wrap_len(&self, start: usize, end: usize) -> usize {
if end >= start {
end - start
} else {
Self::WRAP_MAX - start + end
}
}
pub fn len(&self) -> usize {
let start = self.start.load(Ordering::Relaxed);
let end = self.end.load(Ordering::Relaxed);
self.wrap_len(start, end)
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn is_full(&self) -> bool {
self.len() >= Self::CAPACITY
}
#[inline]
unsafe fn buffer_read(&self, off: usize) -> T {
ptr::read(self.ptr().add(off))
}
#[inline]
unsafe fn buffer_write(&self, off: usize, value: T) {
ptr::write(self.ptr().add(off), value);
}
#[inline]
fn index(&self, idx: usize) -> usize {
idx % Self::CAPACITY
}
#[inline]
fn next_idx(&self, old: usize) -> usize {
if old == Self::WRAP_MAX - 1 {
0
} else {
old + 1
}
}
fn add_ptr_end(&self, old: usize) -> Result<usize, usize> {
let new = self.next_idx(old);
self.end
.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed)
}
fn add_ptr_start(&self, old: usize) -> Result<usize, usize> {
let new = self.next_idx(old);
self.start
.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed)
}
pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
let ptr = self.ptr();
let start = self.start.load(Ordering::Relaxed);
let end = self.end.load(Ordering::Relaxed);
if start == end {
return (&mut [], &mut []);
}
let start = self.index(start);
let end = self.index(end);
if end > start {
(
unsafe { slice::from_raw_parts_mut(ptr.add(start), end - start) },
&mut [],
)
} else {
(
unsafe { slice::from_raw_parts_mut(ptr.add(start), N - start) },
unsafe { slice::from_raw_parts_mut(ptr, end) },
)
}
}
pub fn clear(&mut self) {
let (a, b) = self.as_mut_slices();
unsafe { ptr::drop_in_place(a) };
unsafe { ptr::drop_in_place(b) };
self.end.store(0, Ordering::Relaxed);
self.start.store(0, Ordering::Relaxed);
self.ops = [Self::INIT_STATE; N];
}
pub fn pop(&self) -> Result<T, Error<()>> {
#[cfg(target_os = "none")]
let _cs = interrupt::CriticalSection::new();
let mut start = self.start.load(Ordering::Relaxed);
loop {
let cycle = MemoryRing::cycle_of_idx(start, Self::CAPACITY);
let index = self.index(start);
let expect = MemoryRing::new(cycle, MemoryState::Initialized);
let op = self.ops[index].load(Ordering::Acquire);
let state = op.state();
if op >= expect {
if let Err(i) = self.add_ptr_start(start) {
start = i;
continue;
} else {
let ret = unsafe { self.buffer_read(index) };
let op = MemoryRing::new(cycle + 1, MemoryState::Uninitialized);
self.ops[index].store(op, Ordering::Release);
return Ok(ret);
}
} else {
return Err(Error {
state,
input: (),
retry: false,
});
}
}
}
pub fn push(&self, value: T) -> Result<(), Error<T>> {
#[cfg(target_os = "none")]
let _cs = interrupt::CriticalSection::new();
let mut end = self.end.load(Ordering::Relaxed);
loop {
let cycle = MemoryRing::cycle_of_idx(end, Self::CAPACITY);
let index = self.index(end);
let expect = MemoryRing::new(cycle, MemoryState::Uninitialized);
let op = self.ops[index].load(Ordering::Acquire);
let state = op.state();
if op >= expect {
if let Err(i) = self.add_ptr_end(end) {
end = i;
continue;
} else {
unsafe { self.buffer_write(index, value) };
let op = MemoryRing::new(cycle, MemoryState::Initialized);
self.ops[index].store(op, Ordering::Release);
return Ok(());
}
} else {
return Err(Error {
state,
input: value,
retry: false,
});
}
}
}
}
impl<T, const N: usize> Drop for Ring<T, N> {
fn drop(&mut self) {
self.clear()
}
}