From 00839aaa6f12a56392ae709d515806c838d1ffba Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sun, 8 Jan 2023 20:41:17 +1300 Subject: [PATCH] Refactor config_trait crate and add doc comment examples --- config-traits/src/lib.rs | 244 +++++++++++++++++++---------- daemon/src/config.rs | 6 +- daemon/src/ctrl_anime/config.rs | 6 +- daemon/src/ctrl_aura/config.rs | 6 +- daemon/src/ctrl_profiles/config.rs | 12 +- daemon/src/daemon.rs | 10 +- 6 files changed, 177 insertions(+), 107 deletions(-) diff --git a/config-traits/src/lib.rs b/config-traits/src/lib.rs index 64708117..0ab2369b 100644 --- a/config-traits/src/lib.rs +++ b/config-traits/src/lib.rs @@ -18,65 +18,63 @@ where fn new() -> Self; /// Return the config files names, such as `wibble.cfg` - fn file_name() -> &'static str; + fn file_name(&self) -> String; /// Return the full path to the directory the config file resides in fn config_dir() -> PathBuf; /// Return the full path to the config file - fn file_path() -> PathBuf { + fn file_path(&self) -> PathBuf { let mut config = Self::config_dir(); if !config.exists() { create_dir(config.as_path()) .unwrap_or_else(|e| panic!("Could not create {:?} {e}", Self::config_dir())); } - config.push(Self::file_name()); + config.push(self.file_name()); config } /// Directly open the config file for read and write. If the config file /// does not exist it is created, including the directories the file /// resides in. - fn file_open() -> File { + fn file_open(&self) -> File { OpenOptions::new() .read(true) .write(true) .create(true) - .open(Self::file_path()) - .unwrap_or_else(|e| panic!("Could not open {:?} {e}", Self::file_path())) + .open(self.file_path()) + .unwrap_or_else(|e| panic!("Could not open {:?} {e}", self.file_path())) } /// Open and parse the config file to self from ron format fn read(&mut self) { - let mut file = match OpenOptions::new().read(true).open(Self::file_path()) { + let mut file = match OpenOptions::new().read(true).open(self.file_path()) { Ok(data) => data, Err(err) => { - error!("Error reading {:?}: {}", Self::file_path(), err); + error!("Error reading {:?}: {}", self.file_path(), err); return; } }; let mut buf = String::new(); if let Ok(l) = file.read_to_string(&mut buf) { if l == 0 { - warn!("File is empty {:?}", Self::file_path()); + warn!("File is empty {:?}", self.file_path()); } else if let Ok(data) = ron::from_str(&buf) { *self = data; - } else if let Ok(data) = serde_json::from_str(&buf) { - *self = data; } else { - warn!("Could not deserialise {:?}", Self::file_path()); + warn!("Could not deserialise {:?}", self.file_path()); } } } /// Write the config file data to pretty ron format fn write(&self) { - let mut file = match File::create(Self::file_path()) { + let mut file = match File::create(self.file_path()) { Ok(data) => data, Err(e) => { error!( "Couldn't overwrite config {:?}, error: {e}", - Self::file_path() + self.file_path() ); return; } @@ -84,7 +82,7 @@ where let ron = match ron::ser::to_string_pretty(&self, PrettyConfig::new().depth_limit(4)) { Ok(data) => data, Err(e) => { - error!("Parse {:?} to RON failed, error: {e}", Self::file_path()); + error!("Parse {:?} to RON failed, error: {e}", self.file_path()); return; } }; @@ -93,17 +91,17 @@ where } /// Renames the existing file to `-old` - fn rename_file_old() { + fn rename_file_old(&self) { warn!( "Renaming {} to {}-old and recreating config", - Self::file_name(), - Self::file_name() + self.file_name(), + self.file_name() ); - let cfg_old = Self::file_path().to_string_lossy().to_string() + "-old"; - std::fs::rename(Self::file_path(), cfg_old).unwrap_or_else(|err| { + let cfg_old = self.file_path().to_string_lossy().to_string() + "-old"; + std::fs::rename(self.file_path(), cfg_old).unwrap_or_else(|err| { error!( "Could not rename. Please remove {} then restart service: Error {}", - Self::file_name(), + self.file_name(), err ) }); @@ -111,112 +109,184 @@ where } /// Base trait for loading/parsing. This can be used to help update configs to -/// new versions ```ignore -/// impl StdConfigLoad1 for FanCurveConfig {} +/// 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 +pub trait StdConfigLoad1 where - T: StdConfig + DeserializeOwned + Serialize, + Self: StdConfig + DeserializeOwned + Serialize, { - fn load() -> T { - let mut file = T::file_open(); + fn load(mut self) -> Self { + let mut file = self.file_open(); let mut buf = String::new(); - let config: T; if let Ok(read_len) = file.read_to_string(&mut buf) { - if read_len == 0 { - config = T::new(); - } else if let Ok(data) = ron::from_str(&buf) { - config = data; - } else if let Ok(data) = serde_json::from_str(&buf) { - config = data; + 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 { + self.rename_file_old(); + self = Self::new(); + } } else { - T::rename_file_old(); - config = T::new(); + error!("Config file {} zero read length", self.file_name()); } - } else { - config = T::new(); } - config.write(); - config + self.write(); + self } } /// Base trait for loading/parsing. This is intended to be used to help update -/// configs to new versions ```ignore -/// impl StdConfigLoad2 for FanCurveConfig {} +/// 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 +pub trait StdConfigLoad2 where - T1: StdConfig + DeserializeOwned + Serialize, - T2: DeserializeOwned + Into, + Self: StdConfig + DeserializeOwned + Serialize, + OldConfig: DeserializeOwned + Into, { - fn load() -> T1 { - let mut file = T1::file_open(); + fn load(mut self) -> Self { + let mut file = self.file_open(); let mut buf = String::new(); - let config: T1; if let Ok(read_len) = file.read_to_string(&mut buf) { - if read_len == 0 { - config = T1::new(); - } else if let Ok(data) = ron::from_str(&buf) { - config = data; - } else if let Ok(data) = serde_json::from_str(&buf) { - config = data; - } else if let Ok(data) = serde_json::from_str::(&buf) { - config = data.into(); + 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) = serde_json::from_str::(&buf) { + self = data.into(); + } else { + self.rename_file_old(); + self = Self::new(); + } } else { - T1::rename_file_old(); - config = T1::new(); + error!("Config file {} zero read length", self.file_name()); } - } else { - config = T1::new(); } - config.write(); - config + self.write(); + self } } /// Base trait for loading/parsing. This is intended to be used to help update -/// configs to new versions ```ignore -/// impl StdConfigLoad3 for FanCurveConfig {} +/// 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 +pub trait StdConfigLoad3: StdConfig where - T1: StdConfig + DeserializeOwned + Serialize, - T2: DeserializeOwned + Into, - T3: DeserializeOwned + Into, + Self: StdConfig + DeserializeOwned + Serialize, + OldConfig: DeserializeOwned + Into, + OldConfig2: DeserializeOwned + Into, { - fn load() -> T1 { - let mut file = T1::file_open(); + fn load(mut self) -> Self { + let mut file = self.file_open(); let mut buf = String::new(); - let config: T1; if let Ok(read_len) = file.read_to_string(&mut buf) { - if read_len == 0 { - config = T1::new(); - } else if let Ok(data) = ron::from_str(&buf) { - config = data; - } else if let Ok(data) = serde_json::from_str(&buf) { - config = data; - } else if let Ok(data) = serde_json::from_str::(&buf) { - config = data.into(); - } else if let Ok(data) = serde_json::from_str::(&buf) { - config = data.into(); + 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) = serde_json::from_str::(&buf) { + self = data.into(); + } else if let Ok(data) = serde_json::from_str::(&buf) { + self = data.into(); + } else { + self.rename_file_old(); + self = Self::new(); + } } else { - T1::rename_file_old(); - config = T1::new(); + error!("Config file {} zero read length", self.file_name()); } - } else { - config = T1::new(); } - config.write(); - config + self.write(); + self } } diff --git a/daemon/src/config.rs b/daemon/src/config.rs index fb9d055f..9861a929 100644 --- a/daemon/src/config.rs +++ b/daemon/src/config.rs @@ -28,12 +28,12 @@ impl StdConfig for Config { std::path::PathBuf::from(crate::CONFIG_PATH_BASE) } - fn file_name() -> &'static str { - CONFIG_FILE + fn file_name(&self) -> String { + CONFIG_FILE.to_string() } } -impl StdConfigLoad3 for Config {} +impl StdConfigLoad3 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 6f801e55..c00ecc5f 100644 --- a/daemon/src/ctrl_anime/config.rs +++ b/daemon/src/ctrl_anime/config.rs @@ -144,12 +144,12 @@ impl StdConfig for AnimeConfig { std::path::PathBuf::from(crate::CONFIG_PATH_BASE) } - fn file_name() -> &'static str { - CONFIG_FILE + fn file_name(&self) -> String { + CONFIG_FILE.to_string() } } -impl StdConfigLoad3 for AnimeConfig {} +impl StdConfigLoad3 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 c160ec3c..9333821a 100644 --- a/daemon/src/ctrl_aura/config.rs +++ b/daemon/src/ctrl_aura/config.rs @@ -194,12 +194,12 @@ impl StdConfig for AuraConfig { std::path::PathBuf::from(crate::CONFIG_PATH_BASE) } - fn file_name() -> &'static str { - CONFIG_FILE + fn file_name(&self) -> String { + CONFIG_FILE.to_string() } } -impl StdConfigLoad1 for AuraConfig {} +impl StdConfigLoad1 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 c683a7a0..7b360549 100644 --- a/daemon/src/ctrl_profiles/config.rs +++ b/daemon/src/ctrl_profiles/config.rs @@ -27,12 +27,12 @@ impl StdConfig for ProfileConfig { PathBuf::from(CONFIG_PATH_BASE) } - fn file_name() -> &'static str { - CONFIG_FILE + fn file_name(&self) -> String { + CONFIG_FILE.to_string() } } -impl StdConfigLoad1 for ProfileConfig {} +impl StdConfigLoad1 for ProfileConfig {} #[derive(Deserialize, Serialize, Debug, Default)] pub struct FanCurveConfig { @@ -76,9 +76,9 @@ impl StdConfig for FanCurveConfig { PathBuf::from(CONFIG_PATH_BASE) } - fn file_name() -> &'static str { - CONFIG_FAN_FILE + fn file_name(&self) -> String { + CONFIG_FAN_FILE.to_string() } } -impl StdConfigLoad1 for FanCurveConfig {} +impl StdConfigLoad1 for FanCurveConfig {} diff --git a/daemon/src/daemon.rs b/daemon/src/daemon.rs index 428c5b59..243a3376 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::{StdConfigLoad1, StdConfigLoad3}; +use config_traits::{StdConfig, StdConfigLoad1, StdConfigLoad3}; use daemon::config::Config; use daemon::ctrl_anime::config::AnimeConfig; use daemon::ctrl_anime::trait_impls::CtrlAnimeZbus; @@ -71,7 +71,7 @@ async fn start_daemon() -> Result<(), Box> { // Start zbus server let mut connection = Connection::system().await?; - let config = Config::load(); + let config = Config::new().load(); let config = Arc::new(Mutex::new(config)); supported.add_to_server(&mut connection).await; @@ -97,7 +97,7 @@ async fn start_daemon() -> Result<(), Box> { } if Profile::is_platform_profile_supported() { - let profile_config = ProfileConfig::load(); + let profile_config = ProfileConfig::new().load(); match CtrlPlatformProfile::new(profile_config) { Ok(ctrl) => { let zbus = ProfileZbus(Arc::new(Mutex::new(ctrl))); @@ -112,7 +112,7 @@ async fn start_daemon() -> Result<(), Box> { warn!("platform_profile support not found"); } - match CtrlAnime::new(AnimeConfig::load()) { + match CtrlAnime::new(AnimeConfig::new().load()) { Ok(ctrl) => { let zbus = CtrlAnimeZbus(Arc::new(Mutex::new(ctrl))); let sig_ctx = CtrlAnimeZbus::signal_context(&connection)?; @@ -124,7 +124,7 @@ async fn start_daemon() -> Result<(), Box> { } let laptop = LaptopLedData::get_data(); - let aura_config = AuraConfig::load(); + let aura_config = AuraConfig::new().load(); match CtrlKbdLed::new(laptop, aura_config) { Ok(ctrl) => { let zbus = CtrlKbdLedZbus(Arc::new(Mutex::new(ctrl)));