bothan_lib/worker/
error.rs

1// ! Error types for asset workers.
2//!
3//! This module provides error handling functionality for asset workers. It defines
4//! a custom error type that can wrap other errors and provide additional context.
5//!
6//! The module provides:
7//!
8//! - The [`AssetWorkerError`] struct which serves as a universal error type for all worker implementations
9//! - Methods for creating errors with or without source errors
10//! - Implementations of standard error traits
11//!
12//! # Error Handling Strategy
13//!
14//! The error handling strategy in this module follows these principles:
15//!
16//! 1. **Context Preservation**: Errors include both a human-readable message and the original error
17//! 2. **Error Propagation**: The `From` trait implementation allows easy conversion from other error types
18//! 3. **Diagnostic Information**: Errors provide clear and helpful diagnostic information
19//!
20//! When implementing worker types, use this error type to provide consistent error
21//! handling throughout the asset worker system.
22
23use std::error::Error;
24use std::fmt;
25
26/// A custom error type for asset workers that wraps another error with an optional message.
27///
28/// `AssetWorkerError` provides a consistent error type for all asset worker implementations,
29/// allowing errors to be propagated with context. It can be used either as a standalone error
30/// with just a message, or it can wrap another error while adding additional context.
31///
32/// # Examples
33///
34/// Creating a standalone error:
35///
36/// ```
37/// use bothan_lib::worker::error::AssetWorkerError;
38///
39/// let error = AssetWorkerError::new("Failed to initialize worker");
40/// ```
41///
42/// Creating an error that wraps another error:
43///
44/// ```
45/// use bothan_lib::worker::error::AssetWorkerError;
46/// use std::io;
47///
48/// let io_error = io::Error::new(io::ErrorKind::NotFound, "Resource not found");
49/// let error = AssetWorkerError::with_source("Failed to fetch asset data", io_error);
50/// ```
51///
52/// Using the `From` trait for automatic conversion with the `?` operator for any error type that implements the `Error` trait:
53///
54/// ```
55/// use bothan_lib::worker::error::AssetWorkerError;
56/// use std::io;
57///
58/// fn process() -> Result<(), AssetWorkerError> {
59///     // The ? operator automatically converts io::Error to AssetWorkerError using From
60///     let result = std::fs::read_to_string("config.json")?;
61///     
62///     // Process the result...
63///     Ok(())
64/// }
65/// ```
66///
67pub struct AssetWorkerError {
68    /// A human-readable error message.
69    pub msg: String,
70
71    /// The optional source error that caused this error.
72    pub source: Option<Box<dyn Error + Send + Sync>>,
73}
74
75impl AssetWorkerError {
76    /// Create a new `AssetWorkerError` with a message.
77    ///
78    /// This method creates a standalone error without a source error.
79    /// Use this when the error originates within the worker code.
80    ///
81    /// # Examples
82    ///
83    /// ```
84    /// use bothan_lib::worker::error::AssetWorkerError;
85    ///
86    /// let error = AssetWorkerError::new("Failed to initialize worker");
87    /// ```
88    pub fn new(msg: impl Into<String>) -> Self {
89        Self {
90            msg: msg.into(),
91            source: None,
92        }
93    }
94
95    /// Create a new `AssetWorkerError` with a message and a source error.
96    ///
97    /// This method creates an error that wraps another error, adding context
98    /// about the operation that was being performed when the error occurred.
99    ///
100    /// # Examples
101    ///
102    /// ```
103    /// use bothan_lib::worker::error::AssetWorkerError;
104    /// use std::io;
105    ///
106    /// let io_error = io::Error::new(io::ErrorKind::NotFound, "Resource not found");
107    /// let error = AssetWorkerError::with_source("Failed to fetch asset data", io_error);
108    /// ```
109    pub fn with_source<E>(msg: impl Into<String>, source: E) -> Self
110    where
111        E: Error + Send + Sync + 'static,
112    {
113        Self {
114            msg: msg.into(),
115            source: Some(Box::new(source)),
116        }
117    }
118}
119
120impl fmt::Display for AssetWorkerError {
121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122        write!(f, "{}", self.msg)?;
123        if let Some(source) = &self.source {
124            write!(f, ": {}", source)?;
125        }
126        Ok(())
127    }
128}
129
130impl fmt::Debug for AssetWorkerError {
131    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132        fmt::Display::fmt(self, f)
133    }
134}
135
136impl<E> From<E> for AssetWorkerError
137where
138    E: Error + Send + Sync + 'static,
139{
140    fn from(err: E) -> Self {
141        Self {
142            msg: format!("An error occurred: {}", err),
143            source: Some(Box::new(err)),
144        }
145    }
146}