mqute-codec 0.4.2

A full-featured implementation of MQTT protocol serialization in Rust, supporting versions 3.1, 3.1.1 and 5.0.
Documentation
//! # SubAck Packet V4
//!
//! This module initializes the `SubAck` packet for MQTT protocol.
//! It uses the `suback!` macro to define the `SubAck` packet structure.

use crate::Error;
use crate::protocol::common::suback;
use crate::protocol::{QoS, traits};

/// Represents the return codes for a `SubAck` packet.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ReturnCode {
    /// Indicates a successful subscription with the granted QoS level.
    Success(QoS),

    /// Indicates that the subscription failed.
    Failure,
}

impl TryFrom<u8> for ReturnCode {
    type Error = Error;

    /// Converts a `u8` value into a `ReturnCode`.
    fn try_from(value: u8) -> Result<Self, Self::Error> {
        let code = match value {
            0x0 => ReturnCode::Success(QoS::AtMostOnce),
            0x1 => ReturnCode::Success(QoS::AtLeastOnce),
            0x2 => ReturnCode::Success(QoS::ExactlyOnce),
            0x80 => ReturnCode::Failure,
            _ => return Err(Error::InvalidReasonCode(value)),
        };

        Ok(code)
    }
}

impl From<ReturnCode> for u8 {
    /// Converts a `ReturnCode` into a `u8` value.
    fn from(value: ReturnCode) -> Self {
        match value {
            ReturnCode::Success(qos) => qos as u8,
            ReturnCode::Failure => 0x80,
        }
    }
}

// Defines the `SubAck` packet
suback!(ReturnCode);

impl traits::SubAck for SubAck {}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::codec::{Decode, Encode, PacketCodec};
    use crate::protocol::PacketType;
    use bytes::BytesMut;
    use tokio_util::codec::Decoder;

    #[test]
    fn suback_decode() {
        let mut codec = PacketCodec::new(None, None);

        let data = &[
            (PacketType::SubAck as u8) << 4, // Packet type
            0x04,                            // Remaining len
            0x12,                            // Packet ID
            0x34,
            0x02, // Success
            0x80, // Failure
        ];

        let mut stream = BytesMut::new();

        stream.extend_from_slice(&data[..]);

        let raw_packet = codec.decode(&mut stream).unwrap().unwrap();
        let packet = SubAck::decode(raw_packet).unwrap();

        assert_eq!(
            packet,
            SubAck::new(
                0x1234,
                vec![ReturnCode::Success(QoS::ExactlyOnce), ReturnCode::Failure]
            )
        );
    }

    #[test]
    fn suback_encode() {
        let packet = SubAck::new(
            0x1234,
            vec![ReturnCode::Success(QoS::ExactlyOnce), ReturnCode::Failure],
        );

        let mut stream = BytesMut::new();
        packet.encode(&mut stream).unwrap();
        assert_eq!(
            stream,
            vec![
                (PacketType::SubAck as u8) << 4,
                0x04,
                0x12,
                0x34,
                0x02,
                0x80
            ]
        );
    }
}