Skip to main content

imferno_core/validation/
isxd_codes.rs

1//! Typed validation-code catalogue for SMPTE ST 2067-202 (ISXD Plug-in).
2
3use crate::diagnostics::codes::ValidationCode;
4use crate::diagnostics::{Category, Severity};
5
6// ─────────────────────────────────────────────────────────────────────────────
7// Spec-agnostic reason codes
8// ─────────────────────────────────────────────────────────────────────────────
9
10/// Spec-agnostic reason codes for ISXD Plug-in validation.
11///
12/// Passed to each edition's `for_code` dispatch function to get the full
13/// `&'static str` code without any runtime string building.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum IsxdCode {
16    /// ISXDDataEssenceDescriptor: ContainerConstraintsSubDescriptor shall be present (§5).
17    SubDescriptorMissing,
18    /// ISXDDataEssenceDescriptor: NamespaceURI is absent (§5).
19    NamespaceUriMissing,
20    /// ISXDSequence shall contain at least one Resource (§6).
21    ISXDSequenceNoResources,
22    /// ISXDSequence Resource.SourceEncoding does not reference an ISXDDataEssenceDescriptor (§6).
23    ISXDSequenceSourceEncodingInvalid,
24    /// Resources in the same ISXDSequence reference descriptors with inconsistent NamespaceURI values (§6).
25    NamespaceUriMismatch,
26}
27
28// ─────────────────────────────────────────────────────────────────────────────
29// Edition-specific enum (generated by macro)
30// ─────────────────────────────────────────────────────────────────────────────
31
32macro_rules! define_isxd_enum {
33    ($name:ident, $prefix:literal) => {
34        /// ISXD Plug-in validation codes, edition
35        #[doc = $prefix]
36        #[derive(Debug, Clone, Copy, PartialEq, Eq, strum::EnumIter)]
37        pub enum $name {
38            /// ISXDDataEssenceDescriptor: ContainerConstraintsSubDescriptor shall be present (§5).
39            SubDescriptorMissing,
40            /// ISXDDataEssenceDescriptor: NamespaceURI is absent (§5).
41            NamespaceUriMissing,
42            /// ISXDSequence shall contain at least one Resource (§6).
43            ISXDSequenceNoResources,
44            /// ISXDSequence Resource.SourceEncoding does not reference an ISXDDataEssenceDescriptor (§6).
45            ISXDSequenceSourceEncodingInvalid,
46            /// Resources in the same ISXDSequence reference descriptors with inconsistent NamespaceURI values (§6).
47            NamespaceUriMismatch,
48        }
49
50        impl ValidationCode for $name {
51            fn code(&self) -> &'static str {
52                match self {
53                    Self::SubDescriptorMissing              => concat!($prefix, ":5/SubDescriptorMissing"),
54                    Self::NamespaceUriMissing               => concat!($prefix, ":5/NamespaceUriMissing"),
55                    Self::ISXDSequenceNoResources           => concat!($prefix, ":6/ISXDSequenceNoResources"),
56                    Self::ISXDSequenceSourceEncodingInvalid => concat!($prefix, ":6/ISXDSequenceSourceEncodingInvalid"),
57                    Self::NamespaceUriMismatch              => concat!($prefix, ":6/NamespaceUriMismatch"),
58                }
59            }
60            fn description(&self) -> &'static str {
61                match self {
62                    Self::SubDescriptorMissing =>
63                        "ISXDDataEssenceDescriptor: ContainerConstraintsSubDescriptor shall be present.",
64                    Self::NamespaceUriMissing =>
65                        "ISXDDataEssenceDescriptor: NamespaceURI is absent.",
66                    Self::ISXDSequenceNoResources =>
67                        "ISXDSequence shall contain at least one Resource.",
68                    Self::ISXDSequenceSourceEncodingInvalid =>
69                        "ISXDSequence Resource.SourceEncoding does not reference an ISXDDataEssenceDescriptor.",
70                    Self::NamespaceUriMismatch =>
71                        "Resources in the same ISXDSequence reference descriptors with inconsistent NamespaceURI values.",
72                }
73            }
74            fn default_severity(&self) -> Severity {
75                match self {
76                    Self::NamespaceUriMissing => Severity::Warning,
77                    _ => Severity::Error,
78                }
79            }
80            fn category(&self) -> Category {
81                // ISXD carries dynamic data essence (sidecar metadata
82                // streams). Not audio — the previous tagging was wrong.
83                Category::Data
84            }
85            fn example(&self) -> Option<&'static str> {
86                Some(match self {
87                    Self::SubDescriptorMissing =>
88                        "<ISXDDataEssenceDescriptor>…</ISXDDataEssenceDescriptor>  <!-- no ContainerConstraintsSubDescriptor inside -->",
89                    Self::NamespaceUriMissing =>
90                        "<ISXDDataEssenceDescriptor>  <!-- missing required <NamespaceURI>… --> </ISXDDataEssenceDescriptor>",
91                    Self::ISXDSequenceNoResources =>
92                        "<ISXDSequence><ResourceList/></ISXDSequence>",
93                    Self::ISXDSequenceSourceEncodingInvalid =>
94                        "<ISXDSequence>…<SourceEncoding>urn:uuid:…</SourceEncoding></ISXDSequence>  <!-- UUID doesn't resolve to an ISXDDataEssenceDescriptor -->",
95                    Self::NamespaceUriMismatch =>
96                        "Two Resources in the same ISXDSequence point at descriptors whose <NamespaceURI> differs.",
97                })
98            }
99        }
100
101        impl $name {
102            pub const ALL: &'static [Self] = &[
103                Self::SubDescriptorMissing,
104                Self::NamespaceUriMissing,
105                Self::ISXDSequenceNoResources,
106                Self::ISXDSequenceSourceEncodingInvalid,
107                Self::NamespaceUriMismatch,
108            ];
109
110            /// Dispatch from the spec-agnostic [`IsxdCode`] to this
111            /// edition's static code string. Used by the shared validator helpers.
112            pub fn for_code(r: IsxdCode) -> &'static str {
113                match r {
114                    IsxdCode::SubDescriptorMissing              => concat!($prefix, ":5/SubDescriptorMissing"),
115                    IsxdCode::NamespaceUriMissing               => concat!($prefix, ":5/NamespaceUriMissing"),
116                    IsxdCode::ISXDSequenceNoResources           => concat!($prefix, ":6/ISXDSequenceNoResources"),
117                    IsxdCode::ISXDSequenceSourceEncodingInvalid => concat!($prefix, ":6/ISXDSequenceSourceEncodingInvalid"),
118                    IsxdCode::NamespaceUriMismatch              => concat!($prefix, ":6/NamespaceUriMismatch"),
119                }
120            }
121        }
122
123        impl From<$name> for String {
124            fn from(c: $name) -> String {
125                c.code().to_string()
126            }
127        }
128    };
129}
130
131define_isxd_enum!(St2067_202_2022, "ST2067-202:2022");