Skip to main content

imferno_core/package/
codes.rs

1//! Typed validation-code catalogue for codes emitted by the package module.
2//!
3//! Re-exports per-spec enums from their home modules within imferno-core.
4
5pub use crate::diagnostics::codes::ValidationCode;
6
7pub use crate::assetmap::codes::St2067_2_2020;
8pub use crate::assetmap::volindex_codes::St429_9_2014;
9pub use crate::cpl::codes::St2067_3_2020;
10pub use crate::mxf::codes::St377_1_2011;
11pub use crate::scm::codes::St2067_9_2018;
12
13use crate::diagnostics::{Category, Severity};
14
15// ─────────────────────────────────────────────────────────────────────────────
16// imferno tool-level codes  (not derived from any SMPTE spec)
17// ─────────────────────────────────────────────────────────────────────────────
18
19/// Tool-level observation codes emitted by imferno itself.
20///
21/// These are not normative violations — they reflect structural observations
22/// that the tool surfaces as informational findings.  Code strings use the
23/// `IMFERNO:` namespace prefix to distinguish them from spec codes.
24#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::EnumIter)]
25pub enum ImfernoCode {
26    /// An asset is present in the AssetMap but has no CPL Virtual Track
27    /// reference and no SCM declaration.  Likely a sidecar essence (e.g.
28    /// Dolby Atmos MXF) delivered without an accompanying SCM document.
29    UnreferencedAsset,
30    /// A file is present in the package directory but not listed as a
31    /// chunk in any AssetMap entry.  The file is completely outside the
32    /// package manifest and will be ignored by any conforming IMF reader.
33    UnlistedEssence,
34    /// IMF package failed to parse (top-level structural failure).
35    ParseError,
36    /// A PKL referenced by the AssetMap could not be parsed.
37    PklParseError,
38    /// An XML asset could not be parsed as CPL, OPL, or SCM.
39    XmlAssetParseError,
40    /// An XML file could not be read from disk.
41    XmlReadError,
42    /// Could not scan the package directory.
43    ReadDirError,
44    /// Could not read a directory entry while scanning for unlisted essences.
45    DirEntryError,
46    /// An asset chunk path attempts to escape the package root directory.
47    PathTraversal,
48}
49
50impl ValidationCode for ImfernoCode {
51    fn code(&self) -> &'static str {
52        match self {
53            Self::UnreferencedAsset => "IMFERNO:Package/UnreferencedAsset",
54            Self::UnlistedEssence => "IMFERNO:Package/UnlistedEssence",
55            Self::ParseError => "IMFERNO:Package/ParseError",
56            Self::PklParseError => "IMFERNO:Package/PklParseError",
57            Self::XmlAssetParseError => "IMFERNO:Package/XmlAssetParseError",
58            Self::XmlReadError => "IMFERNO:Package/XmlReadError",
59            Self::ReadDirError => "IMFERNO:Package/ReadDirError",
60            Self::DirEntryError => "IMFERNO:Package/DirEntryError",
61            Self::PathTraversal => "IMFERNO:Package/PathTraversal",
62        }
63    }
64
65    fn description(&self) -> &'static str {
66        match self {
67            Self::UnreferencedAsset =>
68                "Asset is present in the AssetMap but not referenced by any CPL Virtual Track and has no SCM declaration. Likely a sidecar essence without an SCM.",
69            Self::UnlistedEssence =>
70                "File is present in the package directory but not listed in the AssetMap. The file is invisible to any conforming IMF reader.",
71            Self::ParseError =>
72                "IMF package failed to parse due to a structural error.",
73            Self::PklParseError =>
74                "A Packing List referenced by the AssetMap could not be parsed.",
75            Self::XmlAssetParseError =>
76                "An XML asset could not be parsed as CPL, OPL, or SCM.",
77            Self::XmlReadError =>
78                "An XML file could not be read from disk.",
79            Self::ReadDirError =>
80                "Could not scan the package directory.",
81            Self::DirEntryError =>
82                "Could not read a directory entry while scanning for unlisted essences.",
83            Self::PathTraversal =>
84                "An asset chunk path attempts to escape the package root directory (path traversal).",
85        }
86    }
87
88    fn default_severity(&self) -> Severity {
89        match self {
90            Self::UnreferencedAsset => Severity::Info,
91            Self::UnlistedEssence => Severity::Warning,
92            Self::ParseError => Severity::Critical,
93            Self::PklParseError => Severity::Error,
94            Self::XmlAssetParseError => Severity::Warning,
95            Self::XmlReadError => Severity::Warning,
96            Self::ReadDirError => Severity::Info,
97            Self::DirEntryError => Severity::Info,
98            Self::PathTraversal => Severity::Error,
99        }
100    }
101
102    fn category(&self) -> Category {
103        Category::Structure
104    }
105}
106
107impl ImfernoCode {
108    pub const ALL: &'static [Self] = &[
109        Self::UnreferencedAsset,
110        Self::UnlistedEssence,
111        Self::ParseError,
112        Self::PklParseError,
113        Self::XmlAssetParseError,
114        Self::XmlReadError,
115        Self::ReadDirError,
116        Self::DirEntryError,
117        Self::PathTraversal,
118    ];
119}
120
121impl From<ImfernoCode> for String {
122    fn from(c: ImfernoCode) -> String {
123        c.code().to_string()
124    }
125}