1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use std::io;
use std::path::PathBuf;
use thiserror::Error;
/// Error returned while resolving or validating configuration.
#[derive(Debug, Error)]
pub enum ConfigError {
/// A parsed or overridden value violates a configuration invariant.
#[error("invalid configuration field `{field}`: {message}")]
Validation {
/// Stable dotted field path.
field: &'static str,
/// Value-independent validation explanation.
message: &'static str,
},
/// An explicit environment file could not be loaded.
#[error("failed to load environment file `{path}`")]
Environment {
/// File that failed to load.
path: PathBuf,
/// Sanitized dotenv failure that never retains a parsed line or value.
#[source]
source: EnvironmentFileError,
},
/// The immutable process configuration was already initialized from different files.
#[error("configuration files have already been loaded for this process")]
EnvironmentAlreadyLoaded,
/// A process variable and its `_FILE` companion were both supplied.
#[error("configuration variable `{variable}` conflicts with `{variable}_FILE`")]
VariableConflict {
/// Base environment-variable name.
variable: &'static str,
},
/// A requested raw environment variable was not supplied.
#[error("configuration variable `{variable}` is not set")]
VariableMissing {
/// Environment-variable name.
variable: String,
},
/// A process variable is not valid Unicode.
#[error("configuration variable `{variable}` must be valid Unicode")]
VariableUnicode {
/// Environment-variable name.
variable: String,
},
/// A configured value is empty or cannot be parsed into its typed field.
#[error("configuration variable `{variable}` {message}")]
VariableValue {
/// Environment-variable name.
variable: &'static str,
/// Value-independent explanation.
message: &'static str,
},
/// A file selected through a `_FILE` variable could not be read.
#[error("failed to read configuration value selected by `{variable}_FILE`")]
VariableFile {
/// Base environment-variable name.
variable: &'static str,
/// Underlying filesystem error.
#[source]
source: io::Error,
},
}
/// Sanitized cause for an explicitly selected dotenv file.
#[derive(Debug, Error)]
pub enum EnvironmentFileError {
/// The file could not be read.
#[error("environment file could not be read")]
Io(#[source] io::Error),
/// A dotenv line has invalid syntax at the reported character index.
#[error("invalid dotenv syntax at character index {index}")]
Syntax {
/// Zero-based character index reported within the invalid line.
index: usize,
},
/// A referenced process variable was unavailable or not valid Unicode.
#[error("referenced environment variable is unavailable")]
Variable,
/// A future dotenv error kind was returned by the non-exhaustive API.
#[error("environment file could not be loaded")]
Other,
}
impl EnvironmentFileError {
pub(crate) fn from_dotenv(error: dotenv::Error) -> Self {
match error {
dotenv::Error::Parse(error, _) => Self::Syntax {
index: error.column().saturating_sub(1),
},
dotenv::Error::Io(source, _) => Self::Io(source),
dotenv::Error::NotPresent(_)
| dotenv::Error::NotUnicode(_, _)
| dotenv::Error::NotUnicodeName(_) => 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: dotenv::Error) -> Self {
Self::Environment {
path,
source: EnvironmentFileError::from_dotenv(error),
}
}
}
/// Result type used by this crate.
pub type Result<T> = std::result::Result<T, ConfigError>;