use std::cell::Cell; use std::future::Future; use std::marker::PhantomData; use std::pin::Pin; use std::ptr; use std::task::{Context, Poll}; #[derive(Debug)] pub struct Sender { _p: PhantomData, } #[derive(Debug)] pub struct Receiver { _p: PhantomData, } pub(crate) struct Enter<'a, T> { _rx: &'a mut Receiver, prev: *mut (), } pub fn pair() -> (Sender, Receiver) { let tx = Sender { _p: PhantomData }; let rx = Receiver { _p: PhantomData }; (tx, rx) } // Tracks the pointer to `Option`. // // TODO: Ensure wakers match? thread_local!(static STORE: Cell<*mut ()> = Cell::new(ptr::null_mut())); // ===== impl Sender ===== impl Sender { pub fn send(&mut self, value: T) -> impl Future { Send { value: Some(value) } } } struct Send { value: Option, } impl Future for Send { type Output = (); fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> { if self.value.is_none() { return Poll::Ready(()); } STORE.with(|cell| unsafe { let ptr = cell.get() as *mut Option; let option_ref = ptr.as_mut().expect("invalid usage"); if option_ref.is_none() { *option_ref = self.value.take(); } Poll::Pending }) } } // ===== impl Receiver ===== impl Receiver { pub(crate) fn enter<'a>(&'a mut self, dst: &'a mut Option) -> Enter<'a, T> { let prev = STORE.with(|cell| { let prev = cell.get(); cell.set(dst as *mut _ as *mut ()); prev }); Enter { _rx: self, prev } } } // ===== impl Enter ===== impl<'a, T> Drop for Enter<'a, T> { fn drop(&mut self) { STORE.with(|cell| cell.set(self.prev)); } }