1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//! Shared on-disk/wire header shape for batpak's fixed-prefix formats.
//!
//! Several store/wire formats (checkpoint, idempotency index, keyset, hidden
//! ranges, fork-evidence, mmap index) open with the identical 12-byte prefix:
//!
//! ```text
//! magic (6 bytes) | version (u16 LE) | crc32 (u32 LE)
//! ```
//!
//! followed by a format-specific body over which the CRC is computed. Only the
//! byte LAYOUT is centralized here. Each format keeps its own magic literal,
//! current version, version-acceptance policy (strict / range / future-version),
//! and error types — those genuinely differ between formats and MUST stay with
//! the format, so the parse helper reports a minimal [`PrefixError`] the caller
//! maps into its own error surface.
use std::ops::Range;
/// Length of the magic prefix every format leads with.
pub(crate) const MAGIC_LEN: usize = 6;
/// Byte range of the little-endian `u16` format version.
pub(crate) const VERSION_RANGE: Range<usize> = 6..8;
/// Byte range of the little-endian `u32` CRC-32 of the body.
pub(crate) const CRC_RANGE: Range<usize> = 8..12;
/// Total prefix length (`magic(6) + version(2) + crc(4)`).
pub(crate) const HEADER_LEN: usize = 12;
/// Why a prefix failed to parse. Each caller maps these to its own error so the
/// format-specific error surface is preserved.
#[derive(Debug)]
pub(crate) enum PrefixError {
/// The input is shorter than the 12-byte prefix; carries the actual length.
TooShort { len: usize },
/// The leading [`MAGIC_LEN`] bytes did not match the expected magic.
BadMagic,
}
/// A parsed 12-byte prefix plus a borrow of the body that follows it.
pub(crate) struct Prefix<'a> {
/// The little-endian `u16` version read from [`VERSION_RANGE`].
pub version: u16,
/// The little-endian `u32` CRC read from [`CRC_RANGE`].
pub stored_crc: u32,
/// The bytes after the prefix (`raw[HEADER_LEN..]`) — the CRC-covered body.
pub body: &'a [u8],
}
/// Parse the shared 12-byte prefix, checking length then magic.
///
/// The version-acceptance policy and the CRC verification stay with the caller —
/// only the fixed byte layout is centralized here.
pub(crate) fn parse<'a>(raw: &'a [u8], magic: &[u8; MAGIC_LEN]) -> Result<Prefix<'a>, PrefixError> {
if raw.len() < HEADER_LEN {
return Err(PrefixError::TooShort { len: raw.len() });
}
if raw[..MAGIC_LEN] != magic[..] {
return Err(PrefixError::BadMagic);
}
// Direct fixed-width copies (not `try_into().expect(...)`): core denies
// `clippy::expect_used`, and the length is already guaranteed by the
// `HEADER_LEN` check above. `VERSION_RANGE`/`CRC_RANGE` span exactly 2 and 4
// bytes.
let mut version_bytes = [0u8; 2];
version_bytes.copy_from_slice(&raw[VERSION_RANGE]);
let version = u16::from_le_bytes(version_bytes);
let mut crc_bytes = [0u8; 4];
crc_bytes.copy_from_slice(&raw[CRC_RANGE]);
let stored_crc = u32::from_le_bytes(crc_bytes);
Ok(Prefix {
version,
stored_crc,
body: &raw[HEADER_LEN..],
})
}
/// Build the 12-byte prefix `magic | version | crc`, ready to write or extend
/// into the output ahead of the body.
pub(crate) fn encode(magic: &[u8; MAGIC_LEN], version: u16, crc: u32) -> [u8; HEADER_LEN] {
let mut prefix = [0u8; HEADER_LEN];
prefix[..MAGIC_LEN].copy_from_slice(magic);
prefix[VERSION_RANGE].copy_from_slice(&version.to_le_bytes());
prefix[CRC_RANGE].copy_from_slice(&crc.to_le_bytes());
prefix
}
#[cfg(test)]
mod tests {
use super::{encode, parse, PrefixError, CRC_RANGE, HEADER_LEN, MAGIC_LEN, VERSION_RANGE};
const MAGIC: &[u8; MAGIC_LEN] = b"FBATXX";
#[test]
fn ranges_are_contiguous_and_total_header_len() {
assert_eq!(MAGIC_LEN, 6);
assert_eq!(VERSION_RANGE, 6..8);
assert_eq!(CRC_RANGE, 8..12);
assert_eq!(HEADER_LEN, 12);
}
#[test]
fn encode_then_parse_round_trips() {
let mut image = encode(MAGIC, 7, 0xdead_beef).to_vec();
image.extend_from_slice(b"body-bytes");
let parsed = parse(&image, MAGIC).expect("well-formed prefix must parse");
assert_eq!(parsed.version, 7);
assert_eq!(parsed.stored_crc, 0xdead_beef);
assert_eq!(parsed.body, b"body-bytes");
}
#[test]
fn rejects_short_and_bad_magic() {
assert!(matches!(
parse(&[0u8; 4], MAGIC),
Err(PrefixError::TooShort { len: 4 })
));
let mut image = encode(b"OTHER!", 1, 0).to_vec();
image.extend_from_slice(b"body");
assert!(matches!(parse(&image, MAGIC), Err(PrefixError::BadMagic)));
}
}