| use std::fmt; |
| |
| use crate::context::ConfigKey; |
| use crate::context::Definition; |
| use crate::context::key::ArrayItemKeyPath; |
| use crate::util::ConfigValue; |
| |
| /// Internal error for serde errors. |
| #[derive(Debug)] |
| pub struct ConfigError { |
| error: anyhow::Error, |
| definition: Option<Definition>, |
| } |
| |
| impl ConfigError { |
| pub(super) fn new(message: String, definition: Definition) -> ConfigError { |
| ConfigError { |
| error: anyhow::Error::msg(message), |
| definition: Some(definition), |
| } |
| } |
| |
| pub(super) fn expected(key: &ConfigKey, expected: &str, found: &ConfigValue) -> ConfigError { |
| ConfigError { |
| error: anyhow::anyhow!( |
| "`{}` expected {}, but found a {}", |
| key, |
| expected, |
| found.desc() |
| ), |
| definition: Some(found.definition().clone()), |
| } |
| } |
| |
| pub(super) fn is_missing_field(&self) -> bool { |
| self.error.downcast_ref::<MissingFieldError>().is_some() |
| } |
| |
| pub(super) fn missing(key: &ConfigKey) -> ConfigError { |
| ConfigError { |
| error: anyhow::anyhow!("missing config key `{}`", key), |
| definition: None, |
| } |
| } |
| |
| pub(super) fn with_key_context( |
| self, |
| key: &ConfigKey, |
| definition: Option<Definition>, |
| ) -> ConfigError { |
| ConfigError { |
| error: anyhow::Error::from(self) |
| .context(format!("could not load config key `{}`", key)), |
| definition: definition, |
| } |
| } |
| |
| pub(super) fn with_array_item_key_context( |
| self, |
| key: &ArrayItemKeyPath, |
| definition: Option<Definition>, |
| ) -> ConfigError { |
| ConfigError { |
| error: anyhow::Error::from(self).context(format!("failed to parse config at `{key}`")), |
| definition, |
| } |
| } |
| } |
| |
| impl std::error::Error for ConfigError { |
| fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { |
| self.error.source() |
| } |
| } |
| |
| impl fmt::Display for ConfigError { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| if let Some(definition) = &self.definition { |
| write!(f, "error in {}: {}", definition, self.error) |
| } else { |
| self.error.fmt(f) |
| } |
| } |
| } |
| |
| #[derive(Debug)] |
| struct MissingFieldError(String); |
| |
| impl fmt::Display for MissingFieldError { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| write!(f, "missing field `{}`", self.0) |
| } |
| } |
| |
| impl std::error::Error for MissingFieldError {} |
| |
| impl serde::de::Error for ConfigError { |
| fn custom<T: fmt::Display>(msg: T) -> Self { |
| ConfigError { |
| error: anyhow::Error::msg(msg.to_string()), |
| definition: None, |
| } |
| } |
| |
| fn missing_field(field: &'static str) -> Self { |
| ConfigError { |
| error: anyhow::Error::new(MissingFieldError(field.to_string())), |
| definition: None, |
| } |
| } |
| } |
| |
| impl From<anyhow::Error> for ConfigError { |
| fn from(error: anyhow::Error) -> Self { |
| ConfigError { |
| error, |
| definition: None, |
| } |
| } |
| } |