use std::collections::HashMap;
use std::env;
use std::env::VarsOs;
use std::ffi::{OsStr, OsString};
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Env {
inner: HashMap<OsString, OsString>,
}
impl Env {
#[must_use]
pub fn from_current() -> Self {
env::vars_os().into()
}
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn insert(&mut self, key: impl Into<OsString>, value: impl Into<OsString>) -> &mut Self {
self.inner.insert(key.into(), value.into());
self
}
#[must_use]
pub fn get(&self, key: impl AsRef<OsStr>) -> Option<&OsString> {
self.inner.get(key.as_ref())
}
#[must_use]
pub fn get_string_lossy(&self, key: impl AsRef<OsStr>) -> Option<String> {
self.get(key)
.map(|os_string| os_string.to_string_lossy().to_string())
}
#[must_use]
pub fn contains_key(&self, key: impl AsRef<OsStr>) -> bool {
self.inner.contains_key(key.as_ref())
}
#[must_use]
pub fn iter(&self) -> std::collections::hash_map::Iter<'_, OsString, OsString> {
self.inner.iter()
}
}
impl From<VarsOs> for Env {
fn from(vars_os: VarsOs) -> Self {
Self {
inner: vars_os.collect(),
}
}
}
impl<'a> IntoIterator for &'a Env {
type Item = (&'a OsString, &'a OsString);
type IntoIter = std::collections::hash_map::Iter<'a, OsString, OsString>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[cfg(test)]
mod tests {
#[test]
#[cfg(target_family = "unix")]
fn into_iterator() {
use crate::Env;
use std::process::Command;
let mut env = Env::new();
env.insert("FOO", "FOO");
env.insert("FOO", "BAR");
env.insert("BAZ", "BLAH");
let output = Command::new("printenv")
.env_clear()
.envs(&env)
.output()
.unwrap();
assert_eq!(
"BAZ=BLAH\nFOO=BAR\n",
String::from_utf8_lossy(&output.stdout)
);
}
}