chk_defaced 0.1.0

Detect 'defaced' documents: verify the coherence of the fonts used to render text (PDF, DOCX, HTML+CSS) and build a JSON index of the system fonts' cmaps.
Documentation
//! Serializable report model (aligned with the project plan, simplified for v1).

use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum Severity {
    Info,
    Low,
    Medium,
    High,
    Critical,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Category {
    FontIntegrity,
    UnicodeHygiene,
    HiddenContent,
    Structural,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Finding {
    pub rule: String,
    pub severity: Severity,
    pub category: Category,
    pub message: String,
    /// Where (free-form: page/part/selector/font), human-readable.
    pub location: String,
    pub confidence: f32,
}

impl Finding {
    pub fn new(
        rule: &str,
        severity: Severity,
        category: Category,
        location: impl Into<String>,
        message: impl Into<String>,
        confidence: f32,
    ) -> Self {
        Finding {
            rule: rule.to_string(),
            severity,
            category,
            location: location.into(),
            message: message.into(),
            confidence,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Report {
    pub file: String,
    pub format: String,
    pub fonts_examined: usize,
    pub findings: Vec<Finding>,
}

impl Report {
    pub fn new(file: &str, format: &str) -> Self {
        Report { file: file.to_string(), format: format.to_string(), fonts_examined: 0, findings: Vec::new() }
    }
    pub fn push(&mut self, f: Finding) {
        self.findings.push(f);
    }
    pub fn max_severity(&self) -> Option<Severity> {
        self.findings.iter().map(|f| f.severity).max()
    }
}