mod declare;
mod destination;
use std::borrow::Cow;
use std::fmt;
use std::marker::PhantomData;
pub use declare::{
Absent, CapOpen, DeadLetterOpen, DeclareCap, DeclareDeadLetter, DeclareMount, Declaring,
Present, RouteDeclaring, StepOpen, StepTaken,
};
pub use destination::{
DestinationDeclared, DestinationLast, DestinationOpen, DestinationUndeclared, FixedDestination,
OpenDestination, RetryOffer, RetryStackUse, SettlesDestination,
};
use crate::Broker;
use crate::runtime::publish::{CallCodec, PublishTransformStack, Reads, UnnamedCodec};
use crate::runtime::router::{AttachRetry, Router, RouterCommit, RouterWith};
use crate::runtime::slot::{
AdmitsAt, BatchTransformLast, BindAt, CodecLast, MapPolicyLast, NamedStep, NoReply,
OutAttachment, OutSlot, Reply, ReplyLast, SlotPos, TransactionalLast, TransformLast,
};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct Retry;
impl OutSlot for Retry {
const NAME: &'static str = "Retry";
type Destination = Reads;
}
#[doc(hidden)]
#[derive(Debug, Clone, Copy, Default)]
pub struct RetryPos;
impl NamedStep for RetryPos {}
#[doc(hidden)]
#[derive(Debug, Clone, Copy, Default)]
pub struct RetryMount;
#[doc(hidden)]
pub struct Retried<Under, Attachment, Dest = OpenDestination> {
under: Under,
slot: Attachment,
destination: Option<Cow<'static, str>>,
_dest: PhantomData<fn() -> Dest>,
}
impl<Under, Attachment, Dest> fmt::Debug for Retried<Under, Attachment, Dest> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Retried")
.field("destination", &self.destination)
.finish_non_exhaustive()
}
}
impl<Under, Attachment, Dest> Retried<Under, Attachment, Dest> {
pub(crate) fn new(under: Under, slot: Attachment) -> Self {
Self {
under,
slot,
destination: None,
_dest: PhantomData,
}
}
fn map<NewUnder>(
self,
f: impl FnOnce(Under) -> NewUnder,
) -> Retried<NewUnder, Attachment, Dest> {
Retried {
under: f(self.under),
slot: self.slot,
destination: self.destination,
_dest: PhantomData,
}
}
fn map_slot<NewAttachment>(
self,
f: impl FnOnce(Attachment) -> NewAttachment,
) -> Retried<Under, NewAttachment, Dest> {
Retried {
under: self.under,
slot: f(self.slot),
destination: self.destination,
_dest: PhantomData,
}
}
fn name_destination(
self,
destination: Cow<'static, str>,
) -> Retried<Under, Attachment, FixedDestination> {
Retried {
under: self.under,
slot: self.slot,
destination: Some(destination),
_dest: PhantomData,
}
}
}
#[doc(hidden)]
#[diagnostic::on_unimplemented(
message = "this registration has no open deferred-retry position",
label = "`.out(Retry, ..)` has nothing to bind here",
note = "`.out(Retry, policy)` - or its sugar `.out_retry(policy)` - names the publish policy \
a deferred `retry_after` copy leaves through, once per registration"
)]
pub trait RetryOpen {}
impl<Rep, Slots> RetryOpen for (Rep, Slots) {}
impl<Mount, Policy, Attach: RetryOpen> BindAt<Mount, Retry, Policy, RetryPos> for Attach {
type Out = Retried<Self, OutAttachment<Retry, Policy>>;
fn bind_at(self, policy: Policy) -> Self::Out {
Retried::new(self, OutAttachment::new(policy))
}
}
#[doc(hidden)]
#[diagnostic::on_unimplemented(
message = "this registration has no unbound publish position marked `{Self}`",
label = "`.out({Self}, ..)` has no position to bind here",
note = "a handler that publishes nothing of its own binds one position, `Retry`, the deferred \
`retry_after` copy's publisher - and binds it once"
)]
pub trait RoutePosition<B, Chain, Policy> {
type Out;
fn bind(chain: Chain, policy: Policy) -> Self::Out;
}
#[doc(hidden)]
pub type RetryChain<Chain, Policy> = RouterWith<
RetryMount,
Chain,
(),
Retried<(NoReply, ()), OutAttachment<Retry, Policy>, OpenDestination>,
RetryPos,
>;
impl<B, Head, Tail, C, Layers, Pipe, Policy>
RoutePosition<B, Router<B, (Head, Tail), C, Layers, Pipe>, Policy> for Retry
where
B: Broker + 'static,
Head: RetryOpen,
{
type Out = RetryChain<Router<B, (Head, Tail), C, Layers, Pipe>, Policy>;
fn bind(chain: Router<B, (Head, Tail), C, Layers, Pipe>, policy: Policy) -> Self::Out {
RouterWith::new(
(),
Retried::new((NoReply, ()), OutAttachment::new(policy)),
chain,
)
}
}
impl<R> RouterCommit<RetryMount, R, ()> for (NoReply, ()) {
type Out = R;
fn commit(self, (): (), router: R) -> R {
router
}
}
impl<Mount, Policy, Under, Attachment, Dest> BindAt<Mount, Reply, Policy, ReplyLast>
for Retried<Under, Attachment, Dest>
where
Under: BindAt<Mount, Reply, Policy, ReplyLast>,
{
type Out = Retried<Under::Out, Attachment, Dest>;
fn bind_at(self, policy: Policy) -> Self::Out {
self.map(|under| under.bind_at(policy))
}
}
impl<Mount, M, Policy, Under, Attachment, Dest, const POS: usize>
BindAt<Mount, M, Policy, SlotPos<POS>> for Retried<Under, Attachment, Dest>
where
Under: BindAt<Mount, M, Policy, SlotPos<POS>>,
{
type Out = Retried<Under::Out, Attachment, Dest>;
fn bind_at(self, policy: Policy) -> Self::Out {
self.map(|under| under.bind_at(policy))
}
}
impl<Cd, Under, Policy, Layers, Dest> CodecLast<Cd, RetryPos>
for Retried<Under, OutAttachment<Retry, Policy, Layers, UnnamedCodec>, Dest>
{
type Step = RetryPos;
type Out = Retried<Under, OutAttachment<Retry, Policy, Layers, CallCodec<Cd>>, Dest>;
fn codec_last(self, codec: Cd) -> Self::Out {
self.map_slot(|slot| slot.name_codec(codec))
}
}
impl<N, Under, Policy, Layers, Enc, Dest> TransformLast<N, RetryPos>
for Retried<Under, OutAttachment<Retry, Policy, Layers, Enc>, Dest>
{
type Step = RetryPos;
type Out =
Retried<Under, OutAttachment<Retry, Policy, PublishTransformStack<Layers, N>, Enc>, Dest>;
fn transform_last(self, transform: N) -> Self::Out {
self.map_slot(|slot| slot.add_transform(transform))
}
}
impl<N, Under, Policy, Layers, Enc, Mount, Def, B, Dest> AdmitsAt<N, RetryPos, Mount, Def, B>
for Retried<Under, OutAttachment<Retry, Policy, Layers, Enc>, Dest>
{
}
impl<Under, Policy, Layers, Enc, Dest> MapPolicyLast<RetryPos>
for Retried<Under, OutAttachment<Retry, Policy, Layers, Enc>, Dest>
{
type Step = RetryPos;
type Policy = Policy;
fn map_policy_last(self, f: impl FnOnce(Policy) -> Policy) -> Self {
self.map_slot(|slot| slot.map_policy(f))
}
}
impl<N, Under, Attachment, Dest> BatchTransformLast<N, RetryPos>
for Retried<Under, Attachment, Dest>
{
type Step = RetryPos;
type Out = Self;
fn batch_transform_last(self, _transform: N) -> Self {
self
}
}
impl<Under, Attachment, Dest> TransactionalLast<RetryPos> for Retried<Under, Attachment, Dest> {
type Step = RetryPos;
type Out = Self;
fn transactional_last(self) -> Self {
self
}
}
impl<Cd, Under, Attachment, Dest> CodecLast<Cd, ReplyLast> for Retried<Under, Attachment, Dest>
where
Under: CodecLast<Cd, ReplyLast>,
{
type Step = Under::Step;
type Out = Retried<Under::Out, Attachment, Dest>;
fn codec_last(self, codec: Cd) -> Self::Out {
self.map(|under| under.codec_last(codec))
}
}
impl<Cd, Under, Attachment, Dest, const POS: usize> CodecLast<Cd, SlotPos<POS>>
for Retried<Under, Attachment, Dest>
where
Under: CodecLast<Cd, SlotPos<POS>>,
{
type Step = Under::Step;
type Out = Retried<Under::Out, Attachment, Dest>;
fn codec_last(self, codec: Cd) -> Self::Out {
self.map(|under| under.codec_last(codec))
}
}
impl<N, Under, Attachment, Dest> TransformLast<N, ReplyLast> for Retried<Under, Attachment, Dest>
where
Under: TransformLast<N, ReplyLast>,
{
type Step = Under::Step;
type Out = Retried<Under::Out, Attachment, Dest>;
fn transform_last(self, transform: N) -> Self::Out {
self.map(|under| under.transform_last(transform))
}
}
impl<N, Under, Attachment, Dest, const POS: usize> TransformLast<N, SlotPos<POS>>
for Retried<Under, Attachment, Dest>
where
Under: TransformLast<N, SlotPos<POS>>,
{
type Step = Under::Step;
type Out = Retried<Under::Out, Attachment, Dest>;
fn transform_last(self, transform: N) -> Self::Out {
self.map(|under| under.transform_last(transform))
}
}
impl<N, Under, Attachment, Dest, Mount, Def, B> AdmitsAt<N, ReplyLast, Mount, Def, B>
for Retried<Under, Attachment, Dest>
where
Under: AdmitsAt<N, ReplyLast, Mount, Def, B>,
{
}
impl<N, Under, Attachment, Dest, Mount, Def, B, const POS: usize>
AdmitsAt<N, SlotPos<POS>, Mount, Def, B> for Retried<Under, Attachment, Dest>
where
Under: AdmitsAt<N, SlotPos<POS>, Mount, Def, B>,
{
}
impl<N, Under, Attachment, Dest> BatchTransformLast<N, ReplyLast>
for Retried<Under, Attachment, Dest>
where
Under: BatchTransformLast<N, ReplyLast>,
{
type Step = Under::Step;
type Out = Retried<Under::Out, Attachment, Dest>;
fn batch_transform_last(self, transform: N) -> Self::Out {
self.map(|under| under.batch_transform_last(transform))
}
}
impl<N, Under, Attachment, Dest, const POS: usize> BatchTransformLast<N, SlotPos<POS>>
for Retried<Under, Attachment, Dest>
where
Under: BatchTransformLast<N, SlotPos<POS>>,
{
type Step = Under::Step;
type Out = Retried<Under::Out, Attachment, Dest>;
fn batch_transform_last(self, transform: N) -> Self::Out {
self.map(|under| under.batch_transform_last(transform))
}
}
impl<Under, Attachment, Dest> TransactionalLast<ReplyLast> for Retried<Under, Attachment, Dest>
where
Under: TransactionalLast<ReplyLast>,
{
type Step = Under::Step;
type Out = Retried<Under::Out, Attachment, Dest>;
fn transactional_last(self) -> Self::Out {
self.map(TransactionalLast::transactional_last)
}
}
impl<Under, Attachment, Dest, const POS: usize> TransactionalLast<SlotPos<POS>>
for Retried<Under, Attachment, Dest>
where
Under: TransactionalLast<SlotPos<POS>>,
{
type Step = Under::Step;
type Out = Retried<Under::Out, Attachment, Dest>;
fn transactional_last(self) -> Self::Out {
self.map(TransactionalLast::transactional_last)
}
}
impl<Under: MapPolicyLast<ReplyLast>, Attachment, Dest> MapPolicyLast<ReplyLast>
for Retried<Under, Attachment, Dest>
{
type Step = Under::Step;
type Policy = Under::Policy;
fn map_policy_last(self, f: impl FnOnce(Self::Policy) -> Self::Policy) -> Self {
self.map(|under| under.map_policy_last(f))
}
}
impl<Under, Attachment, Dest, const POS: usize> MapPolicyLast<SlotPos<POS>>
for Retried<Under, Attachment, Dest>
where
Under: MapPolicyLast<SlotPos<POS>>,
{
type Step = Under::Step;
type Policy = Under::Policy;
fn map_policy_last(self, f: impl FnOnce(Self::Policy) -> Self::Policy) -> Self {
self.map(|under| under.map_policy_last(f))
}
}
impl<Under, Attachment> DestinationLast<RetryPos> for Retried<Under, Attachment, OpenDestination> {
type Step = StepOpen;
type Out = Retried<Under, Attachment, FixedDestination>;
fn destination_last(self, destination: Cow<'static, str>) -> Self::Out {
self.name_destination(destination)
}
}
impl<Under, Attachment> DestinationLast<RetryPos> for Retried<Under, Attachment, FixedDestination> {
type Step = StepTaken;
type Out = Self;
fn destination_last(self, _destination: Cow<'static, str>) -> Self {
self
}
}
macro_rules! no_destination_step {
($([$($extra:tt)*] $index:ty => $attach:ty),+ $(,)?) => {$(
impl<$($extra)*> DestinationLast<$index> for $attach {
type Step = StepTaken;
type Out = Self;
fn destination_last(self, _destination: Cow<'static, str>) -> Self {
self
}
}
)+};
}
no_destination_step!(
[Rep, Slots] ReplyLast => (Rep, Slots),
[Rep, Slots, const POS: usize] SlotPos<POS> => (Rep, Slots),
[Under, Cap, Dead] ReplyLast => Declaring<Under, Cap, Dead>,
[Under, Cap, Dead, const POS: usize] SlotPos<POS> => Declaring<Under, Cap, Dead>,
[Under, Attachment, Dest] ReplyLast => Retried<Under, Attachment, Dest>,
[Under, Attachment, Dest, const POS: usize] SlotPos<POS> => Retried<Under, Attachment, Dest>,
);
impl<Mount, R, Def, Under, Policy, Layers, Enc, Dest> RouterCommit<Mount, R, Def>
for Retried<Under, OutAttachment<Retry, Policy, Layers, Enc>, Dest>
where
Under: RouterCommit<Mount, R, Def>,
Under::Out: AttachRetry<OutAttachment<Retry, Policy, Layers, Enc>, Dest>,
{
type Out = <Under::Out as AttachRetry<OutAttachment<Retry, Policy, Layers, Enc>, Dest>>::Out;
fn commit(self, def: Def, router: R) -> Self::Out {
self.under
.commit(def, router)
.attach_retry(self.slot, self.destination)
}
}