use std::ffi::OsString;
use std::sync::{Mutex, MutexGuard};
static ENV_LOCK: Mutex<()> = Mutex::new(());
pub(crate) struct EnvGuard {
_lock: MutexGuard<'static, ()>,
saved: Vec<(&'static str, Option<OsString>)>,
}
impl EnvGuard {
pub(crate) fn clear(vars: &[&'static str]) -> Self {
Self::apply(vars.iter().map(|&name| (name, None)))
}
pub(crate) fn set(vars: &[(&'static str, &str)]) -> Self {
Self::apply(vars.iter().map(|&(name, value)| (name, Some(value))))
}
fn apply<'a>(vars: impl Iterator<Item = (&'static str, Option<&'a str>)>) -> Self {
let lock = ENV_LOCK.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
let saved = vars
.map(|(name, value)| {
let previous = std::env::var_os(name);
unsafe {
match value {
Some(value) => std::env::set_var(name, value),
None => std::env::remove_var(name),
}
}
(name, previous)
})
.collect();
Self { _lock: lock, saved }
}
}
impl Drop for EnvGuard {
fn drop(&mut self) {
for (name, previous) in &self.saved {
unsafe {
match previous {
Some(value) => std::env::set_var(name, value),
None => std::env::remove_var(name),
}
}
}
}
}