use core::{cell::Cell, ops::RangeBounds, sync::atomic::Ordering};
use super::AtomicBool;
use crate::{buffer::Buffer, sink::Sink};
#[macro_export]
macro_rules! static_buffer {
($vis:vis static $name:ident::<$ty:ty, $lit:literal>) => {
$vis static $name: $crate::StaticBuffer<$ty, $lit> = $crate::StaticBuffer::new();
};
}
pub struct StaticBuffer<T, const N: usize> {
buf: Buffer<T, N>,
writer: AtomicBool,
}
impl<T: Copy, const N: usize> StaticBuffer<T, N> {
#[allow(clippy::new_without_default)]
#[cfg_attr(feature = "loom", maybe_const::maybe_const)]
pub const fn new() -> Self {
Self {
buf: Buffer::new(),
writer: AtomicBool::new(false),
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
#[inline]
pub fn get_writer(&self) -> Option<Writer<'_, T, N>> {
if self
.writer
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Relaxed)
.is_ok()
{
Some(Writer {
buf: self,
_marker: core::marker::PhantomData,
})
} else {
None
}
}
#[must_use]
#[inline]
pub fn write(&self, value: T) -> Option<()> {
if self
.writer
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Relaxed)
.is_ok()
{
self.buf.write(value);
self.writer.store(false, Ordering::Release);
Some(())
} else {
None
}
}
#[inline]
pub fn get(&self, n: usize) -> Option<T> {
self.buf.get(n)
}
#[inline]
pub fn get_latest(&self) -> Option<T> {
self.get(0)
}
#[inline]
#[must_use]
pub fn get_range<R, S>(&self, range: R, buf: &mut S) -> Option<()>
where
S: Sink<Item = T> + ?Sized,
R: RangeBounds<usize>,
{
self.buf.get_range(range, buf)
}
#[inline]
pub fn read(&self, n: usize) -> Option<T> {
self.buf.read(n)
}
#[inline]
pub fn read_latest(&self) -> T {
self.read(0).unwrap()
}
#[must_use]
#[inline]
pub fn read_range<R, S>(&self, range: R, buf: &mut S) -> Option<()>
where
S: Sink<Item = T> + ?Sized,
R: RangeBounds<usize>,
{
self.buf.read_range(range, buf)
}
}
pub struct Writer<'a, T: 'a, const N: usize> {
buf: &'a StaticBuffer<T, N>,
_marker: core::marker::PhantomData<Cell<()>>,
}
impl<'a, T: Copy + 'a, const N: usize> Writer<'a, T, N> {
#[inline]
pub fn write(&self, value: T) {
self.buf.buf.write(value);
}
}
impl<'a, T: 'a, const N: usize> Drop for Writer<'a, T, N> {
#[inline]
fn drop(&mut self) {
self.buf.writer.store(false, Ordering::Release);
}
}