dmxparser 0.1.0

Reading the Valve Data Model eXchange (DMX) format
Documentation
use std::{
    io::BufRead,
    mem::swap,
    ops::Deref,
    os::raw::{c_char, c_float, c_int},
    str::from_utf8,
};

use anyhow::{anyhow, Context, Error, Result};

pub trait Reader {
    type Buffer: Deref<Target = [u8]>;
    type String: Readable<Self> + ReaderString;
    fn read_into(&mut self, buf: &mut [u8]) -> Result<()>;
    fn read_bytes(&mut self, size: usize) -> Result<Self::Buffer>;
    fn read_until(&mut self, predicate: u8) -> Result<Self::Buffer>;
}

pub struct Slice<'a>(pub &'a [u8]);

impl<'a> Reader for Slice<'a> {
    type Buffer = &'a [u8];
    type String = &'a str;

    fn read_into(&mut self, buf: &mut [u8]) -> Result<()> {
        let (head, tail) = self.0.split_at(buf.len());
        buf.copy_from_slice(head);
        self.0 = tail;
        Ok(())
    }

    fn read_bytes(&mut self, size: usize) -> Result<&'a [u8]> {
        let (head, tail) = self.0.split_at(size);
        self.0 = tail;
        Ok(head)
    }

    fn read_until(&mut self, predicate: u8) -> Result<&'a [u8]> {
        let index = self
            .0
            .iter()
            .position(|byte| *byte == predicate)
            .ok_or_else(|| anyhow!("Delimiter {:?} not found in {:?}", predicate, self.0))?;

        let (head, tail) = self.0.split_at(index + 1);
        self.0 = tail;
        Ok(head)
    }
}

impl<R: BufRead> Reader for R {
    type Buffer = Vec<u8>;
    type String = String;

    fn read_into(&mut self, buf: &mut [u8]) -> Result<()> {
        self.read_exact(buf)?;
        Ok(())
    }

    fn read_bytes(&mut self, size: usize) -> Result<Vec<u8>> {
        let mut buffer = vec![0; size];
        self.read_exact(&mut buffer)?;
        Ok(buffer)
    }

    fn read_until(&mut self, predicate: u8) -> Result<Vec<u8>> {
        let mut buffer = Vec::new();
        self.read_until(predicate, &mut buffer)?;
        Ok(buffer)
    }
}

pub trait ReaderString: Deref<Target = str> {
    fn split(&mut self, index: usize) -> Self;
}

impl<'a> ReaderString for &'a str {
    fn split(&mut self, index: usize) -> Self {
        let (head, tail) = self.split_at(index);
        *self = tail;
        head
    }
}

impl ReaderString for String {
    fn split(&mut self, index: usize) -> Self {
        let mut tail = self.split_off(index);
        swap(&mut tail, self);
        tail
    }
}

pub trait Readable<R: ?Sized>
where
    Self: Sized,
{
    fn read(reader: &mut R) -> Result<Self>;
}

macro_rules! impl_from_bytes {
    ( $ty:ty ) => {
        impl<R: Reader> Readable<R> for $ty {
            fn read(reader: &mut R) -> anyhow::Result<Self> {
                let mut bytes = [0; std::mem::size_of::<$ty>()];
                reader.read_into(&mut bytes)?;
                Ok(<$ty>::from_le_bytes(bytes))
            }
        }
    };
}

impl_from_bytes!(u8);
impl_from_bytes!(c_char);
impl_from_bytes!(c_int);
impl_from_bytes!(c_float);
impl_from_bytes!(u64);

impl<'a, R: Reader<Buffer = &'a [u8]>> Readable<R> for &'a str {
    fn read(reader: &mut R) -> Result<Self> {
        let bytes = reader.read_until(0)?;
        let bytes = &bytes[..bytes.len() - 1];
        from_utf8(bytes)
            .with_context(|| format!("Could not read utf-8 string from bytes {:?}", bytes))
    }
}

impl<'a, R: Reader<Buffer = Vec<u8>>> Readable<R> for String {
    fn read(reader: &mut R) -> Result<Self> {
        let mut vec = reader.read_until(0)?;
        vec.pop().unwrap();

        String::from_utf8(vec).map_err(|err| {
            let utf8_error = err.utf8_error();
            let message = format!(
                "Could not read utf-8 string from bytes {:?}",
                err.into_bytes()
            );

            Error::new(utf8_error).context(message)
        })
    }
}