Skip to main content

ruststream_sqlx/outbox/spec/
declaration.rs

1//! The settings of an outbox table as one type: each marker sets one slot, a tuple folds its
2//! markers slot by slot, and a slot set twice has no fold.
3
4#[cfg(doc)]
5use super::Set;
6use super::{Merge, Unset};
7
8/// The settings of an outbox table, one associated type per setting: [`Unset`] where the table
9/// keeps the default, [`Set`] with the marker that sets it otherwise.
10///
11/// Each marker of [`outbox::spec`](super) is one, and so is a tuple of them.
12pub trait Declaration {
13    /// The headers column: [`Headers`](super::Headers).
14    type Headers;
15    /// The time a record was processed: [`ProcessedAt`](super::ProcessedAt).
16    type ProcessedAt;
17    /// The record's own fetch: [`own::Fetch`](super::own::Fetch).
18    type OwnFetch;
19    /// The record's own ack: [`own::Ack`](super::own::Ack).
20    type OwnAck;
21    /// The record's own retry: [`own::Retry`](super::own::Retry).
22    type OwnRetry;
23    /// The record's own discard: [`own::Discard`](super::own::Discard).
24    type OwnDiscard;
25    /// The record's own recovery: [`own::Recover`](super::own::Recover).
26    type OwnRecover;
27}
28
29/// One marker: it sets its own slot to itself and leaves every other slot unset.
30macro_rules! setting {
31    ($(#[$doc:meta])* $name:ident, $slot:ident) => {
32        $(#[$doc])*
33        #[derive(Debug)]
34        pub struct $name;
35
36        impl Declaration for $name {
37            setting!(@slots $slot, Set<Self>;
38                Headers ProcessedAt OwnFetch OwnAck OwnRetry OwnDiscard OwnRecover);
39        }
40    };
41    (@slots $slot:ident, $value:ty; $($each:ident)*) => {
42        $(setting!(@slot $slot, $value; $each);)*
43    };
44    (@slot Headers, $value:ty; Headers) => { type Headers = $value; };
45    (@slot ProcessedAt, $value:ty; ProcessedAt) => { type ProcessedAt = $value; };
46    (@slot OwnFetch, $value:ty; OwnFetch) => { type OwnFetch = $value; };
47    (@slot OwnAck, $value:ty; OwnAck) => { type OwnAck = $value; };
48    (@slot OwnRetry, $value:ty; OwnRetry) => { type OwnRetry = $value; };
49    (@slot OwnDiscard, $value:ty; OwnDiscard) => { type OwnDiscard = $value; };
50    (@slot OwnRecover, $value:ty; OwnRecover) => { type OwnRecover = $value; };
51    (@slot $slot:ident, $value:ty; $other:ident) => { type $other = Unset; };
52}
53
54pub(super) use setting;
55
56impl Declaration for () {
57    type Headers = Unset;
58    type ProcessedAt = Unset;
59    type OwnFetch = Unset;
60    type OwnAck = Unset;
61    type OwnRetry = Unset;
62    type OwnDiscard = Unset;
63    type OwnRecover = Unset;
64}
65
66/// A tuple of markers folds its head into the declaration of its tail, slot by slot.
67macro_rules! tuple {
68    ($head:ident $(, $tail:ident)*) => {
69        tuple!(@impl [$head $(, $tail)*] $head, ($($tail,)*);
70            Headers ProcessedAt OwnFetch OwnAck OwnRetry OwnDiscard OwnRecover);
71    };
72    (@impl [$($each:ident),*] $head:ident, $tail:ty; $($slot:ident)*) => {
73        impl<$($each: Declaration),*> Declaration for ($($each,)*)
74        where
75            $tail: Declaration,
76            $($head::$slot: Merge<<$tail as Declaration>::$slot>,)*
77        {
78            $(type $slot = <$head::$slot as Merge<<$tail as Declaration>::$slot>>::Out;)*
79        }
80    };
81}
82
83// One marker per setting, and a tuple one longer than the settings, so a setting given twice
84// reaches the fold's message instead of a missing impl.
85tuple!(Setting1);
86tuple!(Setting1, Setting2);
87tuple!(Setting1, Setting2, Setting3);
88tuple!(Setting1, Setting2, Setting3, Setting4);
89tuple!(Setting1, Setting2, Setting3, Setting4, Setting5);
90tuple!(Setting1, Setting2, Setting3, Setting4, Setting5, Setting6);
91tuple!(
92    Setting1, Setting2, Setting3, Setting4, Setting5, Setting6, Setting7
93);
94tuple!(
95    Setting1, Setting2, Setting3, Setting4, Setting5, Setting6, Setting7, Setting8
96);