strut_rabbitmq/util/
field_table.rs

1use crate::util::field_table::push::Push;
2use crate::util::field_table::retrieve::Retrieve;
3use lapin::types::FieldTable;
4
5pub mod push;
6pub mod retrieve;
7
8/// Special name of the RabbitMQ header that stores the attempt number (how many
9/// times the processing of this message has been attempted).
10pub const HEADER_ATTEMPT: &str = "x-attempt";
11
12/// Artificial trait implemented for [`FieldTable`] to allow convenient handling
13/// of the header [`HEADER_ATTEMPT`] that carries the processing attempt number.
14pub trait Attempt {
15    /// Extracts the header value at the key [`HEADER_ATTEMPT`] in this
16    /// [`FieldTable`], if it can be inferred as a valid `u32`.
17    ///
18    /// This method does not do any logical inference: e.g., if no attempt value
19    /// is present, [`None`] is promptly returned.
20    fn retrieve_attempt(&self) -> Option<u32>;
21
22    /// Sets the header value at the key [`HEADER_ATTEMPT`] in this
23    /// [`FieldTable`] to the given `u32` value.
24    fn push_attempt(&mut self, attempt: u32);
25
26    /// Increments the existing header value at the key [`HEADER_ATTEMPT`] in
27    /// this [`FieldTable`] by one. If no value exists at that key, sets the new
28    /// value to one.
29    fn increment_attempt(&mut self);
30}
31
32impl Attempt for FieldTable {
33    fn retrieve_attempt(&self) -> Option<u32> {
34        self.retrieve(HEADER_ATTEMPT)
35    }
36
37    fn push_attempt(&mut self, attempt: u32) {
38        self.push(HEADER_ATTEMPT, attempt);
39    }
40
41    fn increment_attempt(&mut self) {
42        let current_attempt = self.retrieve_attempt().unwrap_or(0);
43
44        self.push_attempt(current_attempt + 1);
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51    use pretty_assertions::assert_eq;
52
53    #[test]
54    fn field_table_attempts() {
55        let mut table = FieldTable::default();
56        assert_eq!(table.retrieve_attempt(), None);
57
58        table.increment_attempt();
59        assert_eq!(table.retrieve_attempt(), Some(1));
60
61        table.increment_attempt();
62        assert_eq!(table.retrieve_attempt(), Some(2));
63
64        table.push_attempt(0);
65        assert_eq!(table.retrieve_attempt(), Some(0));
66    }
67
68    #[test]
69    fn field_table_set_and_get() {
70        let mut table = FieldTable::default();
71        table.push("bool_key", true);
72        assert_eq!(table.retrieve("bool_key"), Some(true));
73
74        table.push("str_key", "hello");
75        assert_eq!(table.retrieve("str_key"), Some("hello".to_string()));
76
77        table.push("i8_key", -8);
78        assert_eq!(table.retrieve("i8_key"), Some(-8));
79
80        table.push("i16_key", -16);
81        assert_eq!(table.retrieve("i16_key"), Some(-16));
82
83        table.push("i32_key", -32);
84        assert_eq!(table.retrieve("i32_key"), Some(-32));
85
86        table.push("i64_key", -64);
87        assert_eq!(table.retrieve("i64_key"), Some(-64));
88
89        table.push("u8_key", 8);
90        assert_eq!(table.retrieve("u8_key"), Some(8));
91
92        table.push("u16_key", 16);
93        assert_eq!(table.retrieve("u16_key"), Some(16));
94
95        table.push("u32_key", 32);
96        assert_eq!(table.retrieve("u32_key"), Some(32));
97
98        table.push("u64_key", 64);
99        assert_eq!(table.retrieve("u64_key"), Some(64));
100    }
101
102    #[test]
103    fn field_table_invalid_gets() {
104        let table = FieldTable::default();
105        assert_eq!(table.retrieve("missing_key"), None::<bool>);
106        assert_eq!(table.retrieve("missing_key"), None::<i32>);
107        assert_eq!(table.retrieve("missing_key"), None::<u64>);
108    }
109}