use crate::types::{Header, HEADER_SIZE, MAGIC};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StructureCheck {
Pass,
Fail,
}
impl StructureCheck {
#[must_use]
pub fn is_pass(self) -> bool {
matches!(self, StructureCheck::Pass)
}
}
#[must_use]
pub fn check_magic(data: &[u8]) -> StructureCheck {
if data.len() >= 4 && data[0..4] == MAGIC {
StructureCheck::Pass
} else {
StructureCheck::Fail
}
}
#[must_use]
pub fn check_header_size(data: &[u8]) -> StructureCheck {
if data.len() >= HEADER_SIZE {
StructureCheck::Pass
} else {
StructureCheck::Fail
}
}
#[must_use]
pub fn check_version(header: &Header) -> StructureCheck {
if header.version.0 <= crate::types::FORMAT_VERSION.0 {
StructureCheck::Pass
} else {
StructureCheck::Fail
}
}
#[must_use]
pub fn check_flags(header: &Header) -> StructureCheck {
if header.flags.bits() & 0b1000_0000 == 0 {
StructureCheck::Pass
} else {
StructureCheck::Fail
}
}
#[must_use]
pub fn validate_structure(data: &[u8]) -> bool {
if !check_magic(data).is_pass() || !check_header_size(data).is_pass() {
return false;
}
match Header::from_bytes(&data[..HEADER_SIZE]) {
Ok(header) => check_version(&header).is_pass() && check_flags(&header).is_pass(),
Err(_) => false,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::{Header, ModelType};
fn good_header_bytes() -> Vec<u8> {
let mut v = Header::new(ModelType::LinearRegression).to_bytes().to_vec();
v.resize(HEADER_SIZE, 0);
v
}
#[test]
fn test_check_magic_pass_and_fail() {
assert!(check_magic(&good_header_bytes()).is_pass());
assert!(!check_magic(b"GGUF").is_pass());
}
#[test]
fn test_validate_structure_round_trip() {
assert!(validate_structure(&good_header_bytes()));
let mut bad = good_header_bytes();
bad[0] = 0x00; assert!(!validate_structure(&bad));
}
}