config/
env.rs

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