use std::path::PathBuf;
use serde::Serialize;
use serde::de::DeserializeOwned;
pub struct Settings<T> {
pub data: T,
app_name: String,
}
impl<T: Default> Default for Settings<T> {
fn default() -> Self {
Self {
data: T::default(),
app_name: String::new(),
}
}
}
impl<T: Serialize + DeserializeOwned + Default> Settings<T> {
pub fn load(app_name: impl Into<String>) -> Self {
let app_name = app_name.into();
let data = Self::load_from_disk(&app_name).unwrap_or_default();
Self { data, app_name }
}
pub fn save(&self) -> Result<(), String> {
let path = self
.settings_path()
.ok_or_else(|| "Could not determine config directory".to_string())?;
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)
.map_err(|error| format!("Failed to create config directory: {}", error))?;
}
let json = serde_json::to_string_pretty(&self.data)
.map_err(|error| format!("Failed to serialize settings: {}", error))?;
std::fs::write(&path, json)
.map_err(|error| format!("Failed to write settings file: {}", error))
}
pub fn settings_path(&self) -> Option<PathBuf> {
dirs::config_dir().map(|config_dir| config_dir.join(&self.app_name).join("settings.json"))
}
fn load_from_disk(app_name: &str) -> Option<T> {
let config_dir = dirs::config_dir()?;
let path = config_dir.join(app_name).join("settings.json");
let contents = std::fs::read_to_string(path).ok()?;
serde_json::from_str(&contents).ok()
}
}