use crate::{Config, ConfigError};
use serde::de::DeserializeOwned;
use std::{fs, path::Path};
#[derive(Debug, Clone, Copy)]
pub enum ConfigFormat {
Toml,
Json,
}
impl ConfigFormat {
pub fn from_extension(ext: &str) -> Option<Self> {
match ext.to_ascii_lowercase().as_str() {
"toml" => Some(Self::Toml),
"json" => Some(Self::Json),
_ => None,
}
}
}
pub fn parse_config_file<T>(
path: impl AsRef<Path>,
format_hint: Option<ConfigFormat>,
) -> Result<T, ConfigError>
where
T: Config + DeserializeOwned,
{
let path = path.as_ref();
let contents = fs::read_to_string(path).map_err(|e| {
ConfigError::new("Failed to read config file")
.with_kind("IOError")
.with_context(path.display().to_string())
.with_source(e)
})?;
let format = format_hint.or_else(|| {
path.extension()
.and_then(|ext| ext.to_str())
.and_then(ConfigFormat::from_extension)
});
match format {
Some(ConfigFormat::Toml) => T::from_toml_str(&contents)?.validate_and_build(),
Some(ConfigFormat::Json) => T::from_json_str(&contents)?.validate_and_build(),
None => Err(ConfigError::new("Unknown configuration format")
.with_kind("FormatError")
.with_context(path.display().to_string())),
}
}