diff --git a/cove-tui/src/main.rs b/cove-tui/src/main.rs index b3d6126..d379da1 100644 --- a/cove-tui/src/main.rs +++ b/cove-tui/src/main.rs @@ -1,3 +1,5 @@ +mod replies; + use std::io::{self, Stdout}; use std::time::Duration; diff --git a/cove-tui/src/replies.rs b/cove-tui/src/replies.rs new file mode 100644 index 0000000..564922c --- /dev/null +++ b/cove-tui/src/replies.rs @@ -0,0 +1,60 @@ +use std::collections::HashMap; +use std::hash::Hash; +use std::result; +use std::time::Duration; + +use tokio::sync::oneshot::{self, Receiver, Sender}; +use tokio::time; + +pub enum Error { + TimedOut, + Canceled, +} + +pub type Result = result::Result; + +pub struct PendingReply { + timeout: Duration, + result: Receiver, +} + +impl PendingReply { + pub async fn get(self) -> Result { + let result = time::timeout(self.timeout, self.result).await; + match result { + Err(_) => Err(Error::TimedOut), + Ok(Err(_)) => Err(Error::Canceled), + Ok(Ok(value)) => Ok(value), + } + } +} + +pub struct Replies { + timeout: Duration, + pending: HashMap>, +} + +impl Replies { + pub async fn wait_for(&mut self, id: I) -> PendingReply { + let (tx, rx) = oneshot::channel(); + self.pending.insert(id, tx); + PendingReply { + timeout: self.timeout, + result: rx, + } + } + + pub fn complete(&mut self, id: &I, result: R) { + if let Some(tx) = self.pending.remove(id) { + let _ = tx.send(result); + } + } + + pub fn cancel(&mut self, id: &I) { + self.pending.remove(id); + } + + pub fn purge(&mut self) { + self.pending.retain(|_, tx| !tx.is_closed()); + } +}