#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct SegmentHeader {
pub magic: u32,
pub version: u8,
pub seg_type: u8,
pub flags: u16,
pub segment_id: u64,
pub payload_length: u64,
pub timestamp_ns: u64,
pub checksum_algo: u8,
pub compression: u8,
pub reserved_0: u16,
pub reserved_1: u32,
pub content_hash: [u8; 16],
pub uncompressed_len: u32,
pub alignment_pad: u32,
}
const _: () = assert!(core::mem::size_of::<SegmentHeader>() == 64);
impl SegmentHeader {
pub const fn new(seg_type: u8, segment_id: u64) -> Self {
Self {
magic: crate::constants::SEGMENT_MAGIC,
version: crate::constants::SEGMENT_VERSION,
seg_type,
flags: 0,
segment_id,
payload_length: 0,
timestamp_ns: 0,
checksum_algo: 0,
compression: 0,
reserved_0: 0,
reserved_1: 0,
content_hash: [0u8; 16],
uncompressed_len: 0,
alignment_pad: 0,
}
}
#[inline]
pub const fn is_valid_magic(&self) -> bool {
self.magic == crate::constants::SEGMENT_MAGIC
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::constants::SEGMENT_MAGIC;
#[test]
fn header_size_is_64() {
assert_eq!(core::mem::size_of::<SegmentHeader>(), 64);
}
#[test]
fn header_alignment() {
assert!(core::mem::align_of::<SegmentHeader>() <= 64);
}
#[test]
fn new_header_has_valid_magic() {
let h = SegmentHeader::new(0x01, 42);
assert!(h.is_valid_magic());
assert_eq!(h.magic, SEGMENT_MAGIC);
assert_eq!(h.seg_type, 0x01);
assert_eq!(h.segment_id, 42);
}
#[test]
fn field_offsets() {
let h = SegmentHeader::new(0x01, 0);
let base = &h as *const _ as usize;
let magic_off = &h.magic as *const _ as usize - base;
let version_off = &h.version as *const _ as usize - base;
let seg_type_off = &h.seg_type as *const _ as usize - base;
let flags_off = &h.flags as *const _ as usize - base;
let segment_id_off = &h.segment_id as *const _ as usize - base;
let payload_length_off = &h.payload_length as *const _ as usize - base;
let timestamp_ns_off = &h.timestamp_ns as *const _ as usize - base;
let checksum_algo_off = &h.checksum_algo as *const _ as usize - base;
let compression_off = &h.compression as *const _ as usize - base;
let reserved_0_off = &h.reserved_0 as *const _ as usize - base;
let reserved_1_off = &h.reserved_1 as *const _ as usize - base;
let content_hash_off = &h.content_hash as *const _ as usize - base;
let uncompressed_len_off = &h.uncompressed_len as *const _ as usize - base;
let alignment_pad_off = &h.alignment_pad as *const _ as usize - base;
assert_eq!(magic_off, 0x00);
assert_eq!(version_off, 0x04);
assert_eq!(seg_type_off, 0x05);
assert_eq!(flags_off, 0x06);
assert_eq!(segment_id_off, 0x08);
assert_eq!(payload_length_off, 0x10);
assert_eq!(timestamp_ns_off, 0x18);
assert_eq!(checksum_algo_off, 0x20);
assert_eq!(compression_off, 0x21);
assert_eq!(reserved_0_off, 0x22);
assert_eq!(reserved_1_off, 0x24);
assert_eq!(content_hash_off, 0x28);
assert_eq!(uncompressed_len_off, 0x38);
assert_eq!(alignment_pad_off, 0x3C);
}
}