use std::path::PathBuf;
use crate::config::{Config, ConfigError, ConfigPath};
#[derive(Debug)]
#[non_exhaustive]
pub enum ConfigLoadOutcome {
Unresolved,
NotFound { path: PathBuf, explicit: bool },
IoError {
path: PathBuf,
source: ConfigError,
warnings: Vec<String>,
},
ParseError {
path: PathBuf,
source: ConfigError,
warnings: Vec<String>,
},
Loaded {
path: PathBuf,
config: Box<Config>,
warnings: Vec<String>,
},
}
#[must_use]
pub fn load_config(resolved: Option<&ConfigPath>) -> ConfigLoadOutcome {
let Some(cp) = resolved else {
return ConfigLoadOutcome::Unresolved;
};
let mut warnings = Vec::new();
match Config::load_validated(&cp.path, |msg| warnings.push(msg.to_string())) {
Ok(Some(config)) => ConfigLoadOutcome::Loaded {
path: cp.path.clone(),
config: Box::new(config),
warnings,
},
Ok(None) => ConfigLoadOutcome::NotFound {
path: cp.path.clone(),
explicit: cp.explicit,
},
Err(source @ ConfigError::Io { .. }) => ConfigLoadOutcome::IoError {
path: cp.path.clone(),
source,
warnings,
},
Err(source @ ConfigError::Parse { .. }) => ConfigLoadOutcome::ParseError {
path: cp.path.clone(),
source,
warnings,
},
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Write;
#[test]
fn parse_error_preserves_validation_warnings_collected_before_type_mismatch() {
let mut tmp = tempfile::NamedTempFile::new().unwrap();
tmp.write_all(b"unknown_top = 1\ntheme = 123\n").unwrap();
let cp = ConfigPath {
path: tmp.path().to_owned(),
explicit: true,
};
match load_config(Some(&cp)) {
ConfigLoadOutcome::ParseError { warnings, .. } => {
assert_eq!(warnings.len(), 1, "expected one unknown-key warning");
assert!(
warnings[0].contains("unknown_top"),
"warning: {:?}",
warnings[0]
);
}
other => panic!("expected ParseError, got {other:?}"),
}
}
}