1use byteorder::WriteBytesExt;
6
7#[derive(Copy, Clone, Debug, Eq, PartialEq)]
9pub enum Version {
10 V1,
12}
13
14impl std::fmt::Display for Version {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 write!(f, "{}", u8::from(*self))
17 }
18}
19
20impl From<Version> for u8 {
21 fn from(value: Version) -> Self {
22 match value {
23 Version::V1 => 1,
24 }
25 }
26}
27
28impl TryFrom<u8> for Version {
29 type Error = ();
30 fn try_from(value: u8) -> Result<Self, Self::Error> {
31 match value {
32 1 => Ok(Self::V1),
33 _ => Err(()),
34 }
35 }
36}
37
38const MAGIC_BYTES: [u8; 3] = [b'V', b'L', b'G'];
39
40impl Version {
41 #[allow(unused)]
43 pub(crate) fn len() -> u8 {
44 5
45 }
46
47 pub(crate) fn parse_file_header(bytes: &[u8]) -> Option<Self> {
48 let first_three = bytes.get(0..3)?;
49
50 if first_three == MAGIC_BYTES {
51 let version = *bytes.get(3)?;
52 let version = Self::try_from(version).ok()?;
53
54 Some(version)
55 } else {
56 None
57 }
58 }
59
60 pub(crate) fn write_file_header<W: std::io::Write>(
61 self,
62 writer: &mut W,
63 ) -> std::io::Result<usize> {
64 writer.write_all(&MAGIC_BYTES)?;
65 writer.write_u8(u8::from(self))?;
66 Ok(5)
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73 use test_log::test;
74
75 #[test]
76 #[allow(clippy::expect_used)]
77 pub fn version_serialize() -> crate::Result<()> {
78 let mut bytes = vec![];
79 Version::V1.write_file_header(&mut bytes)?;
80 assert_eq!(bytes, &[b'V', b'L', b'G', 1]);
81 Ok(())
82 }
83
84 #[test]
85 #[allow(clippy::expect_used)]
86 pub fn version_deserialize_success() {
87 let version = Version::parse_file_header(&[b'V', b'L', b'G', 1]);
88 assert_eq!(version, Some(Version::V1));
89 }
90
91 #[test]
92 #[allow(clippy::expect_used)]
93 pub fn version_deserialize_fail() {
94 let version = Version::parse_file_header(&[b'F', b'J', b'X', 1]);
95 assert!(version.is_none());
96 }
97
98 #[test]
99 #[allow(clippy::expect_used)]
100 pub fn version_serde_round_trip() {
101 let mut buf = vec![];
102 Version::V1.write_file_header(&mut buf).expect("can't fail");
103
104 let version = Version::parse_file_header(&buf);
105 assert_eq!(version, Some(Version::V1));
106 }
107
108 #[test]
109 #[allow(clippy::expect_used)]
110 pub fn version_len() {
111 let mut buf = vec![];
112 let size = Version::V1.write_file_header(&mut buf).expect("can't fail");
113 assert_eq!(Version::len() as usize, size);
114 }
115}