#
cargo/util/context/
error.rs

    1use std::fmt;
    2
    3use crate::util::ConfigValue;
    4use crate::util::context::ConfigKey;
    5use crate::util::context::Definition;
    6use crate::util::context::key::ArrayItemKeyPath;
    7
    8/// Internal error for serde errors.
    9#[derive(Debug)]
    10pub struct ConfigError {
    11    error: anyhow::Error,
    12    definition: Option<Definition>,
    13}
    14
    15impl ConfigError {
    16    pub(super) fn new(message: String, definition: Definition) -> ConfigError {
    17        ConfigError {
    18            error: anyhow::Error::msg(message),
    19            definition: Some(definition),
    20        }
    21    }
    22
    23    pub(super) fn expected(key: &ConfigKey, expected: &str, found: &ConfigValue) -> ConfigError {
    24        ConfigError {
    25            error: anyhow::anyhow!(
    26                "`{}` expected {}, but found a {}",
    27                key,
    28                expected,
    29                found.desc()
    30            ),
    31            definition: Some(found.definition().clone()),
    32        }
    33    }
    34
    35    pub(super) fn is_missing_field(&self) -> bool {
    36        self.error.downcast_ref::<MissingFieldError>().is_some()
    37    }
    38
    39    pub(super) fn missing(key: &ConfigKey) -> ConfigError {
    40        ConfigError {
    41            error: anyhow::anyhow!("missing config key `{}`", key),
    42            definition: None,
    43        }
    44    }
    45
    46    pub(super) fn with_key_context(
    47        self,
    48        key: &ConfigKey,
    49        definition: Option<Definition>,
    50    ) -> ConfigError {
    51        ConfigError {
    52            error: anyhow::Error::from(self)
    53                .context(format!("could not load config key `{}`", key)),
    54            definition: definition,
    55        }
    56    }
    57
    58    pub(super) fn with_array_item_key_context(
    59        self,
    60        key: &ArrayItemKeyPath,
    61        definition: Option<Definition>,
    62    ) -> ConfigError {
    63        ConfigError {
    64            error: anyhow::Error::from(self).context(format!("failed to parse config at `{key}`")),
    65            definition,
    66        }
    67    }
    68}
    69
    70impl std::error::Error for ConfigError {
    71    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
    72        self.error.source()
    73    }
    74}
    75
    76impl fmt::Display for ConfigError {
    77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    78        if let Some(definition) = &self.definition {
    79            write!(f, "error in {}: {}", definition, self.error)
    80        } else {
    81            self.error.fmt(f)
    82        }
    83    }
    84}
    85
    86#[derive(Debug)]
    87struct MissingFieldError(String);
    88
    89impl fmt::Display for MissingFieldError {
    90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    91        write!(f, "missing field `{}`", self.0)
    92    }
    93}
    94
    95impl std::error::Error for MissingFieldError {}
    96
    97impl serde::de::Error for ConfigError {
    98    fn custom<T: fmt::Display>(msg: T) -> Self {
    99        ConfigError {
    100            error: anyhow::Error::msg(msg.to_string()),
    101            definition: None,
    102        }
    103    }
    104
    105    fn missing_field(field: &'static str) -> Self {
    106        ConfigError {
    107            error: anyhow::Error::new(MissingFieldError(field.to_string())),
    108            definition: None,
    109        }
    110    }
    111}
    112
    113impl From<anyhow::Error> for ConfigError {
    114    fn from(error: anyhow::Error) -> Self {
    115        ConfigError {
    116            error,
    117            definition: None,
    118        }
    119    }
    120}