1use thiserror::Error;
4
5use crate::node::{NodeId, PortKind};
6
7#[derive(Debug, Error, Clone)]
8pub enum LumenError {
9 #[error("graph validation error: {0}")]
10 GraphValidation(#[from] GraphValidationError),
11 #[error("property resolution error: {0}")]
12 Property(#[from] PropertyError),
13 #[error("expression error: {0}")]
14 Expression(#[from] ExpressionError),
15 #[error("media error: {0}")]
16 Media(#[from] MediaError),
17 #[error("render error: {0}")]
18 Render(#[from] RenderError),
19}
20
21#[derive(Debug, Error, Clone)]
22pub enum GraphValidationError {
23 #[error("graph contains a cycle")]
24 Cycle { path: Vec<NodeId> },
25 #[error("connection target node is missing")]
26 MissingTargetNode { node_id: NodeId },
27 #[error("connection source node is missing")]
28 MissingSourceNode { node_id: NodeId },
29 #[error("connection target port `{port}` is missing")]
30 MissingTargetPort { node_id: NodeId, port: String },
31 #[error("connection source port `{port}` is missing")]
32 MissingSourcePort { node_id: NodeId, port: String },
33 #[error("missing required input `{port}`")]
34 MissingRequiredInput { node_id: NodeId, port: String },
35 #[error("port kind mismatch for `{to_port}`")]
36 PortKindMismatch {
37 from_node: NodeId,
38 from_port: String,
39 from_kind: PortKind,
40 to_node: NodeId,
41 to_port: String,
42 expected_kind: PortKind,
43 },
44 #[error("exactly one media output node is required")]
45 MissingMediaOutput,
46 #[error("exactly one media output node is required")]
47 MultipleMediaOutputs { count: usize },
48 #[error("target node is not reachable or missing")]
49 InvalidEvaluationTarget { node_id: NodeId },
50}
51
52#[derive(Debug, Error, Clone)]
53pub enum PropertyError {
54 #[error("property `{property_path}` is missing")]
55 MissingProperty {
56 node_id: NodeId,
57 property_path: String,
58 },
59 #[error("property `{property_path}` has invalid type")]
60 InvalidType {
61 node_id: NodeId,
62 property_path: String,
63 expected: &'static str,
64 actual: &'static str,
65 },
66}
67
68#[derive(Debug, Error, Clone)]
69pub enum ExpressionError {
70 #[error("expression parse failed: {details}")]
71 Parse {
72 path: Option<String>,
73 details: String,
74 },
75 #[error("expression evaluation failed: {details}")]
76 Evaluate {
77 path: Option<String>,
78 details: String,
79 },
80 #[error("undefined variable in expression")]
81 UndefinedVariable { path: Option<String>, name: String },
82}
83
84#[derive(Debug, Error, Clone)]
85pub enum MediaError {
86 #[error("media source not found: {media_source}")]
87 SourceNotFound { media_source: String },
88 #[error("media decoding failed for {media_source}: {details}")]
89 Decode {
90 media_source: String,
91 details: String,
92 },
93 #[error("media frame {frame} is out of range for {media_source} ({frame_count} frames)")]
94 FrameOutOfRange {
95 media_source: String,
96 frame: u32,
97 frame_count: u32,
98 },
99}
100
101#[derive(Debug, Error, Clone)]
102pub enum RenderError {
103 #[error("frame is out of range")]
104 FrameOutOfRange { frame: u32, duration_frames: u32 },
105 #[error("node evaluation failed")]
106 NodeEvaluation {
107 frame: u32,
108 node_id: NodeId,
109 node_kind: &'static str,
110 details: String,
111 },
112 #[error("referenced node is missing from the graph")]
113 MissingNode { frame: u32, node_id: NodeId },
114 #[error("surface allocation failed")]
115 SurfaceAllocation { width: u32, height: u32 },
116 #[error("node output is missing")]
117 MissingNodeOutput { frame: u32, node_id: NodeId },
118 #[error("node output has invalid type")]
119 InvalidNodeOutputType {
120 frame: u32,
121 node_id: NodeId,
122 expected: &'static str,
123 actual: &'static str,
124 },
125 #[error("media output node did not produce raster output")]
126 InvalidMediaOutputType { frame: u32, node_id: NodeId },
127 #[error("pixel readback failed")]
128 PixelReadbackFailed { width: u32, height: u32 },
129 #[error("all scratch surfaces are currently in use")]
130 ScratchSurfaceUnavailable,
131 #[error("{backend} backend is busy")]
132 BackendBusy { backend: &'static str },
133 #[error("render cancelled")]
134 Cancelled { frame: u32 },
135 #[error("GPU render failed: {details}")]
136 Gpu { details: String },
137}
138
139#[derive(Debug, Clone, PartialEq)]
140pub enum Warning {
141 FpsMismatch {
142 node_id: NodeId,
143 composition_fps: f32,
144 source_fps: f32,
145 },
146 CapabilityMissing {
147 node_id: NodeId,
148 requirement: &'static str,
149 },
150}