1use thiserror::Error;
4
5use crate::node::NodeId;
6use crate::port::PortId;
7
8pub type GraphResult<T> = Result<T, GraphError>;
10
11#[derive(Error, Debug)]
13pub enum GraphError {
14 #[error("node not found: {0:?}")]
16 NodeNotFound(NodeId),
17
18 #[error("port not found: node {node:?}, port {port:?}")]
20 PortNotFound {
21 node: NodeId,
23 port: PortId,
25 },
26
27 #[error(
29 "connection already exists from {from_node:?}:{from_port:?} to {to_node:?}:{to_port:?}"
30 )]
31 ConnectionExists {
32 from_node: NodeId,
34 from_port: PortId,
36 to_node: NodeId,
38 to_port: PortId,
40 },
41
42 #[error("incompatible formats: source {source_format}, destination {dest_format}")]
44 IncompatibleFormats {
45 source_format: String,
47 dest_format: String,
49 },
50
51 #[error("cycle detected in graph involving node {0:?}")]
53 CycleDetected(NodeId),
54
55 #[error("graph configuration error: {0}")]
57 ConfigurationError(String),
58
59 #[error("processing error in node {node:?}: {message}")]
61 ProcessingError {
62 node: NodeId,
64 message: String,
66 },
67
68 #[error("end of stream")]
70 EndOfStream,
71
72 #[error("no data available, try again")]
74 WouldBlock,
75
76 #[error("invalid state transition for node {node:?}: from {from} to {to}")]
78 InvalidStateTransition {
79 node: NodeId,
81 from: String,
83 to: String,
85 },
86
87 #[error("graph has no nodes")]
89 EmptyGraph,
90
91 #[error("graph has no source nodes")]
93 NoSourceNodes,
94
95 #[error("graph has no sink nodes")]
97 NoSinkNodes,
98
99 #[error("port type mismatch: expected {expected}, got {actual}")]
101 PortTypeMismatch {
102 expected: String,
104 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}