Skip to main content

config/
env.rs

1use crate::{pascal_case, path, Result, Settings};
2use std::{borrow::Cow, env::vars};
3
4fn escape(name: &str) -> Cow<'_, str> {
5    if name.contains("__") {
6        Cow::Owned(name.replace("__", ":"))
7    } else {
8        Cow::Borrowed(name)
9    }
10}
11
12/// Represents a [configuration provider](crate::Provider) for environment variables.
13#[derive(Debug, Default)]
14pub struct Provider(String);
15
16impl Provider {
17    /// Initializes a new environment variables configuration provider.
18    ///
19    /// # Arguments
20    ///
21    /// * `prefix` - A prefix used to filter environment variables
22    ///
23    /// # Safety
24    ///
25    /// If no prefix is specified, then all environment variables are loaded, which might include sensitive data.
26    #[inline]
27    pub fn new(prefix: impl Into<String>) -> Self {
28        Self(prefix.into())
29    }
30}
31
32impl crate::Provider for Provider {
33    #[inline]
34    fn name(&self) -> &str {
35        "Environment"
36    }
37
38    fn load(&self, settings: &mut Settings) -> Result {
39        if self.0.is_empty() {
40            for (key, value) in vars() {
41                settings.insert(pascal_case(&escape(&key)), value);
42            }
43        } else {
44            let prefix = &self.0;
45            let len = prefix.len();
46
47            for (key, value) in vars() {
48                if path::starts_with(&key, prefix) {
49                    settings.insert(pascal_case(&escape(&key[len..])), value);
50                }
51            }
52        }
53
54        Ok(())
55    }
56}