Mountain/Error/
ConfigurationError.rs1use std::{error::Error as StdError, fmt};
8
9use serde::{Deserialize, Serialize};
10
11use super::CoreError::{ErrorContext, ErrorKind, ErrorSeverity, MountainError};
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
15pub enum ConfigurationError {
16 KeyNotFound { context:ErrorContext, key:String, section:Option<String> },
18
19 InvalidValue { context:ErrorContext, key:String, expected_type:String },
21
22 ValidationFailed { context:ErrorContext, errors:Vec<String> },
24
25 ParseError { context:ErrorContext, format:String, source:String },
27
28 FileNotFound { context:ErrorContext, path:String },
30
31 FileReadError { context:ErrorContext, path:String, source:String },
33
34 FileWriteError { context:ErrorContext, path:String, source:String },
36
37 CircularDependency { context:ErrorContext, keys:Vec<String> },
39}
40
41impl ConfigurationError {
42 pub fn context(&self) -> &ErrorContext {
44 match self {
45 ConfigurationError::KeyNotFound { context, .. } => context,
46
47 ConfigurationError::InvalidValue { context, .. } => context,
48
49 ConfigurationError::ValidationFailed { context, .. } => context,
50
51 ConfigurationError::ParseError { context, .. } => context,
52
53 ConfigurationError::FileNotFound { context, .. } => context,
54
55 ConfigurationError::FileReadError { context, .. } => context,
56
57 ConfigurationError::FileWriteError { context, .. } => context,
58
59 ConfigurationError::CircularDependency { context, .. } => context,
60 }
61 }
62
63 pub fn key_not_found(key:impl Into<String>, section:Option<String>) -> Self {
65 let key = key.into();
66
67 let message = if let Some(section) = §ion {
68 format!("Configuration key '{}' not found in section '{}'", key, section)
69 } else {
70 format!("Configuration key '{}' not found", key)
71 };
72
73 Self::KeyNotFound {
74 context:ErrorContext::new(message)
75 .with_kind(ErrorKind::Configuration)
76 .with_severity(ErrorSeverity::Error),
77
78 key,
79
80 section,
81 }
82 }
83
84 pub fn invalid_value(key:impl Into<String>, expected_type:impl Into<String>) -> Self {
86 let key_str = key.into();
87
88 let expected_type_str = expected_type.into();
89
90 Self::InvalidValue {
91 context:ErrorContext::new(format!(
92 "Invalid value for key '{}': expected type '{}'",
93 key_str, expected_type_str
94 ))
95 .with_kind(ErrorKind::Configuration)
96 .with_severity(ErrorSeverity::Error),
97
98 key:key_str,
99
100 expected_type:expected_type_str,
101 }
102 }
103
104 pub fn validation_failed(errors:Vec<String>) -> Self {
106 Self::ValidationFailed {
107 context:ErrorContext::new(format!("Configuration validation failed with {} error(s)", errors.len()))
108 .with_kind(ErrorKind::Configuration)
109 .with_severity(ErrorSeverity::Error),
110
111 errors,
112 }
113 }
114
115 pub fn parse_error(format:impl Into<String>, source:impl Into<String>, message:impl Into<String>) -> Self {
117 Self::ParseError {
118 context:ErrorContext::new(message)
119 .with_kind(ErrorKind::Configuration)
120 .with_severity(ErrorSeverity::Error),
121
122 format:format.into(),
123
124 source:source.into(),
125 }
126 }
127
128 pub fn file_not_found(path:impl Into<String>) -> Self {
130 let path_str = path.into();
131
132 Self::FileNotFound {
133 context:ErrorContext::new(format!("Configuration file not found: {}", path_str))
134 .with_kind(ErrorKind::Configuration)
135 .with_severity(ErrorSeverity::Error),
136
137 path:path_str,
138 }
139 }
140
141 pub fn circular_dependency(keys:Vec<String>) -> Self {
143 Self::CircularDependency {
144 context:ErrorContext::new(format!("Circular dependency detected in configuration: {}", keys.join(" -> ")))
145 .with_kind(ErrorKind::Configuration)
146 .with_severity(ErrorSeverity::Critical),
147
148 keys,
149 }
150 }
151}
152
153impl fmt::Display for ConfigurationError {
154 fn fmt(&self, f:&mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.context()) }
155}
156
157impl StdError for ConfigurationError {}
158
159impl From<ConfigurationError> for MountainError {
160 fn from(err:ConfigurationError) -> Self { MountainError::new(err.context().clone()).with_source(err.to_string()) }
161}