pub enum PromiseState<T> {
Pending,
Ready(T),
Disconnected,
}
pub struct Promise<T> {
rx: oneshot::Receiver<T>,
}
unsafe impl<T> Sync for Promise<T> {}
impl<T> Promise<T> {
pub fn new() -> (Fulfiller<T>, Promise<T>) {
let (tx, rx) = oneshot::channel();
(Fulfiller { tx }, Promise { rx })
}
pub fn poll(&self) -> PromiseState<T> {
match self.rx.try_recv() {
Ok(value) => PromiseState::Ready(value),
Err(oneshot::TryRecvError::Empty) => PromiseState::Pending,
Err(oneshot::TryRecvError::Disconnected) => PromiseState::Disconnected,
}
}
}
pub struct Fulfiller<T> {
tx: oneshot::Sender<T>,
}
impl<T> Fulfiller<T> {
pub fn fulfill(self, value: T) {
let _ = self.tx.send(value);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn poll_is_pending_before_a_fulfill_and_ready_after() {
let (fulfiller, promise) = Promise::new();
assert!(matches!(promise.poll(), PromiseState::Pending));
fulfiller.fulfill(42);
assert!(matches!(promise.poll(), PromiseState::Ready(42)));
}
#[test]
fn poll_is_disconnected_once_the_fulfiller_is_dropped_without_fulfilling() {
let (fulfiller, promise) = Promise::<i32>::new();
drop(fulfiller);
assert!(matches!(promise.poll(), PromiseState::Disconnected));
}
}