use std::cell::UnsafeCell;
use std::sync::atomic::{AtomicUsize, Ordering};
use crate::constants::{DEFAULT_DIFF_SIZE, DEFAULT_RING_SIZE, MIN_DIFF_SIZE, MIN_RING_SIZE};
pub struct RingBuffer {
buf: UnsafeCell<Vec<u8>>,
read_pos: AtomicUsize,
write_pos: AtomicUsize,
ring_size: usize,
diff_size: usize,
}
unsafe impl Send for RingBuffer {}
unsafe impl Sync for RingBuffer {}
impl RingBuffer {
pub fn new(ring_size: usize, diff_size: usize) -> Self {
let ring_size = ring_size.max(MIN_RING_SIZE);
let diff_size = diff_size.max(MIN_DIFF_SIZE);
Self {
buf: UnsafeCell::new(vec![0u8; ring_size]),
read_pos: AtomicUsize::new(0),
write_pos: AtomicUsize::new(0),
ring_size,
diff_size,
}
}
pub fn with_defaults() -> Self {
Self::new(DEFAULT_RING_SIZE, DEFAULT_DIFF_SIZE)
}
pub fn capacity(&self) -> usize {
self.ring_size
}
pub fn diff_threshold(&self) -> usize {
self.diff_size
}
pub fn has_data(&self) -> bool {
let r = self.read_pos.load(Ordering::Acquire);
let w = self.write_pos.load(Ordering::Acquire);
r != w && r.abs_diff(w) > self.diff_size
}
pub fn is_empty(&self) -> bool {
self.read_pos.load(Ordering::Acquire) == self.write_pos.load(Ordering::Acquire)
}
pub fn diff(&self) -> usize {
self.read_pos
.load(Ordering::Acquire)
.abs_diff(self.write_pos.load(Ordering::Acquire))
}
pub fn is_full(&self) -> bool {
let w = self.write_pos.load(Ordering::Relaxed);
let r = self.read_pos.load(Ordering::Acquire);
(w + 1) % self.ring_size == r
}
pub fn put(&self, item: u8) -> bool {
let w = self.write_pos.load(Ordering::Relaxed);
let r = self.read_pos.load(Ordering::Acquire);
if (w + 1) % self.ring_size == r {
return false; }
unsafe { (&mut (*self.buf.get()))[w] = item };
self.write_pos
.store((w + 1) % self.ring_size, Ordering::Release);
true
}
pub fn get(&self) -> u8 {
let r = self.read_pos.load(Ordering::Relaxed);
let item = unsafe { (&(*self.buf.get()))[r] };
self.read_pos
.store((r + 1) % self.ring_size, Ordering::Release);
item
}
pub fn reset(&self) {
self.read_pos.store(0, Ordering::Release);
self.write_pos.store(0, Ordering::Release);
}
pub fn set_ring_size(&mut self, size: usize) {
self.ring_size = size.max(MIN_RING_SIZE);
self.buf.get_mut().resize(self.ring_size, 0);
self.reset();
}
pub fn set_diff_size(&mut self, size: usize) {
self.diff_size = size.max(MIN_DIFF_SIZE);
}
pub fn reinit(&mut self, ring_size: usize, diff_size: usize) {
self.set_ring_size(ring_size);
self.set_diff_size(diff_size);
}
pub fn reinit_defaults(&mut self) {
self.reinit(DEFAULT_RING_SIZE, DEFAULT_DIFF_SIZE);
}
}