use thiserror::Error;
use qubit_datatype::DataConversionError;
use qubit_datatype::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("Variable substitution cycle detected: {}", chain.join(" -> "))]
SubstitutionCycle {
chain: Vec<String>,
},
#[error("Configuration merge failed: {0}")]
MergeError(String),
#[error("Property '{0}' is final and cannot be overridden")]
PropertyIsFinal(String),
#[error("Configuration key conflict at '{path}': existing {existing}, incoming {incoming}")]
KeyConflict {
path: String,
existing: String,
incoming: 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,
#[source]
source: Option<Box<ConfigError>>,
},
#[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(),
}
}
pub fn from_data_conversion_error(key: &str, err: DataConversionError) -> Self {
match err {
DataConversionError::NoValue => ConfigError::PropertyHasNoValue(key.to_string()),
DataConversionError::ConversionFailed { from, to } => ConfigError::ConversionError {
key: key.to_string(),
message: format!("From {from} to {to}"),
},
DataConversionError::ConversionError(message) => ConfigError::ConversionError {
key: key.to_string(),
message,
},
DataConversionError::JsonSerializationError(message) => ConfigError::ConversionError {
key: key.to_string(),
message: format!("JSON serialization error: {message}"),
},
DataConversionError::JsonDeserializationError(message) => {
ConfigError::ConversionError {
key: key.to_string(),
message: format!("JSON deserialization error: {message}"),
}
}
}
}
}
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}"),
},
}
}
}