use thiserror::Error;
use crate::node::NodeId;
use crate::port::PortId;
pub type GraphResult<T> = Result<T, GraphError>;
#[derive(Error, Debug)]
pub enum GraphError {
#[error("node not found: {0:?}")]
NodeNotFound(NodeId),
#[error("port not found: node {node:?}, port {port:?}")]
PortNotFound {
node: NodeId,
port: PortId,
},
#[error(
"connection already exists from {from_node:?}:{from_port:?} to {to_node:?}:{to_port:?}"
)]
ConnectionExists {
from_node: NodeId,
from_port: PortId,
to_node: NodeId,
to_port: PortId,
},
#[error("incompatible formats: source {source_format}, destination {dest_format}")]
IncompatibleFormats {
source_format: String,
dest_format: String,
},
#[error("cycle detected in graph involving node {0:?}")]
CycleDetected(NodeId),
#[error("graph configuration error: {0}")]
ConfigurationError(String),
#[error("processing error in node {node:?}: {message}")]
ProcessingError {
node: NodeId,
message: String,
},
#[error("end of stream")]
EndOfStream,
#[error("no data available, try again")]
WouldBlock,
#[error("invalid state transition for node {node:?}: from {from} to {to}")]
InvalidStateTransition {
node: NodeId,
from: String,
to: String,
},
#[error("graph has no nodes")]
EmptyGraph,
#[error("graph has no source nodes")]
NoSourceNodes,
#[error("graph has no sink nodes")]
NoSinkNodes,
#[error("port type mismatch: expected {expected}, got {actual}")]
PortTypeMismatch {
expected: String,
actual: String,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = GraphError::NodeNotFound(NodeId(42));
assert!(err.to_string().contains("42"));
let err = GraphError::CycleDetected(NodeId(1));
assert!(err.to_string().contains("cycle"));
let err = GraphError::EmptyGraph;
assert!(err.to_string().contains("no nodes"));
}
#[test]
fn test_port_not_found_error() {
let err = GraphError::PortNotFound {
node: NodeId(1),
port: PortId(2),
};
let msg = err.to_string();
assert!(msg.contains("1"));
assert!(msg.contains("2"));
}
#[test]
fn test_incompatible_formats_error() {
let err = GraphError::IncompatibleFormats {
source_format: "video/yuv420p".to_string(),
dest_format: "audio/pcm".to_string(),
};
let msg = err.to_string();
assert!(msg.contains("video"));
assert!(msg.contains("audio"));
}
}