snops-common 0.1.0

Common types and utilities for snops
Documentation
use std::io::{Read, Write};

use super::{DataFormat, DataFormatReader, DataFormatWriter, DataReadError, DataWriteError};

impl<T: DataFormat> DataFormat for Option<T> {
    type Header = T::Header;
    const LATEST_HEADER: Self::Header = T::LATEST_HEADER;

    fn write_data<W: Write>(&self, writer: &mut W) -> Result<usize, DataWriteError> {
        Ok(match self {
            None => writer.write(&[0u8])?,
            Some(value) => writer.write(&[1u8])? + writer.write_data(value)?,
        })
    }

    fn read_data<R: Read>(reader: &mut R, header: &Self::Header) -> Result<Self, DataReadError> {
        let mut byte = [0u8; 1];
        reader.read_exact(&mut byte)?;
        Ok(match byte[0] {
            0 => None,
            1 => Some(reader.read_data(header)?),
            _ => return Err(DataReadError::Custom("invalid Option tag".to_string())),
        })
    }
}

impl<T: DataFormat> DataFormat for Box<T> {
    type Header = T::Header;
    const LATEST_HEADER: Self::Header = T::LATEST_HEADER;

    fn write_data<W: Write>(&self, writer: &mut W) -> Result<usize, DataWriteError> {
        self.as_ref().write_data(writer)
    }

    fn read_data<R: Read>(reader: &mut R, header: &Self::Header) -> Result<Self, DataReadError> {
        Ok(Box::new(reader.read_data(header)?))
    }
}

#[cfg(test)]
#[rustfmt::skip]
mod test {
    use crate::format::DataFormat;

    macro_rules! case {
        ($name:ident, $ty:ty, $a:expr, $b:expr) => {
            #[test]
            fn $name() {
                let mut data = Vec::new();
                let value: $ty = $a;
                value.write_data(&mut data).unwrap();
                assert_eq!(data, &$b);

                let mut reader = &data[..];
                let read_value = <$ty>::read_data(&mut reader, &<$ty as DataFormat>::LATEST_HEADER).unwrap();
                assert_eq!(read_value, value);

            }

        };
    }

    case!(test_option_none, Option<u8>, None, [0]);
    case!(test_option_some, Option<u8>, Some(1), [1, 1]);
}