use std::ffi::{OsStr, OsString};
use std::path::{Path, PathBuf};
use std::sync::{Mutex, MutexGuard};
static SERIAL_LOCK: Mutex<()> = Mutex::new(());
fn lock() -> MutexGuard<'static, ()> {
SERIAL_LOCK.lock().unwrap_or_else(|e| e.into_inner())
}
pub(crate) struct CwdGuard {
_lock: MutexGuard<'static, ()>,
prev: PathBuf,
}
impl CwdGuard {
pub(crate) fn enter(dir: &Path) -> Self {
let lock = lock();
let prev = std::env::current_dir().expect("read current dir");
std::env::set_current_dir(dir).expect("set current dir");
CwdGuard { _lock: lock, prev }
}
}
impl Drop for CwdGuard {
fn drop(&mut self) {
let _ = std::env::set_current_dir(&self.prev);
}
}
pub(crate) struct EnvVarGuard {
_lock: MutexGuard<'static, ()>,
key: OsString,
prev: Option<OsString>,
}
impl EnvVarGuard {
pub(crate) fn set(key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> Self {
let lock = lock();
let key = key.as_ref().to_os_string();
let prev = std::env::var_os(&key);
unsafe { std::env::set_var(&key, value) };
EnvVarGuard {
_lock: lock,
key,
prev,
}
}
}
impl Drop for EnvVarGuard {
fn drop(&mut self) {
unsafe {
match &self.prev {
Some(v) => std::env::set_var(&self.key, v),
None => std::env::remove_var(&self.key),
}
}
}
}