use std::fmt::{Display, Debug};
#[doc(hidden)]
pub use paste::paste;
#[doc(hidden)]
pub use lazy_static::lazy_static;
#[macro_export]
macro_rules! env_var_opt {
($env_name:ident $(-> $short_name:ident)?) => {
env_var_opt!(impl $env_name, $($short_name)? $env_name);
};
(impl $env_name:ident, $var_name:ident $($extra:ident)?) => {
$crate::paste! {
$crate::lazy_static! {
pub static ref $var_name: Option<String> = std::env::var(stringify!($env_name)).ok();
}
pub fn [<$var_name:lower>]() -> Option<&'static str> {
$var_name.as_ref()
}
}
}
}
#[macro_export]
macro_rules! env_var_opt_default {
($env_name:ident (default $default_env_name:ident) $(-> $short_name:ident)?) => {
env_var_opt_default!(impl $env_name, $default_env_name, $($short_name)? $env_name);
};
(impl $env_name:ident, $default_env_name:ident, $var_name:ident $($extra:ident)?) => {
$crate::paste! {
$crate::lazy_static! {
pub static ref $var_name: Result<String, &'static str> = std::env::var(stringify!($env_name))
.or_else(|_| std::env::var(stringify!($default_env_name)).map_err(|_| stringify!($env_name)));
}
pub fn [<$var_name:lower>]() -> &'static str {
$var_name.as_ref().unwrap()
}
}
}
}
#[macro_export]
macro_rules! env_var_req {
($env_name:ident $(-> $short_name:ident)?) => {
env_var_req!(impl $env_name, $($short_name)? $env_name);
};
(impl $env_name:ident, $var_name:ident $($extra:ident)?) => {
$crate::paste! {
$crate::lazy_static! {
pub static ref $var_name: Result<String, &'static str> = std::env::var(stringify!($env_name)).map_err(|_| stringify!($env_name));
}
pub fn [<$var_name:lower>]() -> &'static str {
$var_name.as_ref().unwrap()
}
}
}
}
#[macro_export]
macro_rules! assert_req_env {
($check_name_fn:ident: $($names:ident),+) => {
const NAMES_LEN: usize = [$(stringify!($names)),+].len();
pub fn $check_name_fn() -> Result<(), EnvVarErr<NAMES_LEN>> {
let errs = [$($names.as_ref().err().map(|e| *e)),+];
if errs.iter().any(Option::is_some) {
Err(EnvVarErr::new(errs))
} else {
Ok(())
}
}
};
}
pub struct EnvVarErr<const T: usize>([Option<&'static str>; T]);
impl<const T: usize> EnvVarErr<T> {
pub fn new(inner: [Option<&'static str>; T]) -> Self {
Self(inner)
}
}
impl<const T: usize> Display for EnvVarErr<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0
.into_iter()
.flatten()
.enumerate()
.try_for_each(
|(idx, var_name)| if idx == 0 {
write!(f, "{var_name}")
} else {
write!(f, ", {var_name}")
}
)
}
}
impl<const T: usize> Debug for EnvVarErr<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self}")
}
}