use std::cell::UnsafeCell;
use std::fmt;
use std::future::Future;
use std::mem::MaybeUninit;
use std::pin::Pin;
use std::ptr::{self, NonNull};
use std::sync::atomic::{AtomicU8, Ordering};
use std::sync::Mutex;
use std::task::{self, Poll};
pub fn new_oneshot<T>() -> (Sender<T>, Receiver<T>) {
let shared = NonNull::from(Box::leak(Box::new(Shared::new())));
(Sender { shared }, Receiver { shared })
}
const RECEIVER_ALIVE: u8 = 0b1000_0000;
const SENDER_ALIVE: u8 = 0b0100_0000;
const SENDER_ACCESS: u8 = 0b0010_0000;
#[inline(always)]
const fn has_receiver(status: u8) -> bool {
status & RECEIVER_ALIVE != 0
}
#[inline(always)]
const fn has_sender(status: u8) -> bool {
status & SENDER_ALIVE != 0
}
#[inline(always)]
const fn has_sender_access(status: u8) -> bool {
status & SENDER_ACCESS != 0
}
const EMPTY: u8 = 0b0000_0000;
const FILLED: u8 = 0b0000_0001;
const MARK_FILLED: u8 = 0b0000_0001; const MARK_EMPTY: u8 = !MARK_FILLED; const INITIAL: u8 = RECEIVER_ALIVE | SENDER_ALIVE | SENDER_ACCESS | EMPTY;
#[inline(always)]
const fn is_empty(status: u8) -> bool {
status & FILLED == 0
}
#[inline(always)]
const fn is_filled(status: u8) -> bool {
status & FILLED != 0
}
pub struct Sender<T> {
shared: NonNull<Shared<T>>,
}
impl<T> Sender<T> {
pub fn try_send(self, value: T) -> Result<(), T> {
if !self.is_connected() {
return Err(value);
}
let shared = self.shared();
unsafe { ptr::write(shared.message.get(), MaybeUninit::new(value)) };
let old_status = shared.status.fetch_add(MARK_FILLED, Ordering::AcqRel);
debug_assert!(is_empty(old_status));
Ok(())
}
pub fn is_connected(&self) -> bool {
let status = self.shared().status.load(Ordering::Relaxed);
has_receiver(status)
}
pub fn sends_to(&self, receiver: &Receiver<T>) -> bool {
self.shared == receiver.shared
}
fn shared(&self) -> &Shared<T> {
unsafe { self.shared.as_ref() }
}
}
impl<T> fmt::Debug for Sender<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Sender")
}
}
unsafe impl<T: Send> Send for Sender<T> {}
unsafe impl<T> Sync for Sender<T> {}
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
let shared = self.shared();
let old_status = shared.status.fetch_and(!SENDER_ALIVE, Ordering::AcqRel);
if has_receiver(old_status) {
if let Some(waker) = shared.receiver_waker.lock().unwrap().take() {
waker.wake();
}
}
let old_status = shared.status.fetch_and(!SENDER_ACCESS, Ordering::AcqRel);
if !has_receiver(old_status) {
unsafe { drop(Box::from_raw(self.shared.as_ptr())) }
}
}
}
pub struct Receiver<T> {
shared: NonNull<Shared<T>>,
}
#[derive(Debug, Eq, PartialEq)]
pub enum RecvError {
NoValue,
Disconnected,
}
impl fmt::Display for RecvError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RecvError::NoValue => f.write_str("no value available"),
RecvError::Disconnected => f.write_str("sender disconnected"),
}
}
}
impl<T> Receiver<T> {
pub fn try_recv(&mut self) -> Result<T, RecvError> {
let shared = self.shared();
let status = shared.status.fetch_and(MARK_EMPTY, Ordering::AcqRel);
if is_empty(status) {
if has_sender(status) {
Err(RecvError::NoValue)
} else {
Err(RecvError::Disconnected)
}
} else {
let msg = unsafe { (&*shared.message.get()).assume_init_read() };
Ok(msg)
}
}
pub fn recv(&mut self) -> RecvValue<T> {
RecvValue { receiver: self }
}
pub fn recv_once(self) -> RecvOnce<T> {
RecvOnce { receiver: self }
}
pub fn try_reset(&mut self) -> Option<Sender<T>> {
let shared = self.shared();
let status = shared.status.load(Ordering::Acquire);
if has_sender_access(status) {
return None;
} else if is_filled(status) {
unsafe { (&mut *shared.message.get()).assume_init_drop() }
}
shared.status.store(INITIAL, Ordering::Release);
Some(Sender {
shared: self.shared,
})
}
pub fn is_connected(&self) -> bool {
let status = self.shared().status.load(Ordering::Relaxed);
has_sender(status)
}
pub fn register_waker(&mut self, waker: &task::Waker) -> bool {
let shared = self.shared();
let mut receiver_waker = shared.receiver_waker.lock().unwrap();
if let Some(receiver_waker) = &*receiver_waker {
if receiver_waker.will_wake(waker) {
return false;
}
}
*receiver_waker = Some(waker.clone());
drop(receiver_waker);
true
}
fn shared(&self) -> &Shared<T> {
unsafe { self.shared.as_ref() }
}
}
impl<T> fmt::Debug for Receiver<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Receiver")
}
}
unsafe impl<T: Send> Send for Receiver<T> {}
unsafe impl<T: Send> Sync for Receiver<T> {}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
let shared = self.shared();
let old_status = shared.status.fetch_and(!RECEIVER_ALIVE, Ordering::AcqRel);
if !has_sender_access(old_status) {
unsafe { drop(Box::from_raw(self.shared.as_ptr())) }
}
}
}
#[derive(Debug)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct RecvValue<'r, T> {
receiver: &'r mut Receiver<T>,
}
macro_rules! recv_future_impl {
($self: ident, $ctx: ident) => {
match $self.receiver.try_recv() {
Ok(ok) => Poll::Ready(Some(ok)),
Err(RecvError::NoValue) => {
if !$self.receiver.register_waker($ctx.waker()) {
return Poll::Pending;
}
match $self.receiver.try_recv() {
Ok(ok) => Poll::Ready(Some(ok)),
Err(RecvError::NoValue) => Poll::Pending,
Err(RecvError::Disconnected) => Poll::Ready(None),
}
}
Err(RecvError::Disconnected) => Poll::Ready(None),
}
};
}
impl<'r, T> Future for RecvValue<'r, T> {
type Output = Option<T>;
fn poll(mut self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll<Self::Output> {
recv_future_impl!(self, ctx)
}
}
impl<'r, T> Unpin for RecvValue<'r, T> {}
#[derive(Debug)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct RecvOnce<T> {
receiver: Receiver<T>,
}
impl<T> Future for RecvOnce<T> {
type Output = Option<T>;
fn poll(mut self: Pin<&mut Self>, ctx: &mut task::Context) -> Poll<Self::Output> {
recv_future_impl!(self, ctx)
}
}
impl<T> Unpin for RecvOnce<T> {}
struct Shared<T> {
status: AtomicU8,
message: UnsafeCell<MaybeUninit<T>>,
receiver_waker: Mutex<Option<task::Waker>>,
}
impl<T> Shared<T> {
const fn new() -> Shared<T> {
Shared {
status: AtomicU8::new(INITIAL),
message: UnsafeCell::new(MaybeUninit::uninit()),
receiver_waker: Mutex::new(None),
}
}
}
impl<T> Drop for Shared<T> {
fn drop(&mut self) {
let status = self.status.load(Ordering::Relaxed);
if is_filled(status) {
unsafe { ptr::drop_in_place((&mut *self.message.get()).as_mut_ptr()) }
}
}
}