use async_event::Event;
use std::num::NonZeroUsize;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
struct Inner {
sender_notifier: Event,
receiver_notifier: Event,
value: AtomicUsize,
}
#[derive(Clone)]
struct Sender {
inner: Arc<Inner>,
}
#[derive(Clone)]
struct Receiver {
inner: Arc<Inner>,
}
fn channel() -> (Sender, Receiver) {
let inner = Arc::new(Inner {
sender_notifier: Event::new(),
receiver_notifier: Event::new(),
value: AtomicUsize::new(0),
});
(
Sender {
inner: inner.clone(),
},
Receiver { inner },
)
}
impl Sender {
async fn send(&self, value: NonZeroUsize) {
self.inner
.sender_notifier
.wait_until(|| {
self.inner
.value
.compare_exchange(0, value.get(), Ordering::Relaxed, Ordering::Relaxed)
.ok()
})
.await;
self.inner.receiver_notifier.notify(1);
}
}
impl Receiver {
async fn recv(&self) -> NonZeroUsize {
let value = self
.inner
.receiver_notifier
.wait_until(|| NonZeroUsize::new(self.inner.value.swap(0, Ordering::Relaxed)))
.await;
self.inner.sender_notifier.notify(1);
value
}
}
#[tokio::main]
async fn main() {
let (s1, r1) = channel();
let s2 = s1.clone();
let r2 = r1.clone();
let task1 = tokio::spawn(async move { r1.recv().await });
let task2 = tokio::spawn(async move { r2.recv().await });
tokio::spawn(async move {
s1.send(NonZeroUsize::new(1).unwrap()).await;
});
tokio::spawn(async move {
s2.send(NonZeroUsize::new(2).unwrap()).await;
});
println!("Task 1 received value {}", task1.await.unwrap());
println!("Task 2 received value {}", task2.await.unwrap());
}