use crate::{
BatchSubscriber, Broker, Connected, DefaultPublish, PublishPolicy, SubscriptionSource,
};
use crate::codec::Codec;
use crate::runtime::SourceSubscriber;
use crate::runtime::batch_inject::BatchInjectDef;
use crate::runtime::batch_publishing::BatchPublishingDef;
use crate::runtime::inject::InjectDef;
use crate::runtime::input::DecodeWith;
#[cfg(any(feature = "json", feature = "cbor", feature = "msgpack"))]
use crate::runtime::publish::ReplyWiring;
use crate::runtime::publish::{LowerOutTransforms, NarrowToUse, RawReplyWiring, SlotStackUse};
use crate::runtime::publishing::PublishingDef;
use crate::runtime::settings::{BatchSized, DefMountCodec, MountsWith};
use crate::runtime::slot::{
BindSlots, HasSlots, InitSlots, IntoSlotSource, NoReply, OutAttachment, OutSlot, SlotCodec,
SlotPolicy, WithSource,
};
use super::builder::Router;
use super::builders::{RouterCommit, RouterOut, RouterPublishingOut, RouterWith};
use super::mount::{
BatchInjectMount, BatchPublishInjectMount, DefaultReply, InjectMount, MountCodec,
PublishInjectMount, RawReplyInjectMount, RouterMount,
};
use super::{
BatchInjectedRouter, BatchPublishingRouter, InjectedRouter, PublishingRouter, RawReplyRouter,
forms,
};
macro_rules! slot_form {
($($form:ty => $mount:ty, $reply:expr, $alias:ident),+ $(,)?) => {$(
impl<B, Routes, RouteCodec, RouteLayers, RoutePipe, Def>
RouterMount<Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>, Def> for $form
where
B: Broker + 'static,
Def: HasSlots,
Def::Markers: InitSlots,
{
type Out = $alias<
$mount,
Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>,
Def,
<Def::Markers as InitSlots>::Init,
>;
fn begin(
def: Def,
router: Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>,
) -> Self::Out {
RouterWith::new(def, ($reply, <Def::Markers as InitSlots>::init()), router)
}
}
)+};
}
slot_form! {
forms::Out => InjectMount, NoReply, RouterOut,
forms::BatchOut => BatchInjectMount, NoReply, RouterOut,
forms::PublishingOut => PublishInjectMount, DefaultReply, RouterPublishingOut,
forms::RawReplyOut => RawReplyInjectMount, DefaultReply, RouterPublishingOut,
forms::BatchPublishingOut => BatchPublishInjectMount, DefaultReply, RouterPublishingOut,
}
type SlotPipeline<Layers, Pipe> = <Layers as LowerOutTransforms<Pipe>>::Out;
type SlotLive<Policy, B> = <Policy as PublishPolicy<Connected<B>>>::Live;
macro_rules! slot_source {
($attach:ident, $layers:ident, $enc:ident, $surface:ty, $pipe:ty) => {
(
SlotPolicy<$layers, $attach, SlotLive<$attach, B>>,
<$enc as SlotCodec<$surface>>::Codec,
SlotPipeline<$layers, $pipe>,
)
};
}
macro_rules! impl_inject_out_commit {
($(($($marker:ident / $attach:ident / $layers:ident / $enc:ident),+))+) => {$(
impl<B, Routes, RouteCodec, RouteLayers, RoutePipe, Def, Bound, Extra,
$($marker, $attach, $layers, $enc),+>
RouterCommit<InjectMount, Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>, Def>
for (NoReply, ($(WithSource<OutAttachment<$marker, $attach, $layers, $enc>>,)+))
where
B: Broker + 'static,
RouteCodec: MountCodec,
RoutePipe: Clone,
$(
$marker: OutSlot,
$enc: SlotCodec<RouteCodec::Codec, Codec: Codec>,
$attach: PublishPolicy<Connected<B>>,
$layers: LowerOutTransforms<RoutePipe> + SlotStackUse<SlotLive<$attach, B>>,
<$layers as SlotStackUse<SlotLive<$attach, B>>>::Destination: NarrowToUse<$attach>,
)+
Def: BindSlots<
Connected<B>,
($(slot_source!($attach, $layers, $enc, RouteCodec::Codec, RoutePipe),)+),
Bound = Bound,
Extra = Extra,
>,
Def: MountsWith<<Bound as InjectDef>::Input, RouteCodec>,
Bound: InjectDef + 'static,
Bound::Source: SubscriptionSource<Connected<B>> + Send + 'static,
SourceSubscriber<B, Bound::Source>: Send + 'static,
Bound::Input: DecodeWith<DefMountCodec<Def, <Bound as InjectDef>::Input, RouteCodec>>,
{
type Out = InjectedRouter<
B,
Bound::Source,
Bound,
DefMountCodec<Def, <Bound as InjectDef>::Input, RouteCodec>,
Extra,
RouteCodec,
RouteLayers,
RoutePipe,
Routes,
>;
fn commit(
self,
def: Def,
router: Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>,
) -> Self::Out {
#[allow(non_snake_case)]
let (_no_reply, ($($attach,)+)) = self;
let codec = router.codec.mount_codec();
let pipeline = router.pipeline.clone();
let decode = def.mounted_codec(&router.codec);
let slots = [$($attach
.source()
.describe::<Connected<B>, RouteCodec::Codec>(),)+];
let (def, extra) = def.bind(($(
$attach.into_source().wire(codec.clone(), pipeline.clone()),
)+));
let source = def.source();
router
.mount_inject(source, def, decode, extra)
.describing_slots(&slots)
}
}
impl<B, Routes, RouteCodec, RouteLayers, RoutePipe, Def, Bound, Extra,
$($marker, $attach, $layers, $enc),+>
RouterCommit<
BatchInjectMount,
Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>,
Def,
>
for (NoReply, ($(WithSource<OutAttachment<$marker, $attach, $layers, $enc>>,)+))
where
B: Broker + 'static,
RouteCodec: MountCodec,
RoutePipe: Clone,
$(
$marker: OutSlot,
$enc: SlotCodec<RouteCodec::Codec, Codec: Codec>,
$attach: PublishPolicy<Connected<B>>,
$layers: LowerOutTransforms<RoutePipe> + SlotStackUse<SlotLive<$attach, B>>,
<$layers as SlotStackUse<SlotLive<$attach, B>>>::Destination: NarrowToUse<$attach>,
)+
Def: BindSlots<
Connected<B>,
($(slot_source!($attach, $layers, $enc, RouteCodec::Codec, RoutePipe),)+),
Bound = Bound,
Extra = Extra,
>,
Def: MountsWith<<Bound as BatchInjectDef>::Input, RouteCodec>,
Bound: BatchInjectDef + BatchSized + 'static,
Bound::Source: SubscriptionSource<Connected<B>> + Send + 'static,
SourceSubscriber<B, Bound::Source>: BatchSubscriber + Send + 'static,
Bound::Input:
DecodeWith<DefMountCodec<Def, <Bound as BatchInjectDef>::Input, RouteCodec>>,
{
type Out = BatchInjectedRouter<
B,
Bound::Source,
Bound,
DefMountCodec<Def, <Bound as BatchInjectDef>::Input, RouteCodec>,
Extra,
RouteCodec,
RouteLayers,
RoutePipe,
Routes,
>;
fn commit(
self,
def: Def,
router: Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>,
) -> Self::Out {
#[allow(non_snake_case)]
let (_no_reply, ($($attach,)+)) = self;
let codec = router.codec.mount_codec();
let pipeline = router.pipeline.clone();
let decode = def.mounted_codec(&router.codec);
let slots = [$($attach
.source()
.describe::<Connected<B>, RouteCodec::Codec>(),)+];
let (def, extra) = def.bind(($(
$attach.into_source().wire(codec.clone(), pipeline.clone()),
)+));
let source = def.source();
router
.mount_batch_inject(source, def, decode, extra)
.describing_slots(&slots)
}
}
)+};
}
impl_inject_out_commit! {
(M0 / A0 / L0 / E0)
(M0 / A0 / L0 / E0, M1 / A1 / L1 / E1)
(M0 / A0 / L0 / E0, M1 / A1 / L1 / E1, M2 / A2 / L2 / E2)
}
macro_rules! impl_publishing_out_commit {
($(($($marker:ident / $attach:ident / $layers:ident / $enc:ident),+))+) => {$(
impl<B, Routes, RouteCodec, RouteLayers, RoutePipe, Def, Policy, Bound, Extra,
$($marker, $attach, $layers, $enc),+>
RouterCommit<
PublishInjectMount,
Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>,
Def,
>
for (
WithSource<Policy>,
($(WithSource<OutAttachment<$marker, $attach, $layers, $enc>>,)+),
)
where
B: Broker + 'static,
RouteCodec: MountCodec,
RoutePipe: Clone,
$(
$marker: OutSlot,
$enc: SlotCodec<RouteCodec::Codec, Codec: Codec>,
$attach: PublishPolicy<Connected<B>>,
$layers: LowerOutTransforms<RoutePipe> + SlotStackUse<SlotLive<$attach, B>>,
<$layers as SlotStackUse<SlotLive<$attach, B>>>::Destination: NarrowToUse<$attach>,
)+
Def: BindSlots<
Connected<B>,
($(slot_source!($attach, $layers, $enc, RouteCodec::Codec, RoutePipe),)+),
Bound = Bound,
Extra = Extra,
>,
Def: MountsWith<<Bound as PublishingDef>::Input, RouteCodec>,
Bound: PublishingDef + 'static,
Bound::Source: SubscriptionSource<Connected<B>> + Send + 'static,
SourceSubscriber<B, Bound::Source>: Send + 'static,
Bound::Input:
DecodeWith<DefMountCodec<Def, <Bound as PublishingDef>::Input, RouteCodec>>,
Policy: 'static,
{
type Out = PublishingRouter<
B,
Bound::Source,
Bound,
DefMountCodec<Def, <Bound as PublishingDef>::Input, RouteCodec>,
Policy,
Extra,
RouteCodec,
RouteLayers,
RoutePipe,
Routes,
>;
fn commit(
self,
def: Def,
router: Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>,
) -> Self::Out {
let (reply, slots) = self;
#[allow(non_snake_case)]
let ($($attach,)+) = slots;
let codec = router.codec.mount_codec();
let pipeline = router.pipeline.clone();
let decode = def.mounted_codec(&router.codec);
let slots = [$($attach
.source()
.describe::<Connected<B>, RouteCodec::Codec>(),)+];
let (def, extra) = def.bind(($(
$attach.into_source().wire(codec.clone(), pipeline.clone()),
)+));
let source = def.source();
router
.mount_publishing_source(source, def, decode, reply.into_source(), extra)
.describing_slots(&slots)
}
}
impl<B, Routes, RouteCodec, RouteLayers, RoutePipe, Def, Policy, Bound, Extra,
$($marker, $attach, $layers, $enc),+>
RouterCommit<
RawReplyInjectMount,
Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>,
Def,
>
for (
WithSource<Policy>,
($(WithSource<OutAttachment<$marker, $attach, $layers, $enc>>,)+),
)
where
B: Broker + 'static,
RouteCodec: MountCodec,
RoutePipe: Clone,
$(
$marker: OutSlot,
$enc: SlotCodec<RouteCodec::Codec, Codec: Codec>,
$attach: PublishPolicy<Connected<B>>,
$layers: LowerOutTransforms<RoutePipe> + SlotStackUse<SlotLive<$attach, B>>,
<$layers as SlotStackUse<SlotLive<$attach, B>>>::Destination: NarrowToUse<$attach>,
)+
Def: BindSlots<
Connected<B>,
($(slot_source!($attach, $layers, $enc, RouteCodec::Codec, RoutePipe),)+),
Bound = Bound,
Extra = Extra,
>,
Def: MountsWith<<Bound as PublishingDef>::Input, RouteCodec>,
Bound: PublishingDef + 'static,
Bound::Source: SubscriptionSource<Connected<B>> + Send + 'static,
SourceSubscriber<B, Bound::Source>: Send + 'static,
Bound::Input:
DecodeWith<DefMountCodec<Def, <Bound as PublishingDef>::Input, RouteCodec>>,
Policy: 'static,
{
type Out = RawReplyRouter<
B,
Bound::Source,
Bound,
DefMountCodec<Def, <Bound as PublishingDef>::Input, RouteCodec>,
Policy,
Extra,
RouteCodec,
RouteLayers,
RoutePipe,
Routes,
>;
fn commit(
self,
def: Def,
router: Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>,
) -> Self::Out {
let (reply, slots) = self;
#[allow(non_snake_case)]
let ($($attach,)+) = slots;
let codec = router.codec.mount_codec();
let pipeline = router.pipeline.clone();
let decode = def.mounted_codec(&router.codec);
let slots = [$($attach
.source()
.describe::<Connected<B>, RouteCodec::Codec>(),)+];
let (def, extra) = def.bind(($(
$attach.into_source().wire(codec.clone(), pipeline.clone()),
)+));
let source = def.source();
router
.mount_raw_reply_source(source, def, decode, reply.into_source(), extra)
.describing_slots(&slots)
}
}
impl<B, Routes, RouteCodec, RouteLayers, RoutePipe, Def, Policy, Bound, Extra,
$($marker, $attach, $layers, $enc),+>
RouterCommit<
BatchPublishInjectMount,
Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>,
Def,
>
for (
WithSource<Policy>,
($(WithSource<OutAttachment<$marker, $attach, $layers, $enc>>,)+),
)
where
B: Broker + 'static,
RouteCodec: MountCodec,
RoutePipe: Clone,
$(
$marker: OutSlot,
$enc: SlotCodec<RouteCodec::Codec, Codec: Codec>,
$attach: PublishPolicy<Connected<B>>,
$layers: LowerOutTransforms<RoutePipe> + SlotStackUse<SlotLive<$attach, B>>,
<$layers as SlotStackUse<SlotLive<$attach, B>>>::Destination: NarrowToUse<$attach>,
)+
Def: BindSlots<
Connected<B>,
($(slot_source!($attach, $layers, $enc, RouteCodec::Codec, RoutePipe),)+),
Bound = Bound,
Extra = Extra,
>,
Def: MountsWith<<Bound as BatchPublishingDef>::Input, RouteCodec>,
Bound: BatchPublishingDef + BatchSized + 'static,
Bound::Source: SubscriptionSource<Connected<B>> + Send + 'static,
SourceSubscriber<B, Bound::Source>: BatchSubscriber + Send + 'static,
Bound::Input:
DecodeWith<DefMountCodec<Def, <Bound as BatchPublishingDef>::Input, RouteCodec>>,
Policy: 'static,
{
type Out = BatchPublishingRouter<
B,
Bound::Source,
Bound,
DefMountCodec<Def, <Bound as BatchPublishingDef>::Input, RouteCodec>,
Policy,
Extra,
RouteCodec,
RouteLayers,
RoutePipe,
Routes,
>;
fn commit(
self,
def: Def,
router: Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>,
) -> Self::Out {
let (reply, slots) = self;
#[allow(non_snake_case)]
let ($($attach,)+) = slots;
let codec = router.codec.mount_codec();
let pipeline = router.pipeline.clone();
let decode = def.mounted_codec(&router.codec);
let slots = [$($attach
.source()
.describe::<Connected<B>, RouteCodec::Codec>(),)+];
let (def, extra) = def.bind(($(
$attach.into_source().wire(codec.clone(), pipeline.clone()),
)+));
let source = def.source();
router
.mount_batch_publishing_source(
source,
def,
decode,
reply.into_source(),
extra,
)
.describing_slots(&slots)
}
}
)+};
}
impl_publishing_out_commit! {
(M0 / A0 / L0 / E0)
(M0 / A0 / L0 / E0, M1 / A1 / L1 / E1)
(M0 / A0 / L0 / E0, M1 / A1 / L1 / E1, M2 / A2 / L2 / E2)
}
#[cfg(any(feature = "json", feature = "cbor", feature = "msgpack"))]
macro_rules! impl_default_typed_reply_slot_commit {
($($mount:ident),+ $(,)?) => {$(
impl<B, Routes, RouteCodec, RouteLayers, RoutePipe, Def, Slots>
RouterCommit<$mount, Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>, Def>
for (DefaultReply, Slots)
where
B: Broker + 'static,
B::Connected: DefaultPublish,
(
WithSource<ReplyWiring<<B::Connected as DefaultPublish>::Policy>>,
Slots,
): RouterCommit<$mount, Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>, Def>,
{
type Out = <(
WithSource<ReplyWiring<<B::Connected as DefaultPublish>::Policy>>,
Slots,
) as RouterCommit<
$mount,
Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>,
Def,
>>::Out;
fn commit(
self,
def: Def,
router: Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>,
) -> Self::Out {
(
WithSource::new(ReplyWiring::new(
<B::Connected as DefaultPublish>::Policy::default(),
)),
self.1,
)
.commit(def, router)
}
}
)+};
}
#[cfg(any(feature = "json", feature = "cbor", feature = "msgpack"))]
impl_default_typed_reply_slot_commit!(PublishInjectMount, BatchPublishInjectMount);
impl<B, Routes, RouteCodec, RouteLayers, RoutePipe, Def, Slots>
RouterCommit<RawReplyInjectMount, Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>, Def>
for (DefaultReply, Slots)
where
B: Broker + 'static,
B::Connected: DefaultPublish,
(
WithSource<RawReplyWiring<<B::Connected as DefaultPublish>::Policy>>,
Slots,
): RouterCommit<
RawReplyInjectMount,
Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>,
Def,
>,
{
type Out = <(
WithSource<RawReplyWiring<<B::Connected as DefaultPublish>::Policy>>,
Slots,
) as RouterCommit<
RawReplyInjectMount,
Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>,
Def,
>>::Out;
fn commit(
self,
def: Def,
router: Router<B, Routes, RouteCodec, RouteLayers, RoutePipe>,
) -> Self::Out {
(
WithSource::new(RawReplyWiring::new(
<B::Connected as DefaultPublish>::Policy::default(),
)),
self.1,
)
.commit(def, router)
}
}