Skip to main content

config/
env.rs

1use crate::{
2    util::accumulate_child_keys, ConfigurationBuilder, ConfigurationProvider, ConfigurationSource, LoadResult, Value,
3};
4use std::collections::HashMap;
5use std::env::vars;
6
7/// Represents a [`ConfigurationProvider`](crate::ConfigurationProvider) for environment variables.
8#[derive(Default)]
9pub struct EnvironmentVariablesConfigurationProvider {
10    prefix: String,
11    data: HashMap<String, (String, Value)>,
12}
13
14impl EnvironmentVariablesConfigurationProvider {
15    /// Initializes a new environment variables configuration provider.
16    ///
17    /// # Arguments
18    ///
19    /// * `prefix` - A prefix used to filter the environment variables
20    pub fn new(prefix: String) -> Self {
21        Self {
22            prefix,
23            data: HashMap::with_capacity(0),
24        }
25    }
26}
27
28impl ConfigurationProvider for EnvironmentVariablesConfigurationProvider {
29    fn get(&self, key: &str) -> Option<Value> {
30        self.data.get(&key.to_uppercase()).map(|t| t.1.clone())
31    }
32
33    fn load(&mut self) -> LoadResult {
34        let mut data = HashMap::new();
35        let prefix = self.prefix.to_uppercase();
36        let prefix_len = self.prefix.len();
37
38        for (key, value) in vars() {
39            if key.to_uppercase().starts_with(&prefix) {
40                let new_key = key[prefix_len..].to_string();
41                data.insert(new_key.to_uppercase().replace("__", ":"), (new_key, value.into()));
42            }
43        }
44
45        data.shrink_to_fit();
46        self.data = data;
47        Ok(())
48    }
49
50    fn child_keys(&self, earlier_keys: &mut Vec<String>, parent_path: Option<&str>) {
51        accumulate_child_keys(&self.data, earlier_keys, parent_path)
52    }
53}
54
55/// Represents a [`ConfigurationSource`](crate::ConfigurationSource) for environment variables.
56#[derive(Default)]
57pub struct EnvironmentVariablesConfigurationSource {
58    /// A prefix used to filter environment variables.
59    pub prefix: String,
60}
61
62impl EnvironmentVariablesConfigurationSource {
63    /// Initializes a new environment variables configuration source.
64    ///
65    /// # Arguments
66    ///
67    /// * `prefix` - A prefix used to filter environment variables
68    pub fn new(prefix: &str) -> Self {
69        Self {
70            prefix: prefix.to_owned(),
71        }
72    }
73}
74
75impl ConfigurationSource for EnvironmentVariablesConfigurationSource {
76    fn build(&self, _builder: &dyn ConfigurationBuilder) -> Box<dyn ConfigurationProvider> {
77        Box::new(EnvironmentVariablesConfigurationProvider::new(self.prefix.clone()))
78    }
79}
80
81pub mod ext {
82
83    use super::*;
84
85    /// Defines extension methods for [`ConfigurationBuilder`](crate::ConfigurationBuilder).
86    pub trait EnvironmentVariablesExtensions {
87        /// Adds environment variables as a configuration source.
88        fn add_env_vars(&mut self) -> &mut Self;
89
90        /// Adds environment variables as a configuration source.
91        ///
92        /// # Arguments
93        ///
94        /// * `prefix` - The prefix that environment variable names must start with. The prefix will be removed from
95        ///   the environment variable names.
96        fn add_env_vars_with_prefix(&mut self, prefix: &str) -> &mut Self;
97    }
98
99    impl EnvironmentVariablesExtensions for dyn ConfigurationBuilder + '_ {
100        fn add_env_vars(&mut self) -> &mut Self {
101            self.add_env_vars_with_prefix("")
102        }
103
104        fn add_env_vars_with_prefix(&mut self, prefix: &str) -> &mut Self {
105            self.add(Box::new(EnvironmentVariablesConfigurationSource::new(prefix)));
106            self
107        }
108    }
109
110    impl<T: ConfigurationBuilder> EnvironmentVariablesExtensions for T {
111        fn add_env_vars(&mut self) -> &mut Self {
112            self.add_env_vars_with_prefix("")
113        }
114
115        fn add_env_vars_with_prefix(&mut self, prefix: &str) -> &mut Self {
116            self.add(Box::new(EnvironmentVariablesConfigurationSource::new(prefix)));
117            self
118        }
119    }
120}