use super::error::VastError;
use super::node::NODE_STRIDE_U32;
pub const VAST_MAGIC: [u8; 4] = *b"VAST";
pub const VAST_VERSION: u16 = 0;
pub const HEADER_LEN: usize = 24;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct VastHeader {
pub version: u16,
pub source_lang: u16,
pub node_count: u32,
pub file_count: u32,
pub string_blob_len: u32,
pub attr_blob_len: u32,
}
impl VastHeader {
pub fn decode(bytes: &[u8]) -> Result<Self, VastError> {
if bytes.len() < HEADER_LEN {
return Err(VastError::TooShort {
need: HEADER_LEN,
got: bytes.len(),
});
}
if bytes[0..4] != VAST_MAGIC {
let m: [u8; 4] = bytes[0..4].try_into().unwrap_or([0; 4]);
return Err(VastError::BadMagic(m));
}
let version = u16::from_le_bytes([bytes[4], bytes[5]]);
if version != VAST_VERSION {
return Err(VastError::UnsupportedVersion(version));
}
let source_lang = u16::from_le_bytes([bytes[6], bytes[7]]);
let node_count = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]);
let file_count = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]);
let string_blob_len = u32::from_le_bytes([bytes[16], bytes[17], bytes[18], bytes[19]]);
let attr_blob_len = u32::from_le_bytes([bytes[20], bytes[21], bytes[22], bytes[23]]);
Ok(Self {
version,
source_lang,
node_count,
file_count,
string_blob_len,
attr_blob_len,
})
}
#[must_use]
pub fn total_byte_len(self) -> Option<usize> {
let nodes = (self.node_count as usize).checked_mul(NODE_STRIDE_U32 * 4)?;
let files = (self.file_count as usize).checked_mul(12)?;
let strings = self.string_blob_len as usize;
let attrs = self.attr_blob_len as usize;
HEADER_LEN
.checked_add(nodes)?
.checked_add(files)?
.checked_add(strings)?
.checked_add(attrs)
}
}