common/serde/
key_prefix.rs1use bytes::{BufMut, Bytes, BytesMut};
29
30use super::DeserializeError;
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub struct KeyPrefix {
56 subsystem: u8,
57 version: u8,
58}
59
60pub const KEY_PREFIX_LEN: usize = 2;
62
63impl KeyPrefix {
64 pub fn new(subsystem: u8, version: u8) -> Self {
70 assert!(subsystem > 0, "subsystem 0 is reserved");
71 assert!(version > 0, "key version 0 is reserved");
72 Self { subsystem, version }
73 }
74
75 pub fn subsystem(&self) -> u8 {
77 self.subsystem
78 }
79
80 pub fn version(&self) -> u8 {
82 self.version
83 }
84
85 pub fn from_bytes(data: &[u8]) -> Result<Self, DeserializeError> {
94 if data.len() < KEY_PREFIX_LEN {
95 return Err(DeserializeError {
96 message: format!(
97 "buffer too short for key prefix: need {} bytes, got {}",
98 KEY_PREFIX_LEN,
99 data.len()
100 ),
101 });
102 }
103 let subsystem = validate_subsystem(data[0])?;
104 let version = validate_key_version(data[1])?;
105 Ok(Self { subsystem, version })
106 }
107
108 pub fn from_bytes_with_validation(
119 data: &[u8],
120 expected_subsystem: u8,
121 expected_version: u8,
122 ) -> Result<Self, DeserializeError> {
123 let prefix = Self::from_bytes(data)?;
124 if prefix.subsystem != expected_subsystem {
125 return Err(DeserializeError {
126 message: format!(
127 "invalid subsystem: expected 0x{:02x}, got 0x{:02x}",
128 expected_subsystem, prefix.subsystem
129 ),
130 });
131 }
132 if prefix.version != expected_version {
133 return Err(DeserializeError {
134 message: format!(
135 "invalid key version: expected 0x{:02x}, got 0x{:02x}",
136 expected_version, prefix.version
137 ),
138 });
139 }
140 Ok(prefix)
141 }
142
143 pub fn to_bytes(&self) -> Bytes {
145 Bytes::from(vec![self.subsystem, self.version])
146 }
147
148 pub fn write_to(&self, buf: &mut BytesMut) {
150 buf.put_u8(self.subsystem);
151 buf.put_u8(self.version);
152 }
153}
154
155fn validate_key_version(byte: u8) -> Result<u8, DeserializeError> {
156 if byte == 0 {
157 return Err(DeserializeError {
158 message: format!(
159 "invalid key version: 0x{:02x} (version 0 is reserved)",
160 byte
161 ),
162 });
163 }
164 Ok(byte)
165}
166
167fn validate_subsystem(byte: u8) -> Result<u8, DeserializeError> {
168 if byte == 0 {
169 return Err(DeserializeError {
170 message: format!(
171 "invalid subsystem: 0x{:02x} (subsystem 0 is reserved)",
172 byte
173 ),
174 });
175 }
176 Ok(byte)
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182
183 #[test]
184 fn should_create_key_prefix() {
185 let subsystem = 0x10;
187 let version = 0x01;
188
189 let prefix = KeyPrefix::new(subsystem, version);
191
192 assert_eq!(prefix.subsystem(), subsystem);
194 assert_eq!(prefix.version(), version);
195 }
196
197 #[test]
198 #[should_panic(expected = "subsystem 0 is reserved")]
199 fn should_panic_on_zero_subsystem() {
200 KeyPrefix::new(0, 0x01);
201 }
202
203 #[test]
204 #[should_panic(expected = "key version 0 is reserved")]
205 fn should_panic_on_zero_version() {
206 KeyPrefix::new(0x10, 0);
207 }
208
209 #[test]
210 fn should_parse_prefix_from_bytes() {
211 let bytes = [0x42, 0x17];
213
214 let key_prefix = KeyPrefix::from_bytes(&bytes).unwrap();
216
217 assert_eq!(key_prefix.subsystem(), 0x42);
219 assert_eq!(key_prefix.version(), 0x17);
220 }
221
222 #[test]
223 fn should_parse_prefix_ignoring_trailing_bytes() {
224 let bytes = [0x42, 0x17, 0x99, 0xAA, 0xBB];
226
227 let key_prefix = KeyPrefix::from_bytes(&bytes).unwrap();
229
230 assert_eq!(key_prefix.subsystem(), 0x42);
232 assert_eq!(key_prefix.version(), 0x17);
233 }
234
235 #[test]
236 fn should_reject_zero_subsystem_byte() {
237 let bytes = [0x00, 0x17];
239
240 let result = KeyPrefix::from_bytes(&bytes);
242
243 assert!(
245 matches!(result, Err(DeserializeError { message }) if message.contains("subsystem 0 is reserved"))
246 );
247 }
248
249 #[test]
250 fn should_reject_zero_version_byte() {
251 let bytes = [0x53, 0x00];
253
254 let result = KeyPrefix::from_bytes(&bytes);
256
257 assert!(
259 matches!(result, Err(DeserializeError { message }) if message.contains("version 0 is reserved"))
260 );
261 }
262
263 #[test]
264 fn should_write_and_read_key_prefix() {
265 let prefix = KeyPrefix::new(0x10, 0x01);
267 let mut buf = BytesMut::new();
268
269 prefix.write_to(&mut buf);
271 let parsed = KeyPrefix::from_bytes(&buf).unwrap();
272
273 assert_eq!(parsed, prefix);
275 }
276
277 #[test]
278 fn should_serialize_key_prefix_to_bytes() {
279 let prefix = KeyPrefix::new(0x10, 0x01);
281
282 let bytes = prefix.to_bytes();
284
285 assert_eq!(bytes.len(), KEY_PREFIX_LEN);
287 assert_eq!(bytes[0], 0x10);
288 assert_eq!(bytes[1], 0x01);
289 }
290
291 #[test]
292 fn should_parse_key_prefix_with_validation() {
293 let expected_subsystem = 0x10;
295 let expected_version = 0x01;
296 let data = [expected_subsystem, expected_version];
297
298 let prefix =
300 KeyPrefix::from_bytes_with_validation(&data, expected_subsystem, expected_version)
301 .unwrap();
302
303 assert_eq!(prefix.subsystem(), expected_subsystem);
305 assert_eq!(prefix.version(), expected_version);
306 }
307
308 #[test]
309 fn should_reject_wrong_subsystem() {
310 let data = [0x10, 0x01];
312
313 let result = KeyPrefix::from_bytes_with_validation(&data, 0x20, 0x01);
315
316 assert!(
318 matches!(result, Err(DeserializeError { message }) if message.contains("invalid subsystem"))
319 );
320 }
321
322 #[test]
323 fn should_reject_wrong_version() {
324 let data = [0x10, 0x02]; let result = KeyPrefix::from_bytes_with_validation(&data, 0x10, 0x01);
329
330 assert!(
332 matches!(result, Err(DeserializeError { message }) if message.contains("invalid key version"))
333 );
334 }
335
336 #[test]
337 fn should_reject_short_buffer() {
338 let data = [0x01]; let result = KeyPrefix::from_bytes(&data);
343
344 assert!(
346 matches!(result, Err(DeserializeError { message }) if message.contains("buffer too short"))
347 );
348 }
349}