Skip to main content

pcf_debug/model/
diag.rs

1//! Diagnostics produced while walking and modelling a PCF file.
2//!
3//! A debugger must describe broken files, not reject them. Every structural
4//! anomaly we can detect is captured here as a [`Diagnostic`] rather than an
5//! error that aborts the walk.
6
7/// The class of an anomaly found in a file.
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum DiagKind {
10    /// Two physical regions cover overlapping bytes.
11    Overlap { start: u64, len: u64 },
12    /// A run of bytes covered by no region (dead space / padding).
13    Gap { start: u64, len: u64 },
14    /// A declared region runs past the end of the file.
15    Truncated { start: u64, want: u64, have: u64 },
16    /// The block chain links back to a block already visited.
17    ChainCycle { at_offset: u64 },
18    /// A `next_table_offset` points to an earlier offset (legal under the
19    /// PFS-MS append model, surfaced for information only).
20    BackwardChainLink { from: u64, to: u64 },
21    /// A partition's stored `data_hash` does not match its bytes.
22    DataHashMismatch { uid: [u8; 16] },
23    /// A table block's stored `table_hash` does not match its bytes.
24    TableHashMismatch { block_index: usize },
25    /// A live entry failed the PCF conformance checks.
26    EntryInvalid { uid: [u8; 16], reason: String },
27    /// The file header could not be parsed.
28    BadHeader { reason: String },
29    /// A table block header could not be parsed.
30    BadBlock { offset: u64, reason: String },
31}
32
33/// How serious a [`Diagnostic`] is.
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum Severity {
36    Info,
37    Warning,
38    Error,
39}
40
41impl Severity {
42    /// Short uppercase tag used in text output.
43    pub fn tag(self) -> &'static str {
44        match self {
45            Severity::Info => "INFO",
46            Severity::Warning => "WARN",
47            Severity::Error => "ERROR",
48        }
49    }
50}
51
52/// One finding about a file.
53#[derive(Debug, Clone)]
54pub struct Diagnostic {
55    pub severity: Severity,
56    pub kind: DiagKind,
57    pub message: String,
58}
59
60impl Diagnostic {
61    pub fn info(kind: DiagKind, message: impl Into<String>) -> Self {
62        Self {
63            severity: Severity::Info,
64            kind,
65            message: message.into(),
66        }
67    }
68    pub fn warn(kind: DiagKind, message: impl Into<String>) -> Self {
69        Self {
70            severity: Severity::Warning,
71            kind,
72            message: message.into(),
73        }
74    }
75    pub fn error(kind: DiagKind, message: impl Into<String>) -> Self {
76        Self {
77            severity: Severity::Error,
78            kind,
79            message: message.into(),
80        }
81    }
82}