lumen-engine 0.2.2

Core composition model and rendering orchestration for Lumen.
Documentation
//! Error types and diagnostics for the Lumen compositing engine.

use thiserror::Error;

use crate::node::{NodeId, PortKind};

#[derive(Debug, Error, Clone)]
pub enum LumenError {
    #[error("graph validation error: {0}")]
    GraphValidation(#[from] GraphValidationError),
    #[error("property resolution error: {0}")]
    Property(#[from] PropertyError),
    #[error("expression error: {0}")]
    Expression(#[from] ExpressionError),
    #[error("media error: {0}")]
    Media(#[from] MediaError),
    #[error("render error: {0}")]
    Render(#[from] RenderError),
}

#[derive(Debug, Error, Clone)]
pub enum GraphValidationError {
    #[error("graph contains a cycle")]
    Cycle { path: Vec<NodeId> },
    #[error("connection target node is missing")]
    MissingTargetNode { node_id: NodeId },
    #[error("connection source node is missing")]
    MissingSourceNode { node_id: NodeId },
    #[error("connection target port `{port}` is missing")]
    MissingTargetPort { node_id: NodeId, port: String },
    #[error("connection source port `{port}` is missing")]
    MissingSourcePort { node_id: NodeId, port: String },
    #[error("missing required input `{port}`")]
    MissingRequiredInput { node_id: NodeId, port: String },
    #[error("port kind mismatch for `{to_port}`")]
    PortKindMismatch {
        from_node: NodeId,
        from_port: String,
        from_kind: PortKind,
        to_node: NodeId,
        to_port: String,
        expected_kind: PortKind,
    },
    #[error("exactly one media output node is required")]
    MissingMediaOutput,
    #[error("exactly one media output node is required")]
    MultipleMediaOutputs { count: usize },
    #[error("target node is not reachable or missing")]
    InvalidEvaluationTarget { node_id: NodeId },
}

#[derive(Debug, Error, Clone)]
pub enum PropertyError {
    #[error("property `{property_path}` is missing")]
    MissingProperty {
        node_id: NodeId,
        property_path: String,
    },
    #[error("property `{property_path}` has invalid type")]
    InvalidType {
        node_id: NodeId,
        property_path: String,
        expected: &'static str,
        actual: &'static str,
    },
}

#[derive(Debug, Error, Clone)]
pub enum ExpressionError {
    #[error("expression parse failed: {details}")]
    Parse {
        path: Option<String>,
        details: String,
    },
    #[error("expression evaluation failed: {details}")]
    Evaluate {
        path: Option<String>,
        details: String,
    },
    #[error("undefined variable in expression")]
    UndefinedVariable { path: Option<String>, name: String },
}

#[derive(Debug, Error, Clone)]
pub enum MediaError {
    #[error("media source not found: {media_source}")]
    SourceNotFound { media_source: String },
    #[error("media decoding failed for {media_source}: {details}")]
    Decode {
        media_source: String,
        details: String,
    },
    #[error("media frame {frame} is out of range for {media_source} ({frame_count} frames)")]
    FrameOutOfRange {
        media_source: String,
        frame: u32,
        frame_count: u32,
    },
}

#[derive(Debug, Error, Clone)]
pub enum RenderError {
    #[error("frame is out of range")]
    FrameOutOfRange { frame: u32, duration_frames: u32 },
    #[error("node evaluation failed")]
    NodeEvaluation {
        frame: u32,
        node_id: NodeId,
        node_kind: &'static str,
        details: String,
    },
    #[error("referenced node is missing from the graph")]
    MissingNode { frame: u32, node_id: NodeId },
    #[error("surface allocation failed")]
    SurfaceAllocation { width: u32, height: u32 },
    #[error("node output is missing")]
    MissingNodeOutput { frame: u32, node_id: NodeId },
    #[error("node output has invalid type")]
    InvalidNodeOutputType {
        frame: u32,
        node_id: NodeId,
        expected: &'static str,
        actual: &'static str,
    },
    #[error("media output node did not produce raster output")]
    InvalidMediaOutputType { frame: u32, node_id: NodeId },
    #[error("pixel readback failed")]
    PixelReadbackFailed { width: u32, height: u32 },
    #[error("all scratch surfaces are currently in use")]
    ScratchSurfaceUnavailable,
    #[error("{backend} backend is busy")]
    BackendBusy { backend: &'static str },
    #[error("render cancelled")]
    Cancelled { frame: u32 },
    #[error("GPU render failed: {details}")]
    Gpu { details: String },
}

#[derive(Debug, Clone, PartialEq)]
pub enum Warning {
    FpsMismatch {
        node_id: NodeId,
        composition_fps: f32,
        source_fps: f32,
    },
    CapabilityMissing {
        node_id: NodeId,
        requirement: &'static str,
    },
}