use std::borrow::Borrow;
use crate::{ConfigError, ConfigValue, Configuration, FromConfig};
#[macro_export]
macro_rules! from_static_map {
( $ty:ty, { $( $key:expr => $value:expr ),* $(,)? } ) => {{
use $crate::*;
use std::collections::HashMap;
let mut config: HashMap<String, String> = HashMap::new();
$(
config.insert($key.to_string(), $value.to_string());
)*
from_map::<$ty, _, _, _>(config, "").expect("from_static_map failed")
}};
}
#[allow(unused_mut)]
pub fn from_map<
T: FromConfig,
I: IntoIterator<Item = (K, V)>,
K: Borrow<str>,
V: Into<ConfigValue<'static>>,
>(
map: I,
prefix: &str,
) -> Result<T, ConfigError> {
let mut config = Configuration::new().register_kv("default");
for (k, v) in map {
config = config.set(k, v);
}
let mut config = config.finish()?;
#[cfg(feature = "rand")]
{
config = config.register_random()?;
}
config.get(prefix)
}
#[allow(unused_mut)]
pub fn from_env<T: FromConfig>(prefix: &str) -> Result<T, ConfigError> {
let mut config = Configuration::new().register_prefix_env(prefix)?;
#[cfg(feature = "rand")]
{
config = config.register_random()?;
}
config.get("")
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
use crate::FromConfig;
use std::collections::HashMap;
#[derive(Debug, PartialEq, FromConfig)]
#[config(crate = "crate")]
struct TestApp {
port: u16,
host: String,
}
#[test]
fn test_from_map_happy_path() {
let mut map = HashMap::new();
map.insert("cfg.app.port", "8080");
map.insert("cfg.app.host", "localhost");
let cfg: TestApp = from_map(map, "cfg.app").expect("from_map failed");
assert_eq!(
cfg,
TestApp {
port: 8080,
host: "localhost".to_string()
}
);
}
#[test]
fn test_from_env_happy_path() {
let prefix = "TEST_APP";
unsafe {
std::env::set_var("TEST_APP_PORT", "9090");
std::env::set_var("TEST_APP_HOST", "127.0.0.1");
}
let cfg: TestApp = from_env(prefix).expect("from_env failed");
assert_eq!(
cfg,
TestApp {
port: 9090,
host: "127.0.0.1".to_string()
}
);
unsafe {
std::env::remove_var("TEST_APP_PORT");
std::env::remove_var("TEST_APP_HOST");
}
}
#[test]
fn test_load_from_map_macro_happy_path() {
let app: TestApp = from_static_map!(TestApp, {
"port" => "8080",
"host" => "localhost",
});
assert_eq!(
app,
TestApp {
port: 8080,
host: "localhost".to_string()
}
);
}
#[test]
fn test_load_from_map_macro_single_entry() {
#[derive(Debug, PartialEq, FromConfig)]
#[config(crate = "crate")]
struct OnlyPort {
port: u16,
}
let only: OnlyPort = from_static_map!(OnlyPort, { "port" => "7070" });
assert_eq!(only, OnlyPort { port: 7070 });
}
}