1use thiserror::Error;
16
17use qubit_datatype::DataConversionError;
18use qubit_datatype::DataType;
19use qubit_value::ValueError;
20
21#[derive(Debug, Error)]
34pub enum ConfigError {
35 #[error("Property not found: {0}")]
37 PropertyNotFound(String),
38
39 #[error("Property '{0}' has no value")]
41 PropertyHasNoValue(String),
42
43 #[error("Type mismatch at '{key}': expected {expected}, actual {actual}")]
45 TypeMismatch {
46 key: String,
48 expected: DataType,
50 actual: DataType,
52 },
53
54 #[error("Type conversion failed at '{key}': {message}")]
56 ConversionError {
57 key: String,
59 message: String,
61 },
62
63 #[error("Index out of bounds: index {index}, length {len}")]
65 IndexOutOfBounds {
66 index: usize,
68 len: usize,
70 },
71
72 #[error("Variable substitution failed: {0}")]
74 SubstitutionError(String),
75
76 #[error("Variable substitution depth exceeded maximum limit: {0}")]
78 SubstitutionDepthExceeded(usize),
79
80 #[error("Variable substitution cycle detected: {}", chain.join(" -> "))]
82 SubstitutionCycle {
83 chain: Vec<String>,
85 },
86
87 #[error("Configuration merge failed: {0}")]
89 MergeError(String),
90
91 #[error("Property '{0}' is final and cannot be overridden")]
93 PropertyIsFinal(String),
94
95 #[error("Configuration key conflict at '{path}': existing {existing}, incoming {incoming}")]
97 KeyConflict {
98 path: String,
100 existing: String,
102 incoming: String,
104 },
105
106 #[error("IO error: {0}")]
108 IoError(#[from] std::io::Error),
109
110 #[error("Parse error: {0}")]
112 ParseError(String),
113
114 #[error("Deserialization error at '{path}': {message}")]
116 DeserializeError {
117 path: String,
119 message: String,
121 #[source]
123 source: Option<Box<ConfigError>>,
124 },
125
126 #[error("Configuration error: {0}")]
128 Other(String),
129}
130
131impl ConfigError {
132 #[inline]
144 pub(crate) fn type_mismatch_no_key(expected: DataType, actual: DataType) -> Self {
145 ConfigError::TypeMismatch {
146 key: String::new(),
147 expected,
148 actual,
149 }
150 }
151
152 #[inline]
162 pub(crate) fn conversion_error_no_key(message: impl Into<String>) -> Self {
163 ConfigError::ConversionError {
164 key: String::new(),
165 message: message.into(),
166 }
167 }
168
169 pub fn from_data_conversion_error(key: &str, err: DataConversionError) -> Self {
180 match err {
181 DataConversionError::NoValue => ConfigError::PropertyHasNoValue(key.to_string()),
182 DataConversionError::ConversionFailed { from, to } => ConfigError::ConversionError {
183 key: key.to_string(),
184 message: format!("From {from} to {to}"),
185 },
186 DataConversionError::ConversionError(message) => ConfigError::ConversionError {
187 key: key.to_string(),
188 message,
189 },
190 DataConversionError::JsonSerializationError(message) => ConfigError::ConversionError {
191 key: key.to_string(),
192 message: format!("JSON serialization error: {message}"),
193 },
194 DataConversionError::JsonDeserializationError(message) => ConfigError::ConversionError {
195 key: key.to_string(),
196 message: format!("JSON deserialization error: {message}"),
197 },
198 }
199 }
200}
201
202impl From<ValueError> for ConfigError {
203 fn from(err: ValueError) -> Self {
204 match err {
205 ValueError::NoValue => ConfigError::PropertyHasNoValue(String::new()),
206 ValueError::TypeMismatch { expected, actual } => ConfigError::type_mismatch_no_key(expected, actual),
207 ValueError::ConversionFailed { from, to } => {
208 ConfigError::conversion_error_no_key(format!("From {from} to {to}"))
209 }
210 ValueError::ConversionError(msg) => ConfigError::conversion_error_no_key(msg),
211 ValueError::IndexOutOfBounds { index, len } => ConfigError::IndexOutOfBounds { index, len },
212 ValueError::JsonSerializationError(msg) => {
213 ConfigError::conversion_error_no_key(format!("JSON serialization error: {msg}"))
214 }
215 ValueError::JsonDeserializationError(msg) => {
216 ConfigError::conversion_error_no_key(format!("JSON deserialization error: {msg}"))
217 }
218 }
219 }
220}
221
222impl From<(&str, ValueError)> for ConfigError {
223 fn from((key, err): (&str, ValueError)) -> Self {
224 match err {
225 ValueError::NoValue => ConfigError::PropertyHasNoValue(key.to_string()),
226 ValueError::TypeMismatch { expected, actual } => ConfigError::TypeMismatch {
227 key: key.to_string(),
228 expected,
229 actual,
230 },
231 ValueError::ConversionFailed { from, to } => ConfigError::ConversionError {
232 key: key.to_string(),
233 message: format!("From {from} to {to}"),
234 },
235 ValueError::ConversionError(message) => ConfigError::ConversionError {
236 key: key.to_string(),
237 message,
238 },
239 ValueError::IndexOutOfBounds { index, len } => ConfigError::IndexOutOfBounds { index, len },
240 ValueError::JsonSerializationError(message) => ConfigError::ConversionError {
241 key: key.to_string(),
242 message: format!("JSON serialization error: {message}"),
243 },
244 ValueError::JsonDeserializationError(message) => ConfigError::ConversionError {
245 key: key.to_string(),
246 message: format!("JSON deserialization error: {message}"),
247 },
248 }
249 }
250}