use crate::error::Error;
pub use broadcast::*;
pub use broadcast_center::*;
use std::{fmt::Debug, marker::PhantomData};
#[macro_use]
pub mod macros;
pub mod broadcast;
pub mod broadcast_center;
pub mod error;
#[cfg(test)]
pub mod end_to_end_test;
pub trait TelephoneOperation {
type Parameters: Debug + Clone + Send + 'static;
type ReturnValue: Debug + Send + 'static;
}
pub trait MakeCallOn<Call: CallCenter>: TelephoneOperation {
const NAME: &'static str;
fn make_call(request: Self::Parameters) -> (Call::CallEnum, mpsc::Receiver<Self::ReturnValue>);
}
pub trait CallCenter: Clone + Debug {
type CallEnum: Send + Sync + Debug + Clone + 'static;
}
pub struct TelephoneCenter<Call: CallCenter> {
cl: PhantomData<Call>,
tx: mpsc::Sender<Call::CallEnum>,
rx: mpsc::Receiver<Call::CallEnum>,
}
impl<Call: CallCenter> TelephoneCenter<Call> {
pub fn new() -> TelephoneCenter<Call> {
let (tx, rx) = mpsc::channel(100);
Self {
cl: Default::default(),
tx,
rx,
}
}
pub fn make_phone(&self) -> Phone<Call> {
Phone {
tx: self.tx.clone(),
}
}
pub async fn handle_request(&mut self) -> Result<Call::CallEnum, Error> {
self.rx.recv().await.ok_or(Error::PhoneClosed)
}
}
impl<Call: CallCenter> Default for TelephoneCenter<Call> {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct Phone<Call: CallCenter> {
tx: mpsc::Sender<Call::CallEnum>,
}
impl<Call: CallCenter> Phone<Call> {
pub(crate) fn is_alive(&self) -> bool {
!self.tx.is_closed()
}
pub async fn call<Operation>(
&self,
parameters: Operation::Parameters,
) -> Result<Operation::ReturnValue, Error>
where
Operation: TelephoneOperation + MakeCallOn<Call>,
{
#[cfg(feature = "tracing")]
tracing::trace!(
"calling::{}({:?})",
<Operation as MakeCallOn<Call>>::NAME,
¶meters
);
let (req, mut recv) = Operation::make_call(parameters);
self.tx.send(req).await.map_err(|_| Error::PhoneClosed)?;
let resp = recv.recv().await.ok_or(Error::PhoneClosed)?;
#[cfg(feature = "tracing")]
tracing::trace!("response on ::{}({:?})", Operation::NAME, &resp);
Ok(resp)
}
pub async fn call_no_response<Operation>(
&self,
parameters: Operation::Parameters,
) -> Result<(), Error>
where
Operation: TelephoneOperation + MakeCallOn<Call>,
{
#[cfg(feature = "tracing")]
tracing::trace!(
"calling::{}({:?})",
<Operation as MakeCallOn<Call>>::NAME,
¶meters
);
let (req, _) = Operation::make_call(parameters);
self.tx.send(req).await.map_err(|_| Error::PhoneClosed)?;
Ok(())
}
}
pub use tokio::sync::mpsc;