Skip to main content

aspect_core/
error.rs

1//! Error types for aspect execution.
2
3use std::error::Error;
4use std::fmt;
5
6/// Errors that can occur during aspect execution.
7///
8/// This type wraps errors that occur during the execution of advised functions
9/// or within aspect logic itself.
10#[derive(Debug)]
11pub enum AspectError {
12    /// An error occurred during function execution
13    ExecutionError {
14        /// The underlying error message
15        message: String,
16        /// Optional source error
17        source: Option<Box<dyn Error + Send + Sync>>,
18    },
19
20    /// An error occurred during aspect weaving
21    WeavingError {
22        /// Description of the weaving error
23        message: String,
24    },
25
26    /// A custom error defined by user code
27    Custom(Box<dyn Error + Send + Sync>),
28}
29
30impl AspectError {
31    /// Creates a new execution error.
32    ///
33    /// # Example
34    ///
35    /// ```rust
36    /// use aspect_core::error::AspectError;
37    ///
38    /// let err = AspectError::execution("Database connection failed");
39    /// ```
40    pub fn execution(message: impl Into<String>) -> Self {
41        Self::ExecutionError {
42            message: message.into(),
43            source: None,
44        }
45    }
46
47    /// Creates a new execution error with a source.
48    ///
49    /// # Example
50    ///
51    /// ```rust
52    /// use aspect_core::error::AspectError;
53    /// use std::io;
54    ///
55    /// let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
56    /// let err = AspectError::execution_with_source("Failed to read file", io_err);
57    /// ```
58    pub fn execution_with_source(
59        message: impl Into<String>,
60        source: impl Error + Send + Sync + 'static,
61    ) -> Self {
62        Self::ExecutionError {
63            message: message.into(),
64            source: Some(Box::new(source)),
65        }
66    }
67
68    /// Creates a new weaving error.
69    ///
70    /// # Example
71    ///
72    /// ```rust
73    /// use aspect_core::error::AspectError;
74    ///
75    /// let err = AspectError::weaving("Invalid pointcut expression");
76    /// ```
77    pub fn weaving(message: impl Into<String>) -> Self {
78        Self::WeavingError {
79            message: message.into(),
80        }
81    }
82
83    /// Creates a custom error from any error type.
84    ///
85    /// # Example
86    ///
87    /// ```rust
88    /// use aspect_core::error::AspectError;
89    /// use std::io;
90    ///
91    /// let io_err = io::Error::new(io::ErrorKind::Other, "custom error");
92    /// let err = AspectError::custom(io_err);
93    /// ```
94    pub fn custom(error: impl Error + Send + Sync + 'static) -> Self {
95        Self::Custom(Box::new(error))
96    }
97}
98
99impl fmt::Display for AspectError {
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        match self {
102            Self::ExecutionError { message, .. } => {
103                write!(f, "Execution error: {}", message)
104            }
105            Self::WeavingError { message } => {
106                write!(f, "Weaving error: {}", message)
107            }
108            Self::Custom(err) => write!(f, "Custom error: {}", err),
109        }
110    }
111}
112
113impl Error for AspectError {
114    fn source(&self) -> Option<&(dyn Error + 'static)> {
115        match self {
116            Self::ExecutionError { source, .. } => {
117                source.as_ref().map(|e| e.as_ref() as &(dyn Error + 'static))
118            }
119            Self::Custom(err) => Some(err.as_ref()),
120            _ => None,
121        }
122    }
123}
124
125// Conversion from common error types
126impl From<String> for AspectError {
127    fn from(s: String) -> Self {
128        Self::execution(s)
129    }
130}
131
132impl From<&str> for AspectError {
133    fn from(s: &str) -> Self {
134        Self::execution(s)
135    }
136}
137
138impl From<Box<dyn Error + Send + Sync>> for AspectError {
139    fn from(err: Box<dyn Error + Send + Sync>) -> Self {
140        Self::Custom(err)
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147    use std::io;
148
149    #[test]
150    fn test_execution_error() {
151        let err = AspectError::execution("test error");
152        assert!(matches!(err, AspectError::ExecutionError { .. }));
153        assert_eq!(err.to_string(), "Execution error: test error");
154    }
155
156    #[test]
157    fn test_execution_error_with_source() {
158        let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
159        let err = AspectError::execution_with_source("read failed", io_err);
160
161        assert!(err.source().is_some());
162    }
163
164    #[test]
165    fn test_weaving_error() {
166        let err = AspectError::weaving("invalid pointcut");
167        assert!(matches!(err, AspectError::WeavingError { .. }));
168        assert_eq!(err.to_string(), "Weaving error: invalid pointcut");
169    }
170
171    #[test]
172    fn test_custom_error() {
173        let io_err = io::Error::new(io::ErrorKind::Other, "custom");
174        let err = AspectError::custom(io_err);
175
176        assert!(matches!(err, AspectError::Custom(_)));
177    }
178
179    #[test]
180    fn test_from_string() {
181        let err: AspectError = "error message".into();
182        assert!(matches!(err, AspectError::ExecutionError { .. }));
183    }
184}