serde_sbif/
lib.rs

1use std::io::{Read, Write};
2
3use byteorder::{ReadBytesExt, WriteBytesExt};
4use err_derive::Error;
5
6pub(crate) type ByteOrder = byteorder::BigEndian;
7
8mod de;
9mod se;
10
11pub use crate::de::{from_reader, from_slice, Deserializer};
12pub use crate::se::{to_bytes, to_writer, Serializer};
13
14pub type Result<T> = std::result::Result<T, Error>;
15
16pub(crate) mod data_ids {
17    pub const NULL_ID: u8 = 0;
18    pub const BOOL_ID: u8 = 1;
19    pub const I8_ID: u8 = 2;
20    pub const I16_ID: u8 = 3;
21    pub const I32_ID: u8 = 4;
22    pub const I64_ID: u8 = 5;
23    pub const U8_ID: u8 = 6;
24    pub const U16_ID: u8 = 7;
25    pub const U32_ID: u8 = 8;
26    pub const U64_ID: u8 = 9;
27    pub const F32_ID: u8 = 10;
28    pub const F64_ID: u8 = 11;
29    pub const CHAR_ID: u8 = 12;
30    pub const STR_ID: u8 = 13;
31    pub const BYTES_ID: u8 = 14;
32    pub const SEQ_ID: u8 = 15;
33    pub const TUPLE_ID: u8 = 16;
34    pub const UNIT_VARIANT_ID: u8 = 17;
35    pub const ENUM_VARIANT_ID: u8 = 18;
36    pub const TUPLE_STRUCT_ID: u8 = 19;
37    pub const MAP_ID: u8 = 20;
38}
39
40#[derive(Debug, Error)]
41pub enum Error {
42    #[error(display = "IO error: {}", _0)]
43    IoError(#[source] std::io::Error),
44    #[error(display = "From utf8 error: {}", _0)]
45    FromUtf8Error(#[source] std::string::FromUtf8Error),
46    #[error(display = "'{}' is not a valid compression format", _0)]
47    InvalidCompression(u8),
48    #[error(display = "{}", _0)]
49    Custom(String),
50    #[error(display = "Lengths are required for the sbif format")]
51    LengthRequired,
52    #[error(display = "Unexpected string")]
53    UnexpectedString,
54    #[error(
55        display = "Invalid access order. You cannot access 2 map keys or 2 map values in a row"
56    )]
57    InvalidMapAccess,
58    #[error(display = "Invalid sbif header: expected 'SBIF', found {}", _0)]
59    InvalidHeader(String),
60    #[error(display = "Invalid data id: expected {}, found {}", expected, found)]
61    InvalidDataId { expected: String, found: u8 },
62    #[error(
63        display = "Invalid sbif version: expected {}, found {}",
64        expected,
65        found
66    )]
67    InvalidVersion { expected: u8, found: u8 },
68    #[error(display = "{}: expected {}, actual {}", message, expected, actual)]
69    InvalidLength {
70        expected: usize,
71        actual: usize,
72        message: String,
73    },
74}
75
76impl serde::ser::Error for Error {
77    fn custom<T>(msg: T) -> Self
78    where
79        T: std::fmt::Display,
80    {
81        Self::Custom(msg.to_string())
82    }
83}
84
85impl serde::de::Error for Error {
86    fn custom<T>(msg: T) -> Self
87    where
88        T: std::fmt::Display,
89    {
90        Self::Custom(msg.to_string())
91    }
92}
93
94/// The compression format and level used for the sbif file
95#[derive(Debug, Clone, Copy, PartialEq, Eq)]
96pub enum Compression {
97    None,
98    Deflate(u32),
99    GZip(u32),
100    ZLib(u32),
101}
102
103impl Default for Compression {
104    fn default() -> Self {
105        Self::GZip(6)
106    }
107}
108
109pub(crate) struct FileHeader {
110    pub(crate) compression: Compression,
111    pub(crate) version: u8,
112    pub(crate) header_name: String,
113}
114
115impl Default for FileHeader {
116    fn default() -> Self {
117        Self::new(Compression::default())
118    }
119}
120
121impl FileHeader {
122    pub fn new(compression: Compression) -> Self {
123        Self {
124            compression,
125            version: 1,
126            header_name: String::from("SBIF"),
127        }
128    }
129
130    pub fn to_writer<W: Write>(&self, writer: &mut W) -> Result<()> {
131        let name_bytes = self.header_name.as_bytes();
132        writer
133            .write_u16::<ByteOrder>(name_bytes.len() as u16)
134            .map_err(Error::IoError)?;
135        writer.write(name_bytes).map_err(Error::IoError)?;
136        writer.write_u8(self.version).map_err(Error::IoError)?;
137
138        match self.compression {
139            Compression::None => writer.write_u8(0).map_err(Error::IoError)?,
140            Compression::Deflate(v) => {
141                writer.write_u8(1).map_err(Error::IoError)?;
142                writer.write_u32::<ByteOrder>(v).map_err(Error::IoError)?;
143            }
144            Compression::GZip(v) => {
145                writer.write_u8(2).map_err(Error::IoError)?;
146                writer.write_u32::<ByteOrder>(v).map_err(Error::IoError)?;
147            }
148            Compression::ZLib(v) => {
149                writer.write_u8(3).map_err(Error::IoError)?;
150                writer.write_u32::<ByteOrder>(v).map_err(Error::IoError)?;
151            }
152        };
153
154        Ok(())
155    }
156
157    #[cfg(test)]
158    pub fn to_bytes(&self) -> Result<Vec<u8>> {
159        let mut buffer = Vec::new();
160        self.to_writer(&mut buffer)?;
161        Ok(buffer)
162    }
163
164    pub fn from_reader<R: Read>(reader: &mut R) -> Result<Self> {
165        let header_name = {
166            let name_length = reader.read_u16::<ByteOrder>().map_err(Error::IoError)? as usize;
167            let mut buffer = vec![0_u8; name_length];
168            reader.read_exact(&mut buffer).map_err(Error::IoError)?;
169            String::from_utf8(buffer).map_err(Error::FromUtf8Error)?
170        };
171
172        let version = reader.read_u8().map_err(Error::IoError)?;
173        let compression = match reader.read_u8().map_err(Error::IoError)? {
174            0 => Compression::None,
175            1 => Compression::Deflate(reader.read_u32::<ByteOrder>().map_err(Error::IoError)?),
176            2 => Compression::GZip(reader.read_u32::<ByteOrder>().map_err(Error::IoError)?),
177            3 => Compression::ZLib(reader.read_u32::<ByteOrder>().map_err(Error::IoError)?),
178            v => return Err(Error::InvalidCompression(v)),
179        };
180
181        Ok(Self {
182            compression,
183            version,
184            header_name,
185        })
186    }
187}