mqute_codec/protocol/v3/
suback.rs

1//! # SubAck Packet V3
2//!
3//! This module initializes the `SubAck` packet for MQTT protocol.
4//! It uses the `suback!` macro to define the `SubAck` packet structure with support
5//! for Quality of Service (QoS) levels.
6
7use crate::Error;
8use crate::protocol::common::suback;
9use crate::protocol::{QoS, traits};
10
11/// Represents the return codes for a `SubAck` packet.
12///
13/// # Example
14///
15/// ```rust
16/// use mqute_codec::protocol::QoS;
17/// use crate::mqute_codec::protocol::v3::ReturnCode;
18///
19/// let retcode = ReturnCode::new(QoS::AtMostOnce);
20/// ```
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct ReturnCode(QoS);
23
24impl ReturnCode {
25    pub fn new(qos: QoS) -> Self {
26        ReturnCode { 0: qos }
27    }
28}
29
30impl TryFrom<u8> for ReturnCode {
31    type Error = Error;
32
33    /// Converts a `u8` value into a `ReturnCode`.
34    fn try_from(value: u8) -> Result<Self, Self::Error> {
35        let code = match value {
36            0x0 => ReturnCode(QoS::AtMostOnce),
37            0x1 => ReturnCode(QoS::AtLeastOnce),
38            0x2 => ReturnCode(QoS::ExactlyOnce),
39            _ => return Err(Error::InvalidReasonCode(value)),
40        };
41
42        Ok(code)
43    }
44}
45
46impl From<ReturnCode> for u8 {
47    /// Converts a `ReturnCode` into a `u8` value.
48    fn from(value: ReturnCode) -> Self {
49        value.0 as Self
50    }
51}
52
53suback!(ReturnCode);
54
55impl traits::SubAck for SubAck {}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use crate::codec::{Decode, Encode, PacketCodec};
61    use crate::protocol::PacketType;
62    use bytes::BytesMut;
63    use tokio_util::codec::Decoder;
64
65    #[test]
66    fn suback_decode() {
67        let mut codec = PacketCodec::new(None, None);
68
69        let data = &[
70            (PacketType::SubAck as u8) << 4, // Packet type
71            0x05,                            // Remaining len
72            0x12,                            // Packet ID
73            0x34,
74            0x00, // QoS 0
75            0x01, // QoS 1
76            0x02, // QoS 2
77        ];
78
79        let mut stream = BytesMut::new();
80
81        stream.extend_from_slice(&data[..]);
82
83        let raw_packet = codec.decode(&mut stream).unwrap().unwrap();
84        let packet = SubAck::decode(raw_packet).unwrap();
85
86        assert_eq!(
87            packet,
88            SubAck::new(
89                0x1234,
90                vec![
91                    ReturnCode(QoS::AtMostOnce),
92                    ReturnCode(QoS::AtLeastOnce),
93                    ReturnCode(QoS::ExactlyOnce)
94                ]
95            )
96        );
97    }
98
99    #[test]
100    fn suback_encode() {
101        let packet = SubAck::new(
102            0x1234,
103            vec![
104                ReturnCode(QoS::AtMostOnce),
105                ReturnCode(QoS::AtLeastOnce),
106                ReturnCode(QoS::ExactlyOnce),
107            ],
108        );
109
110        let mut stream = BytesMut::new();
111        packet.encode(&mut stream).unwrap();
112        assert_eq!(
113            stream,
114            vec![
115                (PacketType::SubAck as u8) << 4,
116                0x05,
117                0x12,
118                0x34,
119                0x00, // QoS 0
120                0x01, // QoS 1
121                0x02, // QoS 2
122            ]
123        );
124    }
125}