komichi 2.2.0

Application tools for working with file-system paths
Documentation
//! Environment tools.

use camino::Utf8PathBuf;
use std::env;

use std::marker::PhantomData;
use std::path::PathBuf;

pub struct WithoutDefault;
pub struct WithDefault;

/// Used to acquire an environment variable value with a fallback value.
///
/// # Examples
///
/// ```
/// use komichi::EnvVal;
/// use std::env::set_var;
///
/// // Only using unsafe for the example. Most likely the environment-variables
/// // will be set via the shell.
/// unsafe {
///     set_var("TEST_VAR", "Hello Earth");
/// }
///
/// let val: String = EnvVal::from("TEST_VAR")
///     .with_default_value("Hello Mars")
///     .into();
/// assert_eq!("Hello Earth".to_string(), val);
///
/// ```
pub struct EnvVal<State = WithoutDefault> {
    name: String,
    default: String,
    state: PhantomData<State>,
}

impl<WithoutDefault> From<EnvVal<WithoutDefault>>
    for Option<String>
{
    fn from(val: EnvVal<WithoutDefault>) -> Self {
        if let Ok(value) = env::var(val.name) {
            if !value.is_empty() {
                return Some(value);
            }
        }
        None
    }
}

impl<WithoutDefault> From<EnvVal<WithoutDefault>>
    for Option<PathBuf>
{
    fn from(val: EnvVal<WithoutDefault>) -> Self {
        if let Ok(value) = env::var(val.name) {
            if !value.is_empty() {
                return Some(PathBuf::from(value));
            }
        }
        None
    }
}

impl<WithoutDefault> From<EnvVal<WithoutDefault>>
    for Option<Utf8PathBuf>
{
    fn from(val: EnvVal<WithoutDefault>) -> Self {
        if let Ok(value) = env::var(val.name) {
            if !value.is_empty() {
                return Some(Utf8PathBuf::from(value));
            }
        }
        None
    }
}

impl<WithDefault> From<EnvVal<WithDefault>> for String {
    fn from(val: EnvVal<WithDefault>) -> Self {
        if let Ok(value) = env::var(&val.name) {
            if !value.is_empty() {
                return value;
            }
        }
        val.default.clone()
    }
}

impl<WithDefault> From<EnvVal<WithDefault>> for PathBuf {
    fn from(val: EnvVal<WithDefault>) -> Self {
        if let Some(value) = env::var_os(&val.name) {
            if !value.is_empty() {
                return PathBuf::from(value);
            }
        }
        // Default should NOT be none so it's okay to unwrap here.
        PathBuf::from(val.default.clone())
    }
}

impl<WithDefault> From<EnvVal<WithDefault>> for Utf8PathBuf {
    fn from(val: EnvVal<WithDefault>) -> Self {
        if let Some(value) = env::var_os(&val.name) {
            if !value.is_empty() {
                return Utf8PathBuf::from(
                    value.to_string_lossy().to_string(),
                );
            }
        }
        // Default should NOT be none so it's okay to unwrap here.
        Utf8PathBuf::from(val.default.clone())
    }
}

impl<State> EnvVal<State> {
    pub fn with_default_value<T>(
        self,
        val: &T,
    ) -> EnvVal<WithDefault>
    where
        T: AsRef<str> + ?Sized,
    {
        let val = val.as_ref().to_string();
        EnvVal {
            name: self.name,
            default: val,
            state: PhantomData::<WithDefault>,
        }
    }
}

impl From<&str> for EnvVal<WithoutDefault> {
    fn from(name: &str) -> Self {
        let name = name.to_string();
        Self {
            name,
            default: String::new(),
            state: PhantomData,
        }
    }
}

impl From<String> for EnvVal<WithoutDefault> {
    fn from(name: String) -> Self {
        Self {
            name,
            default: String::new(),
            state: PhantomData,
        }
    }
}

impl From<&String> for EnvVal<WithoutDefault> {
    fn from(name: &String) -> Self {
        let name = name.to_string();
        Self {
            name,
            default: String::new(),
            state: PhantomData,
        }
    }
}