use crate::error::Result;
use crate::reader::Reader;
use crate::tables::{TableContext, TableId};
use crate::writer::Writer;
#[derive(Debug, Clone)]
pub struct TablesHeader {
pub reserved: u32,
pub major_version: u8,
pub minor_version: u8,
pub heap_sizes: u8,
pub reserved2: u8,
pub valid: u64,
pub sorted: u64,
pub row_counts: [u32; 64],
pub uncompressed: bool,
}
impl TablesHeader {
pub fn parse(reader: &mut Reader<'_>, uncompressed: bool) -> Result<Self> {
let reserved = reader.read_u32()?;
let major_version = reader.read_u8()?;
let minor_version = reader.read_u8()?;
let heap_sizes = reader.read_u8()?;
let reserved2 = reader.read_u8()?;
let valid = reader.read_u64()?;
let sorted = reader.read_u64()?;
let mut row_counts = [0u32; 64];
for (i, count) in row_counts.iter_mut().enumerate() {
if valid & (1u64 << i) != 0 {
*count = reader.read_u32()?;
}
}
Ok(Self {
reserved,
major_version,
minor_version,
heap_sizes,
reserved2,
valid,
sorted,
row_counts,
uncompressed,
})
}
pub fn write_to(&self, writer: &mut Writer) {
writer.write_u32(self.reserved);
writer.write_u8(self.major_version);
writer.write_u8(self.minor_version);
writer.write_u8(self.heap_sizes);
writer.write_u8(self.reserved2);
writer.write_u64(self.valid);
writer.write_u64(self.sorted);
for i in 0..64 {
if self.valid & (1u64 << i) != 0 {
writer.write_u32(self.row_counts[i]);
}
}
}
#[must_use]
pub fn has_table(&self, table: TableId) -> bool {
self.valid & (1u64 << (table as u8)) != 0
}
#[must_use]
pub fn row_count(&self, table: TableId) -> u32 {
self.row_counts[table as usize]
}
pub fn set_row_count(&mut self, table: TableId, count: u32) {
let bit = 1u64 << (table as u8);
if count > 0 {
self.valid |= bit;
} else {
self.valid &= !bit;
}
self.row_counts[table as usize] = count;
}
#[must_use]
pub fn context(&self) -> TableContext {
TableContext::new(self.heap_sizes, self.row_counts)
}
#[must_use]
pub fn size(&self) -> usize {
let valid_count = self.valid.count_ones() as usize;
24 + valid_count * 4 }
pub fn tables(&self) -> impl Iterator<Item = (TableId, u32)> + '_ {
(0..64u8).filter_map(move |i| {
if self.valid & (1u64 << i) != 0 {
TableId::from_u8(i)
.ok()
.map(|t| (t, self.row_counts[i as usize]))
} else {
None
}
})
}
}