1use super::Provider;
2use crate::{
3 configuration::{merge, Configuration, ConfigurationInfo, ConfigurationTree, Key, Value},
4 parsing,
5};
6use std::{collections::HashMap, convert::Into, default::Default, env};
7
8pub struct EnvironmentProvider {
10 prefix: Option<String>,
11}
12
13impl EnvironmentProvider {
14 pub fn new() -> Self {
16 EnvironmentProvider { prefix: None }
17 }
18
19 pub fn with_prefix<T: Into<String>>(prefix: T) -> Self {
21 EnvironmentProvider {
22 prefix: Some(prefix.into()),
23 }
24 }
25
26 fn get(&self) -> Configuration {
27 let vars = env::vars();
28
29 let node = match self.prefix {
30 Some(ref prefix) => push(vars.filter(|(key, _)| key.starts_with(prefix))),
31 None => push(vars),
32 };
33
34 match node {
35 Some(node) => Configuration::new_singular(
36 ConfigurationInfo::new("environment", "environment"),
37 node,
38 ),
39 None => Configuration::new_empty(),
40 }
41 }
42}
43
44fn push(keys: impl Iterator<Item = (String, String)>) -> Option<ConfigurationTree> {
45 let mut trees: Vec<ConfigurationTree> = Vec::new();
46 for (key, value) in keys {
47 if let Ok(ckey) = parsing::str_to_key(key.as_ref()) {
48 let all_map = ckey.iter().all(|k| std::matches!(k, Key::Map(..)));
49
50 if !all_map {
51 continue;
52 }
53
54 trees.push(create_tree(ckey.iter().map(|k| k.unwrap_map()), value));
55 }
56 }
57
58 let mut drain = trees.drain(..);
59 match drain.next() {
60 Some(node) => {
61 if let Ok(final_node) = drain.try_fold(node, merge) {
62 Some(final_node)
63 } else {
64 None
65 }
66 }
67 None => None,
68 }
69}
70
71fn create_tree(mut keys: impl Iterator<Item = String>, value: String) -> ConfigurationTree {
72 match keys.next() {
73 Some(key) => {
74 let mut map = HashMap::new();
75 map.insert(key, create_tree(keys, value));
76 ConfigurationTree::Map(map)
77 }
78 None => ConfigurationTree::Value(Some(Value::String(value))),
79 }
80}
81
82impl Default for EnvironmentProvider {
83 fn default() -> Self {
84 EnvironmentProvider::new()
85 }
86}
87
88impl Provider for EnvironmentProvider {
89 fn collect(&self) -> Result<Configuration, crate::error::ConfigurationError> {
90 Ok(self.get())
91 }
92
93 fn describe(&self) -> ConfigurationInfo {
94 ConfigurationInfo::new("environment", "environment")
95 }
96}