pub struct SegmentHeader {
pub number: u32,
pub seg_type: u8,
pub deferred_non_retain: bool,
pub retain_bits: u8,
pub referred_to: Vec<u32>,
pub page: u32,
pub data_length: u32,
}
impl SegmentHeader {
pub fn reference_size(&self) -> usize {
if self.number <= 256 {
1
} else if self.number <= 65536 {
2
} else {
4
}
}
pub fn page_size(&self) -> usize {
if self.page <= 255 { 1 } else { 4 }
}
pub fn size(&self) -> usize {
6 + self.reference_size() * self.referred_to.len() + self.page_size() + 4
}
pub fn to_bytes(&self) -> Vec<u8> {
let ref_size = self.reference_size();
let pg_size = self.page_size();
let mut buf = Vec::with_capacity(self.size());
buf.extend_from_slice(&self.number.to_be_bytes());
let page_assoc_size_bit = if pg_size == 4 { 1u8 } else { 0u8 };
let flags = (self.seg_type & 0x3F)
| (page_assoc_size_bit << 6)
| (u8::from(self.deferred_non_retain) << 7);
buf.push(flags);
let count = self.referred_to.len();
assert!(
count <= 7,
"SegmentHeader::to_bytes: referred_to.len() must be <= 7 for short-form encoding, got {count}"
);
let count = count as u8;
let referred_byte = (self.retain_bits & 0x1F) | (count << 5);
buf.push(referred_byte);
for &seg_num in &self.referred_to {
assert!(
seg_num < self.number,
"invalid referred-to segment number {seg_num}: must be less than current segment number {}",
self.number
);
match ref_size {
1 => {
assert!(
seg_num <= u8::MAX as u32,
"invalid referred-to segment number {seg_num}: does not fit in 1 byte"
);
buf.push(seg_num as u8);
}
2 => {
assert!(
seg_num <= u16::MAX as u32,
"invalid referred-to segment number {seg_num}: does not fit in 2 bytes"
);
buf.extend_from_slice(&(seg_num as u16).to_be_bytes());
}
4 => buf.extend_from_slice(&seg_num.to_be_bytes()),
_ => unreachable!(),
}
}
match pg_size {
1 => buf.push(self.page as u8),
4 => buf.extend_from_slice(&self.page.to_be_bytes()),
_ => unreachable!(),
}
buf.extend_from_slice(&self.data_length.to_be_bytes());
debug_assert_eq!(buf.len(), self.size());
buf
}
}