use crate::Result; use serde::{Deserialize, Serialize}; use std::{ collections::HashMap, fs, path::{Path, PathBuf}, }; #[derive(Debug, Default, Serialize, Deserialize)] pub struct StateFile { #[serde(default)] pub profiles: HashMap, } #[derive(Debug, Default, Serialize, Deserialize)] pub struct ProfileState { #[serde(default)] pub user_id: Option, #[serde(default)] pub semesters: HashMap, #[serde(default)] pub courses: HashMap, #[serde(default)] pub files: HashMap, } #[derive(Debug, Default, Serialize, Deserialize, Clone)] pub struct SemesterState { pub id: String, pub title: String, pub key: String, } #[derive(Debug, Default, Serialize, Deserialize, Clone)] pub struct CourseState { pub id: String, pub name: String, pub semester_key: String, #[serde(default)] pub last_sync: Option, } #[derive(Debug, Default, Serialize, Deserialize, Clone)] pub struct FileState { pub id: String, #[serde(default)] pub size: Option, #[serde(default)] pub checksum: Option, #[serde(default)] pub last_downloaded: Option, #[serde(default)] pub remote_modified: Option, #[serde(default)] pub path_hint: Option, } impl StateFile { pub fn load_or_default(path: &Path) -> Result { match fs::read_to_string(path) { Ok(contents) => Ok(toml::from_str(&contents)?), Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(Self::default()), Err(err) => Err(err.into()), } } pub fn save(&self, path: &Path) -> Result<()> { if let Some(parent) = path.parent() { fs::create_dir_all(parent)?; } let contents = toml::to_string_pretty(self)?; fs::write(path, contents)?; Ok(()) } pub fn profile_mut(&mut self, profile: &str) -> &mut ProfileState { self.profiles .entry(profile.to_string()) .or_insert_with(ProfileState::default) } pub fn profile(&self, profile: &str) -> Option<&ProfileState> { self.profiles.get(profile) } }