msgpacker 0.4.8

MessagePack protocol implementation for Rust.
Documentation
use crate::{
    helpers::{take_byte_iter, take_num_iter},
    Unpackable,
};

use super::{
    helpers::{take_byte, take_num},
    Error, Format,
};
use alloc::{string::String, vec::Vec};
use core::str;

pub fn unpack_bytes(mut buf: &[u8]) -> Result<(usize, &[u8]), Error> {
    let format = take_byte(&mut buf)?;
    let (n, len) = match format {
        Format::BIN8 => (2, take_byte(&mut buf)? as usize),
        Format::BIN16 => (3, take_num(&mut buf, u16::from_be_bytes)? as usize),
        Format::BIN32 => (5, take_num(&mut buf, u32::from_be_bytes)? as usize),
        _ => return Err(Error::UnexpectedFormatTag),
    };
    if buf.len() < len {
        return Err(Error::BufferTooShort);
    }
    Ok((n + len, &buf[..len]))
}

pub fn unpack_str(mut buf: &[u8]) -> Result<(usize, &str), Error> {
    let format = take_byte(&mut buf)?;
    let (n, len) = match format {
        0xa0..=0xbf => (1, format as usize & 0x1f),
        Format::STR8 => (2, take_byte(&mut buf)? as usize),
        Format::STR16 => (3, take_num(&mut buf, u16::from_be_bytes)? as usize),
        Format::STR32 => (5, take_num(&mut buf, u32::from_be_bytes)? as usize),
        _ => return Err(Error::UnexpectedFormatTag),
    };
    if buf.len() < len {
        return Err(Error::BufferTooShort);
    }
    let str = str::from_utf8(&buf[..len]).map_err(|_| Error::InvalidUtf8)?;
    Ok((n + len, str))
}

impl Unpackable for Vec<u8> {
    type Error = Error;

    fn unpack(buf: &[u8]) -> Result<(usize, Self), Self::Error> {
        unpack_bytes(buf).map(|(n, b)| (n, b.to_vec()))
    }

    fn unpack_iter<I>(bytes: I) -> Result<(usize, Self), Self::Error>
    where
        I: IntoIterator<Item = u8>,
    {
        let mut bytes = bytes.into_iter();
        let format = take_byte_iter(bytes.by_ref())?;
        let (n, len) = match format {
            Format::BIN8 => (2, take_byte_iter(bytes.by_ref())? as usize),
            Format::BIN16 => (
                3,
                take_num_iter(bytes.by_ref(), u16::from_be_bytes)? as usize,
            ),
            Format::BIN32 => (
                5,
                take_num_iter(bytes.by_ref(), u32::from_be_bytes)? as usize,
            ),
            _ => return Err(Error::UnexpectedFormatTag),
        };
        let v: Vec<_> = bytes.take(len).collect();
        if v.len() < len {
            return Err(Error::BufferTooShort);
        }
        Ok((n + len, v))
    }
}

impl Unpackable for String {
    type Error = Error;

    fn unpack(buf: &[u8]) -> Result<(usize, Self), Self::Error> {
        unpack_str(buf).map(|(n, s)| (n, s.into()))
    }

    fn unpack_iter<I>(bytes: I) -> Result<(usize, Self), Self::Error>
    where
        I: IntoIterator<Item = u8>,
    {
        let mut bytes = bytes.into_iter();
        let format = take_byte_iter(bytes.by_ref())?;
        let (n, len) = match format {
            0xa0..=0xbf => (1, format as usize & 0x1f),
            Format::STR8 => (2, take_byte_iter(bytes.by_ref())? as usize),
            Format::STR16 => (
                3,
                take_num_iter(bytes.by_ref(), u16::from_be_bytes)? as usize,
            ),
            Format::STR32 => (
                5,
                take_num_iter(bytes.by_ref(), u32::from_be_bytes)? as usize,
            ),
            _ => return Err(Error::UnexpectedFormatTag),
        };
        let v: Vec<_> = bytes.take(len).collect();
        if v.len() < len {
            return Err(Error::BufferTooShort);
        }
        let s = String::from_utf8(v).map_err(|_| Error::InvalidUtf8)?;
        Ok((n + len, s))
    }
}