use std::fmt; use std::path::PathBuf; use thiserror::Error; #[derive(Debug, Error)] pub enum ConfigError { #[error("failed to load .env file: {0}")] DotEnv(#[from] dotenvy::Error), #[error("config parse/merge error: {0}")] Figment(Box), #[error("config I/O error: {0}")] Io(#[from] std::io::Error), #[error("config validation failed: {0}")] Validation(String), } impl From for ConfigError { fn from(error: figment::Error) -> Self { // Boxed because a figment error carries ~200 bytes of provenance; an // inline variant would make every `Result<_, ConfigError>` in the // workspace pay for it on the success path too. Self::Figment(Box::new(error)) } } #[derive(Debug)] pub enum ConfigLoadError { Section { key: String, path: PathBuf }, Load { path: PathBuf, message: String }, } impl fmt::Display for ConfigLoadError { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Section { key, path } => { write!(formatter, "{} has no `{key}` section", path.display()) } Self::Load { path, message } => { write!(formatter, "failed to load {}: {message}", path.display()) } } } } impl std::error::Error for ConfigLoadError {}