mqtt5_protocol/
flags.rs

1//! MQTT packet flag definitions using `BeBytes` v2.1.0 flag decomposition
2
3use bebytes::BeBytes;
4
5/// Flags for MQTT CONNECT packet
6#[derive(Debug, Clone, Copy, PartialEq, Eq, BeBytes)]
7#[bebytes(flags)]
8pub enum ConnectFlags {
9    /// Reserved bit - must be 0
10    Reserved = 0x01,
11    /// Clean Start flag
12    CleanStart = 0x02,
13    /// Will Flag
14    WillFlag = 0x04,
15    /// Will `QoS` bit 0
16    WillQoS0 = 0x08,
17    /// Will `QoS` bit 1  
18    WillQoS1 = 0x10,
19    /// Will Retain flag
20    WillRetain = 0x20,
21    /// Password flag
22    PasswordFlag = 0x40,
23    /// Username flag
24    UsernameFlag = 0x80,
25}
26
27impl ConnectFlags {
28    /// Extract Will `QoS` value from flags
29    #[must_use]
30    pub fn extract_will_qos(flags: u8) -> u8 {
31        (flags >> crate::constants::connect_flags::WILL_QOS_SHIFT)
32            & crate::constants::connect_flags::WILL_QOS_MASK
33    }
34
35    #[must_use]
36    /// Create flags byte with Will `QoS` value
37    pub fn with_will_qos(mut flags: u8, qos: u8) -> u8 {
38        // Clear existing QoS bits
39        flags &= crate::constants::connect_flags::WILL_QOS_CLEAR_MASK;
40        // Set new QoS bits
41        flags |= (qos & crate::constants::connect_flags::WILL_QOS_MASK)
42            << crate::constants::connect_flags::WILL_QOS_SHIFT;
43        flags
44    }
45}
46
47/// Flags for MQTT PUBLISH packet
48#[derive(Debug, Clone, Copy, PartialEq, Eq, BeBytes)]
49#[bebytes(flags)]
50pub enum PublishFlags {
51    /// Retain flag
52    Retain = 0x01,
53    /// `QoS` bit 0
54    QoS0 = 0x02,
55    /// `QoS` bit 1
56    QoS1 = 0x04,
57    /// Duplicate delivery flag
58    Dup = 0x08,
59}
60
61impl PublishFlags {
62    /// Extract `QoS` value from flags
63    #[must_use]
64    pub fn extract_qos(flags: u8) -> u8 {
65        (flags >> crate::constants::publish_flags::QOS_SHIFT)
66            & crate::constants::publish_flags::QOS_MASK
67    }
68
69    #[must_use]
70    /// Create flags byte with `QoS` value
71    pub fn with_qos(mut flags: u8, qos: u8) -> u8 {
72        // Clear existing QoS bits
73        flags &= crate::constants::publish_flags::QOS_CLEAR_MASK;
74        // Set new QoS bits
75        flags |= (qos & crate::constants::publish_flags::QOS_MASK)
76            << crate::constants::publish_flags::QOS_SHIFT;
77        flags
78    }
79}
80
81/// Flags for MQTT CONNACK packet
82#[derive(Debug, Clone, Copy, PartialEq, Eq, BeBytes)]
83#[bebytes(flags)]
84pub enum ConnAckFlags {
85    /// Session Present flag
86    SessionPresent = 0x01,
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92
93    #[test]
94    fn test_connect_flags_decompose() {
95        // Clean start + username + password
96        let flags: u8 = 0xC2; // 11000010
97        let decomposed = ConnectFlags::decompose(flags);
98
99        assert_eq!(decomposed.len(), 3);
100        assert!(decomposed.contains(&ConnectFlags::CleanStart));
101        assert!(decomposed.contains(&ConnectFlags::UsernameFlag));
102        assert!(decomposed.contains(&ConnectFlags::PasswordFlag));
103    }
104
105    #[test]
106    fn test_publish_flags_decompose() {
107        // DUP + QoS 2 + Retain = 0x0D (00001101)
108        let flags: u8 = 0x0D;
109        let decomposed = PublishFlags::decompose(flags);
110
111        assert!(decomposed.contains(&PublishFlags::Retain));
112        assert!(decomposed.contains(&PublishFlags::QoS1)); // QoS 2 = both bits set
113        assert!(decomposed.contains(&PublishFlags::Dup));
114
115        // Extract QoS
116        assert_eq!(PublishFlags::extract_qos(flags), 2);
117    }
118
119    #[test]
120    fn test_connack_flags() {
121        let flags: u8 = 0x01;
122        let decomposed = ConnAckFlags::decompose(flags);
123
124        assert_eq!(decomposed.len(), 1);
125        assert!(decomposed.contains(&ConnAckFlags::SessionPresent));
126    }
127
128    #[test]
129    fn test_flag_iteration() {
130        let flags: u8 = 0x0D; // DUP + QoS 2 + Retain
131
132        let collected: Vec<_> = PublishFlags::iter_flags(flags).collect();
133        assert_eq!(collected.len(), 3);
134    }
135}