use std::sync::{Arc, Condvar, Mutex};
use super::error::{report_fault, RuntimeError};
use super::sync_lock;
struct Inner<T> {
slot: Mutex<Option<T>>,
cvar: Condvar,
}
pub struct Sender<T> {
inner: Arc<Inner<T>>,
}
pub struct Receiver<T> {
inner: Arc<Inner<T>>,
}
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
let inner = Arc::new(Inner {
slot: Mutex::new(None),
cvar: Condvar::new(),
});
(
Sender {
inner: inner.clone(),
},
Receiver { inner },
)
}
impl<T> Sender<T> {
pub fn send(self, value: T) {
match sync_lock::lock(&self.inner.slot, "oneshot::send") {
Ok(mut slot) => {
*slot = Some(value);
self.inner.cvar.notify_one();
}
Err(e) => report_fault(e),
}
}
}
impl<T> Receiver<T> {
pub fn join(self) -> Result<T, RuntimeError> {
let mut slot = sync_lock::lock(&self.inner.slot, "oneshot::join")?;
loop {
if let Some(v) = slot.take() {
return Ok(v);
}
slot = sync_lock::wait(&self.inner.cvar, slot, "oneshot::wait")?;
}
}
}