1use std::env;
2use std::str::FromStr;
3
4pub fn eval_env_with<T, F>(var_name: &str, default_value: T, parse_fn: F) -> Result<T, T::Err>
5where
6 T: FromStr,
7 F: FnOnce(&str) -> Result<T, T::Err>,
8{
9 let Ok(var_value) = env::var(var_name) else {
10 return Ok(default_value);
11 };
12
13 let parsed = parse_fn(&var_value)?;
14 Ok(parsed)
15}
16
17pub fn eval_env<T>(var_name: &str, default_value: T) -> Result<T, T::Err>
18where
19 T: FromStr,
20{
21 eval_env_with(var_name, default_value, T::from_str)
22}
23
24pub fn eval_env_or<T>(var_name: &str, default_value: T) -> T
25where
26 T: FromStr + Clone,
27{
28 eval_env(var_name, default_value.clone()).unwrap_or(default_value)
30}
31
32#[cfg(test)]
33mod tests {
34 use std::{
35 net::SocketAddr,
36 path::{Path, PathBuf},
37 };
38
39 use super::*;
40 #[test]
41 fn test_eval_env_or() {
42 {
43 let def = SocketAddr::from(([127, 0, 0, 1], 5423));
44 assert_eq!(eval_env_or::<SocketAddr>("LC_ADDR", def), def);
45 }
46
47 {
48 let def = Path::new("/root/path").to_path_buf();
49 assert_eq!(eval_env_or::<PathBuf>("LC_KEY_DIR", def.clone()), def);
50 }
51 {
52 unsafe { env::set_var("ENABLE", "true") };
53 assert!(eval_env_or::<bool>("ENABLE", false));
54 }
55 {
56 unsafe { env::set_var("LC_ADDR", "localhost:1922") };
57 let def = SocketAddr::from(([127, 0, 0, 1], 5423));
58 assert!(eval_env::<SocketAddr>("LC_ADDR", def).is_err());
60 }
61
62 {
63 unsafe { env::set_var("LC_ADDR", "localhost:1922") };
64 let def = SocketAddr::from(([127, 0, 0, 1], 5423));
65 assert_eq!(
67 eval_env_with::<SocketAddr, _>("LC_ADDR", def, |s| { s.replace("localhost", "127.0.0.1").parse() })
68 .unwrap()
69 .to_string(),
70 "127.0.0.1:1922"
71 );
72 }
73 }
74}