use thiserror::Error;
use qubit_common::DataType;
use qubit_value::ValueError;
#[derive(Debug, Error)]
pub enum ConfigError {
#[error("Property not found: {0}")]
PropertyNotFound(String),
#[error("Property '{0}' has no value")]
PropertyHasNoValue(String),
#[error("Type mismatch at '{key}': expected {expected}, actual {actual}")]
TypeMismatch {
key: String,
expected: DataType,
actual: DataType,
},
#[error("Type conversion failed at '{key}': {message}")]
ConversionError {
key: String,
message: String,
},
#[error("Index out of bounds: index {index}, length {len}")]
IndexOutOfBounds {
index: usize,
len: usize,
},
#[error("Variable substitution failed: {0}")]
SubstitutionError(String),
#[error("Variable substitution depth exceeded maximum limit: {0}")]
SubstitutionDepthExceeded(usize),
#[error("Configuration merge failed: {0}")]
MergeError(String),
#[error("Property '{0}' is final and cannot be overridden")]
PropertyIsFinal(String),
#[error("IO error: {0}")]
IoError(#[from] std::io::Error),
#[error("Parse error: {0}")]
ParseError(String),
#[error("Deserialization error at '{path}': {message}")]
DeserializeError {
path: String,
message: String,
},
#[error("Configuration error: {0}")]
Other(String),
}
impl ConfigError {
#[inline]
pub(crate) fn type_mismatch_no_key(expected: DataType, actual: DataType) -> Self {
ConfigError::TypeMismatch {
key: String::new(),
expected,
actual,
}
}
#[inline]
pub(crate) fn conversion_error_no_key(message: impl Into<String>) -> Self {
ConfigError::ConversionError {
key: String::new(),
message: message.into(),
}
}
}
impl From<ValueError> for ConfigError {
fn from(err: ValueError) -> Self {
match err {
ValueError::NoValue => ConfigError::PropertyHasNoValue(String::new()),
ValueError::TypeMismatch { expected, actual } => {
ConfigError::type_mismatch_no_key(expected, actual)
}
ValueError::ConversionFailed { from, to } => {
ConfigError::conversion_error_no_key(format!("From {from} to {to}"))
}
ValueError::ConversionError(msg) => ConfigError::conversion_error_no_key(msg),
ValueError::IndexOutOfBounds { index, len } => {
ConfigError::IndexOutOfBounds { index, len }
}
ValueError::JsonSerializationError(msg) => {
ConfigError::conversion_error_no_key(format!("JSON serialization error: {msg}"))
}
ValueError::JsonDeserializationError(msg) => {
ConfigError::conversion_error_no_key(format!("JSON deserialization error: {msg}"))
}
}
}
}
impl From<(&str, ValueError)> for ConfigError {
fn from((key, err): (&str, ValueError)) -> Self {
match err {
ValueError::NoValue => ConfigError::PropertyHasNoValue(key.to_string()),
ValueError::TypeMismatch { expected, actual } => ConfigError::TypeMismatch {
key: key.to_string(),
expected,
actual,
},
ValueError::ConversionFailed { from, to } => ConfigError::ConversionError {
key: key.to_string(),
message: format!("From {from} to {to}"),
},
ValueError::ConversionError(message) => ConfigError::ConversionError {
key: key.to_string(),
message,
},
ValueError::IndexOutOfBounds { index, len } => {
ConfigError::IndexOutOfBounds { index, len }
}
ValueError::JsonSerializationError(message) => ConfigError::ConversionError {
key: key.to_string(),
message: format!("JSON serialization error: {message}"),
},
ValueError::JsonDeserializationError(message) => ConfigError::ConversionError {
key: key.to_string(),
message: format!("JSON deserialization error: {message}"),
},
}
}
}