1use ek_event::Event;
13use std::any::Any;
14use std::fmt;
15use std::sync::Arc;
16use std::sync::atomic::{AtomicBool, Ordering};
17use std::sync::mpsc::{RecvTimeoutError, Sender as StdSender};
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(
57 payload: Arc<dyn Any + Send + Sync>,
58 ) -> (Envelope, OneshotReceiver<Box<dyn Any + Send + Sync>>) {
59 let (tx, rx) = oneshot();
60 (Envelope { payload, reply: tx }, rx)
61 }
62
63 pub fn handle<Req, Res>(event: &Event, handler: impl FnOnce(&Req) -> Res)
69 where
70 Req: Any + Send + Sync,
71 Res: Any + Send + Sync,
72 {
73 let Some(env) = event.data.downcast_ref::<Envelope>() else {
74 return;
75 };
76 match Arc::clone(&env.payload).downcast::<Req>() {
77 Ok(req) => {
78 let res = handler(&*req);
79 let _ = env.reply.send(Box::new(Ok::<Res, ReplyErr>(res)));
80 }
81 Err(_) => {
82 let _ = env
83 .reply
84 .send(Box::new(Err::<Res, ReplyErr>(ReplyErr::InvalidPayload)));
85 }
86 }
87 }
88}
89
90pub struct OneshotSender<T> {
95 tx: StdSender<T>,
96 sent: AtomicBool,
97}
98
99impl<T> OneshotSender<T> {
100 pub(crate) fn new_inner(tx: StdSender<T>) -> Self {
101 Self {
102 tx,
103 sent: AtomicBool::new(false),
104 }
105 }
106 pub fn send(&self, v: T) -> Result<(), T> {
108 if self.sent.swap(true, Ordering::SeqCst) {
109 return Err(v);
110 }
111 self.tx.send(v).map_err(|e| e.0)
112 }
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub enum OneshotErr {
118 Timeout,
120 Closed,
122}
123
124pub struct OneshotReceiver<T>(std::sync::mpsc::Receiver<T>);
126
127impl<T> OneshotReceiver<T> {
128 pub(crate) fn new_inner(rx: std::sync::mpsc::Receiver<T>) -> Self {
129 Self(rx)
130 }
131 pub fn recv(self) -> Result<T, OneshotErr> {
133 self.0.recv().map_err(|_| OneshotErr::Closed)
134 }
135 pub fn recv_timeout(self, d: Duration) -> Result<T, OneshotErr> {
137 match self.0.recv_timeout(d) {
138 Ok(v) => Ok(v),
139 Err(RecvTimeoutError::Timeout) => Err(OneshotErr::Timeout),
140 Err(RecvTimeoutError::Disconnected) => Err(OneshotErr::Closed),
141 }
142 }
143}
144
145pub fn oneshot<T>() -> (OneshotSender<T>, OneshotReceiver<T>) {
147 let (tx, rx) = std::sync::mpsc::channel();
148 (OneshotSender::new_inner(tx), OneshotReceiver::new_inner(rx))
149}