use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TraySettings {
pub auto_optimize: bool,
pub threshold: u32,
pub interval_secs: u64,
pub ai_mode: AIModeSettings,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AIModeSettings {
pub game_mode: bool,
pub focus_mode: bool,
pub thermal_prediction: bool,
pub predictive_preload: bool,
pub gpu_monitoring: bool,
pub vram_reserve_percent: u32,
}
impl Default for TraySettings {
fn default() -> Self {
Self {
auto_optimize: true,
threshold: 75,
interval_secs: 60,
ai_mode: AIModeSettings::default(),
}
}
}
impl Default for AIModeSettings {
fn default() -> Self {
Self {
game_mode: true,
focus_mode: true,
thermal_prediction: true,
predictive_preload: true,
gpu_monitoring: true,
vram_reserve_percent: 5,
}
}
}
impl TraySettings {
pub fn config_path() -> PathBuf {
if let Some(appdata) = std::env::var_os("APPDATA") {
let mut path = PathBuf::from(appdata);
path.push("RuVector");
path.push("memopt.toml");
return path;
}
if let Ok(exe) = std::env::current_exe() {
if let Some(dir) = exe.parent() {
return dir.join("memopt.toml");
}
}
PathBuf::from("memopt.toml")
}
pub fn load() -> Self {
let path = Self::config_path();
if path.exists() {
match std::fs::read_to_string(&path) {
Ok(content) => {
match toml::from_str(&content) {
Ok(settings) => {
tracing::info!("Loaded settings from {:?}", path);
return settings;
}
Err(e) => {
tracing::warn!("Failed to parse settings: {}", e);
}
}
}
Err(e) => {
tracing::warn!("Failed to read settings file: {}", e);
}
}
}
tracing::info!("Using default settings");
Self::default()
}
pub fn save(&self) -> Result<(), String> {
let path = Self::config_path();
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)
.map_err(|e| format!("Failed to create config directory: {}", e))?;
}
let content = toml::to_string_pretty(self)
.map_err(|e| format!("Failed to serialize settings: {}", e))?;
std::fs::write(&path, content)
.map_err(|e| format!("Failed to write settings: {}", e))?;
tracing::info!("Saved settings to {:?}", path);
Ok(())
}
pub fn update<F>(&mut self, f: F) -> Result<(), String>
where
F: FnOnce(&mut Self),
{
f(self);
self.save()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_settings() {
let settings = TraySettings::default();
assert!(settings.auto_optimize);
assert_eq!(settings.threshold, 75);
assert!(settings.ai_mode.game_mode);
}
#[test]
fn test_serialize_deserialize() {
let settings = TraySettings::default();
let toml = toml::to_string(&settings).unwrap();
let restored: TraySettings = toml::from_str(&toml).unwrap();
assert_eq!(settings.threshold, restored.threshold);
}
}