snops_common/format/
impl_containers.rs

1use std::io::{Read, Write};
2
3use super::{DataFormat, DataFormatReader, DataFormatWriter, DataReadError, DataWriteError};
4
5impl<T: DataFormat> DataFormat for Option<T> {
6    type Header = T::Header;
7    const LATEST_HEADER: Self::Header = T::LATEST_HEADER;
8
9    fn write_data<W: Write>(&self, writer: &mut W) -> Result<usize, DataWriteError> {
10        Ok(match self {
11            None => writer.write(&[0u8])?,
12            Some(value) => writer.write(&[1u8])? + writer.write_data(value)?,
13        })
14    }
15
16    fn read_data<R: Read>(reader: &mut R, header: &Self::Header) -> Result<Self, DataReadError> {
17        let mut byte = [0u8; 1];
18        reader.read_exact(&mut byte)?;
19        Ok(match byte[0] {
20            0 => None,
21            1 => Some(reader.read_data(header)?),
22            _ => return Err(DataReadError::Custom("invalid Option tag".to_string())),
23        })
24    }
25}
26
27impl<T: DataFormat> DataFormat for Box<T> {
28    type Header = T::Header;
29    const LATEST_HEADER: Self::Header = T::LATEST_HEADER;
30
31    fn write_data<W: Write>(&self, writer: &mut W) -> Result<usize, DataWriteError> {
32        self.as_ref().write_data(writer)
33    }
34
35    fn read_data<R: Read>(reader: &mut R, header: &Self::Header) -> Result<Self, DataReadError> {
36        Ok(Box::new(reader.read_data(header)?))
37    }
38}
39
40#[cfg(test)]
41#[rustfmt::skip]
42mod test {
43    use crate::format::DataFormat;
44
45    macro_rules! case {
46        ($name:ident, $ty:ty, $a:expr, $b:expr) => {
47            #[test]
48            fn $name() {
49                let mut data = Vec::new();
50                let value: $ty = $a;
51                value.write_data(&mut data).unwrap();
52                assert_eq!(data, &$b);
53
54                let mut reader = &data[..];
55                let read_value = <$ty>::read_data(&mut reader, &<$ty as DataFormat>::LATEST_HEADER).unwrap();
56                assert_eq!(read_value, value);
57
58            }
59
60        };
61    }
62
63    case!(test_option_none, Option<u8>, None, [0]);
64    case!(test_option_some, Option<u8>, Some(1), [1, 1]);
65}