Skip to main content

amq_protocol_types/
flags.rs

1use crate::types::Boolean;
2
3use serde::{Deserialize, Serialize};
4
5/// A struct representing AMQP boolean flags for RPC
6#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
7pub struct AMQPFlags {
8    flags: Vec<(String, Boolean)>,
9}
10
11impl AMQPFlags {
12    /// Add a boolean flag with a name
13    pub fn add_flag(&mut self, name: String, flag: Boolean) {
14        self.flags.push((name, flag));
15    }
16
17    /// Get the value of a boolean flag by name, if present
18    pub fn get_flag(&self, name: &str) -> Option<Boolean> {
19        self.flags.iter().find(|(n, _)| n == name).map(|(_, v)| *v)
20    }
21
22    /// Get the AMQPFlags serialized for AMQP RPC
23    pub fn get_bytes(&self) -> Vec<u8> {
24        self.flags
25            .chunks(8)
26            .map(|v| {
27                v.iter()
28                    .enumerate()
29                    .map(|(idx, (_, b))| if *b { 1 << idx } else { 0 })
30                    .sum()
31            })
32            .collect()
33    }
34
35    /// Initialize AMQPFlags from AMQP RPC serialization
36    pub fn from_bytes<I: nom::Input<Item = u8>>(names: &[&str], bytes: I) -> AMQPFlags {
37        let flags = names
38            .iter()
39            .map(ToString::to_string)
40            .zip(
41                bytes
42                    .iter_elements()
43                    .flat_map(|b| (0..8u8).map(move |s| ((b >> s) & 1) == 1)),
44            )
45            .collect();
46
47        AMQPFlags { flags }
48    }
49}
50
51#[cfg(test)]
52mod test {
53    use super::*;
54
55    #[test]
56    fn test_empty_flags() {
57        let empty: &[u8] = &[];
58        assert_eq!(AMQPFlags::default().get_bytes().as_slice(), empty);
59    }
60
61    #[test]
62    fn test_flags() {
63        let mut flags = AMQPFlags::default();
64        flags.add_flag("a".to_string(), true);
65        flags.add_flag("b".to_string(), false);
66        flags.add_flag("c".to_string(), false);
67        flags.add_flag("d".to_string(), true);
68        flags.add_flag("e".to_string(), true);
69        assert_eq!(flags.get_bytes().as_slice(), &[0b00011001])
70    }
71
72    #[test]
73    fn test_many_flags() {
74        let mut flags = AMQPFlags::default();
75        flags.add_flag("a".to_string(), true);
76        flags.add_flag("b".to_string(), false);
77        flags.add_flag("c".to_string(), false);
78        flags.add_flag("d".to_string(), true);
79        flags.add_flag("e".to_string(), true);
80        flags.add_flag("f".to_string(), true);
81        flags.add_flag("g".to_string(), false);
82        flags.add_flag("h".to_string(), false);
83        flags.add_flag("i".to_string(), true);
84        flags.add_flag("j".to_string(), true);
85        assert_eq!(flags.get_bytes().as_slice(), &[0b00111001, 0b00000011])
86    }
87
88    #[test]
89    fn test_lookup_flags() {
90        let mut flags = AMQPFlags::default();
91        flags.add_flag("a".to_string(), true);
92        flags.add_flag("b".to_string(), false);
93        flags.add_flag("c".to_string(), false);
94        flags.add_flag("d".to_string(), true);
95        flags.add_flag("e".to_string(), true);
96        flags.add_flag("f".to_string(), true);
97        flags.add_flag("g".to_string(), false);
98        flags.add_flag("h".to_string(), false);
99        flags.add_flag("i".to_string(), true);
100        flags.add_flag("j".to_string(), true);
101        assert_eq!(flags.get_flag("a"), Some(true));
102        assert_eq!(flags.get_flag("d"), Some(true));
103        assert_eq!(flags.get_flag("e"), Some(true));
104        assert_eq!(flags.get_flag("b"), Some(false));
105        assert_eq!(flags.get_flag("j"), Some(true));
106        assert_eq!(flags.get_flag("h"), Some(false));
107        assert_eq!(flags.get_flag("z"), None);
108    }
109}