mk_codec/bytecode/
header.rs1use crate::error::{Error, Result};
18
19const VERSION_SHIFT: u8 = 4;
21
22const FINGERPRINT_FLAG_MASK: u8 = 0b0000_0100;
24
25const RESERVED_MASK: u8 = 0b0000_1011;
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub struct BytecodeHeader {
31 pub version: u8,
33 pub fingerprint_flag: bool,
35}
36
37impl BytecodeHeader {
38 pub fn parse(byte: u8) -> Result<Self> {
41 let version = byte >> VERSION_SHIFT;
42 if version != 0 {
43 return Err(Error::UnsupportedVersion(version));
44 }
45 if byte & RESERVED_MASK != 0 {
46 return Err(Error::ReservedBitsSet);
47 }
48 Ok(BytecodeHeader {
49 version,
50 fingerprint_flag: byte & FINGERPRINT_FLAG_MASK != 0,
51 })
52 }
53
54 pub fn to_byte(self) -> u8 {
56 let mut byte = (self.version & 0x0F) << VERSION_SHIFT;
57 if self.fingerprint_flag {
58 byte |= FINGERPRINT_FLAG_MASK;
59 }
60 byte
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn round_trip_no_fingerprint() {
70 let h = BytecodeHeader::parse(0x00).unwrap();
71 assert_eq!(h.version, 0);
72 assert!(!h.fingerprint_flag);
73 assert_eq!(h.to_byte(), 0x00);
74 }
75
76 #[test]
77 fn round_trip_with_fingerprint() {
78 let h = BytecodeHeader::parse(0x04).unwrap();
79 assert_eq!(h.version, 0);
80 assert!(h.fingerprint_flag);
81 assert_eq!(h.to_byte(), 0x04);
82 }
83
84 #[test]
85 fn rejects_unsupported_version() {
86 assert!(matches!(
88 BytecodeHeader::parse(0x10),
89 Err(Error::UnsupportedVersion(1)),
90 ));
91 assert!(matches!(
93 BytecodeHeader::parse(0xF0),
94 Err(Error::UnsupportedVersion(15)),
95 ));
96 }
97
98 #[test]
99 fn rejects_reserved_bit_0() {
100 assert!(matches!(
101 BytecodeHeader::parse(0b0000_0001),
102 Err(Error::ReservedBitsSet),
103 ));
104 }
105
106 #[test]
107 fn rejects_reserved_bit_1() {
108 assert!(matches!(
109 BytecodeHeader::parse(0b0000_0010),
110 Err(Error::ReservedBitsSet),
111 ));
112 }
113
114 #[test]
115 fn rejects_reserved_bit_3() {
116 assert!(matches!(
117 BytecodeHeader::parse(0b0000_1000),
118 Err(Error::ReservedBitsSet),
119 ));
120 }
121
122 #[test]
123 fn rejects_combined_reserved_bits() {
124 assert!(matches!(
126 BytecodeHeader::parse(0b0000_0101),
127 Err(Error::ReservedBitsSet),
128 ));
129 }
130}