use super::{
home_path, load_all_from_path, load_from_path, load_home_env, save_to_path, system_paths,
};
use std::{
env,
path::{Path, PathBuf},
str::Utf8Error,
string::String,
};
use serde::{de, ser, Deserialize, Serialize};
pub trait StateFile<E, T = Self>: for<'s> Deserialize<'s> + Serialize
where
for<'s> T: Serialize + Deserialize<'s>,
E: std::error::Error + std::convert::From<std::io::Error>,
{
const APP_DIR_NAME: &'static str = env!("CARGO_CRATE_NAME");
const EXTRA_DIR: &'static str = concat!(env!("CARGO_CRATE_NAME"), ".d");
const HOME_PATH_ENV: &'static str = "XDG_STATE_HOME";
const HOME_PATH_FALLBACK: &'static str = ".local/state";
const FILENAME: &'static str = "state";
fn home() -> PathBuf {
home_path(
Self::HOME_PATH_ENV,
Self::HOME_PATH_FALLBACK,
Self::APP_DIR_NAME,
Self::FILENAME,
)
}
fn save(&self) -> Result<(), E> {
self.save_to_path(&Self::home(), true)
}
fn save_to_path(&self, path: impl AsRef<Path>, create_dirs: bool) -> Result<(), E> {
save_to_path(self, path.as_ref(), create_dirs)
}
fn load() -> Result<T, E> {
Self::load_from_home()
}
fn load_from_home() -> Result<T, E> {
Self::load_from_path(&Self::home())
}
fn load_from_home_extra_dirs() -> Result<Vec<T>, E> {
load_all_from_path(&Self::home())
}
fn load_from_path(path: impl AsRef<Path>) -> Result<T, E> {
load_from_path(path.as_ref())
}
}
mod tests {
use super::*;
use std::env::set_var;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct State;
impl StateFile<std::io::Error> for State {}
#[test]
fn home_path() {
set_var("XDG_STATE_HOME", "/tmp/.local/state/");
assert_eq!(
State::home(),
PathBuf::from("/tmp/.local/state/docopticon/state")
);
set_var("XDG_CONFIG_HOME", "relative/dir");
set_var("HOME", "/tmp/");
assert_eq!(
State::home(),
PathBuf::from("/tmp/.local/state/docopticon/state")
);
}
}