better_config_core/
error.rs

1use std::{error::Error as StdError, fmt};
2
3#[derive(Debug)]
4pub enum Error {
5    /// Failed to load or read a configuration file
6    LoadFileError {
7        name: String,
8        source: Option<Box<dyn StdError + Send + Sync>>,
9    },
10    /// Failed to parse configuration content (JSON, YAML, TOML, etc.)
11    ParseError {
12        name: String,
13        format: String,
14        source: Option<Box<dyn StdError + Send + Sync>>,
15    },
16    /// Invalid configuration value or type conversion error
17    ValueError {
18        key: String,
19        expected_type: String,
20        actual_value: String,
21    },
22    /// Invalid file path or configuration target
23    InvalidPathError { path: String, reason: String },
24    /// Configuration validation failed
25    ValidationError { message: String },
26    /// I/O operation failed
27    IoError {
28        operation: String,
29        source: Option<Box<dyn StdError + Send + Sync>>,
30    },
31}
32
33impl fmt::Display for Error {
34    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35        match self {
36            Error::LoadFileError { name, source } => {
37                write!(f, "Failed to load file {}", name)?;
38                if let Some(source) = source {
39                    write!(f, ": {}", source)?;
40                }
41                Ok(())
42            }
43            Error::ParseError {
44                name,
45                format,
46                source,
47            } => {
48                write!(f, "Failed to parse {} file {} as {}", format, name, format)?;
49                if let Some(source) = source {
50                    write!(f, ": {}", source)?;
51                }
52                Ok(())
53            }
54            Error::ValueError {
55                key,
56                expected_type,
57                actual_value,
58            } => {
59                write!(
60                    f,
61                    "Invalid value for key '{}': expected {}, got '{}'",
62                    key, expected_type, actual_value
63                )
64            }
65            Error::InvalidPathError { path, reason } => {
66                write!(f, "Invalid path '{}': {}", path, reason)
67            }
68            Error::ValidationError { message } => {
69                write!(f, "Configuration validation failed: {}", message)
70            }
71            Error::IoError { operation, source } => {
72                write!(f, "I/O operation '{}' failed", operation)?;
73                if let Some(source) = source {
74                    write!(f, ": {}", source)?;
75                }
76                Ok(())
77            }
78        }
79    }
80}
81
82impl StdError for Error {
83    fn source(&self) -> Option<&(dyn StdError + 'static)> {
84        match self {
85            Error::LoadFileError { source, .. } => {
86                source.as_deref().map(|e| e as &(dyn StdError + 'static))
87            }
88            Error::ParseError { source, .. } => {
89                source.as_deref().map(|e| e as &(dyn StdError + 'static))
90            }
91            Error::IoError { source, .. } => {
92                source.as_deref().map(|e| e as &(dyn StdError + 'static))
93            }
94            _ => None,
95        }
96    }
97}
98
99// Helper constructors for creating common errors
100impl Error {
101    pub fn file_not_found(path: &str) -> Self {
102        Error::LoadFileError {
103            name: path.to_string(),
104            source: Some(Box::new(std::io::Error::new(
105                std::io::ErrorKind::NotFound,
106                format!("File '{}' not found", path),
107            ))),
108        }
109    }
110
111    pub fn parse_json_error(path: &str, source: impl StdError + Send + Sync + 'static) -> Self {
112        Error::ParseError {
113            name: path.to_string(),
114            format: "JSON".to_string(),
115            source: Some(Box::new(source)),
116        }
117    }
118
119    pub fn parse_yaml_error(path: &str, source: impl StdError + Send + Sync + 'static) -> Self {
120        Error::ParseError {
121            name: path.to_string(),
122            format: "YAML".to_string(),
123            source: Some(Box::new(source)),
124        }
125    }
126
127    pub fn parse_toml_error(path: &str, source: impl StdError + Send + Sync + 'static) -> Self {
128        Error::ParseError {
129            name: path.to_string(),
130            format: "TOML".to_string(),
131            source: Some(Box::new(source)),
132        }
133    }
134
135    pub fn invalid_path(path: &str, reason: &str) -> Self {
136        Error::InvalidPathError {
137            path: path.to_string(),
138            reason: reason.to_string(),
139        }
140    }
141
142    pub fn value_conversion_error(key: &str, expected: &str, actual: &str) -> Self {
143        Error::ValueError {
144            key: key.to_string(),
145            expected_type: expected.to_string(),
146            actual_value: actual.to_string(),
147        }
148    }
149}