envir/
lib.rs

1#![warn(warnings)]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc = include_str!("../README.md")]
4
5#[cfg(feature = "derive")]
6mod derive;
7mod errors;
8#[cfg(any(feature = "env_logger", feature = "tracing"))]
9pub mod logger;
10
11#[cfg(feature = "derive")]
12pub use derive::*;
13
14pub use errors::{Error, Result};
15
16/**
17 * Loads the *.env* file and initializes the logger.
18 */
19pub fn init() {
20    #[cfg(all(feature = "dotenv", debug_assertions))]
21    dotenv();
22
23    #[cfg(feature = "logger")]
24    logger::init();
25}
26
27/**
28 * Attempts to load the *.env* file and to initialize the logger.
29 */
30pub fn try_init() -> Result {
31    #[cfg(all(feature = "dotenv", debug_assertions))]
32    dotenvy::dotenv()?;
33
34    #[cfg(feature = "logger")]
35    logger::try_init().map_err(|e| Error::Logger(e.to_string()))?;
36
37    Ok(())
38}
39
40/**
41 * Loads the *.env* files.
42 */
43#[cfg(feature = "dotenv")]
44pub fn dotenv() {
45    dotenvy::dotenv().ok();
46}
47
48/**
49 * Loads environment variables from the specified path.
50 */
51#[cfg(feature = "dotenv")]
52pub fn from_path<P: AsRef<std::path::Path>>(path: P) -> Result {
53    dotenvy::from_path(path).map_err(Into::into)
54}
55
56/**
57 * Retreives all environment variables as an easy printable form.
58 */
59#[must_use]
60pub fn collect() -> std::collections::HashMap<String, String> {
61    std::env::vars().collect()
62}
63
64/**
65 * Likes `try_get` but directly parses the variable value in desired `T` type.
66 */
67pub fn try_parse<T: std::str::FromStr>(key: &str) -> crate::Result<Option<T>>
68where
69    T::Err: ToString,
70{
71    let value = match crate::try_get(key)? {
72        Some(v) => v
73            .parse::<T>()
74            .map_err(|e| crate::Error::parse::<T, _>(key, e.to_string()))?,
75        None => return Ok(None),
76    };
77
78    Ok(Some(value))
79}
80
81/**
82 * Likes `try_parse` but returns a `crate::Error::Missing` if the variable isn’t set.
83 */
84pub fn parse<T: std::str::FromStr>(key: &str) -> crate::Result<T>
85where
86    T::Err: ToString,
87{
88    crate::try_parse(key)?.ok_or_else(|| crate::Error::Missing(key.to_string()))
89}
90
91/**
92 * Gets the environment variable `key`. This returns a `crate::Error::Unicode` if the variable
93 * value isn’t valid unicode.
94 */
95pub fn try_get(key: &str) -> crate::Result<Option<String>> {
96    let Some(value) = std::env::var_os(key) else {
97        return Ok(None);
98    };
99
100    let value = match value.to_str() {
101        Some(v) => v.to_string(),
102        None => return Err(crate::Error::unicode(key, value)),
103    };
104
105    Ok(Some(value))
106}
107
108/**
109 * Likes `try_get` but returns a `crate::Error::Missing` if the variable isn’t set.
110 */
111pub fn get(key: &str) -> crate::Result<String> {
112    crate::try_get(key)?.ok_or_else(|| crate::Error::Missing(key.to_string()))
113}
114
115/**
116 * Sets the environment variable `key` to the `value`.
117 */
118pub fn set<T: ToString>(key: &str, value: T) {
119    unsafe {
120        std::env::set_var(key, value.to_string());
121    }
122}
123
124#[cfg(test)]
125mod test {
126    #[test]
127    fn collect() {
128        assert!(!crate::collect().is_empty());
129    }
130
131    #[test]
132    fn try_parse() -> crate::Result {
133        assert!(crate::try_parse::<String>("MISSING_ENV")?.is_none());
134
135        Ok(())
136    }
137
138    #[test]
139    fn parse() -> crate::Result {
140        crate::set("TEST", 1);
141        assert_eq!(crate::parse::<u8>("TEST")?, 1u8);
142
143        Ok(())
144    }
145
146    #[test]
147    fn try_get() -> crate::Result {
148        assert!(crate::try_get("MISSING_ENV")?.is_none());
149
150        Ok(())
151    }
152
153    #[test]
154    fn get() -> crate::Result {
155        crate::set("TEST", 1);
156        assert_eq!(crate::get("TEST")?, "1");
157
158        Ok(())
159    }
160}