use std::path::{Path, PathBuf};
use std::sync::{Mutex, OnceLock};
fn installed_state_dir() -> &'static Mutex<Option<PathBuf>> {
static STATE: OnceLock<Mutex<Option<PathBuf>>> = OnceLock::new();
STATE.get_or_init(|| Mutex::new(None))
}
fn writable_state_override() -> &'static Mutex<Option<PathBuf>> {
static WRITABLE: OnceLock<Mutex<Option<PathBuf>>> = OnceLock::new();
WRITABLE.get_or_init(|| Mutex::new(None))
}
pub fn set_state_dir<P: Into<PathBuf>>(dir: P) {
*installed_state_dir().lock().unwrap() = Some(dir.into());
}
pub fn clear_state_dir() {
*installed_state_dir().lock().unwrap() = None;
}
pub fn set_writable_state_dir<P: Into<PathBuf>>(dir: P) {
*writable_state_override().lock().unwrap() = Some(dir.into());
}
pub fn clear_writable_state_dir() {
*writable_state_override().lock().unwrap() = None;
}
pub fn state_dir() -> Option<PathBuf> {
installed_state_dir().lock().unwrap().clone()
}
pub fn writable_state_dir() -> Option<PathBuf> {
let over = writable_state_override().lock().unwrap().clone();
resolve_writable_dir(over.as_deref(), state_dir().as_deref())
}
fn resolve_writable_dir(over: Option<&Path>, state: Option<&Path>) -> Option<PathBuf> {
over.or(state).map(Path::to_path_buf)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn resolve_writable_dir_prefers_override_then_falls_back() {
let state = Path::new("/game/MyGame");
let over = Path::new("/users/me/AppData/Local/MyGame");
assert_eq!(
resolve_writable_dir(Some(over), Some(state)).as_deref(),
Some(over)
);
assert_eq!(
resolve_writable_dir(None, Some(state)).as_deref(),
Some(state)
);
}
#[test]
fn resolve_writable_dir_without_a_state_dir() {
let over = Path::new("/users/me/MyGame");
assert_eq!(
resolve_writable_dir(Some(over), None).as_deref(),
Some(over)
);
assert_eq!(resolve_writable_dir(None, None), None);
}
}