1use crate::{FormatError, magic::MAGIC, version::Version};
2
3pub const HEADER_SIZE: usize = 8;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct Header {
9 version: Version,
10}
11
12impl Header {
13 pub const SIZE: usize = HEADER_SIZE;
14
15 pub const fn new(version: Version) -> Self {
16 Self { version }
17 }
18
19 pub const fn current() -> Self {
20 Self::new(Version::CURRENT)
21 }
22
23 pub const fn version(self) -> Version {
24 self.version
25 }
26
27 pub fn encode(self) -> [u8; HEADER_SIZE] {
28 let mut bytes = [0_u8; HEADER_SIZE];
29
30 bytes[0..4].copy_from_slice(&MAGIC);
31 bytes[4..6].copy_from_slice(&self.version.major().to_le_bytes());
32 bytes[6..8].copy_from_slice(&self.version.minor().to_le_bytes());
33
34 bytes
35 }
36
37 pub fn decode(bytes: &[u8]) -> Result<Self, FormatError> {
38 if bytes.len() != Self::SIZE {
39 return Err(FormatError::UnexpectedRecordSize {
40 record: "LXDB header",
41 expected: Self::SIZE,
42 found: bytes.len(),
43 });
44 }
45
46 if bytes[0..4] != MAGIC {
47 return Err(FormatError::InvalidHeader);
48 }
49
50 let major = u16::from_le_bytes(
51 bytes[4..6].try_into().expect("major version must occupy two bytes"),
52 );
53
54 let minor = u16::from_le_bytes(
55 bytes[6..8].try_into().expect("minor version must occupy two bytes"),
56 );
57
58 Ok(Self::new(Version::new(major, minor)))
59 }
60}
61
62impl Default for Header {
63 fn default() -> Self {
64 Self::current()
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::{HEADER_SIZE, Header};
71 use crate::magic::MAGIC;
72
73 #[test]
74 fn encodes_current_header() {
75 let bytes = Header::current().encode();
76
77 assert_eq!(bytes.len(), HEADER_SIZE);
78 assert_eq!(&bytes[0..4], &MAGIC);
79 assert_eq!(u16::from_le_bytes([bytes[4], bytes[5]]), 0);
80 assert_eq!(u16::from_le_bytes([bytes[6], bytes[7]]), 1);
81 }
82
83 #[test]
84 fn encodes_custom_version() {
85 let bytes = Header::new(crate::version::Version::new(2, 7)).encode();
86
87 assert_eq!(u16::from_le_bytes([bytes[4], bytes[5]]), 2);
88 assert_eq!(u16::from_le_bytes([bytes[6], bytes[7]]), 7);
89 }
90}