From 7805a55322fd63054d28df1887c41eb73ca80f40 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Thu, 10 Aug 2023 19:53:20 -0400 Subject: [PATCH 1/2] Added the build scripts for kifu-gtk --- Cargo.lock | 303 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 209 insertions(+), 94 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d933eae..bb74c16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" +checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" dependencies = [ "memchr", ] @@ -70,9 +70,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.2" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" [[package]] name = "bit-set" @@ -139,7 +139,7 @@ checksum = "ab3603c4028a5e368d09b51c8b624b9a46edcd7c3778284077a6125af73c9f0a" dependencies = [ "bitflags 1.3.2", "cairo-sys-rs", - "glib", + "glib 0.17.10", "libc", "once_cell", "thiserror", @@ -151,7 +151,7 @@ version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "691d0c66b1fb4881be80a760cb8fe76ea97218312f9dfe2c9cc0f496ca279cb1" dependencies = [ - "glib-sys", + "glib-sys 0.17.10", "libc", "system-deps", ] @@ -190,9 +190,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "f56b4c72906975ca04becb8a30e102dfecddd0c06181e3e95ddc444be28881f8" dependencies = [ "android-tzdata", "iana-time-zone", @@ -201,7 +201,7 @@ dependencies = [ "serde", "time", "wasm-bindgen", - "winapi", + "windows-targets", ] [[package]] @@ -349,8 +349,8 @@ name = "cyberpunk-splash" version = "0.1.0" dependencies = [ "cairo-rs", - "gio", - "glib", + "gio 0.17.10", + "glib 0.17.10", "gtk4", ] @@ -365,8 +365,8 @@ dependencies = [ "futures", "gdk4", "geo-types", - "gio", - "glib", + "gio 0.17.10", + "glib 0.17.10", "glib-build-tools 0.16.3", "gtk4", "ifc", @@ -442,9 +442,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" dependencies = [ "errno-dragonfly", "libc", @@ -713,8 +713,8 @@ checksum = "695d6bc846438c5708b07007537b9274d883373dd30858ca881d7d71b5540717" dependencies = [ "bitflags 1.3.2", "gdk-pixbuf-sys", - "gio", - "glib", + "gio 0.17.10", + "glib 0.17.10", "libc", "once_cell", ] @@ -725,9 +725,9 @@ version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9285ec3c113c66d7d0ab5676599176f1f42f4944ca1b581852215bf5694870cb" dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", + "gio-sys 0.17.10", + "glib-sys 0.17.10", + "gobject-sys 0.17.10", "libc", "system-deps", ] @@ -742,10 +742,10 @@ dependencies = [ "cairo-rs", "gdk-pixbuf", "gdk4-sys", - "gio", - "glib", + "gio 0.17.10", + "glib 0.17.10", "libc", - "pango", + "pango 0.17.10", ] [[package]] @@ -756,11 +756,11 @@ checksum = "1bc92aa1608c089c49393d014c38ac0390d01e4841e1fedaa75dbcef77aaed64" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", - "gio-sys", - "glib-sys", - "gobject-sys", + "gio-sys 0.17.10", + "glib-sys 0.17.10", + "gobject-sys 0.17.10", "libc", - "pango-sys", + "pango-sys 0.17.10", "pkg-config", "system-deps", ] @@ -818,8 +818,27 @@ dependencies = [ "futures-core", "futures-io", "futures-util", - "gio-sys", - "glib", + "gio-sys 0.17.10", + "glib 0.17.10", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror", +] + +[[package]] +name = "gio" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7884cba6b1c5db1607d970cadf44b14a43913d42bc68766eea6a5e2fe0891524" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys 0.18.1", + "glib 0.18.1", "libc", "once_cell", "pin-project-lite", @@ -833,8 +852,21 @@ version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ccf87c30a12c469b6d958950f6a9c09f2be20b7773f7e70d20b867fdf2628c3" dependencies = [ - "glib-sys", - "gobject-sys", + "glib-sys 0.17.10", + "gobject-sys 0.17.10", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "gio-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +dependencies = [ + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", "system-deps", "winapi", @@ -852,10 +884,33 @@ dependencies = [ "futures-executor", "futures-task", "futures-util", - "gio-sys", - "glib-macros", - "glib-sys", - "gobject-sys", + "gio-sys 0.17.10", + "glib-macros 0.17.10", + "glib-sys 0.17.10", + "gobject-sys 0.17.10", + "libc", + "memchr", + "once_cell", + "smallvec", + "thiserror", +] + +[[package]] +name = "glib" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "331156127e8166dd815cf8d2db3a5beb492610c716c03ee6db4f2d07092af0a7" +dependencies = [ + "bitflags 2.4.0", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys 0.18.1", + "glib-macros 0.18.0", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", "memchr", "once_cell", @@ -890,6 +945,20 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "glib-macros" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "179643c50bf28d20d2f6eacd2531a88f2f5d9747dd0b86b8af1e8bb5dd0de3c0" +dependencies = [ + "heck", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.29", +] + [[package]] name = "glib-sys" version = "0.17.10" @@ -900,6 +969,16 @@ dependencies = [ "system-deps", ] +[[package]] +name = "glib-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +dependencies = [ + "libc", + "system-deps", +] + [[package]] name = "gm-control-panel" version = "0.1.0" @@ -908,8 +987,8 @@ dependencies = [ "config-derive", "futures", "gdk4", - "gio", - "glib", + "gio 0.17.10", + "glib 0.17.10", "glib-build-tools 0.16.3", "gtk4", "libadwaita", @@ -924,7 +1003,18 @@ version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd34c3317740a6358ec04572c1bcfd3ac0b5b6529275fae255b237b314bb8062" dependencies = [ - "glib-sys", + "glib-sys 0.17.10", + "libc", + "system-deps", +] + +[[package]] +name = "gobject-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +dependencies = [ + "glib-sys 0.18.1", "libc", "system-deps", ] @@ -935,7 +1025,7 @@ version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "def4bb01265b59ed548b05455040d272d989b3012c42d4c1bbd39083cb9b40d9" dependencies = [ - "glib", + "glib 0.17.10", "graphene-sys", "libc", ] @@ -946,7 +1036,7 @@ version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1856fc817e6a6675e36cea0bd9a3afe296f5d9709d1e2d3182803ac77f0ab21d" dependencies = [ - "glib-sys", + "glib-sys 0.17.10", "libc", "pkg-config", "system-deps", @@ -970,11 +1060,11 @@ dependencies = [ "bitflags 1.3.2", "cairo-rs", "gdk4", - "glib", + "glib 0.17.10", "graphene-rs", "gsk4-sys", "libc", - "pango", + "pango 0.17.10", ] [[package]] @@ -985,11 +1075,11 @@ checksum = "c07a84fb4dcf1323d29435aa85e2f5f58bef564342bef06775ec7bd0da1f01b0" dependencies = [ "cairo-sys-rs", "gdk4-sys", - "glib-sys", - "gobject-sys", + "glib-sys 0.17.10", + "gobject-sys 0.17.10", "graphene-sys", "libc", - "pango-sys", + "pango-sys 0.17.10", "system-deps", ] @@ -1005,15 +1095,15 @@ dependencies = [ "futures-channel", "gdk-pixbuf", "gdk4", - "gio", - "glib", + "gio 0.17.10", + "glib 0.17.10", "graphene-rs", "gsk4", "gtk4-macros", "gtk4-sys", "libc", "once_cell", - "pango", + "pango 0.17.10", ] [[package]] @@ -1039,13 +1129,13 @@ dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", "gdk4-sys", - "gio-sys", - "glib-sys", - "gobject-sys", + "gio-sys 0.17.10", + "glib-sys 0.17.10", + "gobject-sys 0.17.10", "graphene-sys", "gsk4-sys", "libc", - "pango-sys", + "pango-sys 0.17.10", "system-deps", ] @@ -1107,8 +1197,8 @@ version = "0.1.0" dependencies = [ "cairo-rs", "coordinates", - "gio", - "glib", + "gio 0.17.10", + "glib 0.17.10", "glib-build-tools 0.16.3", "gtk4", "image", @@ -1342,14 +1432,14 @@ name = "kifu-gtk" version = "0.1.0" dependencies = [ "cairo-rs", - "gio", - "glib", + "gio 0.17.10", + "glib 0.17.10", "glib-build-tools 0.17.10", "gtk4", "image", "kifu-core", "libadwaita", - "pango", + "pango 0.18.0", "sgf", "tokio", ] @@ -1375,12 +1465,12 @@ dependencies = [ "bitflags 1.3.2", "gdk-pixbuf", "gdk4", - "gio", - "glib", + "gio 0.17.10", + "glib 0.17.10", "gtk4", "libadwaita-sys", "libc", - "pango", + "pango 0.17.10", ] [[package]] @@ -1390,12 +1480,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4231cb2499a9f0c4cdfa4885414b33e39901ddcac61150bc0bb4ff8a57ede404" dependencies = [ "gdk4-sys", - "gio-sys", - "glib-sys", - "gobject-sys", + "gio-sys 0.17.10", + "glib-sys 0.17.10", + "gobject-sys 0.17.10", "gtk4-sys", "libc", - "pango-sys", + "pango-sys 0.17.10", "system-deps", ] @@ -1435,9 +1525,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f478948fd84d9f8e86967bf432640e46adfb5a4bd4f14ef7e864ab38220534ae" [[package]] name = "memoffset" @@ -1593,11 +1683,11 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.56" +version = "0.10.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729b745ad4a5575dd06a3e1af1414bd330ee561c01b3899eb584baeaa8def17e" +checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "cfg-if", "foreign-types", "libc", @@ -1625,9 +1715,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.91" +version = "0.9.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac" +checksum = "db7e971c2c2bba161b2d2fdf37080177eff520b3bc044787c7f1f5f9e78d869b" dependencies = [ "cc", "libc", @@ -1642,11 +1732,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35be456fc620e61f62dff7ff70fbd54dcbaf0a4b920c0f16de1107c47d921d48" dependencies = [ "bitflags 1.3.2", - "gio", - "glib", + "gio 0.17.10", + "glib 0.17.10", "libc", "once_cell", - "pango-sys", + "pango-sys 0.17.10", +] + +[[package]] +name = "pango" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06a9e54b831d033206160096b825f2070cf5fda7e35167b1c01e9e774f9202d1" +dependencies = [ + "gio 0.18.1", + "glib 0.18.1", + "libc", + "once_cell", + "pango-sys 0.18.0", ] [[package]] @@ -1655,8 +1758,20 @@ version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3da69f9f3850b0d8990d462f8c709561975e95f689c1cdf0fecdebde78b35195" dependencies = [ - "glib-sys", - "gobject-sys", + "glib-sys 0.17.10", + "gobject-sys 0.17.10", + "libc", + "system-deps", +] + +[[package]] +name = "pango-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +dependencies = [ + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", "system-deps", ] @@ -1759,9 +1874,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1953,25 +2068,25 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.3" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.7.4", + "regex-syntax 0.7.5", ] [[package]] name = "regex-automata" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.7.5", ] [[package]] @@ -1982,9 +2097,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "reqwest" @@ -2046,9 +2161,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.8" +version = "0.38.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" +checksum = "ed6248e1caa625eb708e266e06159f135e8c26f2bb7ceb72dc4b2766d0340964" dependencies = [ "bitflags 2.4.0", "errno", @@ -2134,18 +2249,18 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" -version = "1.0.186" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f5db24220c009de9bd45e69fb2938f4b6d2df856aa9304ce377b3180f83b7c1" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.186" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad697f7e0b65af4983a4ce8f56ed5b357e8d3c36651bf6a7e13639c17b8e670" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", @@ -2584,9 +2699,9 @@ dependencies = [ [[package]] name = "url" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna", -- 2.44.1 From d6c2a9519bc89739be860ff092767ac7e37b7b7c Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Fri, 11 Aug 2023 11:03:53 -0400 Subject: [PATCH 2/2] Overhaul the sgf representation --- Cargo.lock | 1 + sgf/Cargo.toml | 3 + sgf/src/go.rs | 178 +++++++++++++++++++++----- sgf/src/lib.rs | 2 +- sgf/src/tree.rs | 333 +++++++++++++++++++++++++++++------------------- 5 files changed, 351 insertions(+), 166 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bb74c16..7137afc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2304,6 +2304,7 @@ name = "sgf" version = "0.1.0" dependencies = [ "chrono", + "cool_asserts", "nom", "serde", "thiserror", diff --git a/sgf/Cargo.toml b/sgf/Cargo.toml index ab75ce2..2dbd6bf 100644 --- a/sgf/Cargo.toml +++ b/sgf/Cargo.toml @@ -11,3 +11,6 @@ nom = { version = "7" } serde = { version = "1", features = [ "derive" ] } thiserror = { version = "1"} typeshare = { version = "1" } + +[dev-dependencies] +cool_asserts = { version = "2" } diff --git a/sgf/src/go.rs b/sgf/src/go.rs index 0fc3db0..d0fa213 100644 --- a/sgf/src/go.rs +++ b/sgf/src/go.rs @@ -74,6 +74,7 @@ use crate::{ Error, }; use serde::{Deserialize, Serialize}; +use std::ops::Deref; use typeshare::typeshare; #[derive(Clone, Debug)] @@ -84,11 +85,18 @@ pub struct Game { pub tree: Tree, } +impl Deref for Game { + type Target = Tree; + fn deref(&self) -> &Self::Target { + &self.tree + } +} + impl TryFrom for Game { type Error = Error; fn try_from(tree: Tree) -> Result { - let board_size = match tree.sequence[0].find_prop("SZ") { + let board_size = match tree.root.find_prop("SZ") { Some(prop) => Size::try_from(prop.values[0].as_str())?, None => Size { width: 19, @@ -96,40 +104,37 @@ impl TryFrom for Game { }, }; let mut info = GameInfo::default(); - info.app_name = tree.sequence[0] - .find_prop("AP") - .map(|prop| prop.values[0].clone()); + info.app_name = tree.root.find_prop("AP").map(|prop| prop.values[0].clone()); - info.game_name = tree.sequence[0] - .find_prop("GN") - .map(|prop| prop.values[0].clone()); + info.game_name = tree.root.find_prop("GN").map(|prop| prop.values[0].clone()); - info.black_player = tree.sequence[0] - .find_prop("PB") - .map(|prop| prop.values.join(", ")); + info.black_player = tree.root.find_prop("PB").map(|prop| prop.values.join(", ")); - info.black_rank = tree.sequence[0] + info.black_rank = tree + .root .find_prop("BR") .and_then(|prop| Rank::try_from(prop.values[0].as_str()).ok()); - info.white_player = tree.sequence[0] - .find_prop("PW") - .map(|prop| prop.values.join(", ")); + info.white_player = tree.root.find_prop("PW").map(|prop| prop.values.join(", ")); - info.white_rank = tree.sequence[0] + info.white_rank = tree + .root .find_prop("WR") .and_then(|prop| Rank::try_from(prop.values[0].as_str()).ok()); - info.result = tree.sequence[0] + info.result = tree + .root .find_prop("RE") .and_then(|prop| GameResult::try_from(prop.values[0].as_str()).ok()); - info.time_limits = tree.sequence[0] + info.time_limits = tree + .root .find_prop("TM") .and_then(|prop| prop.values[0].parse::().ok()) .and_then(|seconds| Some(std::time::Duration::from_secs(seconds))); - info.date = tree.sequence[0] + info.date = tree + .root .find_prop("DT") .and_then(|prop| { let v = prop @@ -149,21 +154,13 @@ impl TryFrom for Game { }) .unwrap_or(vec![]); - info.event = tree.sequence[0] - .find_prop("EV") - .map(|prop| prop.values.join(", ")); + info.event = tree.root.find_prop("EV").map(|prop| prop.values.join(", ")); - info.round = tree.sequence[0] - .find_prop("RO") - .map(|prop| prop.values.join(", ")); + info.round = tree.root.find_prop("RO").map(|prop| prop.values.join(", ")); - info.source = tree.sequence[0] - .find_prop("SO") - .map(|prop| prop.values.join(", ")); + info.source = tree.root.find_prop("SO").map(|prop| prop.values.join(", ")); - info.game_keeper = tree.sequence[0] - .find_prop("US") - .map(|prop| prop.values.join(", ")); + info.game_keeper = tree.root.find_prop("US").map(|prop| prop.values.join(", ")); Ok(Game { board_size, @@ -307,7 +304,7 @@ mod tests { use super::*; use crate::{ date::Date, - tree::{parse_collection, Size}, + tree::{parse_collection, Property, Size}, }; use std::fs::File; use std::io::Read; @@ -390,4 +387,123 @@ mod tests { assert_eq!(tree.info.game_keeper, Some("Arno Hollosi".to_owned())); }); } + + #[test] + fn it_presents_the_mainline_of_game_without_branches() { + with_file( + std::path::Path::new("test_data/2020 USGO DDK, Round 1.sgf"), + |trees| { + assert_eq!(trees.len(), 1); + let tree = &trees[0]; + + let node = &tree.root; + assert_eq!(node.properties.len(), 16); + let expected_properties = vec![ + Property { + ident: "GM".to_owned(), + values: vec!["1".to_owned()], + }, + Property { + ident: "FF".to_owned(), + values: vec!["4".to_owned()], + }, + Property { + ident: "CA".to_owned(), + values: vec!["UTF-8".to_owned()], + }, + Property { + ident: "AP".to_owned(), + values: vec!["CGoban:3".to_owned()], + }, + Property { + ident: "ST".to_owned(), + values: vec!["2".to_owned()], + }, + Property { + ident: "RU".to_owned(), + values: vec!["AGA".to_owned()], + }, + Property { + ident: "SZ".to_owned(), + values: vec!["19".to_owned()], + }, + Property { + ident: "KM".to_owned(), + values: vec!["7.50".to_owned()], + }, + Property { + ident: "TM".to_owned(), + values: vec!["1800".to_owned()], + }, + Property { + ident: "OT".to_owned(), + values: vec!["5x30 byo-yomi".to_owned()], + }, + Property { + ident: "PW".to_owned(), + values: vec!["Geckoz".to_owned()], + }, + Property { + ident: "PB".to_owned(), + values: vec!["savanni".to_owned()], + }, + Property { + ident: "BR".to_owned(), + values: vec!["23k".to_owned()], + }, + Property { + ident: "DT".to_owned(), + values: vec!["2020-08-05".to_owned()], + }, + Property { + ident: "PC".to_owned(), + values: vec!["The KGS Go Server at http://www.gokgs.com/".to_owned()], + }, + Property { + ident: "RE".to_owned(), + values: vec!["W+17.50".to_owned()], + }, + ]; + + for i in 0..16 { + assert_eq!(node.properties[i], expected_properties[i]); + } + + let node = node.next().unwrap(); + let expected_properties = vec![ + Property { + ident: "B".to_owned(), + values: vec!["pp".to_owned()], + }, + Property { + ident: "BL".to_owned(), + values: vec!["1795.449".to_owned()], + }, + Property { + ident: "C".to_owned(), + values: vec!["Geckoz [?]: Good game\nsavanni [23k?]: There we go! This UI is... tough.\nsavanni [23k?]: Have fun! Talk to you at the end.\nGeckoz [?]: Yeah, OGS is much better; I'm a UX professional\n".to_owned()], + } + ]; + + for i in 0..3 { + assert_eq!(node.properties[i], expected_properties[i]); + } + + let node = node.next().unwrap(); + let expected_properties = vec![ + Property { + ident: "W".to_owned(), + values: vec!["dp".to_owned()], + }, + Property { + ident: "WL".to_owned(), + values: vec!["1765.099".to_owned()], + }, + ]; + for i in 0..2 { + assert_eq!(node.properties[i], expected_properties[i]); + } + }, + ); + } } diff --git a/sgf/src/lib.rs b/sgf/src/lib.rs index 4b4f8fa..bd2937c 100644 --- a/sgf/src/lib.rs +++ b/sgf/src/lib.rs @@ -65,7 +65,7 @@ pub fn parse_sgf(input: &str) -> Result, Error> { let (_, trees) = parse_collection::>(input)?; Ok(trees .into_iter() - .map(|t| match t.sequence[0].find_prop("GM") { + .map(|t| match t.root.find_prop("GM") { Some(prop) if prop.values == vec!["1".to_owned()] => { Game::Go(go::Game::try_from(t).expect("properly structured game tree")) } diff --git a/sgf/src/tree.rs b/sgf/src/tree.rs index 59d24c0..e1340a2 100644 --- a/sgf/src/tree.rs +++ b/sgf/src/tree.rs @@ -5,7 +5,6 @@ use nom::{ character::complete::{alpha1, digit1, multispace0, multispace1, none_of}, combinator::{opt, value}, multi::{many0, many1, separated_list1}, - sequence::delimited, IResult, }; use std::num::ParseIntError; @@ -54,29 +53,19 @@ impl TryFrom<&str> for Size { #[derive(Clone, Debug, PartialEq)] pub struct Tree { - pub sequence: Vec, - pub sub_sequences: Vec, + pub root: Node, } impl ToString for Tree { fn to_string(&self) -> String { - let sequence = self - .sequence - .iter() - .map(|node| node.to_string()) - .collect::(); - let subsequences = self - .sub_sequences - .iter() - .map(|seq| seq.to_string()) - .collect::(); - format!("({}{})", sequence, subsequences) + format!("({})", self.root.to_string()) } } #[derive(Clone, Debug, PartialEq)] pub struct Node { pub properties: Vec, + pub next: Vec, } impl ToString for Node { @@ -86,7 +75,21 @@ impl ToString for Node { .iter() .map(|prop| prop.to_string()) .collect::(); - format!(";{}", props) + + let next = if self.next.len() == 1 { + self.next + .iter() + .map(|node| node.to_string()) + .collect::>() + .join("") + } else { + self.next + .iter() + .map(|node| format!("({})", node.to_string())) + .collect::>() + .join("") + }; + format!(";{}{}", props, next) } } @@ -97,6 +100,10 @@ impl Node { .find(|prop| prop.ident == ident) .cloned() } + + pub fn next<'a>(&'a self) -> Option<&'a Node> { + self.next.get(0) + } } #[derive(Clone, Debug, PartialEq)] @@ -119,40 +126,40 @@ impl ToString for Property { pub fn parse_collection<'a, E: nom::error::ParseError<&'a str>>( input: &'a str, ) -> IResult<&'a str, Vec, E> { - separated_list1(multispace1, parse_tree)(input) + let (input, roots) = separated_list1(multispace1, parse_tree)(input)?; + let trees = roots + .into_iter() + .map(|root| Tree { root }) + .collect::>(); + + Ok((input, trees)) } // note: must preserve unknown properties // note: must fix or preserve illegally formatted game-info properties // note: must correct or delete illegally foramtted properties, but display a warning -fn parse_tree<'a, E: nom::error::ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, Tree, E> { +fn parse_tree<'a, E: nom::error::ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, Node, E> { let (input, _) = multispace0(input)?; - delimited(tag("("), parse_sequence, tag(")"))(input) -} + let (input, _) = tag("(")(input)?; + let (input, node) = parse_node(input)?; + let (input, _) = multispace0(input)?; + let (input, _) = tag(")")(input)?; -fn parse_sequence<'a, E: nom::error::ParseError<&'a str>>( - input: &'a str, -) -> IResult<&'a str, Tree, E> { - let (input, _) = multispace0(input)?; - let (input, nodes) = many1(parse_node)(input)?; - let (input, _) = multispace0(input)?; - let (input, sub_sequences) = many0(parse_tree)(input)?; - let (input, _) = multispace0(input)?; - - Ok(( - input, - Tree { - sequence: nodes, - sub_sequences, - }, - )) + Ok((input, node)) } fn parse_node<'a, E: nom::error::ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, Node, E> { let (input, _) = multispace0(input)?; - let (input, _) = tag(";")(input)?; + let (input, _) = opt(tag(";"))(input)?; let (input, properties) = many1(parse_property)(input)?; - Ok((input, Node { properties })) + + let (input, next) = opt(parse_node)(input)?; + let (input, mut next_seq) = many0(parse_tree)(input)?; + + let mut next = next.map(|n| vec![n]).unwrap_or(vec![]); + next.append(&mut next_seq); + + Ok((input, Node { properties, next })) } fn parse_property<'a, E: nom::error::ParseError<&'a str>>( @@ -219,8 +226,6 @@ pub fn parse_size<'a, E: nom::error::ParseError<&'a str>>( #[cfg(test)] mod test { - use std::{fs::File, io::Read}; - use super::*; const EXAMPLE: &'static str = "(;FF[4]C[root](;C[a];C[b](;C[c]) @@ -259,7 +264,8 @@ mod test { properties: vec![Property { ident: "B".to_owned(), values: vec!["ab".to_owned()] - }] + }], + next: vec![] } ); @@ -273,6 +279,25 @@ mod test { properties: vec![Property { ident: "B".to_owned(), values: vec!["ab".to_owned()] + }], + next: vec![Node { + properties: vec![Property { + ident: "W".to_owned(), + values: vec!["dp".to_owned()] + }], + next: vec![Node { + properties: vec![ + Property { + ident: "B".to_owned(), + values: vec!["pq".to_owned()] + }, + Property { + ident: "C".to_owned(), + values: vec!["some comments".to_owned()] + } + ], + next: vec![], + }] }] } ); @@ -286,21 +311,17 @@ mod test { assert_eq!( sequence, - Tree { - sequence: vec![ - Node { - properties: vec![Property { - ident: "B".to_owned(), - values: vec!["ab".to_owned()] - }] - }, - Node { - properties: vec![Property { - ident: "W".to_owned(), - values: vec!["dp".to_owned()] - }] - }, - Node { + Node { + properties: vec![Property { + ident: "B".to_owned(), + values: vec!["ab".to_owned()] + }], + next: vec![Node { + properties: vec![Property { + ident: "W".to_owned(), + values: vec!["dp".to_owned()] + }], + next: vec![Node { properties: vec![ Property { ident: "B".to_owned(), @@ -310,114 +331,158 @@ mod test { ident: "C".to_owned(), values: vec!["some comments".to_owned()] } - ] - } - ], - sub_sequences: vec![], - } + ], + next: vec![], + }] + }], + }, ); } #[test] - fn it_can_parse_a_sequence_with_subsequences() { + fn it_can_parse_a_branching_sequence() { let text = "(;C[a];C[b](;C[c])(;C[d];C[e]))"; - let (_, sequence) = parse_tree::>(text).unwrap(); + let (_, tree) = parse_tree::>(text).unwrap(); - let main_sequence = vec![ - Node { - properties: vec![Property { - ident: "C".to_owned(), - values: vec!["a".to_owned()], - }], - }, - Node { + let expected = Node { + properties: vec![Property { + ident: "C".to_owned(), + values: vec!["a".to_owned()], + }], + next: vec![Node { properties: vec![Property { ident: "C".to_owned(), values: vec!["b".to_owned()], }], - }, - ]; - let subsequence_1 = Tree { - sequence: vec![Node { - properties: vec![Property { - ident: "C".to_owned(), - values: vec!["c".to_owned()], - }], + next: vec![ + Node { + properties: vec![Property { + ident: "C".to_owned(), + values: vec!["c".to_owned()], + }], + next: vec![], + }, + Node { + properties: vec![Property { + ident: "C".to_owned(), + values: vec!["d".to_owned()], + }], + next: vec![Node { + properties: vec![Property { + ident: "C".to_owned(), + values: vec!["e".to_owned()], + }], + next: vec![], + }], + }, + ], }], - sub_sequences: vec![], - }; - let subsequence_2 = Tree { - sequence: vec![ - Node { - properties: vec![Property { - ident: "C".to_owned(), - values: vec!["d".to_owned()], - }], - }, - Node { - properties: vec![Property { - ident: "C".to_owned(), - values: vec!["e".to_owned()], - }], - }, - ], - sub_sequences: vec![], }; - assert_eq!( - sequence, - Tree { - sequence: main_sequence, - sub_sequences: vec![subsequence_1, subsequence_2], - } - ); + assert_eq!(tree, expected); } #[test] fn it_can_parse_example_1() { - let (_, ex_tree) = parse_tree::>(EXAMPLE).unwrap(); - assert_eq!(ex_tree.sequence.len(), 1); + let (_, tree) = parse_tree::>(EXAMPLE).unwrap(); - assert_eq!(ex_tree.sequence[0].properties.len(), 2); - assert_eq!( - ex_tree.sequence[0].properties[0], - Property { - ident: "FF".to_owned(), - values: vec!["4".to_owned()] - } - ); - assert_eq!(ex_tree.sub_sequences.len(), 2); + let j = Node { + properties: vec![Property { + ident: "C".to_owned(), + values: vec!["j".to_owned()], + }], + next: vec![], + }; + let i = Node { + properties: vec![Property { + ident: "C".to_owned(), + values: vec!["i".to_owned()], + }], + next: vec![], + }; + let h = Node { + properties: vec![Property { + ident: "C".to_owned(), + values: vec!["h".to_owned()], + }], + next: vec![i], + }; + let g = Node { + properties: vec![Property { + ident: "C".to_owned(), + values: vec!["g".to_owned()], + }], + next: vec![h], + }; + let f = Node { + properties: vec![Property { + ident: "C".to_owned(), + values: vec!["f".to_owned()], + }], + next: vec![g, j], + }; + let e = Node { + properties: vec![Property { + ident: "C".to_owned(), + values: vec!["e".to_owned()], + }], + next: vec![], + }; + let d = Node { + properties: vec![Property { + ident: "C".to_owned(), + values: vec!["d".to_owned()], + }], + next: vec![e], + }; + let c = Node { + properties: vec![Property { + ident: "C".to_owned(), + values: vec!["c".to_owned()], + }], + next: vec![], + }; + let b = Node { + properties: vec![Property { + ident: "C".to_owned(), + values: vec!["b".to_owned()], + }], + next: vec![c, d], + }; + let a = Node { + properties: vec![Property { + ident: "C".to_owned(), + values: vec!["a".to_owned()], + }], + next: vec![b], + }; + let expected = Node { + properties: vec![ + Property { + ident: "FF".to_owned(), + values: vec!["4".to_owned()], + }, + Property { + ident: "C".to_owned(), + values: vec!["root".to_owned()], + }, + ], + next: vec![a, f], + }; - assert_eq!(ex_tree.sub_sequences[0].sequence.len(), 2); - assert_eq!( - ex_tree.sub_sequences[0].sequence, - vec![ - Node { - properties: vec![Property { - ident: "C".to_owned(), - values: vec!["a".to_owned()] - }] - }, - Node { - properties: vec![Property { - ident: "C".to_owned(), - values: vec!["b".to_owned()] - }] - }, - ] - ); - assert_eq!(ex_tree.sub_sequences[0].sub_sequences.len(), 2); + assert_eq!(tree, expected); } #[test] fn it_can_regenerate_the_tree() { let (_, tree1) = parse_tree::>(EXAMPLE).unwrap(); + let tree1 = Tree { root: tree1 }; assert_eq!( tree1.to_string(), "(;FF[4]C[root](;C[a];C[b](;C[c])(;C[d];C[e]))(;C[f](;C[g];C[h];C[i])(;C[j])))" ); let (_, tree2) = parse_tree::>(&tree1.to_string()).unwrap(); - assert_eq!(tree1, tree2); + assert_eq!(tree1, Tree { root: tree2 }); } #[test] -- 2.44.1