Skip to main content

mq_bridge/
outcomes.rs

1use crate::errors::PublisherError;
2use crate::traits::{BatchCommitFunc, CommitFunc};
3use crate::CanonicalMessage;
4
5/// The outcome of a successful command handling operation.
6#[derive(Debug)]
7pub enum Handled {
8    /// The command was handled successfully. No further message should be sent.
9    /// This is equivalent to acknowledging the message.
10    Ack,
11    /// The command was handled successfully and produced a response to be published.
12    Publish(CanonicalMessage),
13}
14
15/// The outcome of a successful single message publishing operation.
16#[derive(Debug)]
17pub enum Sent {
18    /// Message was successfully sent, no response was generated.
19    Ack,
20    /// Message was successfully sent and a response was generated.
21    Response(CanonicalMessage),
22}
23
24/// The outcome of a successful batch message publishing operation.
25#[derive(Debug)]
26pub enum SentBatch {
27    /// All messages in the batch were sent successfully. No responses were generated.
28    Ack,
29    /// The batch operation resulted in a mix of successes and/or failures.
30    Partial {
31        responses: Option<Vec<CanonicalMessage>>,
32        failed: Vec<(CanonicalMessage, PublisherError)>,
33    },
34}
35
36/// A successfully received single message.
37pub struct Received {
38    pub message: CanonicalMessage,
39    pub commit: CommitFunc,
40}
41
42impl std::fmt::Debug for Received {
43    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44        f.debug_struct("Received")
45            .field("message", &self.message)
46            .field("commit", &"<CommitFunc>")
47            .finish()
48    }
49}
50
51/// A successfully received batch of messages.
52pub struct ReceivedBatch {
53    pub messages: Vec<CanonicalMessage>,
54    pub commit: BatchCommitFunc,
55}
56
57impl ReceivedBatch {
58    /// An empty batch with a no-op commit. Consumers return this to signal idle —
59    /// the route treats it as the drain trigger under `exit_on_empty`/`--drain`.
60    pub fn empty() -> Self {
61        Self {
62            messages: Vec::new(),
63            commit: Box::new(|_| Box::pin(async { Ok(()) })),
64        }
65    }
66}
67
68impl std::fmt::Debug for ReceivedBatch {
69    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        f.debug_struct("ReceivedBatch")
71            .field("messages", &self.messages)
72            .field("commit", &"<BatchCommitFunc>")
73            .finish()
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80    use crate::traits::MessageDisposition;
81
82    #[test]
83    fn test_received_debug_hides_commit_implementation() {
84        let received = Received {
85            message: CanonicalMessage::from("single"),
86            commit: Box::new(|_| Box::pin(async move { Ok(()) })),
87        };
88
89        let debug = format!("{received:?}");
90        assert!(debug.contains("Received"));
91        assert!(debug.contains("<CommitFunc>"));
92        assert!(debug.contains("single"));
93    }
94
95    #[test]
96    fn test_received_batch_debug_hides_commit_implementation() {
97        let batch = ReceivedBatch {
98            messages: vec![
99                CanonicalMessage::from("first"),
100                CanonicalMessage::from("second"),
101            ],
102            commit: Box::new(|dispositions| {
103                Box::pin(async move {
104                    assert_eq!(dispositions.len(), 2);
105                    assert!(dispositions
106                        .into_iter()
107                        .all(|disposition| matches!(disposition, MessageDisposition::Ack)));
108                    Ok(())
109                })
110            }),
111        };
112
113        let debug = format!("{batch:?}");
114        assert!(debug.contains("ReceivedBatch"));
115        assert!(debug.contains("<BatchCommitFunc>"));
116        assert!(debug.contains("first"));
117        assert!(debug.contains("second"));
118    }
119}