open-archery-format 0.1.1

An open source binary file format for archery scoring
Documentation
use std::string::FromUtf8Error;

#[derive(Debug, Clone)]
pub enum BufferError {
    BufferEmpty,
    InvalidUtf8String(FromUtf8Error),
    UsizeTooBig,
}

/// Internal method for converting the lower two bytes of a usize to a Vec<u8>
fn usize_as_u16_as_bytes(len: usize) -> Result<Vec<u8>, BufferError> {
    if len > u16::MAX as usize {
        Err(BufferError::UsizeTooBig)
    } else {
        Ok((len as u16).to_le_bytes().to_vec())
    }
}

#[derive(Debug)]
pub struct Buffer {
    v: Vec<u8>,
}

impl PartialEq<Self> for Buffer {
    fn eq(&self, other: &Self) -> bool {
        self.v == other.v
    }
}

impl PartialEq<Vec<u8>> for Buffer {
    fn eq(&self, other: &Vec<u8>) -> bool {
        self.v == *other
    }
}

impl Buffer {
    /// Returns a Buffer with an empty underlying Vec<u8>
    pub fn new() -> Buffer {
        Buffer {
            v: vec!(),
        }
    }

    /// Returns a Buffer with the provided Vec<u8> as the underlying structure
    pub fn from(v: Vec<u8>) -> Buffer {
        Buffer {
            v,
        }
    }

    pub fn length(&self) -> usize {
        self.v.len()
    }

    pub fn take_underlying_buffer(self) -> Vec<u8> {
        self.v
    }

    /// Appends the lower two bytes of the given usize to the Buffer
    pub fn append_usize(&mut self, len: usize) -> Result<(), BufferError> {
        self.v.append(&mut usize_as_u16_as_bytes(len)?);
        Ok(())
    }

    pub fn append_string(&mut self, str: &String) -> Result<(), BufferError> {
        let b = str.as_bytes();
        self.append_usize(b.len())?;
        self.v.extend_from_slice(b);
        Ok(())
    }

    pub fn append(&mut self, b: &mut Buffer) {
        self.v.append(&mut b.v);
    }

    pub fn append_u16(&mut self, n: u16) {
        self.v.extend_from_slice(&n.to_le_bytes());
    }

    pub fn append_u32(&mut self, n: u32) {
        self.v.extend_from_slice(&n.to_le_bytes());
    }

    pub fn append_u64(&mut self, n: u64) {
        self.v.extend_from_slice(&n.to_le_bytes());
    }

    pub fn append_f32(&mut self, n: f32) {
        self.v.extend_from_slice(&n.to_le_bytes());
    }

    pub fn append_u8(&mut self, n: u8) {
        self.v.extend_from_slice(&n.to_le_bytes());
    }

    pub fn pop_n_bytes(&mut self, n: usize) -> Result<Vec<u8>, BufferError> {
        let mut res = vec![];

        for i in 0..n {
            let ob = self.v.get(i);
            match ob {
                None => return Err(BufferError::BufferEmpty),
                Some(b) => res.push(*b),
            }
        }
        self.v = self.v.split_at(res.len()).1.to_vec();
        Ok(res)
    }

    pub fn pop_usize(&mut self) -> Result<usize, BufferError> {
        let bytes = self.pop_n_bytes(2)?;
        Ok(u16::from_le_bytes(bytes.try_into().unwrap()) as usize)
    }

    pub fn pop_string(&mut self) -> Result<String, BufferError> {
        let len = self.pop_usize()?;
        match String::from_utf8(self.pop_n_bytes(len)?) {
            Ok(str) => Ok(str),
            Err(e) => Err(BufferError::InvalidUtf8String(e)),
        }
    }

    pub fn pop_u16(&mut self) -> Result<u16, BufferError> {
        let bytes = self.pop_n_bytes(2)?;
        Ok(u16::from_le_bytes(bytes.try_into().unwrap()))
    }

    pub fn pop_u32(&mut self) -> Result<u32, BufferError> {
        let bytes = self.pop_n_bytes(4)?;
        Ok(u32::from_le_bytes(bytes.try_into().unwrap()))
    }

    pub fn pop_u64(&mut self) -> Result<u64, BufferError> {
        let bytes = self.pop_n_bytes(8)?;
        Ok(u64::from_le_bytes(bytes.try_into().unwrap()))
    }

    pub fn pop_f32(&mut self) -> Result<f32, BufferError> {
        let bytes = self.pop_n_bytes(4)?;
        Ok(f32::from_le_bytes(bytes.try_into().unwrap()))
    }

    pub fn pop_u8(&mut self) -> Result<u8, BufferError> {
        let bytes = self.pop_n_bytes(1)?;
        Ok(u8::from_le_bytes(bytes.try_into().unwrap()))
    }
}

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

    #[test]
    fn test_buffer_usize() {
        let mut buf = Buffer::new();
        buf.append_usize(5).unwrap();

        assert_eq!(5, buf.pop_usize().unwrap());
    }

    #[test]
    fn test_buffer_string() {
        let mut buf = Buffer::new();
        buf.append_string(&"test".to_string()).unwrap();

        assert_eq!("test", buf.pop_string().unwrap());
    }

    #[test]
    fn test_buffer_u32() {
        let mut buf = Buffer::new();
        buf.append_u32(7);

        assert_eq!(7, buf.pop_u32().unwrap());
    }

    #[test]
    fn test_buffer_f32() {
        let mut buf = Buffer::new();
        buf.append_f32(7.0);

        assert_eq!(7.0, buf.pop_f32().unwrap());
    }

    #[test]
    fn test_buffer_u8() {
        let mut buf = Buffer::new();
        buf.append_u8(15);

        assert_eq!(15, buf.pop_u8().unwrap());
    }

    #[test]
    fn test_buffer_buffer() {
        let mut buf = Buffer::new();
        let mut other = Buffer {
            v: vec![1,2,3,4],
        };

        buf.append(&mut other);

        assert_eq!(vec![1,2,3], buf.pop_n_bytes(3).unwrap());
    }
}