use crate::dirs::system::get_app_bundled_asset;
use once_cell::sync::OnceCell;
use std::path::{Path, PathBuf};
pub mod system;
pub enum Error {
MissingDataDir,
Io(std::io::Error),
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Self::Io(err)
}
}
pub struct App<'a> {
name: &'a str,
data: OnceCell<PathBuf>,
cache: OnceCell<PathBuf>,
docs: OnceCell<PathBuf>,
logs: OnceCell<PathBuf>,
config: OnceCell<PathBuf>,
}
impl<'a> App<'a> {
pub fn new(name: &'a str) -> App<'a> {
App {
name,
data: OnceCell::new(),
cache: OnceCell::new(),
docs: OnceCell::new(),
logs: OnceCell::new(),
config: OnceCell::new(),
}
}
pub fn get_data(&self) -> Result<&Path, Error> {
self.data
.get_or_try_init(|| {
let data = system::get_app_data()
.ok_or(Error::MissingDataDir)?
.join(self.name);
if !data.is_dir() {
std::fs::create_dir_all(&data)?;
}
Ok(data)
})
.map(|v| v.as_ref())
}
pub fn get_cache(&self) -> Result<&Path, Error> {
self.cache
.get_or_try_init(|| {
let cache = match system::get_app_cache() {
None => self.get_data()?.join("Cache"),
Some(cache) => cache.join(self.name),
};
if !cache.is_dir() {
std::fs::create_dir(&cache)?;
}
Ok(cache)
})
.map(|v| v.as_ref())
}
pub fn get_documents(&self) -> Result<&Path, Error> {
self.docs
.get_or_try_init(|| match system::get_app_documents() {
Some(docs) => Ok(docs),
None => {
let docs = self.get_data()?.join("Documents");
if !docs.is_dir() {
std::fs::create_dir(&docs)?;
}
Ok(docs)
}
})
.map(|v| v.as_ref())
}
pub fn get_logs(&self) -> Result<&Path, Error> {
self.logs
.get_or_try_init(|| {
let logs = match system::get_app_logs() {
None => self.get_documents()?.join("Logs"),
Some(logs) => logs.join(self.name),
};
if !logs.is_dir() {
std::fs::create_dir(&logs)?;
}
Ok(logs)
})
.map(|v| v.as_ref())
}
pub fn get_config(&self) -> Result<&Path, Error> {
self.config
.get_or_try_init(|| {
let config = match system::get_app_config() {
None => self.get_data()?.join("Config"),
Some(config) => config.join(self.name),
};
if !config.is_dir() {
std::fs::create_dir(&config)?;
}
Ok(config)
})
.map(|v| v.as_ref())
}
}
impl<'a> Clone for App<'a> {
fn clone(&self) -> Self {
App {
name: self.name,
data: self.data.clone(),
cache: self.cache.clone(),
docs: self.docs.clone(),
logs: self.logs.clone(),
config: self.config.clone(),
}
}
}
pub fn get_asset(file_name: &str) -> Option<PathBuf> {
get_app_bundled_asset(file_name)
}
#[cfg(test)]
mod tests {
use crate::dirs::App;
fn assert_sync_send<T: Sync + Send>(x: T) -> T {
x
}
#[test]
fn test_sync_send() {
let obj = App::new("test");
let _ = assert_sync_send(obj);
}
}