From efec8dfe5a6aca8047d0673a2245735e63beb3a1 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Thu, 17 Aug 2023 22:54:39 -0400 Subject: [PATCH] Convert the kifu config to the config crate --- Cargo.lock | 31 +++++++ Cargo.toml | 1 + config/src/lib.rs | 44 ++++----- kifu/core/Cargo.toml | 2 + kifu/core/src/api.rs | 5 +- kifu/core/src/config.rs | 198 ---------------------------------------- kifu/core/src/lib.rs | 5 + kifu/core/src/types.rs | 28 +++++- 8 files changed, 91 insertions(+), 223 deletions(-) delete mode 100644 kifu/core/src/config.rs diff --git a/Cargo.lock b/Cargo.lock index 533559f..febed69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -928,6 +928,15 @@ dependencies = [ "system-deps", ] +[[package]] +name = "grid" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0634107a3a005070dd73e27e74ecb691a94e9e5ba7829f434db7fbf73a6b5c47" +dependencies = [ + "no-std-compat", +] + [[package]] name = "gsk4" version = "0.6.3" @@ -1288,6 +1297,22 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kifu-core" +version = "0.1.0" +dependencies = [ + "chrono", + "config", + "config-derive", + "cool_asserts", + "grid", + "serde", + "serde_json", + "sgf", + "thiserror", + "typeshare", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1453,6 +1478,12 @@ dependencies = [ "tempfile", ] +[[package]] +name = "no-std-compat" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" + [[package]] name = "nom" version = "7.1.3" diff --git a/Cargo.toml b/Cargo.toml index fcd6eff..25f3e94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ members = [ "emseries", "flow", "fluent-ergonomics", + "kifu/core", "geo-types", "hex-grid", "ifc", diff --git a/config/src/lib.rs b/config/src/lib.rs index ca80e9a..204ac77 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -1,3 +1,13 @@ +/* +use std::{ + collections::HashMap, + fs::File, + hash::Hash, + io::{ErrorKind, Read}, + path::PathBuf, +}; +*/ + pub use config_derive::ConfigOption; use thiserror::Error; @@ -11,63 +21,55 @@ pub enum ConfigReadError { InvalidJSON(serde_json::Error), } +#[macro_export] macro_rules! define_config { ($($name:ident($struct:ident),)+) => ( - use serde::{Deserialize, Serialize}; - use std::{ - collections::HashMap, - fs::File, - hash::Hash, - io::{ErrorKind, Read}, - path::PathBuf, - }; - - #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] + #[derive(Clone, Debug, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub enum ConfigName { $($name),+ } - #[derive(Clone, Debug, Serialize, Deserialize)] + #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum ConfigOption { $($name($struct)),+ } #[derive(Clone, Debug)] pub struct Config { - values: HashMap, + values: std::collections::HashMap, } impl Config { pub fn new() -> Self { Self { - values: HashMap::new(), + values: std::collections::HashMap::new(), } } - pub fn from_path(config_path: PathBuf) -> Result { + pub fn from_path(config_path: std::path::PathBuf) -> Result { let mut settings = config_path.clone(); settings.push("config"); - match File::open(settings) { + match std::fs::File::open(settings) { Ok(mut file) => { let mut buf = String::new(); - file.read_to_string(&mut buf) - .map_err(|err| ConfigReadError::CannotRead(err))?; + std::io::Read::read_to_string(&mut file, &mut buf) + .map_err(|err| $crate::ConfigReadError::CannotRead(err))?; let values = serde_json::from_str(buf.as_ref()) - .map_err(|err| ConfigReadError::InvalidJSON(err))?; + .map_err(|err| $crate::ConfigReadError::InvalidJSON(err))?; Ok(Self { values, }) } Err(io_err) => { match io_err.kind() { - ErrorKind::NotFound => { + std::io::ErrorKind::NotFound => { /* create the path and an empty file */ Ok(Self { - values: HashMap::new(), + values: std::collections::HashMap::new(), }) } - _ => Err(ConfigReadError::CannotOpen(io_err)), + _ => Err($crate::ConfigReadError::CannotOpen(io_err)), } } } diff --git a/kifu/core/Cargo.toml b/kifu/core/Cargo.toml index 737ec89..1157a6f 100644 --- a/kifu/core/Cargo.toml +++ b/kifu/core/Cargo.toml @@ -7,6 +7,8 @@ edition = "2021" [dependencies] chrono = { version = "0.4" } +config = { path = "../../config" } +config-derive = { path = "../../config-derive" } sgf = { path = "../../sgf" } grid = { version = "0.9" } serde_json = { version = "1" } diff --git a/kifu/core/src/api.rs b/kifu/core/src/api.rs index b26af46..38c4d84 100644 --- a/kifu/core/src/api.rs +++ b/kifu/core/src/api.rs @@ -1,7 +1,6 @@ use crate::{ - types::{AppState, GameState, Player, Rank}, + types::{AppState, Config, DatabasePath, GameState, Player, Rank}, ui::{home, playing_field, HomeView, PlayingFieldView}, - Config, DatabasePath, }; use serde::{Deserialize, Serialize}; use std::sync::{Arc, RwLock}; @@ -73,7 +72,7 @@ impl CoreApp { println!("config_path: {:?}", config_path); let config = Config::from_path(config_path).expect("configuration to open"); - let db_path: DatabasePath = config.get(); + let db_path: DatabasePath = config.get().unwrap(); let state = Arc::new(RwLock::new(AppState::new(db_path))); println!("config: {:?}", config); diff --git a/kifu/core/src/config.rs b/kifu/core/src/config.rs deleted file mode 100644 index c2807e4..0000000 --- a/kifu/core/src/config.rs +++ /dev/null @@ -1,198 +0,0 @@ -use crate::types::Player; -use serde::{Deserialize, Serialize}; -use std::{ - collections::HashMap, - fs::File, - io::{ErrorKind, Read}, - path::PathBuf, -}; -use thiserror::Error; - -/* -pub trait ConfigOption { - type Value; -} - -pub struct DatabasePath(PathBuf); - -impl ConfigOption for DatabasePath { - type Value = PathBuf; -} - -impl ConfigOption for Player { - type Value = Player; -} - -pub trait Config { - // fn set_option(option: ConfigOption); - fn get_option(name: Name) -> C -} -*/ - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -enum OptionNames { - DatabasePath, - Me, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -#[serde(untagged)] -pub enum ConfigOption { - DatabasePath(DatabasePath), - Me(Me), -} - -#[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)] -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::DatabasePath(_) => self.values.insert(OptionNames::DatabasePath, val), - ConfigOption::Me(_) => self.values.insert(OptionNames::Me, val), - }; - } - - pub fn get<'a, T>(&'a self) -> T - where - T: From<&'a Self>, - { - self.into() - } -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct DatabasePath(PathBuf); - -impl std::ops::Deref for DatabasePath { - 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)] -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; - 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/kifu/core/src/lib.rs b/kifu/core/src/lib.rs index 7b1cd37..b817d92 100644 --- a/kifu/core/src/lib.rs +++ b/kifu/core/src/lib.rs @@ -1,3 +1,6 @@ +#[macro_use] +extern crate config_derive; + mod api; pub use api::{ CoreApp, CoreRequest, CoreResponse, CreateGameRequest, HotseatPlayerRequest, PlayerInfoRequest, @@ -6,8 +9,10 @@ pub use api::{ mod board; pub use board::*; +/* mod config; pub use config::*; +*/ mod database; diff --git a/kifu/core/src/types.rs b/kifu/core/src/types.rs index 7ee8eba..28ff8f3 100644 --- a/kifu/core/src/types.rs +++ b/kifu/core/src/types.rs @@ -1,14 +1,40 @@ use crate::{ api::PlayStoneRequest, board::{Board, Coordinate}, - config::DatabasePath, database::Database, }; +use config::define_config; +use config_derive::ConfigOption; use serde::{Deserialize, Serialize}; use std::{path::PathBuf, time::Duration}; use thiserror::Error; use typeshare::typeshare; +define_config! { + DatabasePath(DatabasePath), + Me(Me), +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ConfigOption)] +pub struct DatabasePath(PathBuf); + +impl std::ops::Deref for DatabasePath { + type Target = PathBuf; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ConfigOption)] +pub struct Me(Player); + +impl std::ops::Deref for Me { + type Target = Player; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + #[derive(Debug, PartialEq, Error)] pub enum BoardError { #[error("Position is invalid")]