use std::fmt::Display;
use std::path::PathBuf;
use std::str::FromStr;
use crate::{Error, Result};
pub fn load_dotenv() -> Result<Option<PathBuf>> {
match dotenvy::dotenv() {
Ok(path) => Ok(Some(path)),
Err(err) if err.not_found() => Ok(None),
Err(err) => Err(err.into()),
}
}
pub fn var_or(key: &str, default: &str) -> String {
std::env::var(key).unwrap_or_else(|_| default.to_owned())
}
pub fn parse_or<T>(key: &str, default: T) -> Result<T>
where
T: FromStr,
T::Err: Display,
{
match std::env::var(key) {
Ok(value) => parse_value(key, &value),
Err(_) => Ok(default),
}
}
fn parse_value<T>(key: &str, value: &str) -> Result<T>
where
T: FromStr,
T::Err: Display,
{
value
.trim()
.parse()
.map_err(|err: T::Err| Error::InvalidEnv {
key: key.to_owned(),
value: value.to_owned(),
reason: err.to_string(),
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_valid_values() {
assert_eq!(parse_value::<u16>("PORT", " 8080 ").unwrap(), 8080);
}
#[test]
fn reports_invalid_values() {
let err = parse_value::<u16>("PORT", "eighty").unwrap_err();
assert!(err.to_string().contains("PORT"), "{err}");
}
#[test]
fn falls_back_to_default_when_unset() {
assert_eq!(parse_or("SLAVE_TEST_SURELY_UNSET_VAR", 42u16).unwrap(), 42);
assert_eq!(var_or("SLAVE_TEST_SURELY_UNSET_VAR", "x"), "x");
}
}