use serde::{de::DeserializeOwned, Serialize};
use std::{
env,
fmt::Debug,
fs::{self, File},
io::{Read, Write},
path::{Path, PathBuf},
};
#[derive(Debug)]
pub struct XDGStore;
impl XDGStore {
pub fn init_storage(app_name: &str) -> Result<(), String> {
let data_home = app_data_home(app_name);
if !data_home.exists() {
fs::create_dir_all(data_home).map_err(|e| format!("{:?}", e))
} else {
Ok(())
}
}
pub fn save<T: Serialize>(app_name: &str, bundle: &str, data: T) -> Result<(), String> {
let payload = serde_json::to_string(&data).map_err(|e| format!("{:?}", e))?;
let mut file = bundle_file(app_name, bundle, RW::RW)?;
file.write_all(payload.as_bytes())
.map_err(|e| format!("{:?}", e))?;
Ok(())
}
pub fn retrieve<T: DeserializeOwned>(app_name: &str, bundle: &str) -> Result<T, String> {
let mut file = bundle_file(app_name, bundle, RW::RO)?;
let mut content = String::new();
file.read_to_string(&mut content)
.map_err(|e| format!("{:?}", e))?;
let res: T = serde_json::from_str(&content).map_err(|e| format!("{:?}", e))?;
Ok(res)
}
}
fn app_data_home(app_name: &str) -> PathBuf {
xdg_data_home().join(app_name)
}
fn bundle_file(app_name: &str, bundle: &str, mode: RW) -> Result<File, String> {
let mut storage = app_data_home(app_name).join(bundle);
storage.set_extension("json");
match mode {
RW::RO => File::open(storage),
RW::RW => File::create(storage),
}
.map_err(|e| format!("{:?}", e))
}
enum RW {
RO,
RW,
}
#[cfg(not(target_os = "windows"))]
fn xdg_data_home() -> PathBuf {
match env::var("XDG_DATA_HOME") {
Ok(data_home) => Path::new(&data_home).to_path_buf(),
_ => {
let home = env::var("HOME").unwrap();
Path::new(&home).join(".local").join("share").to_path_buf()
}
}
}
#[cfg(target_os = "windows")]
fn xdg_data_home() -> PathBuf {
let data_home = env::var("APPDATA").unwrap();
Path::new(&data_home).to_path_buf()
}