defvar/
lib.rs

1pub extern crate once_cell;
2
3#[macro_export]
4macro_rules! defvar {
5    { $vis:vis $name:ident: $type:ty = $default:expr, or try $var:ident => $transform:block $(;)? } => {
6        $vis static $name: $crate::once_cell::sync::Lazy<$type> = $crate::once_cell::sync::Lazy::new(|| {
7            match ::std::env::var(stringify!($name)) {
8                Ok($var) => {
9                    match $transform {
10                        Ok(var) => var,
11                        Err(err) => {
12                            eprintln!(
13                                "Failed to transform environment variable “{}” with value “{:?}” to type “{}” using specified transform at {}:{}.  Using default “{:?}”.",
14                                stringify!(ident),
15                                $var,
16                                stringify!($type),
17                                file!(),
18                                line!(),
19                                $default,
20                            );
21                            $default
22                        }
23                    }
24                },
25                Err(::std::env::VarError::NotPresent) => {
26                    eprintln!("Environment variable “{}” is not present.  Using default “{:?}”.", stringify!($name), $default);
27                    $default
28                }
29                Err(::std::env::VarError::NotUnicode(envar)) => {
30                    eprintln!(
31                        "Environment variable “{}” does not contain valid Unicode data.  Data: [ {:?} ].  Using default “{:?}”.",
32                        stringify!($ident),
33                        envar,
34                        $default
35                    );
36                    $default
37                }
38            }
39        });
40    };
41    // Macro recursion limits would need to be set in the calling
42    // crate, which is undesirable.  Thus all syntactic sugar forms
43    // expand directly to the main form to keep recursion within
44    // default limits.
45    { $vis:vis $name:ident: $type:ty = $default:expr, or try $var:ident => $transform:expr $(;)? } => {
46        defvar! { $vis $name: $type = $default, or try $var => { $transform } }
47    };
48    { $vis:vis $name:ident: $type:ty = $default:expr, or $var:ident => $transform:block $(;)? } => {
49        defvar! { $vis $name: $type = $default, or try $var => { Result::<$type, ()>::Ok($transform) } }
50    };
51    { $vis:vis $name:ident: $type:ty = $default:expr, or $var:ident => $transform:expr $(;)? } => {
52        defvar! { $vis $name: $type = $default, or try $var => { Result::<$type, ()>::Ok($transform) } }
53    };
54    { $vis:vis $name:ident: String = $default:expr $(;)? } => {
55        defvar! { $vis $name: String = $default, or try v => { Result::<String, ()>::Ok(v.clone()) } }
56    };
57}