justconfig/sources/
env.rs1use crate::source::Source;
34use crate::item::{SourceLocation, StringItem, Value};
35use crate::confpath::ConfPath;
36use std::ffi::{OsStr, OsString};
37use std::collections::hash_map::HashMap;
38use std::fmt;
39use std::env;
40use std::rc::Rc;
41
42#[derive(Debug)]
47struct EnvSourceLocation {
48 env_name: OsString
49}
50
51impl EnvSourceLocation {
52 pub fn new(env_name: &OsStr) -> Rc<Self> {
53 Rc::new(Self {
54 env_name: env_name.to_owned()
55 })
56 }
57}
58
59impl fmt::Display for EnvSourceLocation {
60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61 write!(f, "env:{}", self.env_name.to_string_lossy())
62 }
63}
64
65impl SourceLocation for EnvSourceLocation {}
66
67pub struct Env {
69 env_mapping: HashMap<ConfPath, OsString>
70}
71
72impl Env {
73 pub fn new(env_mapping: &[(ConfPath, &OsStr)]) -> Box<Self> {
83 Box::new(Self {
84 env_mapping: env_mapping.iter().map(|m| (m.0.clone(), m.1.to_owned())).collect()
85 })
86 }
87}
88
89impl Source for Env {
90 fn get(&self, key: ConfPath) -> Option<StringItem> {
91 if let Some(env_name) = self.env_mapping.get(&key) {
92 env::var(env_name).ok().map(|v| StringItem::from(key, &[Value::new(v, EnvSourceLocation::new(env_name))]))
93 } else {
94 None
95 }
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use crate::Config;
103 use crate::error::ConfigError;
104 use crate::item::ValueExtractor;
105 use std::env;
106
107 fn prepare_test_config() -> Config{
108 env::set_var(OsStr::new("existing_value"), OsStr::new("existing_value"));
109
110 let mut c = Config::default();
111
112 c.add_source(Env::new(&[
113 (ConfPath::from(&["testA"]), OsStr::new("existing_value")),
114 (ConfPath::from(&["testB"]), OsStr::new("non_existant_value"))
115 ]));
116
117 c
118 }
119
120 #[test]
121 fn existing_value() {
122 let c = prepare_test_config();
123 assert_eq!((c.get(ConfPath::from(&["testA"])).value() as Result<String, ConfigError>).unwrap(), "existing_value");
124 }
125
126 #[test]
127 #[should_panic(expected = "ValueNotFound")]
128 fn non_existant_env_name() {
129 let c = prepare_test_config();
130
131 (c.get(ConfPath::from(&["testB"])).value() as Result<String, ConfigError>).unwrap();
132 }
133
134 #[test]
135 #[should_panic(expected = "ValueNotFound")]
136 fn non_existant_value() {
137 let c = prepare_test_config();
138
139 (c.get(ConfPath::from(&["testC"])).value() as Result<String, ConfigError>).unwrap();
140 }
141}