Skip to main content

slave_framework/
env.rs

1//! Reading configuration from the process environment and `.env` files.
2
3use std::fmt::Display;
4use std::path::PathBuf;
5use std::str::FromStr;
6
7use crate::{Error, Result};
8
9/// Loads variables from a `.env` file in the current directory or its parents.
10///
11/// Variables already set in the process environment take precedence. A missing
12/// file is not an error; `Ok(None)` is returned instead.
13pub fn load_dotenv() -> Result<Option<PathBuf>> {
14    match dotenvy::dotenv() {
15        Ok(path) => Ok(Some(path)),
16        Err(err) if err.not_found() => Ok(None),
17        Err(err) => Err(err.into()),
18    }
19}
20
21/// Returns the value of `key`, or `default` if it is unset or not valid Unicode.
22pub fn var_or(key: &str, default: &str) -> String {
23    std::env::var(key).unwrap_or_else(|_| default.to_owned())
24}
25
26/// Parses the value of `key`, or returns `default` if it is unset.
27pub fn parse_or<T>(key: &str, default: T) -> Result<T>
28where
29    T: FromStr,
30    T::Err: Display,
31{
32    match std::env::var(key) {
33        Ok(value) => parse_value(key, &value),
34        Err(_) => Ok(default),
35    }
36}
37
38fn parse_value<T>(key: &str, value: &str) -> Result<T>
39where
40    T: FromStr,
41    T::Err: Display,
42{
43    value
44        .trim()
45        .parse()
46        .map_err(|err: T::Err| Error::InvalidEnv {
47            key: key.to_owned(),
48            value: value.to_owned(),
49            reason: err.to_string(),
50        })
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn parses_valid_values() {
59        assert_eq!(parse_value::<u16>("PORT", " 8080 ").unwrap(), 8080);
60    }
61
62    #[test]
63    fn reports_invalid_values() {
64        let err = parse_value::<u16>("PORT", "eighty").unwrap_err();
65        assert!(err.to_string().contains("PORT"), "{err}");
66    }
67
68    #[test]
69    fn falls_back_to_default_when_unset() {
70        assert_eq!(parse_or("SLAVE_TEST_SURELY_UNSET_VAR", 42u16).unwrap(), 42);
71        assert_eq!(var_or("SLAVE_TEST_SURELY_UNSET_VAR", "x"), "x");
72    }
73}