use crate::sync::{AtomicU32, AtomicU64, Ordering};
pub const MAGIC: [u8; 8] = *b"TELXHUB\x07";
pub const SEGMENT_VERSION: u32 = 7;
pub const SEGMENT_HEADER_SIZE: usize = 128;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SegmentHeaderInit {
pub total_size: u64,
pub max_payload_size: u32,
pub inline_threshold: u32,
pub max_guests: u32,
pub bipbuf_capacity: u32,
pub peer_table_offset: u64,
pub var_pool_offset: u64,
pub heartbeat_interval: u64,
pub num_var_slot_classes: u32,
}
#[repr(C)]
pub struct SegmentHeader {
pub magic: [u8; 8],
pub version: u32,
pub header_size: u32,
pub total_size: u64,
pub max_payload_size: u32,
pub inline_threshold: u32,
pub max_guests: u32,
pub bipbuf_capacity: u32,
pub peer_table_offset: u64,
pub var_pool_offset: u64,
pub heartbeat_interval: u64,
pub host_goodbye: AtomicU32,
pub num_var_slot_classes: u32,
pub current_size: AtomicU64,
_reserved: [u8; 48],
}
#[cfg(not(loom))]
const _: () = assert!(core::mem::size_of::<SegmentHeader>() == SEGMENT_HEADER_SIZE);
impl SegmentHeader {
pub unsafe fn init(&mut self, init: SegmentHeaderInit) {
self.magic = MAGIC;
self.version = SEGMENT_VERSION;
self.header_size = SEGMENT_HEADER_SIZE as u32;
self.total_size = init.total_size;
self.max_payload_size = init.max_payload_size;
self.inline_threshold = init.inline_threshold;
self.max_guests = init.max_guests;
self.bipbuf_capacity = init.bipbuf_capacity;
self.peer_table_offset = init.peer_table_offset;
self.var_pool_offset = init.var_pool_offset;
self.heartbeat_interval = init.heartbeat_interval;
self.host_goodbye = AtomicU32::new(0);
self.num_var_slot_classes = init.num_var_slot_classes;
self.current_size = AtomicU64::new(init.total_size);
self._reserved = [0u8; 48];
}
pub fn validate(&self) -> Result<(), &'static str> {
if self.magic != MAGIC {
return Err("bad magic: not a vox segment");
}
if self.version != SEGMENT_VERSION {
return Err("unsupported segment version");
}
if self.header_size != SEGMENT_HEADER_SIZE as u32 {
return Err("unexpected header_size");
}
if self.num_var_slot_classes == 0 {
return Err("segment missing var-slot classes");
}
Ok(())
}
#[inline]
pub fn effective_inline_threshold(&self) -> u32 {
if self.inline_threshold == 0 {
256
} else {
self.inline_threshold
}
}
#[inline]
pub fn current_size(&self) -> u64 {
self.current_size.load(Ordering::Acquire)
}
#[inline]
pub fn host_goodbye(&self) -> bool {
self.host_goodbye.load(Ordering::Acquire) != 0
}
}
#[cfg(all(test, not(loom)))]
mod tests {
use super::*;
use crate::region::HeapRegion;
fn make_header() -> (HeapRegion, *mut SegmentHeader) {
let region = HeapRegion::new_zeroed(SEGMENT_HEADER_SIZE);
let r = region.region();
let hdr: *mut SegmentHeader = unsafe { r.get_mut::<SegmentHeader>(0) };
unsafe {
(*hdr).init(SegmentHeaderInit {
total_size: 65536,
max_payload_size: 65536,
inline_threshold: 0,
max_guests: 4,
bipbuf_capacity: 16384,
peer_table_offset: 128,
var_pool_offset: 4096,
heartbeat_interval: 0,
num_var_slot_classes: 1,
});
}
(region, hdr)
}
#[test]
fn roundtrip() {
let (_region, hdr) = make_header();
let hdr = unsafe { &*hdr };
assert_eq!(hdr.magic, MAGIC);
assert_eq!(hdr.version, SEGMENT_VERSION);
assert_eq!(hdr.header_size, 128);
assert_eq!(hdr.total_size, 65536);
assert_eq!(hdr.max_guests, 4);
assert_eq!(hdr.bipbuf_capacity, 16384);
assert_eq!(hdr.peer_table_offset, 128);
assert_eq!(hdr.var_pool_offset, 4096);
assert_eq!(hdr.num_var_slot_classes, 1);
assert_eq!(hdr.current_size(), 65536);
}
#[test]
fn validate_ok() {
let (_region, hdr) = make_header();
unsafe { &*hdr }.validate().expect("valid header");
}
#[test]
fn validate_bad_magic() {
let (_region, hdr) = make_header();
let hdr = unsafe { &mut *hdr };
hdr.magic[7] = 0x01; assert!(hdr.validate().is_err());
}
#[test]
fn validate_bad_version() {
let (_region, hdr) = make_header();
let hdr = unsafe { &mut *hdr };
hdr.version = 99;
assert!(hdr.validate().is_err());
}
#[test]
fn inline_threshold_default() {
let (_region, hdr) = make_header();
let hdr = unsafe { &*hdr };
assert_eq!(hdr.effective_inline_threshold(), 256);
}
#[test]
fn host_goodbye_flag() {
let (_region, hdr) = make_header();
let hdr = unsafe { &*hdr };
assert!(!hdr.host_goodbye());
hdr.host_goodbye.store(1, Ordering::Release);
assert!(hdr.host_goodbye());
}
#[test]
fn current_size_matches_total() {
let (_region, hdr) = make_header();
let hdr = unsafe { &*hdr };
assert_eq!(hdr.current_size(), hdr.total_size);
}
}