Skip to main content

Mountain/Error/
ConfigurationError.rs

1//! # Configuration Error Types
2//!
3//! Provides configuration management error types for Mountain.
4//! Covers key lookup, value validation, parse failures, file I/O,
5//! and circular-dependency detection in configuration graphs.
6
7use std::{error::Error as StdError, fmt};
8
9use serde::{Deserialize, Serialize};
10
11use super::CoreError::{ErrorContext, ErrorKind, ErrorSeverity, MountainError};
12
13/// Configuration operation error types.
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub enum ConfigurationError {
16	/// Configuration key not found.
17	KeyNotFound { context:ErrorContext, key:String, section:Option<String> },
18
19	/// Invalid configuration value.
20	InvalidValue { context:ErrorContext, key:String, expected_type:String },
21
22	/// Configuration validation failed.
23	ValidationFailed { context:ErrorContext, errors:Vec<String> },
24
25	/// Configuration parse error.
26	ParseError { context:ErrorContext, format:String, source:String },
27
28	/// Configuration file not found.
29	FileNotFound { context:ErrorContext, path:String },
30
31	/// Configuration file read error.
32	FileReadError { context:ErrorContext, path:String, source:String },
33
34	/// Configuration file write error.
35	FileWriteError { context:ErrorContext, path:String, source:String },
36
37	/// Circular dependency detected.
38	CircularDependency { context:ErrorContext, keys:Vec<String> },
39}
40
41impl ConfigurationError {
42	/// Get the error context.
43	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	/// Create a key not found error.
64	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) = &section {
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	/// Create an invalid value error.
85	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	/// Create a validation failed error.
105	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	/// Create a parse error.
116	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	/// Create a file not found error.
129	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	/// Create a circular dependency error.
142	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}