1pub use config::ConfigError;
2use config::{Config, Value};
3use serde::Deserialize;
4use std::{collections::HashMap, fs};
5
6pub trait Configurator {
7 fn get<'de, T: Deserialize<'de>>(&'de self, key: &'de str) -> Result<T, ConfigError>;
8 fn get_str(&self, key: &str) -> Result<String, ConfigError>;
9 fn get_int(&self, key: &str) -> Result<i64, ConfigError>;
10 fn get_float(&self, key: &str) -> Result<f64, ConfigError>;
11 fn get_bool(&self, key: &str) -> Result<bool, ConfigError>;
12 fn get_table(&self, key: &str) -> Result<HashMap<String, Value>, ConfigError>;
13 fn get_array(&self, key: &str) -> Result<Vec<Value>, ConfigError>;
14 fn try_into<'de, T: Deserialize<'de>>(self) -> Result<T, ConfigError>;
15}
16
17pub fn new(path: &str, prefix: &str) -> Result<impl Configurator, ConfigError> {
18 let mut config_builder = Config::builder();
19 let paths = fs::read_dir(path)
20 .map_err(|_| ConfigError::Message(format!("Could not read directory at {}", path)))?
21 .filter_map(|result| result.ok())
22 .map(|de| de.path());
23 for path in paths {
24 config_builder = match path.as_path().to_str() {
25 Some(s) => {
26 if s.ends_with(".yaml") {
27 config_builder.add_source(config::File::with_name(s))
28 } else {
29 config_builder
30 }
31 }
32 None => config_builder,
33 };
34 }
35 config_builder
36 .add_source(config::Environment::with_prefix(prefix).separator("_"))
37 .build()
38}
39
40impl Configurator for Config {
41 fn get<'de, T: Deserialize<'de>>(&'de self, key: &'de str) -> Result<T, ConfigError> {
42 Config::get(self, key)
43 }
44 fn get_str(&self, key: &str) -> Result<String, ConfigError> {
45 Config::get_string(self, key)
46 }
47 fn get_int(&self, key: &str) -> Result<i64, ConfigError> {
48 Config::get_int(self, key)
49 }
50 fn get_float(&self, key: &str) -> Result<f64, ConfigError> {
51 Config::get_float(self, key)
52 }
53 fn get_bool(&self, key: &str) -> Result<bool, ConfigError> {
54 Config::get_bool(self, key)
55 }
56 fn get_table(&self, key: &str) -> Result<HashMap<String, Value>, ConfigError> {
57 Config::get_table(self, key)
58 }
59 fn get_array(&self, key: &str) -> Result<Vec<Value>, ConfigError> {
60 Config::get_array(self, key)
61 }
62 fn try_into<'de, T: Deserialize<'de>>(self) -> Result<T, ConfigError> {
63 Config::try_deserialize(self)
64 }
65}