Skip to main content

oximedia_graph/
error.rs

1//! Error types for the filter graph.
2
3use thiserror::Error;
4
5use crate::node::NodeId;
6use crate::port::PortId;
7
8/// Result type for graph operations.
9pub type GraphResult<T> = Result<T, GraphError>;
10
11/// Errors that can occur in filter graph operations.
12#[derive(Error, Debug)]
13pub enum GraphError {
14    /// Node not found in the graph.
15    #[error("node not found: {0:?}")]
16    NodeNotFound(NodeId),
17
18    /// Port not found on node.
19    #[error("port not found: node {node:?}, port {port:?}")]
20    PortNotFound {
21        /// The node ID.
22        node: NodeId,
23        /// The port ID.
24        port: PortId,
25    },
26
27    /// Connection already exists.
28    #[error(
29        "connection already exists from {from_node:?}:{from_port:?} to {to_node:?}:{to_port:?}"
30    )]
31    ConnectionExists {
32        /// Source node ID.
33        from_node: NodeId,
34        /// Source port ID.
35        from_port: PortId,
36        /// Destination node ID.
37        to_node: NodeId,
38        /// Destination port ID.
39        to_port: PortId,
40    },
41
42    /// Incompatible port formats.
43    #[error("incompatible formats: source {source_format}, destination {dest_format}")]
44    IncompatibleFormats {
45        /// Source format description.
46        source_format: String,
47        /// Destination format description.
48        dest_format: String,
49    },
50
51    /// Cycle detected in the graph.
52    #[error("cycle detected in graph involving node {0:?}")]
53    CycleDetected(NodeId),
54
55    /// Graph is not configured properly.
56    #[error("graph configuration error: {0}")]
57    ConfigurationError(String),
58
59    /// Node processing error.
60    #[error("processing error in node {node:?}: {message}")]
61    ProcessingError {
62        /// The node where processing failed.
63        node: NodeId,
64        /// Error message.
65        message: String,
66    },
67
68    /// End of stream reached.
69    #[error("end of stream")]
70    EndOfStream,
71
72    /// No data available (non-blocking).
73    #[error("no data available, try again")]
74    WouldBlock,
75
76    /// Invalid node state transition.
77    #[error("invalid state transition for node {node:?}: from {from} to {to}")]
78    InvalidStateTransition {
79        /// The node ID.
80        node: NodeId,
81        /// Current state name.
82        from: String,
83        /// Attempted state name.
84        to: String,
85    },
86
87    /// Graph is empty.
88    #[error("graph has no nodes")]
89    EmptyGraph,
90
91    /// No source nodes found.
92    #[error("graph has no source nodes")]
93    NoSourceNodes,
94
95    /// No sink nodes found.
96    #[error("graph has no sink nodes")]
97    NoSinkNodes,
98
99    /// Port type mismatch.
100    #[error("port type mismatch: expected {expected}, got {actual}")]
101    PortTypeMismatch {
102        /// Expected port type.
103        expected: String,
104        /// Actual port type.
105        actual: String,
106    },
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112
113    #[test]
114    fn test_error_display() {
115        let err = GraphError::NodeNotFound(NodeId(42));
116        assert!(err.to_string().contains("42"));
117
118        let err = GraphError::CycleDetected(NodeId(1));
119        assert!(err.to_string().contains("cycle"));
120
121        let err = GraphError::EmptyGraph;
122        assert!(err.to_string().contains("no nodes"));
123    }
124
125    #[test]
126    fn test_port_not_found_error() {
127        let err = GraphError::PortNotFound {
128            node: NodeId(1),
129            port: PortId(2),
130        };
131        let msg = err.to_string();
132        assert!(msg.contains("1"));
133        assert!(msg.contains("2"));
134    }
135
136    #[test]
137    fn test_incompatible_formats_error() {
138        let err = GraphError::IncompatibleFormats {
139            source_format: "video/yuv420p".to_string(),
140            dest_format: "audio/pcm".to_string(),
141        };
142        let msg = err.to_string();
143        assert!(msg.contains("video"));
144        assert!(msg.contains("audio"));
145    }
146}