1#[derive(Clone, Copy, Debug)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9#[repr(C)]
10pub struct SegmentHeader {
11 pub magic: u32,
13 pub version: u8,
15 pub seg_type: u8,
17 pub flags: u16,
19 pub segment_id: u64,
21 pub payload_length: u64,
23 pub timestamp_ns: u64,
25 pub checksum_algo: u8,
27 pub compression: u8,
29 pub reserved_0: u16,
31 pub reserved_1: u32,
33 pub content_hash: [u8; 16],
35 pub uncompressed_len: u32,
37 pub alignment_pad: u32,
39}
40
41const _: () = assert!(core::mem::size_of::<SegmentHeader>() == 64);
43
44impl SegmentHeader {
45 pub const fn new(seg_type: u8, segment_id: u64) -> Self {
48 Self {
49 magic: crate::constants::SEGMENT_MAGIC,
50 version: crate::constants::SEGMENT_VERSION,
51 seg_type,
52 flags: 0,
53 segment_id,
54 payload_length: 0,
55 timestamp_ns: 0,
56 checksum_algo: 0,
57 compression: 0,
58 reserved_0: 0,
59 reserved_1: 0,
60 content_hash: [0u8; 16],
61 uncompressed_len: 0,
62 alignment_pad: 0,
63 }
64 }
65
66 #[inline]
68 pub const fn is_valid_magic(&self) -> bool {
69 self.magic == crate::constants::SEGMENT_MAGIC
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use crate::constants::SEGMENT_MAGIC;
77
78 #[test]
79 fn header_size_is_64() {
80 assert_eq!(core::mem::size_of::<SegmentHeader>(), 64);
81 }
82
83 #[test]
84 fn header_alignment() {
85 assert!(core::mem::align_of::<SegmentHeader>() <= 64);
86 }
87
88 #[test]
89 fn new_header_has_valid_magic() {
90 let h = SegmentHeader::new(0x01, 42);
91 assert!(h.is_valid_magic());
92 assert_eq!(h.magic, SEGMENT_MAGIC);
93 assert_eq!(h.seg_type, 0x01);
94 assert_eq!(h.segment_id, 42);
95 }
96
97 #[test]
98 fn field_offsets() {
99 let h = SegmentHeader::new(0x01, 0);
101 let base = &h as *const _ as usize;
102 let magic_off = &h.magic as *const _ as usize - base;
103 let version_off = &h.version as *const _ as usize - base;
104 let seg_type_off = &h.seg_type as *const _ as usize - base;
105 let flags_off = &h.flags as *const _ as usize - base;
106 let segment_id_off = &h.segment_id as *const _ as usize - base;
107 let payload_length_off = &h.payload_length as *const _ as usize - base;
108 let timestamp_ns_off = &h.timestamp_ns as *const _ as usize - base;
109 let checksum_algo_off = &h.checksum_algo as *const _ as usize - base;
110 let compression_off = &h.compression as *const _ as usize - base;
111 let reserved_0_off = &h.reserved_0 as *const _ as usize - base;
112 let reserved_1_off = &h.reserved_1 as *const _ as usize - base;
113 let content_hash_off = &h.content_hash as *const _ as usize - base;
114 let uncompressed_len_off = &h.uncompressed_len as *const _ as usize - base;
115 let alignment_pad_off = &h.alignment_pad as *const _ as usize - base;
116
117 assert_eq!(magic_off, 0x00);
118 assert_eq!(version_off, 0x04);
119 assert_eq!(seg_type_off, 0x05);
120 assert_eq!(flags_off, 0x06);
121 assert_eq!(segment_id_off, 0x08);
122 assert_eq!(payload_length_off, 0x10);
123 assert_eq!(timestamp_ns_off, 0x18);
124 assert_eq!(checksum_algo_off, 0x20);
125 assert_eq!(compression_off, 0x21);
126 assert_eq!(reserved_0_off, 0x22);
127 assert_eq!(reserved_1_off, 0x24);
128 assert_eq!(content_hash_off, 0x28);
129 assert_eq!(uncompressed_len_off, 0x38);
130 assert_eq!(alignment_pad_off, 0x3C);
131 }
132}