1use ek_event::Event;
13use std::any::Any;
14use std::fmt;
15use std::sync::atomic::{AtomicBool, Ordering};
16use std::sync::mpsc::{RecvTimeoutError, Sender as StdSender};
17use std::sync::Arc;
18use std::time::Duration;
19
20pub fn e_req_type(target: &str) -> String {
22 format!("eReq.{target}")
23}
24
25pub fn e_to_type(target: &str) -> String {
27 format!("eTo.{target}")
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum ReplyErr {
33 InvalidPayload,
35}
36
37impl fmt::Display for ReplyErr {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 match self {
40 Self::InvalidPayload => write!(f, "invalid payload"),
41 }
42 }
43}
44
45pub struct Envelope {
47 pub payload: Arc<dyn Any + Send + Sync>,
49 pub reply: OneshotSender<Box<dyn Any + Send + Sync>>,
52}
53
54impl Envelope {
55 pub fn new(payload: Arc<dyn Any + Send + Sync>) -> (Envelope, OneshotReceiver<Box<dyn Any + Send + Sync>>) {
57 let (tx, rx) = oneshot();
58 (Envelope { payload, reply: tx }, rx)
59 }
60
61 pub fn handle<Req, Res>(event: &Event, handler: impl FnOnce(&Req) -> Res)
67 where
68 Req: Any + Send + Sync,
69 Res: Any + Send + Sync,
70 {
71 let Some(env) = event.data.downcast_ref::<Envelope>() else {
72 return;
73 };
74 match Arc::clone(&env.payload).downcast::<Req>() {
75 Ok(req) => {
76 let res = handler(&*req);
77 let _ = env.reply.send(Box::new(Ok::<Res, ReplyErr>(res)));
78 }
79 Err(_) => {
80 let _ = env.reply.send(Box::new(Err::<Res, ReplyErr>(ReplyErr::InvalidPayload)));
81 }
82 }
83 }
84}
85
86pub struct OneshotSender<T> {
91 tx: StdSender<T>,
92 sent: AtomicBool,
93}
94
95impl<T> OneshotSender<T> {
96 pub(crate) fn new_inner(tx: StdSender<T>) -> Self {
97 Self { tx, sent: AtomicBool::new(false) }
98 }
99 pub fn send(&self, v: T) -> Result<(), T> {
101 if self.sent.swap(true, Ordering::SeqCst) {
102 return Err(v);
103 }
104 self.tx.send(v).map_err(|e| e.0)
105 }
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
110pub enum OneshotErr {
111 Timeout,
113 Closed,
115}
116
117pub struct OneshotReceiver<T>(std::sync::mpsc::Receiver<T>);
119
120impl<T> OneshotReceiver<T> {
121 pub(crate) fn new_inner(rx: std::sync::mpsc::Receiver<T>) -> Self {
122 Self(rx)
123 }
124 pub fn recv(self) -> Result<T, OneshotErr> {
126 self.0.recv().map_err(|_| OneshotErr::Closed)
127 }
128 pub fn recv_timeout(self, d: Duration) -> Result<T, OneshotErr> {
130 match self.0.recv_timeout(d) {
131 Ok(v) => Ok(v),
132 Err(RecvTimeoutError::Timeout) => Err(OneshotErr::Timeout),
133 Err(RecvTimeoutError::Disconnected) => Err(OneshotErr::Closed),
134 }
135 }
136}
137
138pub fn oneshot<T>() -> (OneshotSender<T>, OneshotReceiver<T>) {
140 let (tx, rx) = std::sync::mpsc::channel();
141 (OneshotSender::new_inner(tx), OneshotReceiver::new_inner(rx))
142}