From 236e4094d7fbce07c310f4f949aca2d8acbffeea Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Thu, 17 Aug 2023 23:48:34 -0400 Subject: [PATCH] Set up configuration --- Cargo.lock | 4 + Cargo.toml | 6 -- build.sh | 1 - gm-control-panel/Cargo.toml | 4 + gm-control-panel/src/config.rs | 178 ++++----------------------------- gm-control-panel/src/main.rs | 2 + 6 files changed, 27 insertions(+), 168 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6a3b81f..677d0fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -898,6 +898,8 @@ dependencies = [ name = "gm-control-panel" version = "0.1.0" dependencies = [ + "config", + "config-derive", "futures", "gdk4", "gio", @@ -905,6 +907,8 @@ dependencies = [ "glib-build-tools", "gtk4", "libadwaita", + "serde", + "serde_json", "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index e6b1e27..d2253c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,8 @@ [workspace] members = [ "changeset", -<<<<<<< HEAD "config", "config-derive", -======= ->>>>>>> 36f1bb1 (Make the main app window appear, start working on config) "coordinates", "cyberpunk-splash", "dashboard", @@ -14,10 +11,7 @@ members = [ "fluent-ergonomics", "kifu/core", "geo-types", -<<<<<<< HEAD -======= "gm-control-panel", ->>>>>>> 36f1bb1 (Make the main app window appear, start working on config) "hex-grid", "ifc", "memorycache", diff --git a/build.sh b/build.sh index f96bd5f..b07ea55 100755 --- a/build.sh +++ b/build.sh @@ -1,7 +1,6 @@ #!/usr/bin/env bash set -euo pipefail -set -x RUST_ALL_TARGETS=( "changeset" diff --git a/gm-control-panel/Cargo.toml b/gm-control-panel/Cargo.toml index cb8375a..bf29138 100644 --- a/gm-control-panel/Cargo.toml +++ b/gm-control-panel/Cargo.toml @@ -7,11 +7,15 @@ edition = "2021" [dependencies] adw = { version = "0.4", package = "libadwaita", features = [ "v1_2" ] } +config = { path = "../config" } +config-derive = { path = "../config-derive" } futures = { version = "0.3" } gio = { version = "0.17" } glib = { version = "0.17" } gdk = { version = "0.6", package = "gdk4" } gtk = { version = "0.6", package = "gtk4" } +serde = { version = "1" } +serde_json = { version = "*" } tokio = { version = "1", features = ["full"] } [build-dependencies] diff --git a/gm-control-panel/src/config.rs b/gm-control-panel/src/config.rs index 2d932fb..e8ea768 100644 --- a/gm-control-panel/src/config.rs +++ b/gm-control-panel/src/config.rs @@ -1,184 +1,40 @@ -use crate::types::Player; +use config::define_config; +use config_derive::ConfigOption; use serde::{Deserialize, Serialize}; -use std::{ - collections::HashMap, - fs::File, - io::{ErrorKind, Read}, - path::PathBuf, -}; -use thiserror::Error; +use std::path::PathBuf; -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -enum OptionNames { - Language, - MusicPath, - PlaylistDatabasePath, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -#[serde(untagged)] -pub enum ConfigOption { +define_config! { Language(Language), MusicPath(MusicPath), PlaylistDatabasePath(PlaylistDatabasePath), } -#[derive(Debug, Error)] -pub enum ConfigReadError { - #[error("Cannot read the configuration file: {0}")] - CannotRead(std::io::Error), - #[error("Cannot open the configuration file for reading: {0}")] - CannotOpen(std::io::Error), - #[error("Invalid json data found in the configurationfile: {0}")] - InvalidJSON(serde_json::Error), -} +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ConfigOption)] +pub struct Language(String); -#[derive(Clone, Debug)] -pub struct Config { - config_path: PathBuf, - values: HashMap, -} - -impl Config { - pub fn new(config_path: PathBuf) -> Self { - Self { - config_path, - values: HashMap::new(), - } - } - - pub fn from_path(config_path: PathBuf) -> Result { - let mut settings = config_path.clone(); - settings.push("config"); - - match File::open(settings) { - Ok(mut file) => { - let mut buf = String::new(); - file.read_to_string(&mut buf) - .map_err(|err| ConfigReadError::CannotRead(err))?; - let values = serde_json::from_str(buf.as_ref()) - .map_err(|err| ConfigReadError::InvalidJSON(err))?; - Ok(Self { - config_path, - values, - }) - } - Err(io_err) => { - match io_err.kind() { - ErrorKind::NotFound => { - /* create the path and an empty file */ - Ok(Self { - config_path, - values: HashMap::new(), - }) - } - _ => Err(ConfigReadError::CannotOpen(io_err)), - } - } - } - } - - pub fn set(&mut self, val: ConfigOption) { - let _ = match val { - ConfigOption::Language(_) => self.values.insert(OptionNames::Language, val), - ConfigOption::MusicPath(_) => self.values.insert(OptionNames::MusicPath, val), - ConfigOption::PlaylistDatabasePath(_) => { - self.values.insert(OptionNames::PlaylistDatabasePath, val) - } - }; - } - - pub fn get<'a, T>(&'a self) -> T - where - T: From<&'a Self>, - { - self.into() +impl std::ops::Deref for Language { + type Target = String; + fn deref(&self) -> &Self::Target { + &self.0 } } -/* -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct DatabasePath(PathBuf); +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ConfigOption)] +pub struct MusicPath(PathBuf); -impl std::ops::Deref for DatabasePath { +impl std::ops::Deref for MusicPath { type Target = PathBuf; fn deref(&self) -> &Self::Target { &self.0 } } -impl From<&Config> for DatabasePath { - fn from(config: &Config) -> Self { - match config.values.get(&OptionNames::DatabasePath) { - Some(ConfigOption::DatabasePath(path)) => path.clone(), - _ => DatabasePath(config.config_path.clone()), - } - } -} +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ConfigOption)] +pub struct PlaylistDatabasePath(PathBuf); -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct Me(Player); - -impl From<&Config> for Option { - fn from(config: &Config) -> Self { - config - .values - .get(&OptionNames::Me) - .and_then(|val| match val { - ConfigOption::Me(me) => Some(me.clone()), - _ => None, - }) - } -} - -impl std::ops::Deref for Me { - type Target = Player; +impl std::ops::Deref for PlaylistDatabasePath { + type Target = PathBuf; fn deref(&self) -> &Self::Target { &self.0 } } -*/ - -#[cfg(test)] -mod test { - use super::*; - use crate::types::Rank; - use cool_asserts::assert_matches; - - #[test] - fn it_can_set_and_get_options() { - let mut config = Config::new(PathBuf::from(".")); - config.set(ConfigOption::DatabasePath(DatabasePath(PathBuf::from( - "fixtures/five_games", - )))); - config.set(ConfigOption::Me(Me(Player { - name: "Savanni".to_owned(), - rank: Some(Rank::Kyu(10)), - }))); - } - - #[test] - fn it_can_serialize_and_deserialize() { - let mut config = Config::new(PathBuf::from(".")); - config.set(ConfigOption::DatabasePath(DatabasePath(PathBuf::from( - "fixtures/five_games", - )))); - config.set(ConfigOption::Me(Me(Player { - name: "Savanni".to_owned(), - rank: Some(Rank::Kyu(10)), - }))); - let s = serde_json::to_string(&config.values).unwrap(); - println!("{}", s); - let values: HashMap = serde_json::from_str(s.as_ref()).unwrap(); - println!("options: {:?}", values); - - assert_matches!(values.get(&OptionNames::DatabasePath), - Some(ConfigOption::DatabasePath(db_path)) => - assert_eq!(*db_path, config.get()) - ); - - assert_matches!(values.get(&OptionNames::Me), Some(ConfigOption::Me(val)) => - assert_eq!(Some(val.clone()), config.get()) - ); - } -} diff --git a/gm-control-panel/src/main.rs b/gm-control-panel/src/main.rs index cb63dc7..60900e5 100644 --- a/gm-control-panel/src/main.rs +++ b/gm-control-panel/src/main.rs @@ -8,6 +8,8 @@ use std::{ mod app_window; use app_window::ApplicationWindow; +mod config; + #[derive(Clone, Debug)] pub enum Message {}