use std::cell::UnsafeCell;
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::atomic::{AtomicU32, Ordering};
#[macro_export]
macro_rules! block {
($is_closed:expr, $waker:expr, $selector:expr) => {
let waiter = Waiter::new();
let out_condition = || {
if unlikely($is_closed.load(Ordering::Relaxed)) {
return true;
}
unsafe {
let bucket = &*($selector.ptr as *const Bucket<T>);
if bucket.lap.load(Ordering::Acquire) != $selector.lap {
return true;
}
false
}
};
if $waker.register(&waiter, out_condition) {
waiter.sleep(out_condition);
$waker.unregister(&waiter);
}
};
}
pub(crate) const N_SPIN: u8 = 128;
pub(crate) enum Operation {
Sending,
Receiving,
}
pub(crate) struct Bucket<T> {
pub(crate) lap: AtomicU32,
pub(crate) msg: UnsafeCell<MaybeUninit<T>>,
}
impl<T> Default for Bucket<T> {
fn default() -> Self {
Self {
lap: AtomicU32::new(0),
msg: UnsafeCell::new(MaybeUninit::uninit()),
}
}
}
pub(crate) struct Selector {
pub(crate) ptr: *const u8,
pub(crate) lap: u32,
}
impl Default for Selector {
fn default() -> Self {
Self {
ptr: ptr::null(),
lap: 0,
}
}
}
impl Selector {
#[inline]
pub(crate) fn write_message<T>(&self, msg: T) {
unsafe {
let bucket = &*(self.ptr as *const Bucket<T>);
bucket.msg.get().write(MaybeUninit::new(msg));
bucket.lap.store(self.lap + 1, Ordering::Release);
}
}
#[inline]
pub(crate) fn read_message<T>(&self) -> T {
unsafe {
let bucket = &*(self.ptr as *const Bucket<T>);
let msg = bucket.msg.get().read().assume_init();
bucket.lap.store(self.lap + 1, Ordering::Release);
msg
}
}
}