mqtt5_protocol/
flags.rs

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