plabble-codec 0.1.0

Plabble Transport Protocol codec
Documentation
use crate::abstractions::{Serializable, SerializationError, SerializationInfo};

/// A range of slots.
///
/// # Fields
///
/// * `from` - The first slot in the range. If `None`, the range starts at the first slot.
/// * `to` - The last slot in the range. If `None`, the range ends at the last slot.
#[derive(Debug, PartialEq, Eq)]
pub struct SlotRange {
    pub from: Option<u16>,
    pub to: Option<u16>,
}

impl SlotRange {
    /// Creates a new slot range with no start and no end.
    pub fn empty() -> Self {
        Self {
            from: None,
            to: None,
        }
    }
}

impl Serializable for SlotRange {
    fn size(&self) -> usize {
        let size = if self.from.is_some() { 2 } else { 0 } + if self.to.is_some() { 2 } else { 0 };
        size as usize
    }

    fn get_bytes(&self) -> Vec<u8> {
        let mut buff = Vec::new();
        if let Some(from) = self.from {
            buff.extend_from_slice(&from.to_be_bytes());
            if let Some(to) = self.to {
                buff.extend_from_slice(&to.to_be_bytes());
            }
        }

        buff
    }

    fn from_bytes(data: &[u8], _: Option<SerializationInfo>) -> Result<Self, SerializationError>
    where
        Self: Sized,
    {
        if data.is_empty() {
            Ok(Self {
                from: None,
                to: None,
            })
        } else if data.len() % 2 != 0 {
            Err(SerializationError::TooFewBytes(1))
        } else {
            let mut from = [0u8; 2];
            from.copy_from_slice(&data[..2]);
            let from = Some(u16::from_be_bytes(from));
            Ok(Self {
                from,
                to: if data.len() > 2 {
                    let mut to = [0u8; 2];
                    to.copy_from_slice(&data[2..4]);
                    Some(u16::from_be_bytes(to))
                } else {
                    None
                },
            })
        }
    }
}

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

    #[test]
    fn can_serialize_0_slots() {
        let range = SlotRange::empty();
        assert_eq!(Vec::<u8>::new(), range.get_bytes());
    }

    #[test]
    fn can_serialize_1_slot() {
        let range = SlotRange {
            from: Some(257),
            to: None,
        };
        assert_eq!(vec![1, 1], range.get_bytes());
    }

    #[test]
    fn can_serialize_2_slots() {
        let range = SlotRange {
            from: Some(258),
            to: Some(259),
        };
        assert_eq!(vec![1, 2, 1, 3], range.get_bytes());
    }

    #[test]
    fn can_parse_0_slots() {
        let bytes = &[];
        let range = SlotRange::from_bytes(bytes, None).unwrap();
        assert_eq!(
            SlotRange {
                from: None,
                to: None
            },
            range
        );
    }

    #[test]
    fn can_parse_1_slot() {
        let bytes = &[0, 255];
        let range = SlotRange::from_bytes(bytes, None).unwrap();
        assert_eq!(
            SlotRange {
                from: Some(255),
                to: None
            },
            range
        );
    }

    #[test]
    fn can_parse_2_slots() {
        let bytes = &[255, 255, 255, 254];
        let range = SlotRange::from_bytes(bytes, None).unwrap();
        assert_eq!(
            SlotRange {
                from: Some(u16::MAX),
                to: Some(u16::MAX - 1)
            },
            range
        );
    }
}