2020-01-16 22:05:35 +03:00
|
|
|
use std::ops::Deref;
|
|
|
|
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub trait ToEnvString {
|
|
|
|
fn to_env_string(&self) -> EnvString;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub trait FromEnvString: Sized {
|
|
|
|
type Err;
|
|
|
|
|
|
|
|
fn from_env_string(s: &EnvString) -> Result<Self, Self::Err>;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl<T> ToEnvString for T
|
|
|
|
where
|
|
|
|
T: ToString
|
|
|
|
{
|
|
|
|
#[inline]
|
|
|
|
fn to_env_string(&self) -> EnvString {
|
|
|
|
EnvString(self.to_string())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
macro_rules! from_env_string_numbers_impl {
|
2020-01-19 20:42:26 +03:00
|
|
|
($($ty:ty => $feature:expr),+) => {
|
2020-01-16 22:05:35 +03:00
|
|
|
$(
|
2020-01-19 20:42:26 +03:00
|
|
|
#[cfg(feature = $feature)]
|
2020-01-16 22:05:35 +03:00
|
|
|
impl FromEnvString for $ty {
|
2020-01-19 20:42:26 +03:00
|
|
|
type Err = <$ty as std::str::FromStr>::Err;
|
2020-01-16 22:05:35 +03:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn from_env_string(s: &EnvString) -> Result<Self, Self::Err> {
|
|
|
|
s.0.parse::<Self>()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)+
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
from_env_string_numbers_impl![
|
2020-01-19 20:42:26 +03:00
|
|
|
i8 => "i8",
|
|
|
|
i16 => "i16",
|
|
|
|
i32 => "i32",
|
|
|
|
i64 => "i64",
|
|
|
|
i128 => "i128",
|
|
|
|
isize => "isize",
|
|
|
|
u8 => "u8",
|
|
|
|
u16 => "u16",
|
|
|
|
u32 => "u32",
|
|
|
|
u64 => "u64",
|
|
|
|
u128 => "u128",
|
|
|
|
usize => "usize",
|
|
|
|
f32 => "f32",
|
|
|
|
f64 => "f64"
|
2020-01-16 22:05:35 +03:00
|
|
|
];
|
|
|
|
|
|
|
|
|
2020-01-19 20:42:26 +03:00
|
|
|
#[cfg(feature = "bool")]
|
2020-01-16 22:05:35 +03:00
|
|
|
impl FromEnvString for bool {
|
|
|
|
type Err = ();
|
|
|
|
|
|
|
|
fn from_env_string(s: &EnvString) -> Result<Self, Self::Err> {
|
|
|
|
match s.to_lowercase().as_str() {
|
|
|
|
"true" | "t" | "yes" | "y" | "on" | "1" => Ok(true),
|
|
|
|
_ => Ok(false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-21 11:12:12 +03:00
|
|
|
|
|
|
|
#[cfg(feature = "array")]
|
2020-02-08 20:43:33 +03:00
|
|
|
#[derive(Debug)]
|
2020-01-21 11:12:12 +03:00
|
|
|
pub enum ArrayEnvError {
|
|
|
|
InvalidType,
|
|
|
|
FailedToParse,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "array")]
|
|
|
|
impl<T> FromEnvString for Vec<T>
|
|
|
|
where T: FromEnvString
|
|
|
|
{
|
|
|
|
type Err = ArrayEnvError;
|
|
|
|
|
|
|
|
fn from_env_string(s: &EnvString) -> Result<Self, Self::Err> {
|
|
|
|
serde_json::from_str::<Vec<isize>>(s.trim())
|
|
|
|
.map(|vec| {
|
|
|
|
vec.iter().map(|v| v.to_string()).collect::<Vec<String>>()
|
|
|
|
})
|
|
|
|
.or_else(|_| {
|
|
|
|
serde_json::from_str::<Vec<String>>(s.trim())
|
|
|
|
})
|
|
|
|
.map_err(|_| ArrayEnvError::InvalidType)
|
|
|
|
.and_then(|vec| {
|
|
|
|
vec.iter()
|
|
|
|
.map(|v| {
|
|
|
|
v.to_env_string()
|
|
|
|
.parse::<T>()
|
|
|
|
.map_err(|_| ArrayEnvError::FailedToParse)
|
|
|
|
})
|
|
|
|
.collect::<Result<Vec<T>, _>>()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-16 22:05:35 +03:00
|
|
|
impl FromEnvString for String {
|
|
|
|
type Err = ();
|
|
|
|
|
|
|
|
fn from_env_string(s: &EnvString) -> Result<Self, Self::Err> {
|
|
|
|
Ok(s.0.clone())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-08 15:09:58 +03:00
|
|
|
impl FromEnvString for &'static str {
|
|
|
|
type Err = ();
|
|
|
|
|
|
|
|
fn from_env_string(s: &EnvString) -> Result<Self, Self::Err> {
|
|
|
|
Ok(Box::leak(s.0.clone().into_boxed_str()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-16 22:05:35 +03:00
|
|
|
#[doc(hidden)]
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub struct EnvString(String);
|
|
|
|
|
|
|
|
impl EnvString {
|
|
|
|
pub fn parse<T: FromEnvString>(&self) -> Result<T, T::Err> {
|
|
|
|
FromEnvString::from_env_string(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Deref for EnvString {
|
|
|
|
type Target = String;
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|