snops_common/format/
impl_containers.rs1use 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}