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(bytes.iter_elements().flat_map(|b| {
41                let mut v = Vec::new();
42                for s in 0..8 {
43                    v.push(((b & (1 << s)) >> s) == 1)
44                }
45                v
46            }))
47            .collect();
48
49        AMQPFlags { flags }
50    }
51}
52
53#[cfg(test)]
54mod test {
55    use super::*;
56
57    #[test]
58    fn test_empty_flags() {
59        let empty: &[u8] = &[];
60        assert_eq!(AMQPFlags::default().get_bytes().as_slice(), empty);
61    }
62
63    #[test]
64    fn test_flags() {
65        let mut flags = AMQPFlags::default();
66        flags.add_flag("a".to_string(), true);
67        flags.add_flag("b".to_string(), false);
68        flags.add_flag("c".to_string(), false);
69        flags.add_flag("d".to_string(), true);
70        flags.add_flag("e".to_string(), true);
71        assert_eq!(flags.get_bytes().as_slice(), &[0b00011001])
72    }
73
74    #[test]
75    fn test_many_flags() {
76        let mut flags = AMQPFlags::default();
77        flags.add_flag("a".to_string(), true);
78        flags.add_flag("b".to_string(), false);
79        flags.add_flag("c".to_string(), false);
80        flags.add_flag("d".to_string(), true);
81        flags.add_flag("e".to_string(), true);
82        flags.add_flag("f".to_string(), true);
83        flags.add_flag("g".to_string(), false);
84        flags.add_flag("h".to_string(), false);
85        flags.add_flag("i".to_string(), true);
86        flags.add_flag("j".to_string(), true);
87        assert_eq!(flags.get_bytes().as_slice(), &[0b00111001, 0b00000011])
88    }
89
90    #[test]
91    fn test_lookup_flags() {
92        let mut flags = AMQPFlags::default();
93        flags.add_flag("a".to_string(), true);
94        flags.add_flag("b".to_string(), false);
95        flags.add_flag("c".to_string(), false);
96        flags.add_flag("d".to_string(), true);
97        flags.add_flag("e".to_string(), true);
98        flags.add_flag("f".to_string(), true);
99        flags.add_flag("g".to_string(), false);
100        flags.add_flag("h".to_string(), false);
101        flags.add_flag("i".to_string(), true);
102        flags.add_flag("j".to_string(), true);
103        assert_eq!(flags.get_flag("a"), Some(true));
104        assert_eq!(flags.get_flag("d"), Some(true));
105        assert_eq!(flags.get_flag("e"), Some(true));
106        assert_eq!(flags.get_flag("b"), Some(false));
107        assert_eq!(flags.get_flag("j"), Some(true));
108        assert_eq!(flags.get_flag("h"), Some(false));
109        assert_eq!(flags.get_flag("z"), None);
110    }
111}