tnnl 0.1.17

tnnl gives you full control over whether and when your IoT devices should be reachable from the internet
use std::io::{Cursor, Read};

use byteorder::{LittleEndian, ReadBytesExt};

use crate::apperror::AppError;

#[derive(Debug)]
pub struct Packet {
    pub channel_id: i32,
    pub data: Vec<u8>,
}

impl Packet {
    pub fn serialize(channel_id: i32, data: &[u8]) -> Result<Vec<u8>, AppError> {
        let mut result = vec![0; 4 + data.len()];
        result[0..4].copy_from_slice(&channel_id.to_le_bytes());
        result[4..].copy_from_slice(data);
        Ok(result)
    }

    pub fn deserialize(data: &[u8]) -> Result<Packet, AppError> {
        let mut reader = Cursor::new(data);

        let channel = reader
            .read_i32::<LittleEndian>()
            .map_err(|_| AppError::new("failed to read channel_id"))?;

        let mut data = Vec::with_capacity(data.len() - 4);
        reader
            .read_to_end(&mut data)
            .map_err(|_| AppError::new("failed to read data"))?;

        Ok(Packet {
            channel_id: channel,
            data,
        })
    }
}

#[cfg(test)]
mod packet_tests {
    use super::*;

    #[test]
    fn serialize() {
        let expected: Vec<u8> = vec![135, 214, 18, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
        let packet = Packet::serialize(1234567, &[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]);
        assert_eq!(packet.unwrap(), expected);
    }

    #[test]
    fn deserialize() {
        let packet = Packet::deserialize(&[135, 214, 18, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]).unwrap();
        assert_eq!(packet.channel_id, 1234567);
        assert_eq!(packet.data, vec![9, 8, 7, 6, 5, 4, 3, 2, 1, 0]);
    }
}