drogue_bazaar/core/config/
mod.rs1mod csv;
2
3pub use csv::*;
4
5use serde::Deserialize;
6use std::collections::HashMap;
7
8pub trait ConfigFromEnv<'de>: Sized + Deserialize<'de> {
51 fn from_env() -> Result<Self, config::ConfigError> {
53 Self::from(config::Environment::default())
54 }
55
56 fn from_env_prefix<S: AsRef<str>>(prefix: S) -> Result<Self, config::ConfigError> {
59 Self::from(config::Environment::with_prefix(prefix.as_ref()))
60 }
61
62 fn from(env: config::Environment) -> Result<Self, config::ConfigError>;
63
64 fn from_set<K, V>(set: HashMap<K, V>) -> Result<Self, config::ConfigError>
65 where
66 K: Into<String>,
67 V: Into<String>,
68 {
69 let set = set.into_iter().map(|(k, v)| (k.into(), v.into())).collect();
70 Self::from(config::Environment::default().source(Some(set)))
71 }
72}
73
74impl<'de, T: Deserialize<'de> + Sized> ConfigFromEnv<'de> for T {
75 fn from(env: config::Environment) -> Result<T, config::ConfigError> {
76 let env = env.try_parsing(true).separator("__");
77
78 let cfg = config::Config::builder().add_source(env);
79 cfg.build()?.try_deserialize()
80 }
81}
82
83#[cfg(test)]
84mod test {
85 use super::*;
86 use config::Environment;
87 use serde::Deserialize;
88 use std::collections::HashMap;
89
90 #[test]
91 fn test_prefix() {
92 #[derive(Debug, Deserialize)]
93 struct Foo {
94 pub bar: String,
95 pub r#bool: bool,
96 }
97
98 let mut env = HashMap::<String, String>::new();
99 env.insert("FOO__BAR".into(), "baz".into());
100 env.insert("FOO__BOOL".into(), "true".into());
101
102 let foo = <Foo as ConfigFromEnv>::from(Environment::with_prefix("FOO").source(Some(env)))
103 .unwrap();
104 assert_eq!(foo.bar, "baz");
105 assert_eq!(foo.r#bool, true);
106 }
107
108 #[test]
109 fn test_nested() {
110 #[derive(Debug, Deserialize)]
111 struct Foo {
112 #[serde(default)]
113 pub bar: Option<Bar>,
114 }
115 #[derive(Debug, Deserialize)]
116 struct Bar {
117 pub baz: Baz,
118 }
119 #[derive(Debug, Deserialize)]
120 struct Baz {
121 pub value: String,
122 }
123
124 let mut env = HashMap::<String, String>::new();
125 env.insert("FOO__BAR__BAZ__VALUE".into(), "s1".into());
126
127 let foo =
128 <Foo as ConfigFromEnv>::from(Environment::default().prefix("FOO").source(Some(env)))
129 .unwrap();
130
131 assert_eq!(foo.bar.unwrap().baz.value, "s1");
132 }
133}