imferno-core 2.3.0

SMPTE ST 2067 IMF parser and validator
Documentation
//! Typed validation-code catalogue for SMPTE ST 2067-202 (ISXD Plug-in).

use crate::diagnostics::codes::ValidationCode;
use crate::diagnostics::{Category, Severity};

// ─────────────────────────────────────────────────────────────────────────────
// Spec-agnostic reason codes
// ─────────────────────────────────────────────────────────────────────────────

/// Spec-agnostic reason codes for ISXD Plug-in validation.
///
/// Passed to each edition's `for_code` dispatch function to get the full
/// `&'static str` code without any runtime string building.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IsxdCode {
    /// ISXDDataEssenceDescriptor: ContainerConstraintsSubDescriptor shall be present (§5).
    SubDescriptorMissing,
    /// ISXDDataEssenceDescriptor: NamespaceURI is absent (§5).
    NamespaceUriMissing,
    /// ISXDSequence shall contain at least one Resource (§6).
    ISXDSequenceNoResources,
    /// ISXDSequence Resource.SourceEncoding does not reference an ISXDDataEssenceDescriptor (§6).
    ISXDSequenceSourceEncodingInvalid,
    /// Resources in the same ISXDSequence reference descriptors with inconsistent NamespaceURI values (§6).
    NamespaceUriMismatch,
}

// ─────────────────────────────────────────────────────────────────────────────
// Edition-specific enum (generated by macro)
// ─────────────────────────────────────────────────────────────────────────────

macro_rules! define_isxd_enum {
    ($name:ident, $prefix:literal) => {
        /// ISXD Plug-in validation codes, edition
        #[doc = $prefix]
        #[derive(Debug, Clone, Copy, PartialEq, Eq, strum::EnumIter)]
        pub enum $name {
            /// ISXDDataEssenceDescriptor: ContainerConstraintsSubDescriptor shall be present (§5).
            SubDescriptorMissing,
            /// ISXDDataEssenceDescriptor: NamespaceURI is absent (§5).
            NamespaceUriMissing,
            /// ISXDSequence shall contain at least one Resource (§6).
            ISXDSequenceNoResources,
            /// ISXDSequence Resource.SourceEncoding does not reference an ISXDDataEssenceDescriptor (§6).
            ISXDSequenceSourceEncodingInvalid,
            /// Resources in the same ISXDSequence reference descriptors with inconsistent NamespaceURI values (§6).
            NamespaceUriMismatch,
        }

        impl ValidationCode for $name {
            fn code(&self) -> &'static str {
                match self {
                    Self::SubDescriptorMissing              => concat!($prefix, ":5/SubDescriptorMissing"),
                    Self::NamespaceUriMissing               => concat!($prefix, ":5/NamespaceUriMissing"),
                    Self::ISXDSequenceNoResources           => concat!($prefix, ":6/ISXDSequenceNoResources"),
                    Self::ISXDSequenceSourceEncodingInvalid => concat!($prefix, ":6/ISXDSequenceSourceEncodingInvalid"),
                    Self::NamespaceUriMismatch              => concat!($prefix, ":6/NamespaceUriMismatch"),
                }
            }
            fn description(&self) -> &'static str {
                match self {
                    Self::SubDescriptorMissing =>
                        "ISXDDataEssenceDescriptor: ContainerConstraintsSubDescriptor shall be present.",
                    Self::NamespaceUriMissing =>
                        "ISXDDataEssenceDescriptor: NamespaceURI is absent.",
                    Self::ISXDSequenceNoResources =>
                        "ISXDSequence shall contain at least one Resource.",
                    Self::ISXDSequenceSourceEncodingInvalid =>
                        "ISXDSequence Resource.SourceEncoding does not reference an ISXDDataEssenceDescriptor.",
                    Self::NamespaceUriMismatch =>
                        "Resources in the same ISXDSequence reference descriptors with inconsistent NamespaceURI values.",
                }
            }
            fn default_severity(&self) -> Severity {
                match self {
                    Self::NamespaceUriMissing => Severity::Warning,
                    _ => Severity::Error,
                }
            }
            fn category(&self) -> Category {
                Category::Audio
            }
        }

        impl $name {
            pub const ALL: &'static [Self] = &[
                Self::SubDescriptorMissing,
                Self::NamespaceUriMissing,
                Self::ISXDSequenceNoResources,
                Self::ISXDSequenceSourceEncodingInvalid,
                Self::NamespaceUriMismatch,
            ];

            /// Dispatch from the spec-agnostic [`IsxdCode`] to this
            /// edition's static code string. Used by the shared validator helpers.
            pub fn for_code(r: IsxdCode) -> &'static str {
                match r {
                    IsxdCode::SubDescriptorMissing              => concat!($prefix, ":5/SubDescriptorMissing"),
                    IsxdCode::NamespaceUriMissing               => concat!($prefix, ":5/NamespaceUriMissing"),
                    IsxdCode::ISXDSequenceNoResources           => concat!($prefix, ":6/ISXDSequenceNoResources"),
                    IsxdCode::ISXDSequenceSourceEncodingInvalid => concat!($prefix, ":6/ISXDSequenceSourceEncodingInvalid"),
                    IsxdCode::NamespaceUriMismatch              => concat!($prefix, ":6/NamespaceUriMismatch"),
                }
            }
        }

        impl From<$name> for String {
            fn from(c: $name) -> String {
                c.code().to_string()
            }
        }
    };
}

define_isxd_enum!(St2067_202_2022, "ST2067-202:2022");