diff --git a/Cargo.lock b/Cargo.lock index b25cc16..9891333 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" dependencies = [ "memchr", ] @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.72" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "autocfg" @@ -103,9 +103,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "bumpalo" @@ -185,7 +185,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" name = "changeset" version = "0.1.0" dependencies = [ - "uuid", + "uuid 1.4.1", ] [[package]] @@ -233,6 +233,34 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "config" +version = "0.1.0" +dependencies = [ + "config-derive", + "cool_asserts", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "config-derive" +version = "0.1.0" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cool_asserts" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee9f254e53f61e2688d3677fa2cbe4e9b950afd56f48819c98817417cf6b28ec" +dependencies = [ + "indent_write", +] + [[package]] name = "coordinates" version = "0.1.0" @@ -373,7 +401,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -394,7 +422,7 @@ dependencies = [ "serde_json", "tempfile", "thiserror", - "uuid", + "uuid 0.8.2", ] [[package]] @@ -476,9 +504,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" dependencies = [ "crc32fast", "miniz_oxide", @@ -644,7 +672,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -900,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" @@ -1083,9 +1120,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" @@ -1104,7 +1141,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -1168,9 +1205,9 @@ dependencies = [ [[package]] name = "image" -version = "0.24.6" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" dependencies = [ "bytemuck", "byteorder", @@ -1185,6 +1222,12 @@ dependencies = [ "tiff", ] +[[package]] +name = "indent_write" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cfe9645a18782869361d9c8732246be7b410ad4e919d3609ebabdac00ba12c3" + [[package]] name = "indexmap" version = "1.9.3" @@ -1254,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" @@ -1329,9 +1388,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" @@ -1419,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" @@ -1508,7 +1573,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -1648,14 +1713,14 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] name = "pin-project-lite" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c516611246607d0c04186886dbb3a754368ef82c79e9827a802c6d836dd111c" +checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" [[package]] name = "pin-utils" @@ -1768,9 +1833,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -1940,11 +2005,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.7" +version = "0.38.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "172891ebdceb05aa0005f533a6cbfca599ddd7d966f6f5d4d9b2e70478e70399" +checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "errno", "libc", "linux-raw-sys", @@ -2043,14 +2108,14 @@ checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" dependencies = [ "itoa", "ryu", @@ -2135,6 +2200,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "spin" version = "0.9.8" @@ -2157,9 +2232,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.28" +version = "2.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" dependencies = [ "proc-macro2", "quote", @@ -2200,29 +2275,29 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] name = "tiff" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7449334f9ff2baf290d55d73983a7d6fa15e01198faef72af07e2a8db851e471" +checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211" dependencies = [ "flate2", "jpeg-decoder", @@ -2266,11 +2341,10 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", @@ -2279,7 +2353,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.3", "tokio-macros", "windows-sys", ] @@ -2292,7 +2366,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -2488,6 +2562,15 @@ dependencies = [ "serde", ] +[[package]] +name = "uuid" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +dependencies = [ + "getrandom", +] + [[package]] name = "vcpkg" version = "0.2.15" @@ -2557,7 +2640,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", "wasm-bindgen-shared", ] @@ -2591,7 +2674,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2660,9 +2743,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "27f51fb4c64f8b770a823c043c7fad036323e1c48f55287b7bbb7987b2fcdf3b" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -2675,51 +2758,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "fde1bb55ae4ce76a597a8566d82c57432bc69c039449d61572a7a353da28f68c" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "1513e8d48365a78adad7322fd6b5e4c4e99d92a69db8df2d435b25b1f1f286d4" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "60587c0265d2b842298f5858e1a5d79d146f9ee0c37be5782e92a6eb5e1d7a83" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "224fe0e0ffff5d2ea6a29f82026c8f43870038a0ffc247aa95a52b47df381ac4" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "62fc52a0f50a088de499712cbc012df7ebd94e2d6eb948435449d76a6287e7ad" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "2093925509d91ea3d69bcd20238f4c2ecdb1a29d3c281d026a09705d0dd35f3d" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "b6ade45bc8bf02ae2aa34a9d54ba660a1a58204da34ba793c00d83ca3730b5f1" [[package]] name = "winnow" -version = "0.5.4" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acaaa1190073b2b101e15083c38ee8ec891b5e05cbee516521e94ec008f61e64" +checksum = "d09770118a7eb1ccaf4a594a221334119a44a814fcb0d31c5b85e83e97227a97" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 6536d9e..25f3e94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,19 @@ [workspace] members = [ + "changeset", + "config", + "config-derive", + "coordinates", "cyberpunk-splash", "dashboard", + "emseries", + "flow", "fluent-ergonomics", + "kifu/core", "geo-types", + "hex-grid", "ifc", "memorycache", "screenplay", - "emseries", - "coordinates", - "flow", "sgf", - "changeset", - "hex-grid", ] diff --git a/build.sh b/build.sh index 7a81570..579cc62 100755 --- a/build.sh +++ b/build.sh @@ -4,19 +4,21 @@ set -euo pipefail set -x RUST_ALL_TARGETS=( + "changeset" + "config" + "config-derive" + "coordinates" + "cyberpunk-splash" "dashboard" + "emseries" + "flow" + "fluent-ergonomics" + "geo-types" + "hex-grid" "ifc" "memorycache" - "geo-types" - "fluent-ergonomics" - "cyberpunk-splash" "screenplay" - "emseries" - "coordinates" - "flow" "sgf" - "changeset" - "hex-grid" ) build_rust_targets() { diff --git a/config-derive/Cargo.toml b/config-derive/Cargo.toml new file mode 100644 index 0000000..92aeba0 --- /dev/null +++ b/config-derive/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "config-derive" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +proc-macro = true + +[dependencies] +quote = { version = "1" } +syn = { version = "1", features = [ "extra-traits" ] } + diff --git a/config-derive/src/lib.rs b/config-derive/src/lib.rs new file mode 100644 index 0000000..9b9822d --- /dev/null +++ b/config-derive/src/lib.rs @@ -0,0 +1,23 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; +use quote::quote; + +use syn::{parse_macro_input, DeriveInput}; + +#[proc_macro_derive(ConfigOption)] +pub fn derive(input: TokenStream) -> TokenStream { + let DeriveInput { ident, .. } = parse_macro_input!(input as DeriveInput); + + let result = quote! { + impl From<&Config> for Option<#ident> { + fn from(config: &Config) -> Self { + match config.values.get(&ConfigName::#ident) { + Some(ConfigOption::#ident(val)) => Some(val.clone()), + _ => None, + } + } + } + }; + result.into() +} diff --git a/config/Cargo.toml b/config/Cargo.toml new file mode 100644 index 0000000..52c926b --- /dev/null +++ b/config/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "config" +version = "0.1.0" +edition = "2021" + + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +config-derive = { path = "../config-derive" } +serde_json = { version = "1" } +serde = { version = "1", features = [ "derive" ] } +thiserror = { version = "1" } + +[dev-dependencies] +cool_asserts = { version = "2" } diff --git a/config/src/lib.rs b/config/src/lib.rs new file mode 100644 index 0000000..1c2b36b --- /dev/null +++ b/config/src/lib.rs @@ -0,0 +1,159 @@ +/* +use std::{ + collections::HashMap, + fs::File, + hash::Hash, + io::{ErrorKind, Read}, + path::PathBuf, +}; +*/ + +pub use config_derive::ConfigOption; +use thiserror::Error; + +#[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), +} + +#[macro_export] +macro_rules! define_config { + ($($name:ident($struct:ident),)+) => ( + #[derive(Clone, Debug, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize)] + pub enum ConfigName { + $($name),+ + } + + #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] + pub enum ConfigOption { + $($name($struct)),+ + } + + #[derive(Clone, Debug)] + pub struct Config { + values: std::collections::HashMap, + } + + impl Config { + pub fn new() -> Self { + Self { + values: std::collections::HashMap::new(), + } + } + + pub fn from_path(config_path: std::path::PathBuf) -> Result { + let mut settings = config_path.clone(); + settings.push("config"); + + match std::fs::File::open(settings) { + Ok(mut file) => { + let mut buf = String::new(); + 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| $crate::ConfigReadError::InvalidJSON(err))?; + Ok(Self { + values, + }) + } + Err(io_err) => { + match io_err.kind() { + std::io::ErrorKind::NotFound => { + /* create the path and an empty file */ + Ok(Self { + values: std::collections::HashMap::new(), + }) + } + _ => Err($crate::ConfigReadError::CannotOpen(io_err)), + } + } + } + } + + pub fn set(&mut self, val: ConfigOption) { + let _ = match val { + $(ConfigOption::$struct(_) => self.values.insert(ConfigName::$name, val)),+ + }; + } + + pub fn get<'a, T>(&'a self) -> Option + where + Option: From<&'a Self>, + { + self.into() + } + } + ) +} + +#[cfg(test)] +mod test { + use super::*; + use cool_asserts::assert_matches; + use serde::{Deserialize, Serialize}; + use std::collections::HashMap; + use std::path::PathBuf; + + define_config! { + DatabasePath(DatabasePath), + Me(Me), + } + + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, ConfigOption)] + pub struct DatabasePath(PathBuf); + + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] + enum Rank { + Kyu(i8), + Dan(i8), + } + + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, ConfigOption)] + pub struct Me { + name: String, + rank: Option, + } + + #[test] + fn it_can_set_and_get_options() { + let mut config: Config = Config::new(); + config.set(ConfigOption::DatabasePath(DatabasePath(PathBuf::from( + "./fixtures/five_games", + )))); + + assert_eq!( + Some(DatabasePath(PathBuf::from("./fixtures/five_games"))), + config.get() + ); + } + + #[test] + fn it_can_serialize_and_deserialize() { + let mut config = Config::new(); + config.set(ConfigOption::DatabasePath(DatabasePath(PathBuf::from( + "fixtures/five_games", + )))); + config.set(ConfigOption::Me(Me { + 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(&ConfigName::DatabasePath), + Some(ConfigOption::DatabasePath(ref db_path)) => + assert_eq!(Some(db_path.clone()), config.get()) + ); + + assert_matches!(values.get(&ConfigName::Me), Some(ConfigOption::Me(val)) => + assert_eq!(Some(val.clone()), config.get()) + ); + } +} 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")] diff --git a/rust-toolchain b/rust-toolchain index 6d69e1e..18fbce2 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "1.68.2" +channel = "1.71.1" targets = [ "wasm32-unknown-unknown" ]