use std::fmt;
use super::HttpConfigErrorKind;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HttpConfigError {
pub path: String,
pub message: String,
pub kind: HttpConfigErrorKind,
}
impl HttpConfigError {
pub fn new(
kind: HttpConfigErrorKind,
path: impl Into<String>,
message: impl Into<String>,
) -> Self {
Self {
kind,
path: path.into(),
message: message.into(),
}
}
pub fn missing(path: impl Into<String>, message: impl Into<String>) -> Self {
Self::new(HttpConfigErrorKind::MissingField, path, message)
}
pub fn type_error(path: impl Into<String>, message: impl Into<String>) -> Self {
Self::new(HttpConfigErrorKind::TypeError, path, message)
}
pub fn invalid_value(path: impl Into<String>, message: impl Into<String>) -> Self {
Self::new(HttpConfigErrorKind::InvalidValue, path, message)
}
pub fn invalid_header(path: impl Into<String>, message: impl Into<String>) -> Self {
Self::new(HttpConfigErrorKind::InvalidHeader, path, message)
}
pub fn config_error(path: impl Into<String>, message: impl Into<String>) -> Self {
Self::new(HttpConfigErrorKind::ConfigError, path, message)
}
pub(crate) fn prepend_path_prefix(mut self, prefix: &str) -> Self {
let prefix_with_dot = format!("{prefix}.");
let already_prefixed = self.path == prefix || self.path.starts_with(&prefix_with_dot);
if !already_prefixed {
self.path = self
.path
.find(&prefix_with_dot)
.map(|index| self.path[index..].to_string())
.unwrap_or_else(|| {
[prefix, self.path.as_str()]
.into_iter()
.filter(|part| !part.is_empty())
.collect::<Vec<_>>()
.join(".")
});
}
self
}
}
impl fmt::Display for HttpConfigError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}] {}: {}", self.kind, self.path, self.message)
}
}
impl std::error::Error for HttpConfigError {}
impl From<qubit_config::ConfigError> for HttpConfigError {
fn from(e: qubit_config::ConfigError) -> Self {
use qubit_config::ConfigError;
let msg = e.to_string();
match e {
ConfigError::TypeMismatch { key, .. } | ConfigError::ConversionError { key, .. } => {
HttpConfigError::type_error(key, msg)
}
ConfigError::PropertyHasNoValue(key) => HttpConfigError::type_error(key, msg),
ConfigError::PropertyNotFound(key) => HttpConfigError::config_error(key, msg),
other => HttpConfigError::config_error("", other.to_string()),
}
}
}
#[cfg(coverage)]
#[doc(hidden)]
pub(crate) fn coverage_exercise_config_error_paths() -> Vec<String> {
vec![
HttpConfigError::invalid_value("proxy.host", "bad")
.prepend_path_prefix("proxy")
.path,
HttpConfigError::invalid_value("svc.proxy.host", "bad")
.prepend_path_prefix("proxy")
.path,
HttpConfigError::invalid_value("", "bad")
.prepend_path_prefix("proxy")
.path,
]
}