pub const EVENT_META_SIZE: usize = 24;
pub const DISPATCH_RAW: u8 = 0x00;
pub const FLAG_CAUSAL: u8 = 0b0000_0001;
pub const FLAG_CONTINUITY_PROOF: u8 = 0b0000_0010;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EventMeta {
pub dispatch: u8,
pub flags: u8,
pub _pad: [u8; 2],
pub origin_hash: u64,
pub seq_or_ts: u64,
pub checksum: u32,
}
impl EventMeta {
pub fn new(dispatch: u8, flags: u8, origin_hash: u64, seq_or_ts: u64, checksum: u32) -> Self {
Self {
dispatch,
flags,
_pad: [0; 2],
origin_hash,
seq_or_ts,
checksum,
}
}
#[inline(always)]
pub fn to_bytes(&self) -> [u8; EVENT_META_SIZE] {
let mut out = [0u8; EVENT_META_SIZE];
out[0] = self.dispatch;
out[1] = self.flags;
out[4..12].copy_from_slice(&self.origin_hash.to_le_bytes());
out[12..20].copy_from_slice(&self.seq_or_ts.to_le_bytes());
out[20..24].copy_from_slice(&self.checksum.to_le_bytes());
out
}
#[expect(
clippy::expect_used,
reason = "bytes.len() >= EVENT_META_SIZE (24) checked above; fixed-offset slices convert infallibly to fixed-size arrays"
)]
#[inline(always)]
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
if bytes.len() < EVENT_META_SIZE {
return None;
}
Some(Self {
dispatch: bytes[0],
flags: bytes[1],
_pad: [bytes[2], bytes[3]],
origin_hash: u64::from_le_bytes(bytes[4..12].try_into().expect("8 bytes")),
seq_or_ts: u64::from_le_bytes(bytes[12..20].try_into().expect("8 bytes")),
checksum: u32::from_le_bytes(bytes[20..24].try_into().expect("4 bytes")),
})
}
#[inline]
pub fn has_flag(&self, bits: u8) -> bool {
self.flags & bits != 0
}
fn for_checksum_bytes(&self) -> [u8; EVENT_META_SIZE] {
let mut b = self.to_bytes();
b[20..24].copy_from_slice(&0u32.to_le_bytes());
b
}
}
#[inline]
pub fn compute_checksum(tail: &[u8]) -> u32 {
xxhash_rust::xxh3::xxh3_64(tail) as u32
}
#[inline]
pub fn compute_checksum_with_meta(meta: &EventMeta, tail: &[u8]) -> u32 {
let mut h = xxhash_rust::xxh3::Xxh3::new();
h.update(&meta.for_checksum_bytes());
h.update(tail);
h.digest() as u32
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_size_is_twenty_four() {
assert_eq!(EVENT_META_SIZE, 24);
}
#[test]
fn test_roundtrip_all_fields_distinct() {
let m = EventMeta::new(
0x42,
FLAG_CAUSAL | FLAG_CONTINUITY_PROOF,
0xDEAD_BEEF,
0x0123_4567_89AB_CDEF,
0xCAFE_BABE,
);
let bytes = m.to_bytes();
assert_eq!(bytes.len(), 24);
let decoded = EventMeta::from_bytes(&bytes).unwrap();
assert_eq!(decoded, m);
assert_eq!(decoded.dispatch, 0x42);
assert_eq!(decoded.flags, FLAG_CAUSAL | FLAG_CONTINUITY_PROOF);
assert_eq!(decoded.origin_hash, 0xDEAD_BEEF);
assert_eq!(decoded.seq_or_ts, 0x0123_4567_89AB_CDEF);
assert_eq!(decoded.checksum, 0xCAFE_BABE);
}
#[test]
fn test_regression_pad_is_zeroed_on_write() {
let m = EventMeta {
dispatch: 0x42,
flags: 0,
_pad: [0xAA, 0xBB], origin_hash: 0xDEAD_BEEF,
seq_or_ts: 1,
checksum: 0,
};
let bytes = m.to_bytes();
assert_eq!(
&bytes[2..4],
&[0u8, 0u8],
"pad bytes must be zero on write regardless of struct contents"
);
}
#[test]
fn test_zero_roundtrip() {
let m = EventMeta::new(0, 0, 0, 0, 0);
let decoded = EventMeta::from_bytes(&m.to_bytes()).unwrap();
assert_eq!(decoded, m);
}
#[test]
fn test_unknown_dispatch_decodes_fine() {
let m = EventMeta::new(0xFE, 0, 1, 2, 3);
let decoded = EventMeta::from_bytes(&m.to_bytes()).unwrap();
assert_eq!(decoded.dispatch, 0xFE);
}
#[test]
fn test_short_slice_returns_none() {
let buf = [0u8; 23];
assert!(EventMeta::from_bytes(&buf).is_none());
}
#[test]
fn test_nonzero_pad_tolerated_on_read() {
let mut bytes = [0u8; 24];
bytes[2] = 0xAA;
bytes[3] = 0xBB;
bytes[12..20].copy_from_slice(&0x1234_5678_9ABC_DEF0u64.to_le_bytes());
let decoded = EventMeta::from_bytes(&bytes).unwrap();
assert_eq!(decoded.seq_or_ts, 0x1234_5678_9ABC_DEF0);
assert_eq!(decoded._pad, [0xAA, 0xBB]);
}
#[test]
fn test_has_flag() {
let m = EventMeta::new(0, FLAG_CAUSAL, 0, 0, 0);
assert!(m.has_flag(FLAG_CAUSAL));
assert!(!m.has_flag(FLAG_CONTINUITY_PROOF));
}
#[test]
fn test_field_boundaries_isolated() {
let m = EventMeta::new(u8::MAX, u8::MAX, u64::MAX, u64::MAX, u32::MAX);
let decoded = EventMeta::from_bytes(&m.to_bytes()).unwrap();
assert_eq!(decoded, m);
}
#[test]
fn compute_checksum_with_meta_masks_checksum_slot() {
let tail = b"some payload bytes";
let m_zero = EventMeta::new(0x42, 0, 0xDEAD_BEEF, 7, 0);
let m_nonzero = EventMeta::new(0x42, 0, 0xDEAD_BEEF, 7, 0xFFFF_FFFF);
assert_eq!(
compute_checksum_with_meta(&m_zero, tail),
compute_checksum_with_meta(&m_nonzero, tail),
);
}
#[test]
fn compute_checksum_with_meta_detects_dispatch_bit_flip() {
let tail = b"unchanged payload";
let original = EventMeta::new(0x10 , 0, 0xABCD, 1, 0);
let v2 = compute_checksum_with_meta(&original, tail);
let flipped = EventMeta::new(0x11 , 0, 0xABCD, 1, 0);
let v2_after_flip = compute_checksum_with_meta(&flipped, tail);
assert_ne!(
v2, v2_after_flip,
"v2 must reflect the dispatch byte; a flip changes the checksum",
);
assert_eq!(
compute_checksum(tail),
compute_checksum(tail),
"legacy hash is tail-only; insensitive to header flips by construction",
);
}
#[test]
fn compute_checksum_with_meta_detects_all_header_flips() {
let tail = b"payload";
let base = EventMeta::new(0x10, 0, 0xAAAA, 1, 0);
let v2_base = compute_checksum_with_meta(&base, tail);
let flip_flags = EventMeta::new(0x10, FLAG_CAUSAL, 0xAAAA, 1, 0);
assert_ne!(v2_base, compute_checksum_with_meta(&flip_flags, tail));
let flip_origin = EventMeta::new(0x10, 0, 0xBBBB, 1, 0);
assert_ne!(v2_base, compute_checksum_with_meta(&flip_origin, tail));
let flip_seq = EventMeta::new(0x10, 0, 0xAAAA, 2, 0);
assert_ne!(v2_base, compute_checksum_with_meta(&flip_seq, tail));
let flip_tail = compute_checksum_with_meta(&base, b"different");
assert_ne!(v2_base, flip_tail);
}
#[test]
fn v1_and_v2_checksums_differ_for_typical_inputs() {
let m = EventMeta::new(0x01, 0, 0x1234, 5, 0);
let tail = b"non-empty payload";
assert_ne!(compute_checksum(tail), compute_checksum_with_meta(&m, tail));
}
}