use std::sync::Arc;
use std::sync::Mutex;
use crate::runtime::lifecycle::ConnectedSlot;
use crate::{Broker, Connected, ConnectedBroker, PairError, PublishPolicy};
pub struct Bindable<B: Broker> {
pub(crate) broker: B,
pub(crate) slot: ConnectedSlot<B>,
}
impl<B: Broker + std::fmt::Debug> std::fmt::Debug for Bindable<B> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Bindable")
.field("broker", &self.broker)
.finish_non_exhaustive()
}
}
impl<B: Broker + 'static> Bindable<B> {
#[must_use]
pub fn new(broker: B) -> Self {
Self {
broker,
slot: Arc::new(Mutex::new(None)),
}
}
#[must_use]
pub fn broker(&self) -> &B {
&self.broker
}
#[must_use]
pub fn bind<S>(&self, source: S) -> Bound<B, S>
where
S: PublishPolicy<Connected<B>>,
{
Bound {
slot: Arc::clone(&self.slot),
source,
}
}
}
pub trait BrokerRegistration {
type Broker: Broker + 'static;
#[doc(hidden)]
fn into_parts(self) -> (Self::Broker, ConnectedSlot<Self::Broker>);
}
impl<B: Broker + 'static> BrokerRegistration for B {
type Broker = B;
fn into_parts(self) -> (B, ConnectedSlot<B>) {
(self, Arc::new(Mutex::new(None)))
}
}
impl<B: Broker + 'static> BrokerRegistration for Bindable<B> {
type Broker = B;
fn into_parts(self) -> (B, ConnectedSlot<B>) {
(self.broker, self.slot)
}
}
pub struct Bound<B2: Broker, S> {
pub(crate) slot: ConnectedSlot<B2>,
pub(crate) source: S,
}
impl<B2: Broker, S: std::fmt::Debug> std::fmt::Debug for Bound<B2, S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Bound")
.field("source", &self.source)
.finish_non_exhaustive()
}
}
impl<B2: Broker + 'static, S: Clone> Clone for Bound<B2, S> {
fn clone(&self) -> Self {
Self {
slot: Arc::clone(&self.slot),
source: self.source.clone(),
}
}
}
impl<B2, S> Bound<B2, S>
where
B2: Broker + 'static,
S: PublishPolicy<Connected<B2>>,
{
pub async fn live(self) -> Result<S::Live, PairError> {
pair_bound::<B2, S>(&self.slot, self.source).await
}
}
pub(crate) async fn pair_bound<B2, S>(
slot: &ConnectedSlot<B2>,
source: S,
) -> Result<S::Live, PairError>
where
B2: Broker + 'static,
S: PublishPolicy<Connected<B2>>,
{
let connected = slot
.lock()
.expect("connected slot mutex poisoned")
.clone()
.ok_or_else(|| {
PairError::from_boxed(Box::from(
"the token's broker is not connected: pairing happens after startup connects \
every registered broker",
))
})?;
source.pair(connected.as_ref()).await
}
impl<C, B2, S> PublishPolicy<C> for Bound<B2, S>
where
C: ConnectedBroker,
B2: Broker + 'static,
S: PublishPolicy<Connected<B2>> + Send,
{
type Live = S::Live;
async fn pair(self, _connected: &C) -> Result<Self::Live, PairError> {
pair_bound::<B2, S>(&self.slot, self.source).await
}
}