From 53b854ef6d03bdf931daad17838c17d6b7721c0d Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Mon, 9 Jan 2023 23:19:29 +1300 Subject: [PATCH] Convert repeated code in config-traits to a macro --- config-traits/src/lib.rs | 341 +++++++++++++---------------- daemon-user/src/config.rs | 8 +- daemon-user/src/daemon.rs | 2 +- daemon/src/config.rs | 4 +- daemon/src/ctrl_anime/config.rs | 4 +- daemon/src/ctrl_aura/config.rs | 4 +- daemon/src/ctrl_profiles/config.rs | 6 +- daemon/src/daemon.rs | 2 +- 8 files changed, 172 insertions(+), 199 deletions(-) diff --git a/config-traits/src/lib.rs b/config-traits/src/lib.rs index bcf45759..63e9ba00 100644 --- a/config-traits/src/lib.rs +++ b/config-traits/src/lib.rs @@ -148,197 +148,170 @@ where } } -/// Base trait for loading/parsing. This can be used to help update configs to -/// new versions -/// -/// # Example -/// ```rust -/// use std::path::PathBuf; -/// use serde::{Deserialize, Serialize}; -/// use config_traits::{StdConfig, StdConfigLoad1}; -/// -/// #[derive(Deserialize, Serialize)] -/// struct FanCurveConfig {} -/// -/// impl StdConfig for FanCurveConfig { -/// fn new() -> Self { Self {} } -/// -/// fn file_name(&self) -> std::string::String { "test_name.conf".to_owned() } -/// -/// fn config_dir() -> PathBuf { PathBuf::from("/tmp") } -/// } -/// -/// impl StdConfigLoad1 for FanCurveConfig {} -/// ``` -/// -/// If all of the generics fails to parse, then the old config is renamed and a -/// new one created -pub trait StdConfigLoad1 -where - Self: StdConfig + DeserializeOwned + Serialize, -{ - fn load(mut self) -> Self { - let mut file = self.file_open(); - let mut buf = String::new(); - if let Ok(read_len) = file.read_to_string(&mut buf) { - if read_len != 0 { - if let Ok(data) = ron::from_str(&buf) { - self = data; - } else if let Ok(data) = serde_json::from_str(&buf) { - self = data; - } else if let Ok(data) = toml::from_str(&buf) { - self = data; - } else { - self.rename_file_old(); - self = Self::new(); +#[macro_export] +macro_rules! std_config_load { + ($trait_name:ident: $($generic:ident),*) => { + /// Base trait for loading/parsing. This is intended to be used to help update + /// configs to new versions + /// + /// # Example + /// ```rust + /// use std::path::PathBuf; + /// use serde::{Deserialize, Serialize}; + /// use config_traits::{StdConfig, StdConfigLoad2}; + /// + /// #[derive(Deserialize, Serialize)] + /// struct FanCurveConfigOld {} + /// + /// #[derive(Deserialize, Serialize)] + /// struct FanCurveConfigOlder {} + /// + /// #[derive(Deserialize, Serialize)] + /// struct FanCurveConfig {} + /// + /// impl From for FanCurveConfig { + /// fn from(_: FanCurveConfigOld) -> Self { Self {} } + /// } + /// + /// impl From for FanCurveConfig { + /// fn from(_: FanCurveConfigOlder) -> Self { Self {} } + /// } + /// + /// impl StdConfig for FanCurveConfig { + /// fn new() -> Self { Self {} } + /// + /// fn file_name(&self) -> std::string::String { "test_name.conf".to_owned() } + /// + /// fn config_dir() -> PathBuf { PathBuf::from("/tmp") } + /// } + /// + /// impl StdConfigLoad2 for FanCurveConfig {} + /// ``` + /// + /// If all of the generics fails to parse, then the old config is renamed and a + /// new one created + pub trait $trait_name<$($generic),*> + where + Self: $crate::StdConfig + DeserializeOwned + Serialize, + $($generic: DeserializeOwned + Into),* + { + fn load(mut self) -> Self { + let mut file = self.file_open(); + let mut buf = String::new(); + if let Ok(read_len) = file.read_to_string(&mut buf) { + if read_len != 0 { + if let Ok(data) = ron::from_str(&buf) { + self = data; + } else if let Ok(data) = serde_json::from_str(&buf) { + self = data; + } else if let Ok(data) = toml::from_str(&buf) { + self = data; + } $(else if let Ok(data) = serde_json::from_str::<$generic>(&buf) { + self = data.into(); + } else if let Ok(data) = toml::from_str::<$generic>(&buf) { + self = data.into(); + })* else { + self.rename_file_old(); + self = Self::new(); + } + } else { + error!("Config file {} zero read length", self.file_name()); + } } - } else { - error!("Config file {} zero read length", self.file_name()); + self.write(); + self } } - self.write(); - self - } + }; } -/// Base trait for loading/parsing. This is intended to be used to help update -/// configs to new versions -/// -/// # Example -/// ```rust -/// use std::path::PathBuf; -/// use serde::{Deserialize, Serialize}; -/// use config_traits::{StdConfig, StdConfigLoad2}; -/// -/// #[derive(Deserialize, Serialize)] -/// struct FanCurveConfigOld {} -/// -/// #[derive(Deserialize, Serialize)] -/// struct FanCurveConfig {} -/// -/// impl From for FanCurveConfig { -/// fn from(_: FanCurveConfigOld) -> Self { Self {} } -/// } -/// -/// impl StdConfig for FanCurveConfig { -/// fn new() -> Self { Self {} } -/// -/// fn file_name(&self) -> std::string::String { "test_name.conf".to_owned() } -/// -/// fn config_dir() -> PathBuf { PathBuf::from("/tmp") } -/// } -/// -/// impl StdConfigLoad2 for FanCurveConfig {} -/// ``` -/// -/// If all of the generics fails to parse, then the old config is renamed and a -/// new one created -pub trait StdConfigLoad2 -where - Self: StdConfig + DeserializeOwned + Serialize, - OldConfig: DeserializeOwned + Into, -{ - fn load(mut self) -> Self { - let mut file = self.file_open(); - let mut buf = String::new(); - if let Ok(read_len) = file.read_to_string(&mut buf) { - if read_len != 0 { - if let Ok(data) = ron::from_str(&buf) { - self = data; - } else if let Ok(data) = serde_json::from_str(&buf) { - self = data; - } else if let Ok(data) = toml::from_str(&buf) { - self = data; - } else if let Ok(data) = serde_json::from_str::(&buf) { - self = data.into(); - } else if let Ok(data) = toml::from_str::(&buf) { - self = data.into(); - } else { - self.rename_file_old(); - self = Self::new(); - } - } else { - error!("Config file {} zero read length", self.file_name()); - } - } - self.write(); - self - } -} +std_config_load!(StdConfigLoad:); +std_config_load!(StdConfigLoad1: T1); +std_config_load!(StdConfigLoad2: T1, T2); +std_config_load!(StdConfigLoad3: T1, T2, T3); +std_config_load!(StdConfigLoad4: T1, T2, T3, T4); -/// Base trait for loading/parsing. This is intended to be used to help update -/// configs to new versions -/// -/// # Example -/// ```rust -/// use std::path::PathBuf; -/// use serde::{Deserialize, Serialize}; -/// use config_traits::{StdConfig, StdConfigLoad3}; -/// -/// #[derive(Deserialize, Serialize)] -/// struct FanCurveConfigOld {} -/// -/// #[derive(Deserialize, Serialize)] -/// struct FanCurveConfigOlder {} -/// -/// #[derive(Deserialize, Serialize)] -/// struct FanCurveConfig {} -/// -/// impl From for FanCurveConfig { -/// fn from(_: FanCurveConfigOld) -> Self { Self {} } -/// } -/// -/// impl From for FanCurveConfig { -/// fn from(_: FanCurveConfigOlder) -> Self { Self {} } -/// } -/// -/// impl StdConfig for FanCurveConfig { -/// fn new() -> Self { Self {} } -/// -/// fn file_name(&self) -> std::string::String { "test_name.conf".to_owned() } -/// -/// fn config_dir() -> PathBuf { PathBuf::from("/tmp") } -/// } -/// -/// impl StdConfigLoad3 for FanCurveConfig {} -/// ``` -/// -/// If all of the generics fails to parse, then the old config is renamed and a -/// new one created -pub trait StdConfigLoad3: StdConfig -where - Self: StdConfig + DeserializeOwned + Serialize, - OldConfig: DeserializeOwned + Into, - OldConfig2: DeserializeOwned + Into, -{ - fn load(mut self) -> Self { - let mut file = self.file_open(); - let mut buf = String::new(); - if let Ok(read_len) = file.read_to_string(&mut buf) { - if read_len != 0 { - if let Ok(data) = ron::from_str(&buf) { - self = data; - } else if let Ok(data) = serde_json::from_str(&buf) { - self = data; - } else if let Ok(data) = toml::from_str(&buf) { - self = data; - } else if let Ok(data) = serde_json::from_str::(&buf) { - self = data.into(); - } else if let Ok(data) = toml::from_str::(&buf) { - self = data.into(); - } else if let Ok(data) = serde_json::from_str::(&buf) { - self = data.into(); - } else if let Ok(data) = toml::from_str::(&buf) { - self = data.into(); - } else { - self.rename_file_old(); - self = Self::new(); - } - } else { - error!("Config file {} zero read length", self.file_name()); +#[cfg(test)] +mod tests { + use std::path::PathBuf; + + #[test] + fn check_macro_from_1() { + #[derive(serde::Deserialize, serde::Serialize)] + struct Test {} + + #[derive(serde::Deserialize, serde::Serialize)] + struct Old1 {} + + impl crate::StdConfig for Test { + fn new() -> Self { + Self {} + } + + fn file_name(&self) -> String { + String::new() + } + + fn config_dir() -> PathBuf { + PathBuf::new() } } - self.write(); - self + + impl From for Test { + fn from(_: Old1) -> Self { + Self {} + } + } + + impl crate::StdConfigLoad1 for Test {} + } + + #[test] + fn check_macro_from_3() { + #[derive(serde::Deserialize, serde::Serialize)] + struct Test {} + + #[derive(serde::Deserialize, serde::Serialize)] + struct Old1 {} + + #[derive(serde::Deserialize, serde::Serialize)] + struct Old2 {} + + #[derive(serde::Deserialize, serde::Serialize)] + struct Old3 {} + + impl crate::StdConfig for Test { + fn new() -> Self { + Self {} + } + + fn file_name(&self) -> String { + String::new() + } + + fn config_dir() -> PathBuf { + PathBuf::new() + } + } + + impl From for Test { + fn from(_: Old1) -> Self { + Self {} + } + } + + impl From for Test { + fn from(_: Old2) -> Self { + Self {} + } + } + + impl From for Test { + fn from(_: Old3) -> Self { + Self {} + } + } + + impl crate::StdConfigLoad3 for Test {} } } diff --git a/daemon-user/src/config.rs b/daemon-user/src/config.rs index fef850f8..785bfbf1 100644 --- a/daemon-user/src/config.rs +++ b/daemon-user/src/config.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use std::time::Duration; -use config_traits::{StdConfig, StdConfigLoad1}; +use config_traits::{StdConfig, StdConfigLoad}; use rog_anime::{ActionLoader, AnimTime, AnimeType, Fade, Sequences as AnimeSequences, Vec2}; use rog_aura::advanced::LedCode; use rog_aura::effects::{AdvancedEffects as AuraSequences, Breathe, DoomFlicker, Effect, Static}; @@ -116,7 +116,7 @@ impl StdConfig for ConfigAnime { } } -impl StdConfigLoad1 for ConfigAnime {} +impl StdConfigLoad for ConfigAnime {} #[derive(Debug, Deserialize, Serialize)] pub struct ConfigAura { @@ -188,7 +188,7 @@ impl StdConfig for ConfigAura { } } -impl StdConfigLoad1 for ConfigAura {} +impl StdConfigLoad for ConfigAura {} #[derive(Debug, Default, Deserialize, Serialize)] #[serde(default)] @@ -216,4 +216,4 @@ impl StdConfig for ConfigBase { } } -impl StdConfigLoad1 for ConfigBase {} +impl StdConfigLoad for ConfigBase {} diff --git a/daemon-user/src/daemon.rs b/daemon-user/src/daemon.rs index a3a56c9e..c2d7dc46 100644 --- a/daemon-user/src/daemon.rs +++ b/daemon-user/src/daemon.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; use std::sync::atomic::AtomicBool; use std::sync::{Arc, Mutex}; -use config_traits::{StdConfig, StdConfigLoad1}; +use config_traits::{StdConfig, StdConfigLoad}; use rog_anime::usb::get_anime_type; use rog_aura::aura_detection::LaptopLedData; use rog_aura::layouts::KeyLayout; diff --git a/daemon/src/config.rs b/daemon/src/config.rs index 5ce70570..f3e34551 100644 --- a/daemon/src/config.rs +++ b/daemon/src/config.rs @@ -1,4 +1,4 @@ -use config_traits::{StdConfig, StdConfigLoad3}; +use config_traits::{StdConfig, StdConfigLoad2}; use serde_derive::{Deserialize, Serialize}; const CONFIG_FILE: &str = "asusd.ron"; @@ -33,7 +33,7 @@ impl StdConfig for Config { } } -impl StdConfigLoad3 for Config {} +impl StdConfigLoad2 for Config {} #[derive(Deserialize, Serialize, Default)] #[serde(default)] diff --git a/daemon/src/ctrl_anime/config.rs b/daemon/src/ctrl_anime/config.rs index 20dfa5aa..03db8567 100644 --- a/daemon/src/ctrl_anime/config.rs +++ b/daemon/src/ctrl_anime/config.rs @@ -1,6 +1,6 @@ use std::time::Duration; -use config_traits::{StdConfig, StdConfigLoad3}; +use config_traits::{StdConfig, StdConfigLoad2}; use rog_anime::error::AnimeError; use rog_anime::{ActionData, ActionLoader, AnimTime, AnimeType, Fade, Vec2}; use serde_derive::{Deserialize, Serialize}; @@ -149,7 +149,7 @@ impl StdConfig for AnimeConfig { } } -impl StdConfigLoad3 for AnimeConfig {} +impl StdConfigLoad2 for AnimeConfig {} impl AnimeConfig { // fn clamp_config_brightness(mut config: &mut AnimeConfig) { diff --git a/daemon/src/ctrl_aura/config.rs b/daemon/src/ctrl_aura/config.rs index f49fd3c9..8082c2b8 100644 --- a/daemon/src/ctrl_aura/config.rs +++ b/daemon/src/ctrl_aura/config.rs @@ -1,6 +1,6 @@ use std::collections::{BTreeMap, HashSet}; -use config_traits::{StdConfig, StdConfigLoad1}; +use config_traits::{StdConfig, StdConfigLoad}; use rog_aura::aura_detection::{LaptopLedData, ASUS_KEYBOARD_DEVICES}; use rog_aura::usb::{AuraDev1866, AuraDev19b6, AuraDevTuf, AuraDevice, AuraPowerDev}; use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Direction, LedBrightness, Speed, GRADIENT}; @@ -199,7 +199,7 @@ impl StdConfig for AuraConfig { } } -impl StdConfigLoad1 for AuraConfig {} +impl StdConfigLoad for AuraConfig {} impl AuraConfig { fn create_default(support_data: &LaptopLedData) -> Self { diff --git a/daemon/src/ctrl_profiles/config.rs b/daemon/src/ctrl_profiles/config.rs index f21bae12..4471bd92 100644 --- a/daemon/src/ctrl_profiles/config.rs +++ b/daemon/src/ctrl_profiles/config.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use config_traits::{StdConfig, StdConfigLoad1}; +use config_traits::{StdConfig, StdConfigLoad}; use rog_profiles::fan_curve_set::FanCurveSet; use rog_profiles::{FanCurveProfiles, Profile}; use serde_derive::{Deserialize, Serialize}; @@ -32,7 +32,7 @@ impl StdConfig for ProfileConfig { } } -impl StdConfigLoad1 for ProfileConfig {} +impl StdConfigLoad for ProfileConfig {} #[derive(Deserialize, Serialize, Debug, Default)] pub struct FanCurveConfig { @@ -81,4 +81,4 @@ impl StdConfig for FanCurveConfig { } } -impl StdConfigLoad1 for FanCurveConfig {} +impl StdConfigLoad for FanCurveConfig {} diff --git a/daemon/src/daemon.rs b/daemon/src/daemon.rs index 243a3376..75cb8e2b 100644 --- a/daemon/src/daemon.rs +++ b/daemon/src/daemon.rs @@ -6,7 +6,7 @@ use std::time::Duration; use ::zbus::export::futures_util::lock::Mutex; use ::zbus::Connection; -use config_traits::{StdConfig, StdConfigLoad1, StdConfigLoad3}; +use config_traits::{StdConfig, StdConfigLoad, StdConfigLoad2}; use daemon::config::Config; use daemon::ctrl_anime::config::AnimeConfig; use daemon::ctrl_anime::trait_impls::CtrlAnimeZbus;