miau/provider/
env.rs

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
8/// Provides environmental variables as configuration.
9pub struct EnvironmentProvider {
10    prefix: Option<String>,
11}
12
13impl EnvironmentProvider {
14    /// Creates new `EnvironmentProvider` that retrives all environmental variables.
15    pub fn new() -> Self {
16        EnvironmentProvider { prefix: None }
17    }
18
19    /// Creates new `EnvironmentProvider` that retrives environmental variables prefixed with `prefix`.
20    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}