use std::cell::UnsafeCell;
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::atomic::{AtomicU32, Ordering};
pub(crate) struct Bucket<T> {
lap: AtomicU32,
msg: UnsafeCell<MaybeUninit<T>>,
}
impl<T> Default for Bucket<T> {
fn default() -> Self {
Self {
lap: AtomicU32::new(0),
msg: UnsafeCell::new(MaybeUninit::uninit()),
}
}
}
impl<T> Bucket<T> {
#[inline]
pub(crate) fn get_lap(&self) -> u32 {
self.lap.load(Ordering::Acquire)
}
}
pub(crate) struct Selector<T> {
ptr: *const Bucket<T>,
lap: u32,
}
impl<T> Default for Selector<T> {
fn default() -> Self {
Self {
ptr: ptr::null(),
lap: 0,
}
}
}
impl<T> Selector<T> {
#[inline]
pub(crate) fn set(&mut self, bucket: *const Bucket<T>, lap: u32) {
self.ptr = bucket;
self.lap = lap;
}
#[inline]
pub(crate) fn write_message(&self, msg: T) {
unsafe {
let bucket = &*(self.ptr);
bucket.msg.get().write(MaybeUninit::new(msg));
bucket.lap.store(self.lap + 1, Ordering::Release);
}
}
#[inline]
pub(crate) fn read_message(&self) -> T {
unsafe {
let bucket = &*(self.ptr);
let msg = bucket.msg.get().read().assume_init();
bucket.lap.store(self.lap + 1, Ordering::Release);
msg
}
}
#[inline]
pub(crate) fn is_ready(&self) -> bool {
unsafe {
let bucket = &*(self.ptr);
if bucket.lap.load(Ordering::Acquire) != self.lap {
return true;
}
false
}
}
}