embedded-mqtt 0.1.0

no_std encoder/decoder for MQTT 3.1.1 protocol packets for embedded devices.
Documentation
use core::{
    cmp::min,
    convert::TryFrom,
    result::Result,
};

use crate::{
    status::Status,
    error::{DecodeError, EncodeError},
};

use super::{Decodable, Encodable};

use byteorder::{
    BigEndian,
    ByteOrder,
};

pub fn parse_u8(bytes: &[u8]) -> Result<Status<(usize, u8)>, DecodeError> {
    if bytes.len() < 1 {
        return Ok(Status::Partial(1))
    }

    Ok(Status::Complete((1, bytes[0])))
}

pub fn encode_u8(value: u8, bytes: &mut [u8]) -> Result<usize, EncodeError> {
    if bytes.len() < 1 {
        return Err(EncodeError::OutOfSpace)
    }

    bytes[0] = value;
    Ok(1)
}

pub fn parse_u16(bytes: &[u8]) -> Result<Status<(usize, u16)>, DecodeError> {
    if bytes.len() < 2 {
        return Ok(Status::Partial(2 - bytes.len()))
    }

    Ok(Status::Complete((2, BigEndian::read_u16(&bytes[0..2]))))
}

pub fn encode_u16(value: u16, bytes: &mut [u8]) -> Result<usize, EncodeError> {
    if bytes.len() < 2 {
        return Err(EncodeError::OutOfSpace)
    }

    BigEndian::write_u16(&mut bytes[0..2], value);
    Ok(2)
}

impl<'buf> Decodable<'buf> for &'buf [u8] {
    fn decode(bytes: &'buf [u8]) -> Result<Status<(usize, &'buf [u8])>, DecodeError> {
        parse_bytes(bytes)
    }
}

impl Encodable for [u8] {
    fn encoded_len(&self) -> usize {
        2 + self.len()
    }

    fn encode(&self, bytes: &mut [u8]) -> Result<usize, EncodeError> {
        encode_bytes(self, bytes)
    }
}

pub fn parse_bytes(bytes: &[u8]) -> Result<Status<(usize, &[u8])>, DecodeError> {
    let offset = 0;
    let (offset, len) = read!(parse_u16, bytes, offset);

    let available = bytes.len() - offset;
    let needed = len as usize - min(available, len as usize);
    if needed > 0 {
        return Ok(Status::Partial(needed));
    }
    let payload = &bytes[offset..offset+len as usize];

    Ok(Status::Complete((offset + len as usize, payload)))
}

pub fn encode_bytes(value: &[u8], bytes: &mut [u8]) -> Result<usize, EncodeError> {
    let size = match u16::try_from(value.len()) {
        Err(_) => return Err(EncodeError::ValueTooBig),
        Ok(s) => s,
    };

    let offset = encode_u16(size, bytes)?;

    let payload_size = value.len();
    if offset + payload_size > bytes.len() {
        return Err(EncodeError::OutOfSpace)
    }

    (&mut bytes[offset..offset + payload_size as usize]).copy_from_slice(value);

    Ok(offset + payload_size)
}