pub trait FromEnvValue: Sized {
fn from_env_value(raw: &str) -> Result<Self, String>;
}
impl FromEnvValue for String {
fn from_env_value(raw: &str) -> Result<Self, String> {
Ok(raw.to_string())
}
}
impl FromEnvValue for bool {
fn from_env_value(raw: &str) -> Result<Self, String> {
match raw.to_ascii_lowercase().as_str() {
"true" | "1" => Ok(true),
"false" | "0" => Ok(false),
_ => Err("expected one of `true`, `false`, `1`, `0` (case-insensitive)".to_string()),
}
}
}
impl<T: FromEnvValue> FromEnvValue for Vec<T> {
fn from_env_value(raw: &str) -> Result<Self, String> {
raw.split(',')
.map(|item| item.trim_matches(|c: char| c.is_whitespace() || c == '\u{feff}'))
.filter(|item| !item.is_empty())
.enumerate()
.map(|(index, item)| T::from_env_value(item).map_err(|error| format!("item {}: {error}", index + 1)))
.collect()
}
}
#[macro_export]
macro_rules! settings_via_from_str {
($($ty:ty),+ $(,)?) => {$(
impl $crate::settings::FromEnvValue for $ty {
fn from_env_value(raw: &str) -> ::core::result::Result<Self, ::std::string::String> {
raw.parse::<$ty>().map_err(|error| ::std::string::ToString::to_string(&error))
}
}
)+};
}
crate::settings_via_from_str!(
u8,
u16,
u32,
u64,
u128,
usize,
i8,
i16,
i32,
i64,
i128,
isize,
f32,
f64,
char,
std::path::PathBuf,
std::net::IpAddr,
std::net::Ipv4Addr,
std::net::Ipv6Addr,
std::net::SocketAddr,
std::net::SocketAddrV4,
std::net::SocketAddrV6,
);