embedded-mqtt 0.1.0

no_std encoder/decoder for MQTT 3.1.1 protocol packets for embedded devices.
Documentation
use core::result::Result;

use crate::{
    status::Status,
    fixed_header::{PacketType, PacketFlags},
    error::{DecodeError, EncodeError},
    codec::Encodable,
};

pub mod connect;
pub mod connack;
pub mod packet_identifier;
pub mod publish;

#[derive(Debug)]
pub enum VariableHeader<'a> {
    Connect(connect::Connect<'a>),
    Connack(connack::Connack),
    Subscribe(packet_identifier::PacketIdentifier),
    Suback(packet_identifier::PacketIdentifier),
    Publish(publish::Publish<'a>),
    Puback(packet_identifier::PacketIdentifier),
}

pub trait HeaderDecode<'a>
    where Self: core::marker::Sized {
    fn decode(flags: PacketFlags, bytes: &'a [u8]) -> Result<Status<(usize, Self)>, DecodeError>;
}

pub type PacketId = u16;

macro_rules! decode {
    ($($name:ident, $parser:path;)+) => (
        pub fn decode(r#type: PacketType, flags: PacketFlags, bytes: &'a [u8]) -> Option<Result<Status<(usize, Self)>, DecodeError>> {
            Some(match r#type {
                $(
                    PacketType::$name => $parser(flags, bytes).map(|s| {
                        match s {
                            Status::Complete((offset, var_header)) => {
                                Status::Complete((offset, VariableHeader::$name(var_header)))
                            },
                            Status::Partial(n) => Status::Partial(n),
                        }
                    }),
                )+
                _ => return None,
            })
        }
    )
}

impl<'a> VariableHeader<'a> {
    decode!(
        Connect,   connect::Connect::decode;
        Connack,   connack::Connack::decode;
        Subscribe, packet_identifier::PacketIdentifier::decode;
        Suback,    packet_identifier::PacketIdentifier::decode;
        Publish,   publish::Publish::decode;
        Puback,    packet_identifier::PacketIdentifier::decode;
    );
}

macro_rules! encode {
    ($($enum:ident;)+) => (
        fn encoded_len(&self) -> usize {
            match self {
                $( &VariableHeader::$enum(ref c) => c.encoded_len(), )+
            }
        }

        fn encode(&self, bytes: &mut [u8]) -> Result<usize, EncodeError> {
            match self {
                $( &VariableHeader::$enum(ref c) => c.encode(bytes), )+
            }
        }
    )
}

impl<'buf> Encodable for VariableHeader<'buf> {
    encode!(
        Connect;
        Connack;
        Subscribe;
        Suback;
        Publish;
        Puback;
    );
}