notify/examples/oneshot.rs
2022-03-05 16:57:44 -06:00

124 lines
2.5 KiB
Rust

use notify::{Listener, Notify};
use std::{
sync::{Arc, Mutex},
time::Duration,
};
struct Sender<T> {
item: Arc<Mutex<Option<Result<T, Dropped>>>>,
notify: Notify,
}
struct Receiver<T> {
item: Arc<Mutex<Option<Result<T, Dropped>>>>,
listener: Listener,
}
struct Dropped;
fn main() -> Result<(), Box<dyn std::error::Error>> {
jive::block_on(async move {
let (tx, rx) = oneshot();
jive::spawn(async move {
jive::time::sleep(Duration::from_secs(1)).await;
let _ = tx.send(5);
});
if let Ok(val) = rx.recv().await {
println!("Got {}", val);
}
});
let (tx, rx) = oneshot();
std::thread::spawn(move || {
std::thread::sleep(Duration::from_secs(1));
let _ = tx.send(-5);
});
if let Ok(val) = rx.recv_blocking() {
println!("Got {}", val);
}
Ok(())
}
fn oneshot<T>() -> (Sender<T>, Receiver<T>) {
let item = Arc::new(Mutex::new(None));
let notify = Notify::new();
let listener = notify.listener();
(
Sender {
item: Arc::clone(&item),
notify,
},
Receiver { item, listener },
)
}
impl<T> Sender<T> {
pub fn send(self, item: T) -> Result<(), T> {
let mut guard = self.item.lock().unwrap();
if let Some(Err(Dropped)) = guard.take() {
return Err(item);
}
*guard = Some(Ok(item));
self.notify.notify_one();
Ok(())
}
}
impl<T> Receiver<T> {
pub fn try_recv(&self) -> Option<Result<T, Dropped>> {
let mut guard = self.item.lock().unwrap();
if guard.is_some() {
return guard.replace(Err(Dropped));
}
None
}
pub async fn recv(mut self) -> Result<T, Dropped> {
loop {
if let Some(res) = self.try_recv() {
return res;
}
self.listener.listen().await;
}
}
pub fn recv_blocking(self) -> Result<T, Dropped> {
loop {
if let Some(res) = self.try_recv() {
return res;
}
self.listener.listen_blocking();
}
}
}
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
let mut guard = self.item.lock().unwrap();
if guard.is_none() {
*guard = Some(Err(Dropped));
}
}
}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
let mut guard = self.item.lock().unwrap();
if guard.is_none() {
*guard = Some(Err(Dropped));
}
}
}