flow_gates/
error.rs

1//! Error types for gate operations.
2//!
3//! This module defines `GateError`, a comprehensive error type for all gate-related
4//! operations. It uses `thiserror` for convenient error construction and implements
5//! standard error traits for integration with error handling libraries.
6
7use std::error::Error as StdError;
8use thiserror::Error;
9
10/// Custom error type for gate operations.
11///
12/// All gate operations return `Result<T, GateError>`. The error type provides
13/// detailed context about what went wrong, making debugging easier.
14#[derive(Debug, Error)]
15pub enum GateError {
16    /// Geometry validation failures
17    #[error("Invalid geometry: {message}")]
18    InvalidGeometry { message: String },
19
20    /// Missing required parameter/channel
21    #[error("Missing parameter '{parameter}' in context: {context}")]
22    MissingParameter { parameter: String, context: String },
23
24    /// Invalid coordinate values
25    #[error("Invalid coordinate '{coordinate}': value {value} is not finite or out of range")]
26    InvalidCoordinate { coordinate: String, value: f32 },
27
28    /// Event filtering failures
29    #[error("Filtering error: {message}")]
30    FilteringError { message: String },
31
32    /// Hierarchy operation failures
33    #[error("Hierarchy error: {message}")]
34    HierarchyError { message: String },
35
36    /// Serialization/deserialization errors
37    #[error("Serialization error: {0}")]
38    SerializationError(#[from] serde_json::Error),
39
40    /// EventIndex build/query errors
41    #[error("Index error: {message}")]
42    IndexError { message: String },
43
44    /// Generic error with context (for wrapping other errors)
45    #[error("{message}")]
46    Other {
47        message: String,
48        #[source]
49        source: Option<Box<dyn StdError + Send + Sync>>,
50    },
51}
52
53impl GateError {
54    /// Create an InvalidGeometry error with a message
55    pub fn invalid_geometry(message: impl Into<String>) -> Self {
56        Self::InvalidGeometry {
57            message: message.into(),
58        }
59    }
60
61    /// Create a MissingParameter error
62    pub fn missing_parameter(parameter: impl Into<String>, context: impl Into<String>) -> Self {
63        Self::MissingParameter {
64            parameter: parameter.into(),
65            context: context.into(),
66        }
67    }
68
69    /// Create an InvalidCoordinate error
70    pub fn invalid_coordinate(coordinate: impl Into<String>, value: f32) -> Self {
71        Self::InvalidCoordinate {
72            coordinate: coordinate.into(),
73            value,
74        }
75    }
76
77    /// Create a FilteringError with a message
78    pub fn filtering_error(message: impl Into<String>) -> Self {
79        Self::FilteringError {
80            message: message.into(),
81        }
82    }
83
84    /// Create a HierarchyError with a message
85    pub fn hierarchy_error(message: impl Into<String>) -> Self {
86        Self::HierarchyError {
87            message: message.into(),
88        }
89    }
90
91    /// Create an IndexError with a message
92    pub fn index_error(message: impl Into<String>) -> Self {
93        Self::IndexError {
94            message: message.into(),
95        }
96    }
97
98    /// Add context to an error
99    pub fn with_context(self, context: impl Into<String>) -> Self {
100        match self {
101            Self::InvalidGeometry { message } => Self::InvalidGeometry {
102                message: format!("{}: {}", context.into(), message),
103            },
104            Self::MissingParameter {
105                parameter,
106                context: ctx,
107            } => Self::MissingParameter {
108                parameter,
109                context: format!("{}: {}", context.into(), ctx),
110            },
111            Self::InvalidCoordinate { coordinate, value } => {
112                Self::InvalidCoordinate { coordinate, value }
113            }
114            Self::FilteringError { message } => Self::FilteringError {
115                message: format!("{}: {}", context.into(), message),
116            },
117            Self::HierarchyError { message } => Self::HierarchyError {
118                message: format!("{}: {}", context.into(), message),
119            },
120            Self::SerializationError(e) => Self::Other {
121                message: format!("{}: {}", context.into(), e),
122                source: Some(Box::new(e)),
123            },
124            Self::IndexError { message } => Self::IndexError {
125                message: format!("{}: {}", context.into(), message),
126            },
127            Self::Other { message, source } => Self::Other {
128                message: format!("{}: {}", context.into(), message),
129                source,
130            },
131        }
132    }
133}
134
135// Conversion from anyhow::Error for convenience
136impl From<anyhow::Error> for GateError {
137    fn from(err: anyhow::Error) -> Self {
138        Self::Other {
139            message: err.to_string(),
140            source: None, // anyhow::Error already contains the full context
141        }
142    }
143}
144
145// Type alias for Result using GateError
146pub type Result<T> = std::result::Result<T, GateError>;