1use crate::error::Error;
5pub use broadcast::*;
6pub use broadcast_center::*;
7use std::{fmt::Debug, marker::PhantomData};
8
9#[macro_use]
10pub mod macros;
11
12pub mod broadcast;
13pub mod broadcast_center;
14pub mod error;
15
16#[cfg(test)]
17pub mod end_to_end_test;
18
19pub trait TelephoneOperation {
22 type Parameters: Debug + Clone + Send + 'static;
23 type ReturnValue: Debug + Send + 'static;
24}
25
26pub trait MakeCallOn<Call: CallCenter>: TelephoneOperation {
29 const NAME: &'static str;
30 fn make_call(request: Self::Parameters) -> (Call::CallEnum, mpsc::Receiver<Self::ReturnValue>);
31}
32
33pub trait CallCenter: Clone + Debug {
35 type CallEnum: Send + Sync + Debug + Clone + 'static;
36}
37
38pub struct TelephoneCenter<Call: CallCenter> {
40 cl: PhantomData<Call>,
41
42 tx: mpsc::Sender<Call::CallEnum>,
43 rx: mpsc::Receiver<Call::CallEnum>,
44}
45
46impl<Call: CallCenter> TelephoneCenter<Call> {
47 pub fn new() -> TelephoneCenter<Call> {
48 let (tx, rx) = mpsc::channel(100);
49
50 Self {
51 cl: Default::default(),
52 tx,
53 rx,
54 }
55 }
56
57 pub fn make_phone(&self) -> Phone<Call> {
58 Phone {
59 tx: self.tx.clone(),
60 }
61 }
62
63 pub async fn handle_request(&mut self) -> Result<Call::CallEnum, Error> {
64 self.rx.recv().await.ok_or(Error::PhoneClosed)
65 }
66}
67
68impl<Call: CallCenter> Default for TelephoneCenter<Call> {
69 fn default() -> Self {
70 Self::new()
71 }
72}
73
74#[derive(Clone, Debug)]
76pub struct Phone<Call: CallCenter> {
77 tx: mpsc::Sender<Call::CallEnum>,
78}
79
80impl<Call: CallCenter> Phone<Call> {
81 pub(crate) fn is_alive(&self) -> bool {
82 !self.tx.is_closed()
83 }
84
85 pub async fn call<Operation>(
87 &self,
88 parameters: Operation::Parameters,
89 ) -> Result<Operation::ReturnValue, Error>
90 where
91 Operation: TelephoneOperation + MakeCallOn<Call>,
92 {
93 #[cfg(feature = "tracing")]
94 tracing::trace!(
95 "calling::{}({:?})",
96 <Operation as MakeCallOn<Call>>::NAME,
97 ¶meters
98 );
99
100 let (req, mut recv) = Operation::make_call(parameters);
101 self.tx.send(req).await.map_err(|_| Error::PhoneClosed)?;
102
103 let resp = recv.recv().await.ok_or(Error::PhoneClosed)?;
104
105 #[cfg(feature = "tracing")]
106 tracing::trace!("response on ::{}({:?})", Operation::NAME, &resp);
107 Ok(resp)
108 }
109
110 pub async fn call_no_response<Operation>(
112 &self,
113 parameters: Operation::Parameters,
114 ) -> Result<(), Error>
115 where
116 Operation: TelephoneOperation + MakeCallOn<Call>,
117 {
118 #[cfg(feature = "tracing")]
119 tracing::trace!(
120 "calling::{}({:?})",
121 <Operation as MakeCallOn<Call>>::NAME,
122 ¶meters
123 );
124
125 let (req, _) = Operation::make_call(parameters);
126 self.tx.send(req).await.map_err(|_| Error::PhoneClosed)?;
127
128 Ok(())
129 }
130}
131
132pub use tokio::sync::mpsc;