use std::borrow::Cow;
use std::fmt;
use std::marker::PhantomData;
use std::num::NonZeroU32;
use crate::runtime::retry::{
CapOpen, DeadLetterOpen, DeclareCap, DeclareDeadLetter, DestinationLast, DestinationOpen, Retry,
};
use crate::runtime::slot::{
AdmitsAt, BatchTransformLast, CodecLast, MapPolicyLast, NamedStep, NoOutBound, OutPosition,
Reply, ReplyLast, ReplyStep, TransactionalLast, TransformLast,
};
use super::builder::RouterBroker;
use super::routes::RetryDestinationsDeclared;
#[doc(hidden)]
#[diagnostic::on_unimplemented(
message = "this registration is not ready to mount",
label = "the attachment `{Self}` has an unfilled position",
note = "bind every Out slot the handler declares with .out(marker, policy) before .build(); \
an unbound one shows as `MissingSlot<..>` naming its marker"
)]
pub trait RouterCommit<Mount, R, Def>: Sized {
type Out;
fn commit(self, def: Def, router: R) -> Self::Out;
}
#[must_use = "a router registration is only added once .build() commits it"]
pub struct RouterWith<Mount, R, Def, Attach, Last = NoOutBound> {
def: Def,
attach: Attach,
router: R,
_mount: PhantomData<fn() -> Mount>,
_last: PhantomData<fn() -> Last>,
}
impl<Mount, R, Def, Attach, Last> RouterWith<Mount, R, Def, Attach, Last> {
pub(crate) fn new(def: Def, attach: Attach, router: R) -> Self {
Self {
def,
attach,
router,
_mount: PhantomData,
_last: PhantomData,
}
}
#[allow(clippy::needless_pass_by_value, clippy::type_complexity)]
pub fn out<M, Policy, Index>(
self,
marker: M,
policy: Policy,
) -> RouterWith<
Mount,
R,
Def,
<M as OutPosition<Mount, R::Broker, Attach, Policy, Index>>::Out,
Index,
>
where
R: RouterBroker,
M: OutPosition<Mount, R::Broker, Attach, Policy, Index>,
{
let _ = marker;
RouterWith::new(self.def, M::bind(self.attach, policy), self.router)
}
#[allow(clippy::type_complexity)] pub fn out_reply<Policy>(
self,
policy: Policy,
) -> RouterWith<
Mount,
R,
Def,
<Reply as OutPosition<Mount, R::Broker, Attach, Policy, ReplyLast>>::Out,
ReplyLast,
>
where
R: RouterBroker,
Reply: OutPosition<Mount, R::Broker, Attach, Policy, ReplyLast>,
{
self.out(Reply, policy)
}
#[allow(clippy::type_complexity)] pub fn out_retry<Policy, Index>(
self,
policy: Policy,
) -> RouterWith<
Mount,
R,
Def,
<Retry as OutPosition<Mount, R::Broker, Attach, Policy, Index>>::Out,
Index,
>
where
R: RouterBroker,
Retry: OutPosition<Mount, R::Broker, Attach, Policy, Index>,
{
self.out(Retry, policy)
}
#[allow(clippy::type_complexity)] pub fn max_attempts(
self,
attempts: NonZeroU32,
) -> RouterWith<Mount, R, Def, <Attach as DeclareCap>::Out, Last>
where
Attach: DeclareCap<Step: CapOpen>,
{
RouterWith::new(self.def, self.attach.declare_cap(attempts), self.router)
}
#[allow(clippy::type_complexity)] pub fn dead_letter(
self,
destination: impl Into<Cow<'static, str>>,
) -> RouterWith<Mount, R, Def, <Attach as DeclareDeadLetter>::Out, Last>
where
Attach: DeclareDeadLetter<Step: DeadLetterOpen>,
{
RouterWith::new(
self.def,
self.attach.declare_dead_letter(destination.into()),
self.router,
)
}
#[allow(clippy::type_complexity)] pub fn to(
self,
destination: impl Into<Cow<'static, str>>,
) -> RouterWith<Mount, R, Def, <Attach as DestinationLast<Last>>::Out, Last>
where
Attach: DestinationLast<Last, Step: DestinationOpen>,
{
RouterWith::new(
self.def,
self.attach.destination_last(destination.into()),
self.router,
)
}
#[allow(clippy::type_complexity)] pub fn codec<Cd>(
self,
codec: Cd,
) -> RouterWith<Mount, R, Def, <Attach as CodecLast<Cd, Last>>::Out, Last>
where
Attach: CodecLast<Cd, Last, Step: NamedStep>,
{
RouterWith::new(self.def, self.attach.codec_last(codec), self.router)
}
#[allow(clippy::type_complexity)] pub fn transform<N>(
self,
transform: N,
) -> RouterWith<Mount, R, Def, <Attach as TransformLast<N, Last>>::Out, Last>
where
R: RouterBroker,
Attach: TransformLast<N, Last, Step: NamedStep> + AdmitsAt<N, Last, Mount, Def, R::Broker>,
{
RouterWith::new(self.def, self.attach.transform_last(transform), self.router)
}
#[allow(clippy::type_complexity)] pub fn batch_transform<N>(
self,
transform: N,
) -> RouterWith<Mount, R, Def, <Attach as BatchTransformLast<N, Last>>::Out, Last>
where
Attach: BatchTransformLast<N, Last, Step: ReplyStep>,
{
RouterWith::new(
self.def,
self.attach.batch_transform_last(transform),
self.router,
)
}
#[allow(clippy::type_complexity)] pub fn transactional(
self,
) -> RouterWith<Mount, R, Def, <Attach as TransactionalLast<Last>>::Out, Last>
where
Attach: TransactionalLast<Last, Step: ReplyStep>,
{
RouterWith::new(self.def, self.attach.transactional_last(), self.router)
}
#[allow(clippy::type_complexity)] pub fn build(self) -> <Attach as RouterCommit<Mount, R, Def>>::Out
where
Attach: RouterCommit<Mount, R, Def, Out: RetryDestinationsDeclared>,
{
self.commit_chain()
}
pub(crate) fn commit_chain(self) -> <Attach as RouterCommit<Mount, R, Def>>::Out
where
Attach: RouterCommit<Mount, R, Def>,
{
self.attach.commit(self.def, self.router)
}
}
impl<Mount, R, Def, Attach, Last> fmt::Debug for RouterWith<Mount, R, Def, Attach, Last> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RouterWith").finish_non_exhaustive()
}
}
pub trait MapPublisher: Sized {
type Policy;
#[allow(clippy::return_self_not_must_use)]
fn map_publisher(self, f: impl FnOnce(Self::Policy) -> Self::Policy) -> Self;
}
impl<Mount, R, Def, Attach, Last> MapPublisher for RouterWith<Mount, R, Def, Attach, Last>
where
Attach: MapPolicyLast<Last, Step: NamedStep>,
{
type Policy = Attach::Policy;
fn map_publisher(self, f: impl FnOnce(Self::Policy) -> Self::Policy) -> Self {
Self::new(self.def, self.attach.map_policy_last(f), self.router)
}
}
use super::mount::DefaultReply;
use crate::runtime::slot::NoReply;
pub(crate) type ReplyOnly = (DefaultReply, ());
pub(crate) type SlotsOnly<Slots> = (NoReply, Slots);
pub(crate) type ReplyAndSlots<Slots> = (DefaultReply, Slots);
pub type RouterPublishing<Mount, R, Def> = RouterWith<Mount, R, Def, ReplyOnly>;
pub type RouterOut<Mount, R, Def, Slots> = RouterWith<Mount, R, Def, SlotsOnly<Slots>>;
pub type RouterPublishingOut<Mount, R, Def, Slots> =
RouterWith<Mount, R, Def, ReplyAndSlots<Slots>>;