use crate::shared::*;
use crate::trace_log;
use core::cell::UnsafeCell;
use core::mem::transmute;
use std::future::Future;
use std::pin::Pin;
use std::sync::{
atomic::{AtomicU8, Ordering},
Arc,
};
use std::task::{Context, Poll};
use std::thread;
use std::time::Instant;
const EXIST_FLAG: u8 = 0x1;
const WAKER_SET_FLAG: u8 = 0x2;
const CLOSE_FLAG: u8 = 0x4;
struct OneShot<T> {
state: AtomicU8,
value: UnsafeCell<Option<T>>,
}
unsafe impl<T: Send> Send for OneShot<T> {}
unsafe impl<T: Send> Sync for OneShot<T> {}
impl<T> OneShot<T> {
#[inline]
pub fn new() -> Self {
Self { value: UnsafeCell::new(None), state: AtomicU8::new(0) }
}
#[inline(always)]
fn value_mut(&self) -> &mut Option<T> {
unsafe { transmute(self.value.get()) }
}
#[inline(always)]
fn set_state(&self, flag: u8) -> u8 {
self.state.fetch_or(flag, Ordering::AcqRel)
}
#[inline(always)]
fn unset_state(&self, flag: u8) -> u8 {
self.state.fetch_and(!flag, Ordering::AcqRel)
}
#[inline(always)]
fn _try_recv(&self, order: Ordering) -> Result<T, u8> {
let state = self.state.load(order);
if state & EXIST_FLAG > 0 {
if let Some(item) = self._consume_value() {
Ok(item)
} else {
Err(state | CLOSE_FLAG)
}
} else {
Err(state)
}
}
#[inline(always)]
fn _consume_value(&self) -> Option<T> {
self.value_mut().take()
}
#[inline(always)]
fn send_value(&self, item: T) -> u8 {
self.value_mut().replace(item);
self.set_state(EXIST_FLAG)
}
#[inline(always)]
fn is_empty(&self) -> bool {
let state = self.state.load(Ordering::SeqCst);
state & EXIST_FLAG == 0
}
}
struct Shared<T> {
inner: OneShot<T>,
waker: UnsafeCell<Option<ThinWaker>>,
}
impl<T> Shared<T> {
#[inline]
fn get_waker(&self) -> &mut Option<ThinWaker> {
unsafe { transmute(self.waker.get()) }
}
}
unsafe impl<T: Send> Send for Shared<T> {}
unsafe impl<T: Send> Sync for Shared<T> {}
pub struct TxOneshot<T>(Option<Arc<Shared<T>>>);
impl<T> TxOneshot<T> {
#[inline]
pub fn send(mut self, item: T) {
if let Some(shared) = self.0.take() {
let state = shared.inner.send_value(item);
if state & WAKER_SET_FLAG > 0 {
if let Some(waker) = shared.get_waker().as_ref() {
trace_log!("tx: wake");
waker.wake_by_ref();
} else {
trace_log!("tx: wake flag is set but no waker");
}
} else {
trace_log!("tx: set value");
}
}
}
}
impl<T> Drop for TxOneshot<T> {
#[inline]
fn drop(&mut self) {
if let Some(shared) = self.0.take() {
let state = shared.inner.set_state(CLOSE_FLAG);
if state & WAKER_SET_FLAG > 0 {
if let Some(waker) = shared.get_waker().as_ref() {
trace_log!("drop noti");
waker.wake_by_ref();
} else {
trace_log!("drop missing waker but flag set");
}
} else {
trace_log!("drop no waker");
}
}
}
}
#[must_use]
pub struct RxOneshot<T>(Arc<Shared<T>>);
impl<T> RxOneshot<T> {
#[inline]
pub fn recv(self) -> Result<T, RecvError> {
if let Ok(item) = self._recv_blocking(None) {
return Ok(item);
}
Err(RecvError)
}
#[inline]
pub fn recv_timeout(self) -> Result<T, RecvTimeoutError> {
match self._recv_blocking(None) {
Ok(item) => Ok(item),
Err(true) => Err(RecvTimeoutError::Timeout),
Err(false) => Err(RecvTimeoutError::Disconnected),
}
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.0.inner.is_empty()
}
#[inline]
pub fn try_recv(&self) -> Result<T, TryRecvError> {
match self.0.inner._try_recv(Ordering::Acquire) {
Ok(item) => return Ok(item),
Err(state) => {
if state & CLOSE_FLAG > 0 {
return Err(TryRecvError::Disconnected);
} else {
return Err(TryRecvError::Empty);
}
}
}
}
#[inline]
pub async fn recv_async(self) -> Result<T, RecvError> {
self.await
}
#[inline(always)]
pub(crate) fn _recv_blocking(&self, deadline: Option<Instant>) -> Result<T, bool> {
let shared = &self.0;
loop {
match shared.inner._try_recv(Ordering::SeqCst) {
Ok(item) => {
trace_log!("poll value");
return Ok(item);
}
Err(mut state) => {
if state & CLOSE_FLAG > 0 {
trace_log!("poll closed");
return Err(false);
}
if state & WAKER_SET_FLAG == 0 {
shared.get_waker().replace(ThinWaker::Blocking(thread::current()));
state = shared.inner.set_state(WAKER_SET_FLAG);
if state & EXIST_FLAG > 0 {
if let Some(item) = shared.inner._consume_value() {
trace_log!("poll value");
return Ok(item);
}
trace_log!("poll value closed");
return Err(false);
}
}
if state & CLOSE_FLAG > 0 {
trace_log!("poll closed");
return Err(false);
}
match check_timeout(deadline) {
Ok(None) => {
std::thread::park();
}
Ok(Some(dur)) => {
std::thread::park_timeout(dur);
}
Err(_) => {
trace_log!("poll timeout");
return Err(true);
}
}
}
}
}
}
}
impl<T> Future for RxOneshot<T> {
type Output = Result<T, RecvError>;
#[inline]
fn poll(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> {
let mut _self = self.get_mut();
let shared = &_self.0;
match shared.inner._try_recv(Ordering::SeqCst) {
Ok(item) => {
trace_log!("poll value");
return Poll::Ready(Ok(item));
}
Err(mut state) => {
if state & WAKER_SET_FLAG > 0 {
let waker = shared.get_waker().as_ref().unwrap();
if waker.will_wake(ctx) {
trace_log!("spurious waked state {}", state);
if state & CLOSE_FLAG > 0 {
trace_log!("poll closed");
return Poll::Ready(Err(RecvError));
}
return Poll::Pending;
} else {
state = shared.inner.unset_state(WAKER_SET_FLAG);
if state & EXIST_FLAG > 0 {
if let Some(item) = shared.inner._consume_value() {
trace_log!("poll value");
return Poll::Ready(Ok(item));
} else {
trace_log!("poll value closed");
return Poll::Ready(Err(RecvError));
}
}
}
}
if state & CLOSE_FLAG == 0 {
shared.get_waker().replace(ThinWaker::Async(ctx.waker().clone()));
state = shared.inner.set_state(WAKER_SET_FLAG);
if state & EXIST_FLAG > 0 {
if let Some(item) = shared.inner._consume_value() {
trace_log!("poll value");
return Poll::Ready(Ok(item));
} else {
trace_log!("poll value closed");
return Poll::Ready(Err(RecvError));
}
}
}
if state & CLOSE_FLAG > 0 {
trace_log!("poll closed");
return Poll::Ready(Err(RecvError));
}
trace_log!("poll pending: state={}", state);
return Poll::Pending;
}
}
}
}
#[inline]
pub fn oneshot<T>() -> (TxOneshot<T>, RxOneshot<T>) {
let shared = Arc::new(Shared { inner: OneShot::new(), waker: UnsafeCell::new(None) });
let tx = TxOneshot(Some(shared.clone()));
let rx = RxOneshot(shared);
(tx, rx)
}