use std::path::{Path, PathBuf};
use steamlocate::SteamDir;
pub fn steam_dir() -> anyhow::Result<SteamDir> {
Ok(steamlocate::SteamDir::locate()?)
}
pub fn log_dir() -> PathBuf {
cache_dir().join("logs")
}
macro_rules! dir_override {
($name:ident : $fname:ident) => {
#[cfg(not(debug_assertions))]
pub fn $fname() -> PathBuf {
dirs::$fname().map(|c| c.join("cinc")).unwrap_or_else(|| {
tracing::warn!(
"could not locate system {} directory, falling back to ~/.cinc/{}",
stringify!($name),
stringify!(name)
);
let home = std::env::home_dir().expect("could not locate home directory");
home.join(".cinc").join(stringify!(name))
})
}
#[cfg(debug_assertions)]
pub fn $fname() -> PathBuf {
concat!("./cinc-data/", stringify!($name)).into()
}
};
}
dir_override!(data : data_dir);
dir_override!(config : config_dir);
dir_override!(cache : cache_dir);
pub fn extract_postfix<'p>(base: &'p Path, child: &'p Path) -> &'p Path {
assert!(
base.components()
.zip(child.components())
.all(|(a, b)| a == b),
"child is not prefix of base"
);
child.strip_prefix(base).unwrap()
}
pub fn extract_prefix<'p>(base: &'p Path, child: &Path) -> &'p Path {
let postfix_len = base
.components()
.rev()
.zip(child.components().rev())
.take_while(|(a, b)| a == b)
.count();
assert!(
postfix_len >= 1,
"base is not prefix of child {base:?} and {child:?}"
);
let nb_comps = base.components().count();
let prefix_bytes = base
.components()
.take(nb_comps - postfix_len)
.fold(PathBuf::new(), |p, c| p.join(c))
.as_os_str()
.as_encoded_bytes()
.len();
unsafe {
Path::new(std::ffi::OsStr::from_encoded_bytes_unchecked(
&base.as_os_str().as_encoded_bytes()[..prefix_bytes],
))
}
}
pub trait PathExt {
fn join_good(&self, other: impl Into<PathBuf>) -> PathBuf;
}
impl PathExt for Path {
fn join_good(&self, other: impl Into<PathBuf>) -> PathBuf {
let other = other.into();
if !other.is_absolute() {
self.join(other)
} else {
self.join(".".to_owned() + other.to_str().unwrap())
}
}
}
#[cfg(test)]
mod tests {
use std::path::Path;
use crate::paths::{extract_postfix, extract_prefix};
#[test]
fn postfix_extract() {
let base = Path::new("/");
let child = base.join("yipee").join("yay");
assert_eq!(
extract_postfix(base, &child),
Path::new("yipee").join("yay")
);
}
#[test]
fn prefix_extract_unicode() {
let child = Path::new("🥀");
let base = Path::new("💀").join("😔").join("🥀");
assert_eq!(extract_prefix(&base, child), Path::new("💀").join("😔"));
}
}