use crate::{ util::accumulate_child_keys, ConfigurationBuilder, ConfigurationProvider, ConfigurationSource, LoadResult, Value, }; use std::collections::HashMap; use std::env::vars; /// Represents a [`ConfigurationProvider`](crate::ConfigurationProvider) for environment variables. #[derive(Default)] pub struct EnvironmentVariablesConfigurationProvider { prefix: String, data: HashMap, } impl EnvironmentVariablesConfigurationProvider { /// Initializes a new environment variables configuration provider. /// /// # Arguments /// /// * `prefix` - A prefix used to filter the environment variables pub fn new(prefix: String) -> Self { Self { prefix, data: HashMap::with_capacity(0), } } } impl ConfigurationProvider for EnvironmentVariablesConfigurationProvider { fn get(&self, key: &str) -> Option { self.data.get(&key.to_uppercase()).map(|t| t.1.clone()) } fn load(&mut self) -> LoadResult { let mut data = HashMap::new(); let prefix = self.prefix.to_uppercase(); let prefix_len = self.prefix.len(); for (key, value) in vars() { if key.to_uppercase().starts_with(&prefix) { let new_key = key[prefix_len..].to_string(); data.insert(new_key.to_uppercase().replace("__", ":"), (new_key, value.into())); } } data.shrink_to_fit(); self.data = data; Ok(()) } fn child_keys(&self, earlier_keys: &mut Vec, parent_path: Option<&str>) { accumulate_child_keys(&self.data, earlier_keys, parent_path) } } /// Represents a [`ConfigurationSource`](crate::ConfigurationSource) for environment variables. #[derive(Default)] pub struct EnvironmentVariablesConfigurationSource { /// A prefix used to filter environment variables. pub prefix: String, } impl EnvironmentVariablesConfigurationSource { /// Initializes a new environment variables configuration source. /// /// # Arguments /// /// * `prefix` - A prefix used to filter environment variables pub fn new(prefix: &str) -> Self { Self { prefix: prefix.to_owned(), } } } impl ConfigurationSource for EnvironmentVariablesConfigurationSource { fn build(&self, _builder: &dyn ConfigurationBuilder) -> Box { Box::new(EnvironmentVariablesConfigurationProvider::new( self.prefix.clone(), )) } } pub mod ext { use super::*; /// Defines extension methods for [`ConfigurationBuilder`](crate::ConfigurationBuilder). pub trait EnvironmentVariablesExtensions { /// Adds environment variables as a configuration source. fn add_env_vars(&mut self) -> &mut Self; /// Adds environment variables as a configuration source. /// /// # Arguments /// /// * `prefix` - The prefix that environment variable names must start with. /// The prefix will be removed from the environment variable names. fn add_env_vars_with_prefix(&mut self, prefix: &str) -> &mut Self; } impl EnvironmentVariablesExtensions for dyn ConfigurationBuilder + '_ { fn add_env_vars(&mut self) -> &mut Self { self.add_env_vars_with_prefix("") } fn add_env_vars_with_prefix(&mut self, prefix: &str) -> &mut Self { self.add(Box::new(EnvironmentVariablesConfigurationSource::new( prefix, ))); self } } impl EnvironmentVariablesExtensions for T { fn add_env_vars(&mut self) -> &mut Self { self.add_env_vars_with_prefix("") } fn add_env_vars_with_prefix(&mut self, prefix: &str) -> &mut Self { self.add(Box::new(EnvironmentVariablesConfigurationSource::new( prefix, ))); self } } }