use std::io;
use std::path::PathBuf;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum ConfigError {
#[error("invalid configuration field `{field}`: {message}")]
Validation {
field: &'static str,
message: &'static str,
},
#[error("failed to load environment file `{path}`")]
Environment {
path: PathBuf,
#[source]
source: EnvironmentFileError,
},
#[error("configuration variable `{variable}` conflicts with `{variable}_FILE`")]
VariableConflict {
variable: &'static str,
},
#[error("configuration variable `{variable}` must be valid Unicode")]
VariableUnicode {
variable: String,
},
#[error("configuration variable `{variable}` {message}")]
VariableValue {
variable: &'static str,
message: &'static str,
},
#[error("failed to read configuration value selected by `{variable}_FILE`")]
VariableFile {
variable: &'static str,
#[source]
source: io::Error,
},
}
#[derive(Debug, Error)]
pub enum EnvironmentFileError {
#[error("environment file could not be read")]
Io(#[source] io::Error),
#[error("invalid dotenv syntax at character index {index}")]
Syntax {
index: usize,
},
#[error("referenced environment variable is unavailable")]
Variable,
#[error("environment file could not be loaded")]
Other,
}
impl EnvironmentFileError {
pub(crate) fn from_dotenv(error: dotenvy::Error) -> Self {
match error {
dotenvy::Error::LineParse(_, index) => Self::Syntax { index },
dotenvy::Error::Io(source) => Self::Io(source),
dotenvy::Error::EnvVar(_) => Self::Variable,
_ => Self::Other,
}
}
}
impl ConfigError {
pub(crate) const fn validation(field: &'static str, message: &'static str) -> Self {
Self::Validation { field, message }
}
pub(crate) fn environment(path: PathBuf, error: dotenvy::Error) -> Self {
Self::Environment {
path,
source: EnvironmentFileError::from_dotenv(error),
}
}
}
pub type Result<T> = std::result::Result<T, ConfigError>;