use std::path::{Path, PathBuf};
use bevy::prelude::*;
use etcetera::{AppStrategy, AppStrategyArgs, app_strategy::choose_native_strategy};
#[cfg(target_os = "windows")]
type Strategy = etcetera::app_strategy::Windows;
#[cfg(target_os = "linux")]
type Strategy = etcetera::app_strategy::Xdg;
#[cfg(any(target_os = "macos", target_os = "ios"))]
type Strategy = etcetera::app_strategy::Apple;
#[derive(Resource)]
pub struct Directories(Strategy);
impl Directories {
pub fn new(
top_level_domain: impl Into<String>,
author: impl Into<String>,
app_name: impl Into<String>,
) -> Result<Self, BevyError> {
choose_native_strategy(AppStrategyArgs {
top_level_domain: top_level_domain.into(),
author: author.into(),
app_name: app_name.into(),
})
.map(Self)
.map_err(BevyError::from)
}
pub fn from_string<S>(value: S) -> Result<Self, BevyError>
where
S: AsRef<str>,
{
let values: Vec<&str> = value.as_ref().splitn(3, '.').collect();
match values.len() == 3 {
false => Err("Invalid string provided.".into()),
true => Ok(Self::new(values[0], values[1], values[2])?),
}
}
pub fn home_dir(&self) -> &Path {
self.0.home_dir()
}
pub fn config_dir(&self) -> PathBuf {
self.0.config_dir()
}
pub fn data_dir(&self) -> PathBuf {
self.0.data_dir()
}
pub fn cache_dir(&self) -> PathBuf {
self.0.cache_dir()
}
pub fn state_dir(&self) -> Option<PathBuf> {
self.0.state_dir()
}
pub fn runtime_dir(&self) -> Option<PathBuf> {
self.0.runtime_dir()
}
pub fn strategy(&self) -> &Strategy {
&self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn create_valid_directories_from_string_literals() {
[
"a.b.c",
"1.2.3",
"Testing One.Mycool Bundle.App Name",
"APP$1.90))3,.(DJHG",
]
.iter()
.for_each(|s| {
matches!(Directories::from_string(s), Ok(_));
})
}
#[test]
fn create_invalid_directories_from_string_literals() {
[
"a.b.c.d",
"1.2",
"Testing One..Mycool Bundle.App Name",
"ABCDEFG",
]
.iter()
.for_each(|s| {
matches!(Directories::from_string(s), Err(_));
})
}
}