plabble-codec 0.1.0

Plabble Transport Protocol codec
Documentation
use std::collections::HashMap;

use itertools::Itertools;

use crate::abstractions::{Serializable, SerializationError, SerializationInfo};

use super::{assert_len, dyn_int};

/// A slot body is a map of slot indices to data.
pub type SlotBody = HashMap<u16, Vec<u8>>;

impl Serializable for SlotBody {
    /// Returns the size of the serialized data in bytes.
    fn size(&self) -> usize {
        self.iter()
            .map(|s| 2 + s.1.len() + dyn_int::encoded_size(s.1.len() as u128))
            .sum::<usize>()
    }

    /// Serializes the data into a vector of bytes.
    fn get_bytes(&self) -> Vec<u8> {
        let mut buff = Vec::new();
        for (idx, data) in self.iter().sorted() {
            buff.extend_from_slice(&idx.to_be_bytes());
            buff.append(&mut dyn_int::encode(data.len() as u128));
            buff.extend_from_slice(data);
        }
        buff
    }

    /// Deserializes the data from a vector of bytes.
    fn from_bytes(data: &[u8], _: Option<SerializationInfo>) -> Result<Self, SerializationError>
    where
        Self: Sized,
    {
        let mut slots: HashMap<u16, Vec<u8>> = HashMap::new();
        let mut bytes_read = 0;
        while bytes_read != data.len() {
            assert_len(data, bytes_read + 3)?;
            let mut idx = [0u8; 2];
            idx.copy_from_slice(&data[bytes_read..(bytes_read + 2)]);
            let idx = u16::from_be_bytes(idx);
            bytes_read += 2;
            let (data_len, read) = dyn_int::read_from_slice(&data[bytes_read..])?;
            bytes_read += read;
            assert_len(data, bytes_read + data_len as usize)?;
            let data = data[bytes_read..(bytes_read + data_len as usize)].to_vec();
            bytes_read += data_len as usize;
            let _ = slots.insert(idx, data);
        }

        Ok(slots)
    }
}

#[cfg(test)]
mod test {
    use crate::abstractions::Serializable;

    use super::SlotBody;

    #[test]
    fn can_serialize_slot_body() {
        let mut slots = SlotBody::new();
        slots.insert(0, vec![0u8; 10]);
        slots.insert(5, vec![1u8; 5]);

        let bytes = slots.get_bytes();
        assert_eq!(
            vec![0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 1, 1, 1, 1, 1],
            bytes
        );
    }

    #[test]
    fn can_deserialize_slot_body() {
        let bytes = vec![0, 7, 3, 1, 2, 3, 0, 12, 5, 1, 1, 1, 1, 1];
        let slots = SlotBody::from_bytes(&bytes, None).unwrap();
        assert_eq!(&vec![1, 1, 1, 1, 1], slots.get(&12).unwrap());
        assert_eq!(&vec![1, 2, 3], slots.get(&7).unwrap());
    }
}