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
16pub fn init() {
20 #[cfg(all(feature = "dotenv", debug_assertions))]
21 dotenv();
22
23 #[cfg(feature = "logger")]
24 logger::init();
25}
26
27pub 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#[cfg(feature = "dotenv")]
44pub fn dotenv() {
45 dotenvy::dotenv().ok();
46}
47
48#[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#[must_use]
60pub fn collect() -> std::collections::HashMap<String, String> {
61 std::env::vars().collect()
62}
63
64pub 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
81pub 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
91pub 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
108pub fn get(key: &str) -> crate::Result<String> {
112 crate::try_get(key)?.ok_or_else(|| crate::Error::Missing(key.to_string()))
113}
114
115pub 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}