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    #[must_use]
19    pub fn get_flag(&self, name: &str) -> Option<Boolean> {
20        self.flags.iter().find(|(n, _)| n == name).map(|(_, v)| *v)
21    }
22
23    /// Get the AMQPFlags serialized for AMQP RPC
24    #[must_use]
25    pub fn get_bytes(&self) -> Vec<u8> {
26        self.flags
27            .chunks(8)
28            .map(|v| {
29                v.iter()
30                    .enumerate()
31                    .map(|(idx, (_, b))| if *b { 1 << idx } else { 0 })
32                    .sum()
33            })
34            .collect()
35    }
36
37    /// Initialize AMQPFlags from AMQP RPC serialization
38    pub fn from_bytes<I: nom::Input<Item = u8>>(names: &[&str], bytes: I) -> AMQPFlags {
39        let flags = names
40            .iter()
41            .map(ToString::to_string)
42            .zip(
43                bytes
44                    .iter_elements()
45                    .flat_map(|b| (0..8u8).map(move |s| ((b >> s) & 1) == 1)),
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}