use std::{
future::Future,
pin::Pin,
sync::{Arc, Mutex},
task::{Context, Poll, Waker},
};
pub struct Sender<T>(Arc<Mutex<OneshotInner<T>>>);
pub struct Receiver<T>(Arc<Mutex<OneshotInner<T>>>);
struct OneshotInner<T> {
value: Option<T>,
waker: Option<Waker>,
}
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
let arc = Arc::new(Mutex::new(OneshotInner {
value: None,
waker: None,
}));
(Sender(arc.clone()), Receiver(arc))
}
impl<T> Sender<T> {
pub fn send(self, value: T) {
let waker = {
let mut inner = self.0.lock().unwrap();
inner.value = Some(value);
inner.waker.take()
};
if let Some(waker) = waker {
waker.wake();
}
}
pub fn into_raw(self) -> *const () {
Arc::into_raw(self.0) as *const ()
}
pub unsafe fn from_raw(raw_ptr: *const ()) -> Self {
Self(Arc::from_raw(raw_ptr as *const Mutex<OneshotInner<T>>))
}
}
impl<T> Future for Receiver<T> {
type Output = T;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut inner = self.0.lock().unwrap();
match inner.value.take() {
Some(v) => Poll::Ready(v),
None => {
inner.waker = Some(cx.waker().clone());
Poll::Pending
}
}
}
}