use serde::Deserialize;
use serde_yaml;
use std::env;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
pub fn load_config_from_file<T, P>(path: P) -> Option<T>
where
T: for<'de> Deserialize<'de>,
P: AsRef<std::path::Path>,
{
let mut file = File::open(path).ok()?;
let mut contents = String::new();
file.read_to_string(&mut contents).ok()?;
serde_yaml::from_str(&contents).ok()
}
pub fn load_named_config<T>(config_path: &Path) -> Option<T>
where
T: for<'de> Deserialize<'de>,
{
load_config_from_file(config_path)
}
fn find_config_path(file_name: &str) -> Option<PathBuf> {
let mut current_dir = env::current_dir().ok()?;
loop {
let file_path = current_dir.join(file_name);
if file_path.exists() {
return Some(file_path);
}
if !current_dir.pop() {
break;
}
}
None
}
pub fn load_config<T>() -> Option<T>
where
T: for<'de> Deserialize<'de>,
{
let env_var = env::var("ENV").ok();
let mut candidates = Vec::new();
if let Some(env) = env_var.as_deref() {
if !env.is_empty() {
candidates.push(format!("application.{}.yml", env));
candidates.push(format!("application.{}.yaml", env));
candidates.push(format!("config.{}.yml", env));
candidates.push(format!("config.{}.yaml", env));
}
}
candidates.push("application.yml".to_string());
candidates.push("application.yaml".to_string());
candidates.push("config.yml".to_string());
candidates.push("config.yaml".to_string());
for file_name in candidates {
if let Some(path) = find_config_path(&file_name) {
if let Some(config) = load_config_from_file::<T, _>(path) {
return Some(config);
}
}
}
None
}