//! Commands for a service use super::*; use std::{any::Any, marker::{Send, Sync}}; use std::fmt; use tokio::sync::{ oneshot, }; id_type!(pub CommandID: "ID of a sent command"); /// A response from the service for a sent command pub type Response = Box; /// What kind of command to send to the service? #[derive(Debug, PartialEq, Eq)] pub enum CommandKind { } /// A command to send to a running service. /// /// Created when sending a `CommandKind` to a service. This is your handle for receiving the response. #[derive(Debug)] pub struct Command { id: CommandID, //kind: CommandKind, // `CommandKind` -(sent to)> -(handle returned from send func)> `Command` resp: oneshot::Receiver>, } impl fmt::Display for Command { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "CommandID<{}>", self.id.0.as_bytes().hex()) } } impl Command { /// The unique ID of this command #[inline] pub fn id(&self) -> &CommandID { &self.id } /// Prevent any response from being sent to this `Command` handle from the service. /// /// Indicates to the service we don't care about a response. This has the same effect as calling `ignore` but can be used in a builder-pattern way from a returned `Command` from a send. /// Example: `let comm = service.send_command(comm_kind).ignored();` #[inline(always)] pub fn ignored(mut self) -> Self { self.ignore(); self } /// Close the response channel, indicating to the service that we don't care about the response. #[inline] pub fn ignore(&mut self) { self.resp.close(); } /// Dispose of this `Command`, returning any `Response` that might've already been sent. #[inline] pub fn close(mut self) -> Option { use oneshot::error::TryRecvError; self.resp.close(); self.resp.try_recv().ok().flatten() } /// Poll for a response. If none has been sent yet, then return `self` so it can be polled again. #[inline] pub fn try_into_response(mut self) -> Result, Self> { use oneshot::error::TryRecvError; match self.resp.try_recv() { Ok(v) => Ok(v), Err(TryRecvError::Closed) => Ok(None), Err(TryRecvError::Empty) => Err(self), } } /// Consume this instance into the response from the service. #[inline] pub async fn into_repsonse(self) -> Option { self.resp.await.ok().flatten() } } impl PartialEq for Command { #[inline] fn eq(&self, other: &Self) -> bool { self.id == other.id } }