diff --git a/Cargo.lock b/Cargo.lock index d793d449df..3a23e7d6b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -321,22 +321,21 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.60", ] [[package]] name = "arboard" -version = "3.3.2" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2041f1943049c7978768d84e6d0fd95de98b76d6c4727b09e78ec253d29fa58" +checksum = "9fb4009533e8ff8f1450a5bcbc30f4242a1d34442221f72314bea1f5dc9c7f89" dependencies = [ "clipboard-win", "log", - "objc", - "objc-foundation", - "objc_id", + "objc2 0.5.1", + "objc2-app-kit", + "objc2-foundation", "parking_lot", - "thiserror", "x11rb", ] @@ -395,7 +394,7 @@ checksum = "136d4d23bcc79e27423727b36823d86233aad06dfea531837b038394d11e9928" dependencies = [ "concurrent-queue", "event-listener 5.3.0", - "event-listener-strategy 0.5.1", + "event-listener-strategy 0.5.2", "futures-core", "pin-project-lite", ] @@ -408,7 +407,7 @@ checksum = "b10202063978b3351199d68f8b22c4e47e4b1b822f8d43fd862d5ea8c006b29a" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.0.2", + "fastrand 2.1.0", "futures-lite 2.3.0", "slab", ] @@ -457,8 +456,8 @@ dependencies = [ "futures-io", "futures-lite 2.3.0", "parking", - "polling 3.6.0", - "rustix 0.38.32", + "polling 3.7.0", + "rustix 0.38.34", "slab", "tracing", "windows-sys 0.52.0", @@ -503,15 +502,15 @@ dependencies = [ "cfg-if", "event-listener 3.1.0", "futures-lite 1.13.0", - "rustix 0.38.32", + "rustix 0.38.34", "windows-sys 0.48.0", ] [[package]] name = "async-recursion" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30c5ef0ede93efbf733c1a727f3b6b5a1060bbedd5600183e66f6e4be4af0ec5" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", @@ -520,27 +519,27 @@ dependencies = [ [[package]] name = "async-signal" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5" +checksum = "afe66191c335039c7bb78f99dc7520b0cbb166b3a1cb33a03f53d8a1c6f2afda" dependencies = [ "async-io 2.3.2", - "async-lock 2.8.0", + "async-lock 3.3.0", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix 0.38.32", + "rustix 0.38.34", "signal-hook-registry", "slab", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "async-task" -version = "4.7.0" +version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" @@ -713,11 +712,11 @@ dependencies = [ "nalgebra", "parameters", "parking_lot", + "path_serde", "proc-macro2", "projection", "quote", "serde", - "serialize_hierarchy", "source_analyzer", "spl_network", "spl_network_messages", @@ -892,20 +891,27 @@ dependencies = [ "objc2 0.4.1", ] +[[package]] +name = "block2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ff7d91d3c1d568065b06c899777d1e48dcf76103a672a0adbc238a7f247f1e" +dependencies = [ + "objc2 0.5.1", +] + [[package]] name = "blocking" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" +checksum = "495f7104e962b7356f0aeb34247aca1fe7d2e783b346582db7f2904cb5717e88" dependencies = [ "async-channel", "async-lock 3.3.0", "async-task", - "fastrand 2.0.2", "futures-io", "futures-lite 2.3.0", "piper", - "tracing", ] [[package]] @@ -1000,8 +1006,8 @@ checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" dependencies = [ "bitflags 2.5.0", "log", - "polling 3.6.0", - "rustix 0.38.32", + "polling 3.7.0", + "rustix 0.38.34", "slab", "thiserror", ] @@ -1013,7 +1019,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" dependencies = [ "calloop", - "rustix 0.38.32", + "rustix 0.38.34", "wayland-backend", "wayland-client", ] @@ -1031,12 +1037,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.94" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" +checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd" dependencies = [ "jobserver", "libc", + "once_cell", ] [[package]] @@ -1233,7 +1240,7 @@ dependencies = [ "proc-macro2", "quote", "source_analyzer", - "syn 1.0.109", + "syn 2.0.60", "thiserror", ] @@ -1348,9 +1355,9 @@ dependencies = [ "futures-util", "log", "parameters", + "path_serde", "serde", "serde_json", - "serialize_hierarchy", "thiserror", "tokio", "tokio-tungstenite", @@ -1382,9 +1389,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] @@ -1427,7 +1434,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.60", ] [[package]] @@ -1452,10 +1459,10 @@ dependencies = [ "nalgebra", "num-traits", "ordered-float", + "path_serde", "projection", "rand", "serde", - "serialize_hierarchy", "smallvec", "spl_network_messages", "splines", @@ -1484,8 +1491,8 @@ version = "0.1.0" dependencies = [ "approx", "approx_derive", + "path_serde", "serde", - "serialize_hierarchy", ] [[package]] @@ -1615,9 +1622,9 @@ checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" [[package]] name = "data-encoding" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "depp" @@ -2001,8 +2008,8 @@ name = "energy_optimization" version = "0.1.0" dependencies = [ "filtering", + "path_serde", "serde", - "serialize_hierarchy", "types", ] @@ -2017,9 +2024,9 @@ dependencies = [ [[package]] name = "enum-iterator-derive" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03cdc46ec28bd728e67540c528013c6a10eb69a02eb31078a1bda695438cbfb8" +checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", @@ -2203,9 +2210,9 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "332f51cb23d20b0de8458b86580878211da09bcd4503cb579c225b3d124cabb3" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ "event-listener 5.3.0", "pin-project-lite", @@ -2270,9 +2277,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "fdeflate" @@ -2308,17 +2315,11 @@ dependencies = [ "types", ] -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", @@ -2443,7 +2444,7 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.0.2", + "fastrand 2.1.0", "futures-core", "futures-io", "parking", @@ -2517,8 +2518,8 @@ dependencies = [ "approx_derive", "linear_algebra", "nalgebra", + "path_serde", "serde", - "serialize_hierarchy", ] [[package]] @@ -2554,9 +2555,9 @@ dependencies = [ [[package]] name = "gilrs" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "499067aa54af19f88732dc418f61f23d5912de1518665bb0eca034ca0d07574c" +checksum = "b54e5e39844ab5cddaf3bbbdfdc2923a6cb34e36818b95618da4e3f26302c24c" dependencies = [ "fnv", "gilrs-core", @@ -2739,7 +2740,7 @@ checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" dependencies = [ "bitflags 2.5.0", "gpu-descriptor-types", - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -2810,9 +2811,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", @@ -2953,10 +2954,10 @@ dependencies = [ "linear_algebra", "nalgebra", "object_detection", + "path_serde", "projection", "serde", "serde_json", - "serialize_hierarchy", "source_analyzer", "spl_network", "spl_network_messages", @@ -3029,10 +3030,10 @@ dependencies = [ "linear_algebra", "nalgebra", "object_detection", + "path_serde", "projection", "serde", "serde_json", - "serialize_hierarchy", "source_analyzer", "spl_network", "spl_network_messages", @@ -3091,7 +3092,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.6", + "socket2 0.5.7", "tokio", "tower-service", "tracing", @@ -3208,7 +3209,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -3359,9 +3360,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685a7d121ee3f65ae4fddd72b25a04bb36b6af81bc0828f7d5434c0fe60fa3a2" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] @@ -3443,9 +3444,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "libloading" @@ -3528,8 +3529,8 @@ dependencies = [ "approx", "nalgebra", "num-traits", + "path_serde", "serde", - "serialize_hierarchy", ] [[package]] @@ -3558,9 +3559,9 @@ checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -4018,7 +4019,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.1.0", "proc-macro2", "quote", "syn 2.0.60", @@ -4040,17 +4041,6 @@ dependencies = [ "objc_exception", ] -[[package]] -name = "objc-foundation" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" -dependencies = [ - "block", - "objc", - "objc_id", -] - [[package]] name = "objc-sys" version = "0.2.0-beta.2" @@ -4084,6 +4074,39 @@ dependencies = [ "objc2-encode 3.0.0", ] +[[package]] +name = "objc2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b25e1034d0e636cd84707ccdaa9f81243d399196b8a773946dcffec0401659" +dependencies = [ + "objc-sys 0.3.3", + "objc2-encode 4.0.1", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb79768a710a9a1798848179edb186d1af7e8a8679f369e4b8d201dd2a034047" +dependencies = [ + "block2 0.5.0", + "objc2 0.5.1", + "objc2-core-data", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e092bc42eaf30a08844e6a076938c60751225ec81431ab89f5d1ccd9f958d6c" +dependencies = [ + "block2 0.5.0", + "objc2 0.5.1", + "objc2-foundation", +] + [[package]] name = "objc2-encode" version = "2.0.0-pre.2" @@ -4100,21 +4123,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" [[package]] -name = "objc_exception" -version = "0.1.2" +name = "objc2-encode" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +checksum = "88658da63e4cc2c8adb1262902cd6af51094df0488b760d6fd27194269c0950a" + +[[package]] +name = "objc2-foundation" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfaefe14254871ea16c7d88968c0ff14ba554712a20d76421eec52f0a7fb8904" dependencies = [ - "cc", + "block2 0.5.0", + "objc2 0.5.1", ] [[package]] -name = "objc_id" -version = "0.1.1" +name = "objc_exception" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" dependencies = [ - "objc", + "cc", ] [[package]] @@ -4352,9 +4382,9 @@ checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", "parking_lot_core", @@ -4362,15 +4392,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] @@ -4388,6 +4418,26 @@ dependencies = [ "std_prelude", ] +[[package]] +name = "path_serde" +version = "0.1.0" +dependencies = [ + "nalgebra", + "path_serde_derive", + "serde", + "thiserror", +] + +[[package]] +name = "path_serde_derive" +version = "0.1.0" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.60", +] + [[package]] name = "peeking_take_while" version = "0.1.2" @@ -4424,16 +4474,6 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "petgraph" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" -dependencies = [ - "fixedbitset", - "indexmap 2.2.6", -] - [[package]] name = "pin-project-lite" version = "0.2.14" @@ -4453,7 +4493,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" dependencies = [ "atomic-waker", - "fastrand 2.0.2", + "fastrand 2.1.0", "futures-io", ] @@ -4508,15 +4548,15 @@ dependencies = [ [[package]] name = "polling" -version = "3.6.0" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c976a60b2d7e99d6f229e414670a9b85d13ac305cc6d1e9c134de58c5aaaf6" +checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi 0.3.9", "pin-project-lite", - "rustix 0.38.32", + "rustix 0.38.34", "tracing", "windows-sys 0.52.0", ] @@ -4574,6 +4614,15 @@ dependencies = [ "toml_edit 0.19.15", ] +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -4621,8 +4670,8 @@ dependencies = [ "coordinate_systems", "linear_algebra", "nalgebra", + "path_serde", "serde", - "serialize_hierarchy", "thiserror", "types", ] @@ -4750,6 +4799,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "redox_users" version = "0.4.5" @@ -4929,9 +4987,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.32" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags 2.5.0", "errno", @@ -5109,28 +5167,6 @@ dependencies = [ "yaml-rust", ] -[[package]] -name = "serialize_hierarchy" -version = "0.1.0" -dependencies = [ - "bincode", - "nalgebra", - "serde", - "serde_json", - "serialize_hierarchy_derive", - "thiserror", -] - -[[package]] -name = "serialize_hierarchy_derive" -version = "0.1.0" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "sha1" version = "0.10.6" @@ -5176,9 +5212,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -5239,7 +5275,7 @@ dependencies = [ "libc", "log", "memmap2", - "rustix 0.38.32", + "rustix 0.38.34", "thiserror", "wayland-backend", "wayland-client", @@ -5283,9 +5319,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", @@ -5299,7 +5335,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 1.0.109", + "syn 2.0.60", "thiserror", "threadbound", "toposort-scc", @@ -5353,8 +5389,8 @@ dependencies = [ "nalgebra", "num-derive", "num-traits", + "path_serde", "serde", - "serialize_hierarchy", ] [[package]] @@ -5517,8 +5553,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", - "fastrand 2.0.2", - "rustix 0.38.32", + "fastrand 2.1.0", + "rustix 0.38.34", "windows-sys 0.52.0", ] @@ -5542,18 +5578,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" dependencies = [ "proc-macro2", "quote", @@ -5672,7 +5708,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.6", + "socket2 0.5.7", "tokio-macros", "windows-sys 0.48.0", ] @@ -5733,7 +5769,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.9", + "toml_edit 0.22.12", ] [[package]] @@ -5758,15 +5794,26 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.9" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" +checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" dependencies = [ "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.6", + "winnow 0.6.7", ] [[package]] @@ -5941,11 +5988,8 @@ dependencies = [ "linear_algebra", "nalgebra", "ordered-float", - "petgraph", - "proc-macro2", - "quote", + "path_serde", "serde", - "serialize_hierarchy", "spl_network_messages", "splines", ] @@ -5999,9 +6043,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "unicode-xid" @@ -6121,8 +6165,8 @@ dependencies = [ "linear_algebra", "motionfile", "nalgebra", + "path_serde", "serde", - "serialize_hierarchy", "splines", "types", ] @@ -6216,7 +6260,7 @@ checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40" dependencies = [ "cc", "downcast-rs", - "rustix 0.38.32", + "rustix 0.38.34", "scoped-tls", "smallvec", "wayland-sys", @@ -6229,7 +6273,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f" dependencies = [ "bitflags 2.5.0", - "rustix 0.38.32", + "rustix 0.38.34", "wayland-backend", "wayland-scanner", ] @@ -6251,7 +6295,7 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71ce5fa868dd13d11a0d04c5e2e65726d0897be8de247c0c5a65886e283231ba" dependencies = [ - "rustix 0.38.32", + "rustix 0.38.34", "wayland-client", "xcursor", ] @@ -6491,14 +6535,14 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.32", + "rustix 0.38.34", ] [[package]] name = "wide" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a1851a719f11d1d2fea40e15c72f6c00de8c142d7ac47c1441cc7e4d0d5bc6" +checksum = "0f0e39d2c603fdc0504b12b458cf1f34e0b937ed2f4f2dc20796e3e86f34e11f" dependencies = [ "bytemuck", "safe_arch", @@ -6528,11 +6572,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -6857,7 +6901,7 @@ dependencies = [ "raw-window-handle 0.5.2", "raw-window-handle 0.6.1", "redox_syscall 0.3.5", - "rustix 0.38.32", + "rustix 0.38.34", "sctk-adwaita", "smithay-client-toolkit", "smol_str", @@ -6887,9 +6931,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352" +checksum = "14b9415ee827af173ebb3f15f9083df5a122eb93572ec28741fb153356ea2578" dependencies = [ "memchr", ] @@ -6917,24 +6961,24 @@ dependencies = [ [[package]] name = "x11rb" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" dependencies = [ "as-raw-xcb-connection", "gethostname", "libc", "libloading 0.8.3", "once_cell", - "rustix 0.38.32", + "rustix 0.38.34", "x11rb-protocol", ] [[package]] name = "x11rb-protocol" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" [[package]] name = "xcursor" @@ -7033,7 +7077,7 @@ version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "regex", @@ -7101,7 +7145,7 @@ version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 1.0.109", diff --git a/Cargo.toml b/Cargo.toml index c6776476f8..bda366c8da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,10 +31,10 @@ members = [ "crates/opn", "crates/parameter_tester", "crates/parameters", + "crates/path_serde", + "crates/path_serde_derive", "crates/projection", "crates/repository", - "crates/serialize_hierarchy", - "crates/serialize_hierarchy_derive", "crates/source_analyzer", "crates/spl_network", "crates/spl_network_messages", @@ -142,6 +142,8 @@ opusfile-ng = "0.1.0" ordered-float = "3.1.0" parameters = { path = "crates/parameters" } parking_lot = "0.12.1" +path_serde = { path = "crates/path_serde" } +path_serde_derive = { path = "crates/path_serde_derive" } petgraph = "0.6.2" png = "0.17.6" proc-macro-error = "1.0.4" @@ -161,8 +163,6 @@ serde_bytes = "0.11.8" serde_derive = "1.0.195" serde_json = "1.0.107" serde_test = "1.0.152" -serialize_hierarchy = { path = "crates/serialize_hierarchy" } -serialize_hierarchy_derive = { path = "crates/serialize_hierarchy_derive" } sha2 = "0.10.8" smallvec = "1.9.0" source_analyzer = { path = "crates/source_analyzer" } @@ -170,7 +170,7 @@ spl_network = { path = "crates/spl_network" } spl_network_messages = { path = "crates/spl_network_messages" } splines = { version = "4.2.0", features = ["serde"] } structopt = "0.3.26" -syn = { version = "1.0.101", features = ["full", "extra-traits"] } +syn = { version = "2.0.60", features = ["full", "extra-traits"] } systemd = "0.10.0" tempfile = "3.3.0" thiserror = "1.0.37" diff --git a/crates/approx_derive/src/lib.rs b/crates/approx_derive/src/lib.rs index 45bea69e92..fe241d369b 100644 --- a/crates/approx_derive/src/lib.rs +++ b/crates/approx_derive/src/lib.rs @@ -1,20 +1,18 @@ use proc_macro2::TokenStream; -use proc_macro_error::{abort, proc_macro_error, OptionExt, ResultExt}; +use proc_macro_error::{abort, proc_macro_error}; use quote::quote; -use syn::{ - parse_macro_input, - punctuated::{self}, - Attribute, Data, DeriveInput, Lit, Meta, MetaNameValue, NestedMeta, Type, -}; +use syn::{parse_macro_input, Attribute, Data, DeriveInput, Result, Type}; #[proc_macro_derive(AbsDiffEq, attributes(abs_diff_eq))] #[proc_macro_error] pub fn abs_diff_eq(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as DeriveInput); - generate_abs_diff_eq(input).into() + derive_abs_diff_eq(input) + .unwrap_or_else(syn::Error::into_compile_error) + .into() } -fn generate_abs_diff_eq(input: DeriveInput) -> TokenStream { +fn derive_abs_diff_eq(input: DeriveInput) -> Result { let fields = match input.data { Data::Struct(data) => data.fields, Data::Enum(data) => abort!( @@ -26,7 +24,7 @@ fn generate_abs_diff_eq(input: DeriveInput) -> TokenStream { "`AbsDiffEq` can only be derived for `struct`", ), }; - let epsilon = extract_epsilon(&input.attrs).expect_or_abort("`epsilon` not specified"); + let epsilon_type = extract_epsilon_type(&input.attrs)?; let name = input.ident; let conditions = fields.into_iter().map(|field| { @@ -39,9 +37,9 @@ fn generate_abs_diff_eq(input: DeriveInput) -> TokenStream { } }); - quote! { + Ok(quote! { impl approx::AbsDiffEq for #name { - type Epsilon = #epsilon; + type Epsilon = #epsilon_type; fn default_epsilon() -> Self::Epsilon { Self::Epsilon::default_epsilon() @@ -52,40 +50,28 @@ fn generate_abs_diff_eq(input: DeriveInput) -> TokenStream { true } } - } + }) } -fn extract_epsilon(attrs: &[Attribute]) -> Option { - attrs - .iter() - .filter_map(parse_meta_items) - .flatten() - .find_map(|meta| match meta { - NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, lit, .. })) - if path.is_ident("epsilon") => - { - let string = match lit { - Lit::Str(string) => string, - _ => abort!(lit, "expected string literal"), - }; - let epsilon = string - .parse() - .expect_or_abort("failed to parse epsilon type"); - Some(epsilon) - } - _ => None, - }) -} +fn extract_epsilon_type(attributes: &[Attribute]) -> Result> { + let mut epsilon_type = None; -fn parse_meta_items(attribute: &Attribute) -> Option> { - if !attribute.path.is_ident("abs_diff_eq") { - return None; - } - match attribute.parse_meta() { - Ok(Meta::List(meta)) => Some(meta.nested.into_iter()), - Ok(other) => abort!(other, "expected `#[abs_diff_eq(...)]`",), - Err(error) => abort!(error.span(), error.to_string()), + for attribute in attributes { + if !attribute.path().is_ident("abs_diff_eq") { + continue; + } + attribute.parse_nested_meta(|meta| { + if meta.path.is_ident("epsilon_type") { + let value = meta.value()?; + epsilon_type = Some(value.parse()?); + Ok(()) + } else { + Err(meta.error("unknown attribute")) + } + })?; } + + Ok(epsilon_type) } #[proc_macro_derive(RelativeEq)] diff --git a/crates/code_generation/src/cyclers.rs b/crates/code_generation/src/cyclers.rs index d100f3774b..e950a2e8ff 100644 --- a/crates/code_generation/src/cyclers.rs +++ b/crates/code_generation/src/cyclers.rs @@ -86,7 +86,13 @@ fn generate_cycler_instance(cycler: &Cycler) -> TokenStream { fn generate_database_struct() -> TokenStream { quote! { - #[derive(Default, serde::Deserialize, serde::Serialize, serialize_hierarchy::SerializeHierarchy)] + #[derive( + Default, + serde::Serialize, + serde::Deserialize, + path_serde::PathSerialize, + path_serde::PathIntrospect, + )] pub(crate) struct Database { pub main_outputs: MainOutputs, pub additional_outputs: AdditionalOutputs, diff --git a/crates/code_generation/src/structs.rs b/crates/code_generation/src/structs.rs index 8d58991fa2..d486ad2dae 100644 --- a/crates/code_generation/src/structs.rs +++ b/crates/code_generation/src/structs.rs @@ -4,18 +4,34 @@ use quote::{format_ident, quote}; use source_analyzer::{struct_hierarchy::StructHierarchy, structs::Structs}; pub fn generate_structs(structs: &Structs) -> TokenStream { + let parameters = hierarchy_to_token_stream( + &structs.parameters, + format_ident!("Parameters"), + "e! { + #[derive( + Clone, + Debug, + Default, + serde::Deserialize, + serde::Serialize, + path_serde::PathSerialize, + path_serde::PathDeserialize, + path_serde::PathIntrospect, + )] + }, + ); + let derives = quote! { #[derive( Clone, Debug, Default, - serde::Deserialize, serde::Serialize, - serialize_hierarchy::SerializeHierarchy, + serde::Deserialize, + path_serde::PathSerialize, + path_serde::PathIntrospect, )] }; - let parameters = - hierarchy_to_token_stream(&structs.parameters, format_ident!("Parameters"), &derives); let cyclers = structs .cyclers .iter() diff --git a/crates/communication/Cargo.toml b/crates/communication/Cargo.toml index 650abe17ca..a7b4c824bf 100644 --- a/crates/communication/Cargo.toml +++ b/crates/communication/Cargo.toml @@ -12,9 +12,9 @@ framework = { workspace = true, optional = true} futures-util = { workspace = true } log = { workspace = true } parameters = { workspace = true } +path_serde = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } -serialize_hierarchy = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true } tokio-tungstenite = { workspace = true } diff --git a/crates/communication/src/server/outputs/provider.rs b/crates/communication/src/server/outputs/provider.rs index dd1c06920a..bc15b264c4 100644 --- a/crates/communication/src/server/outputs/provider.rs +++ b/crates/communication/src/server/outputs/provider.rs @@ -1,5 +1,5 @@ use std::{ - collections::{hash_map::Entry, HashMap, HashSet}, + collections::{hash_map::Entry, BTreeSet, HashMap, HashSet}, num::Wrapping, sync::Arc, }; @@ -8,7 +8,7 @@ use bincode::{DefaultOptions, Options}; use framework::{Reader, Writer}; use futures_util::{stream::FuturesUnordered, StreamExt}; use log::error; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathIntrospect, PathSerialize}; use tokio::{ select, spawn, sync::{ @@ -36,15 +36,16 @@ pub fn provider( subscribed_outputs_writer: Writer>, ) -> JoinHandle<()> where - Outputs: SerializeHierarchy + Send + Sync + 'static, + Outputs: PathIntrospect + PathSerialize + Send + Sync + 'static, { spawn(async move { let (request_sender, mut request_receiver) = channel(1); + let fields = Outputs::get_fields(); outputs_sender .send(Request::RegisterCycler { cycler_instance: cycler_instance.to_string(), - fields: Outputs::get_fields(), + fields: fields.clone(), request_sender, }) .await @@ -58,10 +59,11 @@ where request = request_receiver.recv() => { match request { Some(request) => { - handle_client_request::( + handle_client_request( request, cycler_instance, &mut subscriptions, + &fields, ).await }, None => break, @@ -87,14 +89,12 @@ enum SubscriptionsState { Unchanged, } -async fn handle_client_request( +async fn handle_client_request( request: ClientRequest, cycler_instance: &'static str, subscriptions: &mut HashMap<(Client, usize), Subscription>, -) -> SubscriptionsState -where - Outputs: SerializeHierarchy, -{ + fields: &BTreeSet, +) -> SubscriptionsState { let is_get_next = matches!(request.request, OutputsRequest::GetNext { .. }); match request.request { OutputsRequest::GetFields { .. } => { @@ -113,50 +113,7 @@ where format, } => { assert_eq!(cycler_instance, received_cycler_instance); - if Outputs::exists(&path) { - match subscriptions.entry((request.client.clone(), id)) { - Entry::Occupied(_) => { - let error_message = format!("already subscribed with id {id}"); - request - .client - .response_sender - .send(Response::Textual(TextualResponse::Outputs( - if is_get_next { - TextualOutputsResponse::GetNext { - id, - result: Err(error_message), - } - } else { - TextualOutputsResponse::Subscribe { - id, - result: Err(error_message), - } - }, - ))) - .await - .expect("receiver should always wait for all senders"); - SubscriptionsState::Unchanged - } - Entry::Vacant(entry) => { - entry.insert(Subscription { - path, - format, - once: is_get_next, - }); - if !is_get_next { - request - .client - .response_sender - .send(Response::Textual(TextualResponse::Outputs( - TextualOutputsResponse::Subscribe { id, result: Ok(()) }, - ))) - .await - .expect("receiver should always wait for all senders"); - } - SubscriptionsState::Changed - } - } - } else { + if !fields.contains(&path) { request .client .response_sender @@ -168,7 +125,49 @@ where ))) .await .expect("receiver should always wait for all senders"); - SubscriptionsState::Unchanged + return SubscriptionsState::Unchanged; + } + match subscriptions.entry((request.client.clone(), id)) { + Entry::Occupied(_) => { + let error_message = format!("already subscribed with id {id}"); + request + .client + .response_sender + .send(Response::Textual(TextualResponse::Outputs( + if is_get_next { + TextualOutputsResponse::GetNext { + id, + result: Err(error_message), + } + } else { + TextualOutputsResponse::Subscribe { + id, + result: Err(error_message), + } + }, + ))) + .await + .expect("receiver should always wait for all senders"); + SubscriptionsState::Unchanged + } + Entry::Vacant(entry) => { + entry.insert(Subscription { + path, + format, + once: is_get_next, + }); + if !is_get_next { + request + .client + .response_sender + .send(Response::Textual(TextualResponse::Outputs( + TextualOutputsResponse::Subscribe { id, result: Ok(()) }, + ))) + .await + .expect("receiver should always wait for all senders"); + } + SubscriptionsState::Changed + } } } OutputsRequest::Unsubscribe { @@ -231,7 +230,7 @@ fn write_subscribed_outputs_from_subscriptions( } async fn handle_notified_output( - outputs_reader: &Reader, + outputs_reader: &Reader, subscriptions: &mut HashMap<(Client, usize), Subscription>, next_binary_reference_id: &mut Wrapping, ) -> SubscriptionsState { @@ -354,9 +353,9 @@ mod tests { use bincode::serialize; use framework::multiple_buffer_with_slots; - use serde::{de::Deserialize, Deserializer, Serialize, Serializer}; + use path_serde::serialize; + use serde::{Serialize, Serializer}; use serde_json::Value; - use serialize_hierarchy::Error; use tokio::{sync::mpsc::error::TryRecvError, task::yield_now, time::timeout}; use crate::messages::Format; @@ -367,43 +366,30 @@ mod tests { existing_fields: HashMap, } - impl SerializeHierarchy for OutputsFake + impl PathSerialize for OutputsFake where - for<'a> T: Deserialize<'a> + Serialize, + T: Serialize, { - fn serialize_path(&self, path: &str, serializer: S) -> Result> + fn serialize_path( + &self, + path: &str, + serializer: S, + ) -> Result> where S: Serializer, { self.existing_fields .get(path) - .ok_or(Error::UnexpectedPathSegment { - segment: path.to_string(), + .ok_or(serialize::Error::PathDoesNotExist { + path: path.to_owned(), })? .serialize(serializer) - .map_err(Error::SerializationFailed) - } - - fn deserialize_path<'de, D>( - &mut self, - path: &str, - deserializer: D, - ) -> Result<(), Error> - where - D: Deserializer<'de>, - { - self.existing_fields.insert( - path.to_string(), - T::deserialize(deserializer).map_err(Error::DeserializationFailed)?, - ); - Ok(()) - } - - fn exists(field_path: &str) -> bool { - field_path == "a.b.c" + .map_err(serialize::Error::SerializationFailed) } + } - fn fill_fields(fields: &mut BTreeSet, _prefix: &str) { + impl PathIntrospect for OutputsFake { + fn extend_with_fields(fields: &mut BTreeSet, _prefix: &str) { fields.insert("a".to_string()); fields.insert("a.b".to_string()); fields.insert("a.b.c".to_string()); @@ -413,7 +399,7 @@ mod tests { async fn get_registered_request_sender_from_provider( cycler_instance: &'static str, outputs_changed: Arc, - output: Reader, + output: Reader, ) -> ( JoinHandle<()>, BTreeSet, diff --git a/crates/communication/src/server/parameters/storage.rs b/crates/communication/src/server/parameters/storage.rs index b8d9ddc330..dc9f6247eb 100644 --- a/crates/communication/src/server/parameters/storage.rs +++ b/crates/communication/src/server/parameters/storage.rs @@ -2,8 +2,8 @@ use std::{path::Path, sync::Arc}; use framework::Writer; use parameters::directory::{deserialize, serialize}; +use path_serde::{PathDeserialize, PathSerialize}; use serde::{de::DeserializeOwned, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use tokio::{ spawn, sync::{mpsc::Receiver, Notify}, @@ -26,7 +26,14 @@ pub fn storage( head_id: String, ) -> JoinHandle<()> where - Parameters: Clone + DeserializeOwned + Send + Serialize + SerializeHierarchy + Sync + 'static, + Parameters: 'static + + Clone + + DeserializeOwned + + PathDeserialize + + PathSerialize + + Send + + Serialize + + Sync, { spawn(async move { let mut parameters = (*parameters_writer.next()).clone(); @@ -54,7 +61,7 @@ async fn handle_request( body_id: &str, head_id: &str, ) where - Parameters: Clone + DeserializeOwned + Serialize + SerializeHierarchy, + Parameters: Clone + DeserializeOwned + Serialize + PathSerialize + PathDeserialize, { match request { StorageRequest::UpdateParameter { @@ -63,18 +70,6 @@ async fn handle_request( path, data, } => { - if !Parameters::exists(&path) { - respond( - client, - ParametersResponse::Update { - id, - result: Err(format!("path {path:?} does not exist")), - }, - ) - .await; - return; - } - if let Err(error) = parameters.deserialize_path(&path, data) { respond( client, @@ -169,12 +164,12 @@ async fn respond(client: Client, response: ParametersResponse) { #[cfg(test)] mod tests { - use std::collections::{BTreeSet, HashMap}; + use std::collections::HashMap; use framework::multiple_buffer_with_slots; + use path_serde::{deserialize, serialize, PathDeserialize}; use serde::{Deserialize, Deserializer, Serializer}; use serde_json::Value; - use serialize_hierarchy::Error; use tokio::sync::mpsc::{channel, error::TryRecvError}; use crate::server::client::Client; @@ -204,47 +199,46 @@ mod tests { existing_fields: HashMap, } - impl SerializeHierarchy for ParametersFake + impl PathSerialize for ParametersFake where - T: DeserializeOwned + Serialize, + T: Serialize, { - fn serialize_path(&self, path: &str, serializer: S) -> Result> + fn serialize_path( + &self, + path: &str, + serializer: S, + ) -> Result> where S: Serializer, { self.existing_fields .get(path) - .ok_or(Error::UnexpectedPathSegment { - segment: path.to_string(), + .ok_or(serialize::Error::PathDoesNotExist { + path: path.to_string(), })? .serialize(serializer) - .map_err(Error::SerializationFailed) + .map_err(serialize::Error::SerializationFailed) } + } + impl PathDeserialize for ParametersFake + where + for<'de> T: Deserialize<'de>, + { fn deserialize_path<'de, D>( &mut self, path: &str, deserializer: D, - ) -> Result<(), Error> + ) -> Result<(), deserialize::Error> where D: Deserializer<'de>, { self.existing_fields.insert( path.to_string(), - T::deserialize(deserializer).map_err(Error::DeserializationFailed)?, + T::deserialize(deserializer).map_err(deserialize::Error::DeserializationFailed)?, ); Ok(()) } - - fn exists(field_path: &str) -> bool { - field_path == "a.b.c" - } - - fn fill_fields(fields: &mut BTreeSet, _prefix: &str) { - fields.insert("a".to_string()); - fields.insert("a.b".to_string()); - fields.insert("a.b.c".to_string()); - } } #[tokio::test] diff --git a/crates/communication/src/server/parameters/subscriptions.rs b/crates/communication/src/server/parameters/subscriptions.rs index 60b0b59286..a2adecf057 100644 --- a/crates/communication/src/server/parameters/subscriptions.rs +++ b/crates/communication/src/server/parameters/subscriptions.rs @@ -6,7 +6,7 @@ use std::{ use framework::Reader; use futures_util::{stream::FuturesUnordered, StreamExt}; use log::error; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathIntrospect, PathSerialize}; use tokio::{ select, spawn, sync::{ @@ -30,7 +30,7 @@ pub fn subscriptions( storage_request_sender: Sender, ) -> JoinHandle<()> where - Parameters: Send + SerializeHierarchy + Sync + 'static, + Parameters: Send + PathSerialize + Sync + 'static + PathIntrospect, { spawn(async move { let fields = Parameters::get_fields(); @@ -65,7 +65,7 @@ async fn handle_request( subscriptions: &mut HashMap<(Client, usize), Path>, fields: &BTreeSet, ) where - Parameters: SerializeHierarchy, + Parameters: PathSerialize, { match request.request { ParametersRequest::GetFields { id } => { @@ -107,7 +107,7 @@ async fn handle_request( .await; } ParametersRequest::Subscribe { id, ref path } => { - if !Parameters::exists(path) { + if !fields.contains(path) { let error_message = format!("path {path:?} does not exist"); respond( request, @@ -236,7 +236,7 @@ async fn handle_changed_parameters( parameters_reader: &Reader, subscriptions: &HashMap<(Client, usize), Path>, ) where - Parameters: SerializeHierarchy, + Parameters: PathSerialize, { let items: HashMap<_, _> = { let parameters = parameters_reader.next(); @@ -283,9 +283,9 @@ async fn handle_changed_parameters( mod tests { use framework::multiple_buffer_with_slots; use parameters::directory::{Id, Location, Scope}; - use serde::{de::DeserializeOwned, Deserializer, Serialize, Serializer}; + use path_serde::serialize; + use serde::{Serialize, Serializer}; use serde_json::Value; - use serialize_hierarchy::Error; use tokio::{ sync::mpsc::{channel, error::TryRecvError}, task::yield_now, @@ -355,43 +355,30 @@ mod tests { existing_fields: HashMap, } - impl SerializeHierarchy for ParametersFake + impl PathSerialize for ParametersFake where - T: DeserializeOwned + Serialize, + T: Serialize, { - fn serialize_path(&self, path: &str, serializer: S) -> Result> + fn serialize_path( + &self, + path: &str, + serializer: S, + ) -> Result> where S: Serializer, { self.existing_fields .get(path) - .ok_or(Error::UnexpectedPathSegment { - segment: path.to_string(), + .ok_or(serialize::Error::PathDoesNotExist { + path: path.to_string(), })? .serialize(serializer) - .map_err(Error::SerializationFailed) - } - - fn deserialize_path<'de, D>( - &mut self, - path: &str, - deserializer: D, - ) -> Result<(), Error> - where - D: Deserializer<'de>, - { - self.existing_fields.insert( - path.to_string(), - T::deserialize(deserializer).map_err(Error::DeserializationFailed)?, - ); - Ok(()) - } - - fn exists(field_path: &str) -> bool { - field_path == "a.b.c" + .map_err(serialize::Error::SerializationFailed) } + } - fn fill_fields(fields: &mut BTreeSet, _prefix: &str) { + impl PathIntrospect for ParametersFake { + fn extend_with_fields(fields: &mut BTreeSet, _prefix: &str) { fields.insert("a".to_string()); fields.insert("a.b".to_string()); fields.insert("a.b.c".to_string()); diff --git a/crates/communication/src/server/runtime.rs b/crates/communication/src/server/runtime.rs index 3c549b0466..64b8895e1e 100644 --- a/crates/communication/src/server/runtime.rs +++ b/crates/communication/src/server/runtime.rs @@ -10,8 +10,8 @@ use std::{ use framework::{multiple_buffer_with_slots, Reader, Writer}; use parameters::directory::{deserialize, DirectoryError}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{de::DeserializeOwned, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use tokio::{ net::ToSocketAddrs, runtime::{self, Runtime as TokioRuntime}, @@ -54,7 +54,15 @@ pub struct Runtime { impl Runtime where - Parameters: Clone + DeserializeOwned + Send + Serialize + SerializeHierarchy + Sync + 'static, + Parameters: 'static + + DeserializeOwned + + PathDeserialize + + PathIntrospect + + PathSerialize + + Send + + Serialize + + Sync + + Clone, { pub fn start( addresses: Option, @@ -204,7 +212,7 @@ where outputs_reader: Reader, subscribed_outputs_writer: Writer>, ) where - Outputs: SerializeHierarchy + Send + Sync + 'static, + Outputs: Send + Sync + 'static + PathSerialize + PathIntrospect, { let _guard = self.runtime.enter(); provider( diff --git a/crates/context_attribute/src/lib.rs b/crates/context_attribute/src/lib.rs index 3d9b77b88d..e24c0ea311 100644 --- a/crates/context_attribute/src/lib.rs +++ b/crates/context_attribute/src/lib.rs @@ -8,7 +8,7 @@ use syn::{ spanned::Spanned, token::Mut, AngleBracketedGenericArguments, Expr, ExprLit, GenericArgument, GenericParam, ItemStruct, - Lifetime, LifetimeDef, Lit, Path, PathArguments, PathSegment, Type, TypeParam, TypePath, + Lifetime, LifetimeParam, Lit, Path, PathArguments, PathSegment, Type, TypeParam, TypePath, TypeReference, }; @@ -188,7 +188,7 @@ pub fn context(_attributes: TokenStream, input: TokenStream) -> TokenStream { if requires_lifetime_parameter { struct_item.generics.params.insert( 0, - GenericParam::Lifetime(LifetimeDef::new(Lifetime::new( + GenericParam::Lifetime(LifetimeParam::new(Lifetime::new( "'context", Span::call_site(), ))), diff --git a/crates/control/Cargo.toml b/crates/control/Cargo.toml index 6ae0c057ec..b1cbaed33f 100644 --- a/crates/control/Cargo.toml +++ b/crates/control/Cargo.toml @@ -24,10 +24,10 @@ motionfile = { workspace = true } nalgebra = { workspace = true } num-traits = {workspace = true} ordered-float = { workspace = true } +path_serde = { workspace = true } projection = { workspace = true } rand = {workspace = true} serde = { workspace = true } -serialize_hierarchy = { workspace = true } smallvec = { workspace = true } spl_network_messages = { workspace = true } splines = { workspace = true } diff --git a/crates/control/src/motion/obstacle_avoiding_arms.rs b/crates/control/src/motion/obstacle_avoiding_arms.rs index a79c2844ab..69b813b091 100644 --- a/crates/control/src/motion/obstacle_avoiding_arms.rs +++ b/crates/control/src/motion/obstacle_avoiding_arms.rs @@ -4,8 +4,8 @@ use color_eyre::Result; use context_attribute::context; use framework::MainOutput; use motionfile::{SplineInterpolator, TimedSpline}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::{ cycle_time::CycleTime, joints::{arm::ArmJoints, mirror::Mirror as _}, @@ -81,7 +81,9 @@ impl ObstacleAvoidingArms { } } -#[derive(Clone, Debug, Serialize, Deserialize, SerializeHierarchy, Default)] +#[derive( + Clone, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, Default, +)] pub enum Arm { #[default] Swing, diff --git a/crates/coordinate_systems/Cargo.toml b/crates/coordinate_systems/Cargo.toml index 85dcf017f5..b418fe9713 100644 --- a/crates/coordinate_systems/Cargo.toml +++ b/crates/coordinate_systems/Cargo.toml @@ -10,5 +10,5 @@ homepage.workspace = true [dependencies] approx = { workspace = true } approx_derive = { workspace = true } +path_serde = { workspace = true } serde = { workspace = true } -serialize_hierarchy = { workspace = true } diff --git a/crates/coordinate_systems/src/lib.rs b/crates/coordinate_systems/src/lib.rs index f1a8694db0..bb70e597aa 100644 --- a/crates/coordinate_systems/src/lib.rs +++ b/crates/coordinate_systems/src/lib.rs @@ -1,6 +1,6 @@ use approx_derive::{AbsDiffEq, RelativeEq}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; macro_rules! generate_coordinate_system { ($($(#[$doc:meta])* $i:ident),* $(,)?) => { @@ -17,9 +17,11 @@ macro_rules! generate_coordinate_system { Serialize, RelativeEq, AbsDiffEq, - SerializeHierarchy + PathSerialize, + PathDeserialize, + PathIntrospect, )] - #[abs_diff_eq(epsilon = "f32")] + #[abs_diff_eq(epsilon_type = f32)] $(#[$doc])* pub struct $i; )* diff --git a/crates/energy_optimization/Cargo.toml b/crates/energy_optimization/Cargo.toml index f5f84efef6..3731401050 100644 --- a/crates/energy_optimization/Cargo.toml +++ b/crates/energy_optimization/Cargo.toml @@ -6,7 +6,7 @@ license.workspace = true homepage.workspace = true [dependencies] +filtering = { workspace = true } +path_serde = { workspace = true } serde = { workspace = true } -serialize_hierarchy = { workspace = true } types = { workspace = true } -filtering = { workspace = true } diff --git a/crates/energy_optimization/src/current_minimizer.rs b/crates/energy_optimization/src/current_minimizer.rs index 5d44950ee0..01b3e43a3a 100644 --- a/crates/energy_optimization/src/current_minimizer.rs +++ b/crates/energy_optimization/src/current_minimizer.rs @@ -1,18 +1,38 @@ use filtering::hysteresis::less_than_with_hysteresis; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::{cycle_time::CycleTime, joints::Joints}; use crate::parameters::CurrentMinimizerParameters; -#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] enum State { #[default] Optimizing, Resetting, } -#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct CurrentMinimizer { minimum_reached: bool, position_offset: Joints, diff --git a/crates/energy_optimization/src/parameters.rs b/crates/energy_optimization/src/parameters.rs index f2012c1b8b..7b66ba030d 100644 --- a/crates/energy_optimization/src/parameters.rs +++ b/crates/energy_optimization/src/parameters.rs @@ -1,8 +1,18 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::joints::Joints; -#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Copy, + Clone, + Debug, + Default, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct CurrentMinimizerParameters { pub reset_threshold: f32, pub reset_speed: f32, diff --git a/crates/geometry/Cargo.toml b/crates/geometry/Cargo.toml index 737a2e54b9..2d7699969f 100644 --- a/crates/geometry/Cargo.toml +++ b/crates/geometry/Cargo.toml @@ -10,5 +10,5 @@ approx = { workspace = true } approx_derive = { workspace = true } linear_algebra = { workspace = true } nalgebra = { workspace = true } +path_serde = { workspace = true } serde = { workspace = true } -serialize_hierarchy = { workspace = true } diff --git a/crates/geometry/src/arc.rs b/crates/geometry/src/arc.rs index cf8c0eb5fe..4ccf686751 100644 --- a/crates/geometry/src/arc.rs +++ b/crates/geometry/src/arc.rs @@ -1,14 +1,25 @@ use std::f32::consts::TAU; use approx::{AbsDiffEq, RelativeEq}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; use linear_algebra::Point2; -use serialize_hierarchy::SerializeHierarchy; use crate::{circle::Circle, direction::Direction}; -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + PartialEq, + PathDeserialize, + PathIntrospect, + PathSerialize, + Serialize, +)] pub struct Arc { pub circle: Circle, pub start: Point2, diff --git a/crates/geometry/src/circle.rs b/crates/geometry/src/circle.rs index a7fe48a5d1..4a1137b982 100644 --- a/crates/geometry/src/circle.rs +++ b/crates/geometry/src/circle.rs @@ -1,18 +1,28 @@ use std::f32::consts::TAU; use approx::{AbsDiffEq, RelativeEq}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; use linear_algebra::{distance, vector, Point2}; -use serialize_hierarchy::SerializeHierarchy; use crate::{ arc::Arc, circle_tangents::CircleTangents, direction::Direction, line_segment::LineSegment, rectangle::Rectangle, two_line_segments::TwoLineSegments, }; -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, SerializeHierarchy)] -#[serde(bound = "")] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + PartialEq, + PathDeserialize, + PathIntrospect, + PathSerialize, + Serialize, +)] pub struct Circle { pub center: Point2, pub radius: f32, diff --git a/crates/geometry/src/circle_tangents.rs b/crates/geometry/src/circle_tangents.rs index 5eec7d7e8c..ee4f83387b 100644 --- a/crates/geometry/src/circle_tangents.rs +++ b/crates/geometry/src/circle_tangents.rs @@ -1,13 +1,14 @@ use std::cmp::PartialEq; use approx::{AbsDiffEq, RelativeEq}; +use path_serde::{PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::{line_segment::LineSegment, two_line_segments::TwoLineSegments}; -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, SerializeHierarchy)] -#[serialize_hierarchy(bound = "for <'de> Frame: Serialize + Deserialize<'de>")] +#[derive( + Clone, Copy, Debug, Default, Deserialize, PartialEq, PathIntrospect, PathSerialize, Serialize, +)] pub struct CircleTangents { pub inner: Option>, pub outer: TwoLineSegments, diff --git a/crates/geometry/src/line_segment.rs b/crates/geometry/src/line_segment.rs index 2c3576cad9..e24226c121 100644 --- a/crates/geometry/src/line_segment.rs +++ b/crates/geometry/src/line_segment.rs @@ -1,13 +1,25 @@ use std::{cmp::PartialEq, f32::consts::TAU}; use approx::{AbsDiffEq, RelativeEq}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; use linear_algebra::{vector, Point2, Vector2}; use crate::{arc::Arc, direction::Direction}; -#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + Serialize, + PartialEq, + PathSerialize, + PathIntrospect, + PathDeserialize, +)] pub struct LineSegment(pub Point2, pub Point2); impl AbsDiffEq for LineSegment diff --git a/crates/geometry/src/rectangle.rs b/crates/geometry/src/rectangle.rs index 11afc8fb81..93a225d6f6 100644 --- a/crates/geometry/src/rectangle.rs +++ b/crates/geometry/src/rectangle.rs @@ -1,9 +1,19 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; use linear_algebra::{Point2, Vector2}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + PartialEq, + PathDeserialize, + PathIntrospect, + PathSerialize, + Serialize, +)] pub struct Rectangle { pub min: Point2, pub max: Point2, diff --git a/crates/geometry/src/two_line_segments.rs b/crates/geometry/src/two_line_segments.rs index 9f74680dde..85f3bcc45d 100644 --- a/crates/geometry/src/two_line_segments.rs +++ b/crates/geometry/src/two_line_segments.rs @@ -1,45 +1,18 @@ -use std::{cmp::PartialEq, collections::BTreeSet}; - -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use serialize_hierarchy::{Error, SerializeHierarchy}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; +use serde::{Deserialize, Serialize}; use crate::line_segment::LineSegment; -#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + Serialize, + PartialEq, + PathSerialize, + PathIntrospect, + PathDeserialize, +)] pub struct TwoLineSegments(pub LineSegment, pub LineSegment); - -impl SerializeHierarchy for TwoLineSegments { - fn serialize_path(&self, path: &str, _serializer: S) -> Result> - where - S: Serializer, - { - Err(Error::TypeDoesNotSupportSerialization { - type_name: "TwoLineSegments", - path: path.to_string(), - }) - } - - fn deserialize_path<'de, D>( - &mut self, - path: &str, - _deserializer: D, - ) -> Result<(), Error> - where - D: Deserializer<'de>, - { - Err(Error::TypeDoesNotSupportDeserialization { - type_name: "TwoLineSegments", - path: path.to_string(), - }) - } - - fn exists(_path: &str) -> bool { - false - } - - fn get_fields() -> BTreeSet { - Default::default() - } - - fn fill_fields(_fields: &mut BTreeSet, _prefix: &str) {} -} diff --git a/crates/hulk/Cargo.toml b/crates/hulk/Cargo.toml index 48e2c4ce07..5ecf8f9bfc 100644 --- a/crates/hulk/Cargo.toml +++ b/crates/hulk/Cargo.toml @@ -20,11 +20,11 @@ ittapi = { workspace = true } libc = { workspace = true, optional = true } linear_algebra = { workspace = true } nalgebra = { workspace = true } -projection = { workspace = true } object_detection = { workspace = true } +path_serde = { workspace = true } +projection = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } -serialize_hierarchy = { workspace = true } spl_network = { workspace = true } spl_network_messages = { workspace = true } systemd = { workspace = true, optional = true } diff --git a/crates/hulk_replayer/Cargo.toml b/crates/hulk_replayer/Cargo.toml index 15b427fa67..bc299814e6 100644 --- a/crates/hulk_replayer/Cargo.toml +++ b/crates/hulk_replayer/Cargo.toml @@ -8,11 +8,11 @@ homepage.workspace = true [dependencies] audio = { workspace = true } bincode = { workspace = true } +chrono = { workspace = true } color-eyre = { workspace = true } communication = { workspace = true, features = ["server"] } control = { workspace = true } coordinate_systems = { workspace = true } -chrono = { workspace = true } ctrlc = { workspace = true } derive_more = { workspace = true } eframe = { workspace = true } @@ -24,10 +24,10 @@ ittapi = { workspace = true } linear_algebra = { workspace = true } nalgebra = { workspace = true } object_detection = { workspace = true } +path_serde = { workspace = true } projection = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } -serialize_hierarchy = { workspace = true } spl_network = { workspace = true } spl_network_messages = { workspace = true } tokio = { workspace = true } diff --git a/crates/linear_algebra/Cargo.toml b/crates/linear_algebra/Cargo.toml index c546a42429..9bcdcd9f5f 100644 --- a/crates/linear_algebra/Cargo.toml +++ b/crates/linear_algebra/Cargo.toml @@ -9,5 +9,5 @@ homepage = "https://github.com/hulks/hulk" approx = { workspace = true } nalgebra = { workspace = true } num-traits = { workspace = true } +path_serde = { workspace = true } serde = { workspace = true } -serialize_hierarchy = { workspace = true } diff --git a/crates/linear_algebra/src/framed.rs b/crates/linear_algebra/src/framed.rs index 03c046dac4..0f18f63765 100644 --- a/crates/linear_algebra/src/framed.rs +++ b/crates/linear_algebra/src/framed.rs @@ -1,8 +1,9 @@ use approx::{AbsDiffEq, RelativeEq}; use num_traits::Num; +use path_serde::{deserialize, serialize, PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use std::{ + collections::BTreeSet, hash::{Hash, Hasher}, iter::Sum, marker::PhantomData, @@ -163,38 +164,44 @@ where } } -impl SerializeHierarchy for Framed +impl PathSerialize for Framed where - Inner: SerializeHierarchy, + Inner: PathSerialize, { fn serialize_path( &self, path: &str, serializer: S, - ) -> Result> + ) -> Result> where S: serde::Serializer, { self.inner.serialize_path(path, serializer) } +} +impl PathDeserialize for Framed +where + Inner: PathDeserialize, +{ fn deserialize_path<'de, D>( &mut self, path: &str, deserializer: D, - ) -> Result<(), serialize_hierarchy::Error> + ) -> Result<(), deserialize::Error> where D: serde::Deserializer<'de>, { self.inner.deserialize_path(path, deserializer) } +} - fn exists(path: &str) -> bool { - Inner::exists(path) - } - - fn fill_fields(fields: &mut std::collections::BTreeSet, prefix: &str) { - Inner::fill_fields(fields, prefix) +impl PathIntrospect for Framed +where + Inner: PathIntrospect, +{ + fn extend_with_fields(fields: &mut BTreeSet, prefix: &str) { + Inner::extend_with_fields(fields, prefix) } } diff --git a/crates/linear_algebra/src/transform.rs b/crates/linear_algebra/src/transform.rs index 7fc9cb9ca1..39ad5e432c 100644 --- a/crates/linear_algebra/src/transform.rs +++ b/crates/linear_algebra/src/transform.rs @@ -1,8 +1,8 @@ use std::{marker::PhantomData, ops::Mul}; use approx::{AbsDiffEq, RelativeEq}; +use path_serde::{deserialize, serialize, PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::framed::Framed; @@ -159,37 +159,43 @@ where } } -impl SerializeHierarchy for Transform +impl PathSerialize for Transform where - Inner: SerializeHierarchy, + Inner: PathSerialize, { fn serialize_path( &self, path: &str, serializer: S, - ) -> Result> + ) -> Result> where S: serde::Serializer, { self.inner.serialize_path(path, serializer) } +} +impl PathDeserialize for Transform +where + Inner: PathDeserialize, +{ fn deserialize_path<'de, D>( &mut self, path: &str, deserializer: D, - ) -> Result<(), serialize_hierarchy::Error> + ) -> Result<(), deserialize::Error> where D: serde::Deserializer<'de>, { self.inner.deserialize_path(path, deserializer) } +} - fn exists(path: &str) -> bool { - Inner::exists(path) - } - - fn fill_fields(fields: &mut std::collections::BTreeSet, prefix: &str) { - Inner::fill_fields(fields, prefix) +impl PathIntrospect for Transform +where + Inner: PathIntrospect, +{ + fn extend_with_fields(fields: &mut std::collections::BTreeSet, prefix: &str) { + Inner::extend_with_fields(fields, prefix) } } diff --git a/crates/serialize_hierarchy/Cargo.toml b/crates/path_serde/Cargo.toml similarity index 60% rename from crates/serialize_hierarchy/Cargo.toml rename to crates/path_serde/Cargo.toml index a04f9defb5..181a0ba287 100644 --- a/crates/serialize_hierarchy/Cargo.toml +++ b/crates/path_serde/Cargo.toml @@ -1,14 +1,12 @@ [package] -name = "serialize_hierarchy" +name = "path_serde" version.workspace = true edition.workspace = true license.workspace = true homepage.workspace = true [dependencies] -bincode = { workspace = true } nalgebra = { workspace = true } serde = { workspace = true } -serde_json = { workspace = true } -serialize_hierarchy_derive = { workspace = true } +path_serde_derive = { workspace = true } thiserror = { workspace = true } diff --git a/crates/path_serde/src/deserialize.rs b/crates/path_serde/src/deserialize.rs new file mode 100644 index 0000000000..92bba0aa97 --- /dev/null +++ b/crates/path_serde/src/deserialize.rs @@ -0,0 +1,22 @@ +use serde::Deserializer; + +#[derive(Debug, thiserror::Error)] +pub enum Error +where + E: std::error::Error, +{ + #[error("failed to deserialize")] + DeserializationFailed(#[source] E), + #[error("path `{path}` does not exist")] + PathDoesNotExist { path: String }, +} + +pub trait PathDeserialize { + fn deserialize_path<'de, D>( + &mut self, + path: &str, + deserializer: D, + ) -> Result<(), Error> + where + D: Deserializer<'de>; +} diff --git a/crates/path_serde/src/implementation.rs b/crates/path_serde/src/implementation.rs new file mode 100644 index 0000000000..17842c3e15 --- /dev/null +++ b/crates/path_serde/src/implementation.rs @@ -0,0 +1,311 @@ +use std::{ + collections::BTreeSet, + ops::{Deref, DerefMut, Range}, + sync::Arc, +}; + +use nalgebra::{ArrayStorage, Const, Matrix, Point, Scalar, U1}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use crate::{deserialize, serialize, PathDeserialize, PathIntrospect, PathSerialize}; + +impl PathSerialize for Box +where + T: PathSerialize, +{ + fn serialize_path( + &self, + path: &str, + serializer: S, + ) -> Result> + where + S: Serializer, + { + self.deref().serialize_path(path, serializer) + } +} + +impl PathDeserialize for Box +where + T: PathDeserialize, +{ + fn deserialize_path<'de, D>( + &mut self, + path: &str, + deserializer: D, + ) -> Result<(), deserialize::Error> + where + D: Deserializer<'de>, + { + self.deref_mut().deserialize_path(path, deserializer) + } +} + +impl PathIntrospect for Box +where + T: PathIntrospect, +{ + fn extend_with_fields(fields: &mut BTreeSet, prefix: &str) { + T::extend_with_fields(fields, prefix) + } +} + +impl PathSerialize for Arc +where + T: PathSerialize, +{ + fn serialize_path( + &self, + path: &str, + serializer: S, + ) -> Result> + where + S: Serializer, + { + self.deref().serialize_path(path, serializer) + } +} + +impl PathIntrospect for Arc +where + T: PathIntrospect, +{ + fn extend_with_fields(fields: &mut BTreeSet, prefix: &str) { + T::extend_with_fields(fields, prefix) + } +} + +impl PathSerialize for Option +where + T: PathSerialize, +{ + fn serialize_path( + &self, + path: &str, + serializer: S, + ) -> Result> + where + S: Serializer, + { + match self { + Some(some) => some.serialize_path(path, serializer), + None => (None as Option<()>) + .serialize(serializer) + .map_err(serialize::Error::SerializationFailed), + } + } +} + +impl PathDeserialize for Option +where + T: PathDeserialize + Default, +{ + fn deserialize_path<'de, D>( + &mut self, + path: &str, + deserializer: D, + ) -> Result<(), deserialize::Error> + where + D: Deserializer<'de>, + { + match self { + Some(some) => some.deserialize_path(path, deserializer), + None => { + let mut value = T::default(); + value.deserialize_path(path, deserializer)?; + *self = Some(value); + Ok(()) + } + } + } +} + +impl PathIntrospect for Option +where + T: PathIntrospect, +{ + fn extend_with_fields(fields: &mut BTreeSet, prefix: &str) { + T::extend_with_fields(fields, prefix) + } +} + +impl PathSerialize for Range +where + T: PathSerialize + Serialize, +{ + fn serialize_path( + &self, + path: &str, + serializer: S, + ) -> Result> + where + S: Serializer, + { + let split = path.split_once('.'); + match (path, split) { + (_, Some(("start", suffix))) => self.start.serialize_path(suffix, serializer), + (_, Some(("end", suffix))) => self.end.serialize_path(suffix, serializer), + ("start", None) => self + .start + .serialize(serializer) + .map_err(serialize::Error::SerializationFailed), + ("end", None) => self + .end + .serialize(serializer) + .map_err(serialize::Error::SerializationFailed), + _ => Err(serialize::Error::PathDoesNotExist { + path: path.to_owned(), + }), + } + } +} + +impl PathDeserialize for Range +where + T: PathDeserialize, + for<'de> T: Deserialize<'de>, +{ + fn deserialize_path<'de, D>( + &mut self, + path: &str, + deserializer: D, + ) -> Result<(), deserialize::Error> + where + D: Deserializer<'de>, + { + let split = path.split_once('.'); + match (path, split) { + (_, Some(("start", suffix))) => self.start.deserialize_path(suffix, deserializer), + (_, Some(("end", suffix))) => self.end.deserialize_path(suffix, deserializer), + ("start", None) => { + self.start = T::deserialize(deserializer) + .map_err(deserialize::Error::DeserializationFailed)?; + Ok(()) + } + ("end", None) => { + self.end = T::deserialize(deserializer) + .map_err(deserialize::Error::DeserializationFailed)?; + Ok(()) + } + _ => Err(deserialize::Error::PathDoesNotExist { + path: path.to_owned(), + }), + } + } +} + +impl PathIntrospect for Range +where + T: PathIntrospect, +{ + fn extend_with_fields(fields: &mut BTreeSet, prefix: &str) { + fields.insert(format!("{prefix}start")); + fields.insert(format!("{prefix}end")); + } +} + +impl PathSerialize for Matrix, U1, ArrayStorage> +where + T: PathSerialize + Serialize, +{ + fn serialize_path( + &self, + path: &str, + serializer: S, + ) -> Result> + where + S: Serializer, + { + let index = ["x", "y", "z", "w", "v", "u"][0..N] + .iter() + .position(|name| name == &path); + match index { + Some(index) => self[index] + .serialize(serializer) + .map_err(serialize::Error::SerializationFailed), + _ => Err(serialize::Error::PathDoesNotExist { + path: path.to_owned(), + }), + } + } +} + +impl PathDeserialize for Matrix, U1, ArrayStorage> +where + T: PathDeserialize, + for<'de> T: Deserialize<'de>, +{ + fn deserialize_path<'de, D>( + &mut self, + path: &str, + deserializer: D, + ) -> Result<(), deserialize::Error> + where + D: Deserializer<'de>, + { + let index = ["x", "y", "z", "w", "v", "u"][0..N] + .iter() + .position(|name| name == &path); + match index { + Some(index) => { + let deserialized = ::deserialize(deserializer) + .map_err(deserialize::Error::DeserializationFailed)?; + self[index] = deserialized; + Ok(()) + } + None => Err(deserialize::Error::PathDoesNotExist { + path: path.to_owned(), + }), + } + } +} + +impl PathIntrospect for Matrix, U1, ArrayStorage> { + fn extend_with_fields(fields: &mut BTreeSet, prefix: &str) { + for field in &["x", "y", "z", "w", "v", "u"][0..N] { + fields.insert(format!("{prefix}{field}")); + } + } +} + +impl PathSerialize for Point +where + T: PathSerialize + Scalar + Serialize, +{ + fn serialize_path( + &self, + path: &str, + serializer: S, + ) -> Result> + where + S: Serializer, + { + self.coords.serialize_path(path, serializer) + } +} + +impl PathDeserialize for Point +where + T: PathDeserialize + Scalar, + for<'de> T: Deserialize<'de>, +{ + fn deserialize_path<'de, D>( + &mut self, + path: &str, + deserializer: D, + ) -> Result<(), deserialize::Error> + where + D: Deserializer<'de>, + { + self.coords.deserialize_path(path, deserializer) + } +} + +impl PathIntrospect for Point +where + T: PathIntrospect + Scalar, +{ + fn extend_with_fields(fields: &mut BTreeSet, prefix: &str) { + Matrix::, U1, ArrayStorage>::extend_with_fields(fields, prefix) + } +} diff --git a/crates/path_serde/src/introspect.rs b/crates/path_serde/src/introspect.rs new file mode 100644 index 0000000000..f1e1330c08 --- /dev/null +++ b/crates/path_serde/src/introspect.rs @@ -0,0 +1,11 @@ +use std::collections::BTreeSet; + +pub trait PathIntrospect { + fn get_fields() -> BTreeSet { + let mut fields = BTreeSet::default(); + Self::extend_with_fields(&mut fields, ""); + fields + } + + fn extend_with_fields(fields: &mut BTreeSet, prefix: &str); +} diff --git a/crates/path_serde/src/lib.rs b/crates/path_serde/src/lib.rs new file mode 100644 index 0000000000..a5787f98a6 --- /dev/null +++ b/crates/path_serde/src/lib.rs @@ -0,0 +1,10 @@ +pub use deserialize::PathDeserialize; +pub use introspect::PathIntrospect; +pub use path_serde_derive::{PathDeserialize, PathIntrospect, PathSerialize}; +pub use serialize::PathSerialize; + +pub mod deserialize; +mod implementation; +pub mod introspect; +mod not_supported; +pub mod serialize; diff --git a/crates/serialize_hierarchy/src/not_supported.rs b/crates/path_serde/src/not_supported.rs similarity index 69% rename from crates/serialize_hierarchy/src/not_supported.rs rename to crates/path_serde/src/not_supported.rs index 02fa81fd66..40e5a6b108 100644 --- a/crates/serialize_hierarchy/src/not_supported.rs +++ b/crates/path_serde/src/not_supported.rs @@ -5,84 +5,79 @@ use std::{ time::{Duration, SystemTime}, }; +use crate::{deserialize, serialize, PathDeserialize, PathIntrospect, PathSerialize}; use nalgebra::{DMatrix, Isometry2, Isometry3, Rotation3, SMatrix, UnitComplex, UnitQuaternion}; use serde::{Deserializer, Serializer}; -use crate::{error::Error, SerializeHierarchy}; - macro_rules! implement_as_not_supported { ($type:ty) => { - impl SerializeHierarchy for $type { + impl PathSerialize for $type { fn serialize_path( &self, path: &str, _serializer: S, - ) -> Result> + ) -> Result> where S: Serializer, { - Err(Error::TypeDoesNotSupportSerialization { - type_name: stringify!($type), + Err(serialize::Error::PathDoesNotExist { path: path.to_string(), }) } + } + impl PathDeserialize for $type { fn deserialize_path<'de, D>( &mut self, path: &str, _data: D, - ) -> Result<(), Error> + ) -> Result<(), deserialize::Error> where D: Deserializer<'de>, { - Err(Error::TypeDoesNotSupportDeserialization { - type_name: stringify!($type), + Err(deserialize::Error::PathDoesNotExist { path: path.to_string(), }) } + } - fn exists(_path: &str) -> bool { - false - } - - fn fill_fields(_fields: &mut BTreeSet, _prefix: &str) {} + impl PathIntrospect for $type { + fn extend_with_fields(_fields: &mut BTreeSet, _prefix: &str) {} } }; ($type:ty, $($generic:tt),*) => { - impl<$($generic),*> SerializeHierarchy for $type { + impl<$($generic),*> PathSerialize for $type { fn serialize_path( &self, path: &str, _serializer: S, - ) -> Result> + ) -> Result> where S: Serializer, { - Err(Error::TypeDoesNotSupportSerialization { - type_name: stringify!($type), + Err(serialize::Error::PathDoesNotExist { path: path.to_string(), }) } + } + impl<$($generic),*> PathDeserialize for $type { fn deserialize_path<'de, D>( &mut self, path: &str, _data: D, - ) -> Result<(), Error> + ) -> Result<(), deserialize::Error> where D: Deserializer<'de>, { - Err(Error::TypeDoesNotSupportDeserialization { - type_name: stringify!($type), + Err(deserialize::Error::PathDoesNotExist { path: path.to_string(), }) } + } - fn exists(_path: &str) -> bool { - false - } - - fn fill_fields(_fields: &mut BTreeSet, _prefix: &str) {} + impl<$($generic),*> PathIntrospect for $type { + fn extend_with_fields(_fields: &mut BTreeSet, _prefix: &str) {} } }; } diff --git a/crates/path_serde/src/serialize.rs b/crates/path_serde/src/serialize.rs new file mode 100644 index 0000000000..61c88e3794 --- /dev/null +++ b/crates/path_serde/src/serialize.rs @@ -0,0 +1,18 @@ +use serde::Serializer; + +#[derive(Debug, thiserror::Error)] +pub enum Error +where + E: std::error::Error, +{ + #[error("failed to serialize")] + SerializationFailed(#[source] E), + #[error("path `{path}` does not exist")] + PathDoesNotExist { path: String }, +} + +pub trait PathSerialize { + fn serialize_path(&self, path: &str, serializer: S) -> Result> + where + S: Serializer; +} diff --git a/crates/serialize_hierarchy_derive/Cargo.toml b/crates/path_serde_derive/Cargo.toml similarity index 88% rename from crates/serialize_hierarchy_derive/Cargo.toml rename to crates/path_serde_derive/Cargo.toml index 55876ebc89..e20ee81a5d 100644 --- a/crates/serialize_hierarchy_derive/Cargo.toml +++ b/crates/path_serde_derive/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "serialize_hierarchy_derive" +name = "path_serde_derive" version.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/path_serde_derive/src/bound.rs b/crates/path_serde_derive/src/bound.rs new file mode 100644 index 0000000000..626f431cd9 --- /dev/null +++ b/crates/path_serde_derive/src/bound.rs @@ -0,0 +1,50 @@ +use syn::{ + punctuated::Punctuated, token::Plus, BoundLifetimes, DeriveInput, Generics, PredicateType, + Type, TypeParamBound, TypePath, WherePredicate, +}; +use syn::{GenericParam, Token}; + +pub trait ExtendGenerics { + fn remove_defaults(&mut self); + fn extend_with_bounds(&mut self, bounds: Vec); +} + +impl ExtendGenerics for Generics { + fn remove_defaults(&mut self) { + self.params.iter_mut().for_each(|param| { + if let GenericParam::Type(param) = param { + param.eq_token = None; + param.default = None; + } + }); + } + + fn extend_with_bounds(&mut self, bounds: Vec) { + self.make_where_clause().predicates.extend(bounds); + } +} + +pub fn infer_predicates( + input: &DeriveInput, + bounds: Punctuated, + lifetimes: Option, +) -> Vec { + input + .generics + .type_params() + .map(|param| { + Type::Path(TypePath { + qself: None, + path: param.ident.clone().into(), + }) + }) + .map(|bounded_ty| { + WherePredicate::Type(PredicateType { + lifetimes: lifetimes.clone(), + bounded_ty, + colon_token: ::default(), + bounds: bounds.clone(), + }) + }) + .collect() +} diff --git a/crates/path_serde_derive/src/container.rs b/crates/path_serde_derive/src/container.rs new file mode 100644 index 0000000000..f540594f62 --- /dev/null +++ b/crates/path_serde_derive/src/container.rs @@ -0,0 +1,204 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{ + parenthesized, parse::Parse as _, parse_quote, Data, DataStruct, DeriveInput, Ident, Index, + Result, Token, Type, WherePredicate, +}; + +use crate::bound::infer_predicates; + +pub struct Container { + pub fields: Vec, + pub serialize_bounds: Vec, + pub deserialize_bounds: Vec, + pub introspect_bounds: Vec, + pub computed_leaves: Vec, +} + +impl Container { + pub fn try_from_ast(item: &DeriveInput) -> Result { + let mut serialize_bounds = None; + let mut deserialize_bounds = None; + let mut introspect_bounds = None; + let mut computed_leaves = Vec::new(); + + for attribute in &item.attrs { + if !attribute.path().is_ident("path_serde") { + continue; + } + attribute.parse_nested_meta(|meta| { + if meta.path.is_ident("bound") { + let bounds = Some( + meta.value()? + .parse_terminated(WherePredicate::parse, Token![,])? + .into_iter() + .collect(), + ); + serialize_bounds = bounds.clone(); + deserialize_bounds = bounds.clone(); + introspect_bounds = bounds.clone(); + } else if meta.path.is_ident("serialize_bound") { + serialize_bounds = Some( + meta.value()? + .parse_terminated(WherePredicate::parse, Token![,])? + .into_iter() + .collect(), + ); + } else if meta.path.is_ident("deserialize_bound") { + deserialize_bounds = Some( + meta.value()? + .parse_terminated(WherePredicate::parse, Token![,])? + .into_iter() + .collect(), + ); + } else if meta.path.is_ident("introspect_bound") { + introspect_bounds = Some( + meta.value()? + .parse_terminated(WherePredicate::parse, Token![,])? + .into_iter() + .collect(), + ); + } else if meta.path.is_ident("add_leaf") { + let content; + parenthesized!(content in meta.input); + let identifier: Ident = content.parse()?; + content.parse::()?; + let into_type = content.parse::()?; + computed_leaves.push(ComputedLeaf { + identifier, + into_type, + }); + } else { + return Err(meta.error("unknown attribute")); + } + Ok(()) + })?; + } + + let fields = match &item.data { + Data::Struct(data) => read_fields(data)?, + Data::Enum(..) => Vec::new(), + Data::Union(..) => Vec::new(), + }; + let serialize_bounds = serialize_bounds.unwrap_or_else(|| { + infer_predicates( + item, + parse_quote!(path_serde::PathSerialize + serde::Serialize), + None, + ) + }); + let deserialize_bounds = deserialize_bounds.unwrap_or_else(|| { + infer_predicates( + item, + parse_quote!(path_serde::PathDeserialize + serde::Deserialize<'de>), + Some(parse_quote!(for<'de>)), + ) + }); + let introspect_bounds = introspect_bounds.unwrap_or_else(|| { + infer_predicates(item, parse_quote!(path_serde::PathIntrospect), None) + }); + + Ok(Container { + fields, + serialize_bounds, + deserialize_bounds, + introspect_bounds, + computed_leaves, + }) + } +} + +#[derive(Debug)] +pub enum Identifier { + Ident(Ident), + Index(Index), +} + +impl ToTokens for Identifier { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Identifier::Ident(ident) => ident.to_tokens(tokens), + Identifier::Index(index) => index.to_tokens(tokens), + } + } +} + +impl Identifier { + pub fn to_field_name(&self) -> String { + match self { + Identifier::Ident(ident) => ident.to_string(), + Identifier::Index(index) => index.index.to_string(), + } + } +} + +#[derive(Debug)] +pub struct Field { + pub skip_serialize: bool, + pub skip_deserialize: bool, + pub skip_introspect: bool, + pub is_leaf: bool, + pub identifier: Identifier, + pub ty: Type, +} + +impl Field { + fn try_from_ast(index: usize, field: &syn::Field) -> Result { + let mut skip_serialize = false; + let mut skip_deserialize = false; + let mut skip_introspect = false; + let mut is_leaf = false; + + for attribute in &field.attrs { + if !attribute.path().is_ident("path_serde") { + continue; + } + attribute.parse_nested_meta(|meta| { + if meta.path.is_ident("skip") { + skip_serialize = true; + skip_deserialize = true; + skip_introspect = true; + } else if meta.path.is_ident("skip_serialize") { + skip_serialize = true; + } else if meta.path.is_ident("skip_deserialize") { + skip_deserialize = true; + } else if meta.path.is_ident("skip_introspect") { + skip_introspect = true; + } else if meta.path.is_ident("leaf") { + is_leaf = true; + } else { + return Err(meta.error("unknown attribute")); + } + Ok(()) + })?; + } + + let identifier = match &field.ident { + Some(ident) => Identifier::Ident(ident.clone()), + None => Identifier::Index(Index::from(index)), + }; + let ty = field.ty.clone(); + + Ok(Field { + skip_serialize, + skip_deserialize, + skip_introspect, + is_leaf, + identifier, + ty, + }) + } +} + +fn read_fields(data: &DataStruct) -> Result> { + data.fields + .iter() + .enumerate() + .map(|(index, field)| Field::try_from_ast(index, field)) + .collect() +} + +pub struct ComputedLeaf { + pub identifier: Ident, + pub into_type: Type, +} diff --git a/crates/path_serde_derive/src/deserialize.rs b/crates/path_serde_derive/src/deserialize.rs new file mode 100644 index 0000000000..f32e63a6c6 --- /dev/null +++ b/crates/path_serde_derive/src/deserialize.rs @@ -0,0 +1,85 @@ +use proc_macro2::TokenStream; +use quote::quote; +use syn::{DeriveInput, Result}; + +use crate::{bound::ExtendGenerics, container::Container}; + +pub fn derive_path_deserialize(mut input: DeriveInput) -> Result { + let container = Container::try_from_ast(&input)?; + + input.generics.remove_defaults(); + input + .generics + .extend_with_bounds(container.deserialize_bounds.clone()); + + let name = &input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + + let path_deserializations = generate_path_deserializations(&container); + let leaf_deserializations = generate_leaf_deserializations(&container); + + Ok(quote! { + impl #impl_generics path_serde::PathDeserialize for #name #ty_generics #where_clause { + fn deserialize_path<'de, D>( + &mut self, + path: &str, + deserializer: D, + ) -> Result<(), path_serde::deserialize::Error> + where + D: serde::Deserializer<'de>, + { + let split = path.split_once('.'); + match split { + Some((name, suffix)) => match name { + #(#path_deserializations,)* + name => Err(path_serde::deserialize::Error::PathDoesNotExist { + path: name.to_string(), + }), + }, + None => match path { + #(#leaf_deserializations,)* + name => Err(path_serde::deserialize::Error::PathDoesNotExist { + path: name.to_string(), + }), + }, + } + } + } + }) +} + +fn generate_path_deserializations(container: &Container) -> Vec { + container + .fields + .iter() + .filter(|field| !field.skip_deserialize && !field.is_leaf) + .map(|field| { + let identifier = &field.identifier; + let pattern = identifier.to_field_name(); + quote! { + #pattern => self.#identifier.deserialize_path(suffix, deserializer) + } + }) + .collect() +} + +fn generate_leaf_deserializations(container: &Container) -> Vec { + container + .fields + .iter() + .filter(|field| !field.skip_deserialize) + .map(|field| { + let identifier = &field.identifier; + let pattern = identifier.to_field_name(); + let ty = &field.ty; + quote! { + #pattern => { + self.#identifier = + <#ty as serde::Deserialize>::deserialize(deserializer) + .map_err(path_serde::deserialize::Error::DeserializationFailed)?; + Ok(()) + } + } + }) + .collect() +} diff --git a/crates/path_serde_derive/src/introspect.rs b/crates/path_serde_derive/src/introspect.rs new file mode 100644 index 0000000000..e8282eeb40 --- /dev/null +++ b/crates/path_serde_derive/src/introspect.rs @@ -0,0 +1,60 @@ +use proc_macro2::TokenStream; +use quote::quote; +use syn::{DeriveInput, Result}; + +use crate::{bound::ExtendGenerics, container::Container}; + +pub fn derive_path_introspect(mut input: DeriveInput) -> Result { + let container = Container::try_from_ast(&input)?; + + input.generics.remove_defaults(); + input + .generics + .extend_with_bounds(container.introspect_bounds.clone()); + + let name = &input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + + let extend_with_fields = generate_extend_with_fields(&container); + + Ok(quote! { + impl #impl_generics path_serde::PathIntrospect for #name #ty_generics #where_clause { + fn extend_with_fields(fields: &mut std::collections::BTreeSet, prefix: &str) { + #(#extend_with_fields)* + } + } + }) +} + +fn generate_extend_with_fields(container: &Container) -> Vec { + let leafs = container + .fields + .iter() + .filter(|field| !field.skip_introspect); + let children = container + .fields + .iter() + .filter(|field| !field.skip_introspect && !field.is_leaf); + let computed_leafs = container.computed_leaves.iter(); + + leafs.map(|field| { + let field_name = &field.identifier.to_field_name(); + quote! { + fields.insert(format!("{prefix}{}", #field_name)); + } + }) + .chain(children.map(|field| { + let field_name = &field.identifier.to_field_name(); + let ty = &field.ty; + quote! { + <#ty as path_serde::PathIntrospect>::extend_with_fields(fields, &format!("{prefix}{}.", #field_name)); + } + })) + .chain(computed_leafs.map(|leaf| { + let field_name = &leaf.identifier.to_string(); + quote! { + fields.insert(format!("{prefix}{}", #field_name)); + } + })) + .collect() +} diff --git a/crates/path_serde_derive/src/lib.rs b/crates/path_serde_derive/src/lib.rs new file mode 100644 index 0000000000..b7bd5148ae --- /dev/null +++ b/crates/path_serde_derive/src/lib.rs @@ -0,0 +1,38 @@ +use deserialize::derive_path_deserialize; +use introspect::derive_path_introspect; +use proc_macro_error::proc_macro_error; +use serialize::derive_path_serialize; +use syn::{parse_macro_input, DeriveInput}; + +mod bound; +mod container; +mod deserialize; +mod introspect; +mod serialize; + +#[proc_macro_derive(PathSerialize, attributes(path_serde))] +#[proc_macro_error] +pub fn path_serialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = parse_macro_input!(input as DeriveInput); + derive_path_serialize(input) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} + +#[proc_macro_derive(PathDeserialize, attributes(path_serde))] +#[proc_macro_error] +pub fn path_deserialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = parse_macro_input!(input as DeriveInput); + derive_path_deserialize(input) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} + +#[proc_macro_derive(PathIntrospect, attributes(path_serde))] +#[proc_macro_error] +pub fn path_introspect(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = parse_macro_input!(input as DeriveInput); + derive_path_introspect(input) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} diff --git a/crates/path_serde_derive/src/serialize.rs b/crates/path_serde_derive/src/serialize.rs new file mode 100644 index 0000000000..3bbf4cb27a --- /dev/null +++ b/crates/path_serde_derive/src/serialize.rs @@ -0,0 +1,95 @@ +use proc_macro2::TokenStream; +use quote::quote; +use syn::{DeriveInput, Result}; + +use crate::{bound::ExtendGenerics, container::Container}; + +pub fn derive_path_serialize(mut input: DeriveInput) -> Result { + let container = Container::try_from_ast(&input)?; + + input.generics.remove_defaults(); + input + .generics + .extend_with_bounds(container.serialize_bounds.clone()); + + let name = &input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + + let path_serializations = generate_path_serializations(&container); + let leaf_serializations = generate_leaf_serializations(&container); + + Ok(quote! { + impl #impl_generics path_serde::PathSerialize for #name #ty_generics #where_clause { + fn serialize_path( + &self, + path: &str, + serializer: S, + ) -> Result> + where + S: serde::Serializer, + { + let split = path.split_once('.'); + match split { + Some((name, suffix)) => match name { + #(#path_serializations,)* + segment => Err(path_serde::serialize::Error::PathDoesNotExist { + path: segment.to_string(), + }), + }, + None => { + match path { + #(#leaf_serializations,)* + segment => Err(path_serde::serialize::Error::PathDoesNotExist { + path: segment.to_string(), + }), + } + } + } + } + } + }) +} + +fn generate_path_serializations(container: &Container) -> Vec { + container + .fields + .iter() + .filter(|field| !field.skip_serialize && !field.is_leaf) + .map(|field| { + let identifier = &field.identifier; + let pattern = identifier.to_field_name(); + quote! { + #pattern => self.#identifier.serialize_path(suffix, serializer) + } + }) + .collect() +} + +fn generate_leaf_serializations(container: &Container) -> Vec { + container + .fields + .iter() + .filter(|field| !field.skip_serialize) + .map(|field| { + let identifier = &field.identifier; + let pattern = identifier.to_field_name(); + quote! { + #pattern => serde::Serialize::serialize(&self.#identifier, serializer) + .map_err(path_serde::serialize::Error::SerializationFailed) + } + }) + .chain(container.computed_leaves.iter().map(|leaf| { + let identifier = &leaf.identifier; + let into_type = &leaf.into_type; + let pattern = identifier.to_string(); + quote! { + #pattern => { + std::convert::TryInto::<#into_type>::try_into(self) + .map_err(serde::ser::Error::custom) + .and_then(|leaf| serde::Serialize::serialize(&leaf, serializer)) + .map_err(path_serde::serialize::Error::SerializationFailed) + } + } + })) + .collect() +} diff --git a/crates/projection/Cargo.toml b/crates/projection/Cargo.toml index 18271fc8d8..30b1825224 100644 --- a/crates/projection/Cargo.toml +++ b/crates/projection/Cargo.toml @@ -13,8 +13,8 @@ approx = { workspace = true } coordinate_systems = { workspace = true } linear_algebra = { workspace = true } nalgebra = { workspace = true } -thiserror = { workspace = true } +path_serde = { workspace = true } serde = { workspace = true} -serialize_hierarchy = { workspace = true } +thiserror = { workspace = true } types = { workspace = true } diff --git a/crates/projection/src/camera_matrices.rs b/crates/projection/src/camera_matrices.rs index b98831a74d..adb8393965 100644 --- a/crates/projection/src/camera_matrices.rs +++ b/crates/projection/src/camera_matrices.rs @@ -2,13 +2,15 @@ use std::ops::Index; use coordinate_systems::{Camera, Robot}; use linear_algebra::Rotation3; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::camera_position::CameraPosition; use crate::camera_matrix::CameraMatrix; -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct CameraMatrices { pub top: CameraMatrix, pub bottom: CameraMatrix, diff --git a/crates/projection/src/camera_matrix.rs b/crates/projection/src/camera_matrix.rs index 58a17ea3b6..ce8f10d466 100644 --- a/crates/projection/src/camera_matrix.rs +++ b/crates/projection/src/camera_matrix.rs @@ -1,7 +1,7 @@ use coordinate_systems::{Camera, Ground, Head, Pixel, Robot}; use linear_algebra::{IntoFramed, Isometry3, Point2, Rotation3, Vector2}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::{ camera_projection::{CameraProjection, InverseCameraProjection}, @@ -9,9 +9,16 @@ use crate::{ intrinsic::Intrinsic, }; -#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize, SerializeHierarchy)] -#[serialize_hierarchy( - bound = "Camera: SerializeHierarchy + Serialize, for<'de> Camera: Deserialize<'de>" +#[derive( + Clone, + Debug, + Default, + Deserialize, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, )] pub struct CameraMatrix { pub ground_to_robot: Isometry3, diff --git a/crates/projection/src/camera_projection.rs b/crates/projection/src/camera_projection.rs index 75a5e6f44f..396af46447 100644 --- a/crates/projection/src/camera_projection.rs +++ b/crates/projection/src/camera_projection.rs @@ -1,11 +1,21 @@ use coordinate_systems::{Camera, Pixel}; use linear_algebra::{point, Isometry3, Point2, Point3, Transform}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::intrinsic::Intrinsic; -#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Debug, + Default, + Deserialize, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct CameraProjection { extrinsic: Isometry3, intrinsic: Intrinsic, @@ -29,7 +39,17 @@ impl CameraProjection { } } -#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Debug, + Default, + Deserialize, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct InverseCameraProjection { back_project: Transform>, z: f32, diff --git a/crates/projection/src/horizon.rs b/crates/projection/src/horizon.rs index 75ff7557c2..0ee8baeee5 100644 --- a/crates/projection/src/horizon.rs +++ b/crates/projection/src/horizon.rs @@ -1,11 +1,22 @@ use coordinate_systems::{Camera, Ground, Pixel}; use linear_algebra::{point, vector, Isometry3, Point2, Vector2, Vector3}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::intrinsic::Intrinsic; -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct Horizon { pub vanishing_point: Point2, pub normal: Vector2, diff --git a/crates/projection/src/intrinsic.rs b/crates/projection/src/intrinsic.rs index 77f07c1f73..b9235ee3b3 100644 --- a/crates/projection/src/intrinsic.rs +++ b/crates/projection/src/intrinsic.rs @@ -1,9 +1,11 @@ use coordinate_systems::{Camera, NormalizedDeviceCoordinates, Pixel}; use linear_algebra::{point, vector, Point2, Vector3}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Debug, PartialEq, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Intrinsic { focals: nalgebra::Vector2, optical_center: Point2, diff --git a/crates/serialize_hierarchy/src/error.rs b/crates/serialize_hierarchy/src/error.rs deleted file mode 100644 index cf4d77faa7..0000000000 --- a/crates/serialize_hierarchy/src/error.rs +++ /dev/null @@ -1,22 +0,0 @@ -#[derive(Debug, thiserror::Error)] -pub enum Error -where - E: std::error::Error, -{ - #[error("failed to serialize")] - SerializationFailed(E), - #[error("failed to deserialize")] - DeserializationFailed(E), - #[error("type {type_name} does not support serialization for path {path:?}")] - TypeDoesNotSupportSerialization { - type_name: &'static str, - path: String, - }, - #[error("type {type_name} does not support deserialization for path {path:?}")] - TypeDoesNotSupportDeserialization { - type_name: &'static str, - path: String, - }, - #[error("unexpected path segment {segment}")] - UnexpectedPathSegment { segment: String }, -} diff --git a/crates/serialize_hierarchy/src/implementation.rs b/crates/serialize_hierarchy/src/implementation.rs deleted file mode 100644 index 0e1c479517..0000000000 --- a/crates/serialize_hierarchy/src/implementation.rs +++ /dev/null @@ -1,259 +0,0 @@ -use std::{ - collections::BTreeSet, - ops::{Deref, DerefMut, Range}, - sync::Arc, -}; - -use nalgebra::{ArrayStorage, Const, Matrix, Point, Scalar, U1}; -use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize, Serializer}; - -use crate::{error::Error, SerializeHierarchy}; - -impl SerializeHierarchy for Box -where - T: SerializeHierarchy, -{ - fn serialize_path(&self, path: &str, serializer: S) -> Result> - where - S: Serializer, - { - self.deref().serialize_path(path, serializer) - } - - fn deserialize_path<'de, D>(&mut self, path: &str, data: D) -> Result<(), Error> - where - D: Deserializer<'de>, - { - self.deref_mut().deserialize_path(path, data) - } - - fn exists(path: &str) -> bool { - T::exists(path) - } - - fn get_fields() -> BTreeSet { - T::get_fields() - } - - fn fill_fields(fields: &mut BTreeSet, prefix: &str) { - T::fill_fields(fields, prefix) - } -} - -impl SerializeHierarchy for Arc -where - T: SerializeHierarchy, -{ - fn serialize_path(&self, path: &str, serializer: S) -> Result> - where - S: Serializer, - { - self.deref().serialize_path(path, serializer) - } - - fn deserialize_path<'de, D>(&mut self, path: &str, _data: D) -> Result<(), Error> - where - D: Deserializer<'de>, - { - Err(Error::TypeDoesNotSupportDeserialization { - type_name: "Arc", - path: path.to_string(), - }) - } - - fn exists(path: &str) -> bool { - T::exists(path) - } - - fn fill_fields(fields: &mut BTreeSet, prefix: &str) { - T::fill_fields(fields, prefix) - } -} - -impl SerializeHierarchy for Option -where - T: SerializeHierarchy, -{ - fn serialize_path(&self, path: &str, serializer: S) -> Result> - where - S: Serializer, - { - match self { - Some(some) => some.serialize_path(path, serializer), - None => (None as Option<()>) - .serialize(serializer) - .map_err(Error::SerializationFailed), - } - } - - fn deserialize_path<'de, D>(&mut self, path: &str, _data: D) -> Result<(), Error> - where - D: Deserializer<'de>, - { - Err(Error::TypeDoesNotSupportDeserialization { - type_name: "Option", - path: path.to_string(), - }) - } - - fn exists(path: &str) -> bool { - T::exists(path) - } - - fn fill_fields(fields: &mut BTreeSet, prefix: &str) { - T::fill_fields(fields, prefix) - } -} - -impl SerializeHierarchy for Range -where - T: SerializeHierarchy + Serialize, - for<'de> T: Deserialize<'de>, -{ - fn serialize_path(&self, path: &str, serializer: S) -> Result> - where - S: Serializer, - { - let split = path.split_once('.'); - match (path, split) { - (_, Some(("start", suffix))) => self.start.serialize_path(suffix, serializer), - (_, Some(("end", suffix))) => self.end.serialize_path(suffix, serializer), - ("start", None) => self - .start - .serialize(serializer) - .map_err(Error::SerializationFailed), - ("end", None) => self - .end - .serialize(serializer) - .map_err(Error::SerializationFailed), - _ => Err(Error::UnexpectedPathSegment { - segment: path.to_string(), - }), - } - } - - fn deserialize_path<'de, D>( - &mut self, - path: &str, - deserializer: D, - ) -> Result<(), Error> - where - D: Deserializer<'de>, - { - let split = path.split_once('.'); - match (path, split) { - (_, Some(("start", suffix))) => self.start.deserialize_path(suffix, deserializer), - (_, Some(("end", suffix))) => self.end.deserialize_path(suffix, deserializer), - ("start", None) => { - self.start = T::deserialize(deserializer).map_err(Error::DeserializationFailed)?; - Ok(()) - } - ("end", None) => { - self.end = T::deserialize(deserializer).map_err(Error::DeserializationFailed)?; - Ok(()) - } - _ => Err(Error::UnexpectedPathSegment { - segment: path.to_string(), - }), - } - } - - fn exists(path: &str) -> bool { - let split = path.split_once('.'); - match (path, split) { - (_, Some(("start", suffix))) | (_, Some(("end", suffix))) => T::exists(suffix), - ("start", None) | ("end", None) => true, - _ => false, - } - } - - fn fill_fields(fields: &mut BTreeSet, prefix: &str) { - fields.insert(format!("{prefix}start")); - fields.insert(format!("{prefix}end")); - } -} - -impl SerializeHierarchy - for Matrix, U1, ArrayStorage> -{ - fn serialize_path(&self, path: &str, serializer: S) -> Result> - where - S: Serializer, - { - let index = ["x", "y", "z", "w", "v", "u"][0..N] - .iter() - .position(|name| name == &path); - match index { - Some(index) => self[index] - .serialize(serializer) - .map_err(Error::SerializationFailed), - _ => Err(Error::UnexpectedPathSegment { - segment: String::from(path), - }), - } - } - - fn deserialize_path<'de, D>( - &mut self, - path: &str, - deserializer: D, - ) -> Result<(), Error> - where - D: Deserializer<'de>, - { - let index = ["x", "y", "z", "w", "v", "u"][0..N] - .iter() - .position(|name| name == &path); - match index { - Some(index) => { - let deserialized = ::deserialize(deserializer) - .map_err(Error::DeserializationFailed)?; - self[index] = deserialized; - Ok(()) - } - None => Err(Error::UnexpectedPathSegment { - segment: String::from(path), - }), - } - } - - fn exists(path: &str) -> bool { - Matrix::, U1, ArrayStorage>::get_fields().contains(path) - } - - fn fill_fields(fields: &mut BTreeSet, prefix: &str) { - for field in &["x", "y", "z", "w", "v", "u"][0..N] { - fields.insert(format!("{prefix}{field}")); - } - } -} - -impl SerializeHierarchy - for Point -{ - fn serialize_path(&self, path: &str, serializer: S) -> Result> - where - S: Serializer, - { - self.coords.serialize_path(path, serializer) - } - - fn deserialize_path<'de, D>( - &mut self, - path: &str, - deserializer: D, - ) -> Result<(), Error> - where - D: Deserializer<'de>, - { - self.coords.deserialize_path(path, deserializer) - } - - fn exists(path: &str) -> bool { - Matrix::, U1, ArrayStorage>::exists(path) - } - - fn fill_fields(fields: &mut BTreeSet, prefix: &str) { - Matrix::, U1, ArrayStorage>::fill_fields(fields, prefix) - } -} diff --git a/crates/serialize_hierarchy/src/jpeg.rs b/crates/serialize_hierarchy/src/jpeg.rs deleted file mode 100644 index 6555e94a7d..0000000000 --- a/crates/serialize_hierarchy/src/jpeg.rs +++ /dev/null @@ -1,13 +0,0 @@ -pub trait EncodeJpeg { - const DEFAULT_QUALITY: u8; - type Error; - fn encode_as_jpeg(&self, quality: u8) -> Result, Self::Error>; -} - -pub trait DecodeJpeg -where - Self: Sized, -{ - type Error; - fn decode_from_jpeg(jpeg: Vec) -> Result; -} diff --git a/crates/serialize_hierarchy/src/lib.rs b/crates/serialize_hierarchy/src/lib.rs deleted file mode 100644 index 13c7f56496..0000000000 --- a/crates/serialize_hierarchy/src/lib.rs +++ /dev/null @@ -1,75 +0,0 @@ -use std::collections::BTreeSet; - -pub use bincode; -pub use error::Error; - -pub use jpeg::{DecodeJpeg, EncodeJpeg}; -use serde::{Deserializer, Serializer}; -pub use serde_json; -pub use serialize_hierarchy_derive::SerializeHierarchy; - -pub mod error; -mod implementation; -mod jpeg; -mod not_supported; - -pub trait SerializeHierarchy { - fn serialize_path(&self, path: &str, serializer: S) -> Result> - where - S: Serializer; - - fn deserialize_path<'de, D>( - &mut self, - path: &str, - deserializer: D, - ) -> Result<(), Error> - where - D: Deserializer<'de>; - - fn exists(path: &str) -> bool; - - fn get_fields() -> BTreeSet { - let mut fields = BTreeSet::default(); - Self::fill_fields(&mut fields, ""); - fields - } - - fn fill_fields(fields: &mut BTreeSet, prefix: &str); -} - -#[cfg(test)] -mod tests { - use serde::{Deserialize, Serialize}; - - use crate as serialize_hierarchy; - - use super::*; - - #[derive(Deserialize, Serialize, SerializeHierarchy)] - struct Outer { - inner: Inner, - } - - #[derive(Deserialize, Serialize, SerializeHierarchy)] - struct Inner { - field: bool, - } - - #[test] - fn primitive_fields_are_empty() { - assert_eq!(bool::get_fields(), Default::default()); - } - - #[test] - fn flat_struct_fields_contain_fields() { - assert_eq!(Inner::get_fields(), ["field".to_string()].into()); - } - - #[test] - fn nested_struct_fields_contain_fields() { - assert_eq!( - Outer::get_fields(), - ["inner".to_string(), "inner.field".to_string()].into() - ); - } -} diff --git a/crates/serialize_hierarchy_derive/src/lib.rs b/crates/serialize_hierarchy_derive/src/lib.rs deleted file mode 100644 index 8e703832d1..0000000000 --- a/crates/serialize_hierarchy_derive/src/lib.rs +++ /dev/null @@ -1,382 +0,0 @@ -use std::collections::HashSet; - -use proc_macro2::TokenStream; -use proc_macro_error::{abort, proc_macro_error}; -use quote::{quote, ToTokens}; -use syn::{ - parse_macro_input, punctuated::Punctuated, Data, DataStruct, DeriveInput, Generics, Ident, Lit, - Meta, MetaNameValue, NestedMeta, Token, Type, WherePredicate, -}; - -#[proc_macro_derive(SerializeHierarchy, attributes(serialize_hierarchy))] -#[proc_macro_error] -pub fn serialize_hierarchy(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let input = parse_macro_input!(input as DeriveInput); - process_input(input).into() -} - -fn process_input(mut input: DeriveInput) -> TokenStream { - let fields = match &input.data { - Data::Struct(data) => read_fields(data), - Data::Enum(..) => Vec::new(), - Data::Union(data) => { - abort!( - data.union_token, - "`SerializeHierarchy` can only be derived for `struct` or `enum`", - ) - } - }; - let type_attributes = parse_attributes(&input.attrs); - let contains_as_jpeg = type_attributes.contains(&TypeAttribute::AsJpeg); - - extend_where_clause_from_attributes(&mut input.generics, type_attributes); - - let name = &input.ident; - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let serializable_fields: Vec<_> = fields - .iter() - .filter(|field| !field.attributes.contains(&FieldAttribute::Skip)) - .collect(); - let path_serializations = generate_path_serializations(&serializable_fields); - let serde_serializations = generate_serde_serializations(&serializable_fields); - let path_deserializations = generate_path_deserializations(&serializable_fields); - let serde_deserializations = generate_serde_deserializations(&serializable_fields); - let path_exists_getters = generate_path_exists_getters(&serializable_fields); - let field_exists_getters = generate_field_exists_getters(&serializable_fields); - let field_chains = generate_field_chains(&serializable_fields); - let path_field_chains = generate_path_field_chains(&serializable_fields); - let (jpeg_serialization, jpeg_exists_getter, jpeg_field_chain) = if contains_as_jpeg { - ( - quote! { - "jpeg" => self - .encode_as_jpeg(Self::DEFAULT_QUALITY) - .map_err(|error| serialize_hierarchy::Error::SerializationFailed(serde::ser::Error::custom(error)))? - .serialize(serializer) - .map_err(serialize_hierarchy::Error::SerializationFailed), - }, - quote! { - "jpeg" => true, - }, - quote! { - fields.insert(format!("{prefix}jpeg")); - }, - ) - } else { - Default::default() - }; - - let implementation = quote! { - impl #impl_generics serialize_hierarchy::SerializeHierarchy for #name #ty_generics #where_clause { - fn serialize_path( - &self, - path: &str, - serializer: S, - ) -> Result> - where - S: serde::Serializer, - { - let split = path.split_once('.'); - match split { - Some((name, suffix)) => match name { - #(#path_serializations,)* - segment => Err(serialize_hierarchy::Error::UnexpectedPathSegment { - segment: segment.to_string(), - }), - }, - None => { - match path { - #(#serde_serializations,)* - #jpeg_serialization - segment => Err(serialize_hierarchy::Error::UnexpectedPathSegment { - segment: segment.to_string(), - }), - } - } - } - } - - fn deserialize_path<'de, D>( - &mut self, - path: &str, - deserializer: D, - ) -> Result<(), serialize_hierarchy::Error> - where - D: serde::Deserializer<'de>, - { - let split = path.split_once('.'); - match split { - Some((name, suffix)) => match name { - #(#path_deserializations,)* - name => Err(serialize_hierarchy::Error::UnexpectedPathSegment { - segment: name.to_string(), - }), - }, - None => match path { - #(#serde_deserializations,)* - name => Err(serialize_hierarchy::Error::UnexpectedPathSegment { - segment: name.to_string(), - }), - }, - } - } - - fn exists(path: &str) -> bool { - let split = path.split_once('.'); - match split { - Some((name, suffix)) => match name { - #(#path_exists_getters,)* - _ => false, - }, - None => match path { - #(#field_exists_getters,)* - #jpeg_exists_getter - _ => false, - }, - } - } - - fn fill_fields(fields: &mut std::collections::BTreeSet, prefix: &str) { - #(#field_chains)* - #(#path_field_chains)* - #jpeg_field_chain - } - } - }; - implementation -} - -fn extend_where_clause_from_attributes( - generics: &mut Generics, - type_attributes: HashSet, -) { - generics.make_where_clause().predicates.extend({ - type_attributes - .iter() - .filter_map(|attribute| match attribute { - TypeAttribute::Bounds { predicates } => Some(predicates), - _ => None, - }) - .flatten() - .cloned() - }); -} - -fn generate_path_serializations(fields: &[&Field]) -> Vec { - fields - .iter() - .filter(|field| !field.attributes.contains(&FieldAttribute::Leaf)) - .map(|field| { - let identifier = &field.identifier; - let pattern = identifier.to_string(); - quote! { - #pattern => self.#identifier.serialize_path(suffix, serializer) - } - }) - .collect() -} - -fn generate_serde_serializations(fields: &[&Field]) -> Vec { - fields.iter().map(|field| { - let identifier = &field.identifier; - let pattern = identifier.to_string(); - quote! { - #pattern => serde::Serialize::serialize(&self.#identifier, serializer).map_err(serialize_hierarchy::Error::SerializationFailed) - } - }).collect() -} - -fn generate_path_deserializations(fields: &[&Field]) -> Vec { - fields - .iter() - .filter(|field| !field.attributes.contains(&FieldAttribute::Leaf)) - .map(|field| { - let identifier = &field.identifier; - let pattern = identifier.to_string(); - quote! { - #pattern => self.#identifier.deserialize_path(suffix, deserializer) - } - }) - .collect() -} - -fn generate_serde_deserializations(fields: &[&Field]) -> Vec { - fields.iter().map(|field| { - let identifier = &field.identifier; - let pattern = identifier.to_string(); - let ty = &field.ty; - quote! { - #pattern => { - self.#identifier = <#ty as serde::Deserialize>::deserialize(deserializer).map_err(serialize_hierarchy::Error::DeserializationFailed)?; - Ok(()) - } - - } - }).collect() -} - -fn generate_path_exists_getters(fields: &[&Field]) -> Vec { - fields - .iter() - .filter(|field| !field.attributes.contains(&FieldAttribute::Leaf)) - .map(|field| { - let pattern = field.identifier.to_string(); - let ty = &field.ty; - quote! { - #pattern => <#ty as serialize_hierarchy::SerializeHierarchy>::exists(suffix) - } - }) - .collect() -} - -fn generate_field_exists_getters(fields: &[&Field]) -> Vec { - fields - .iter() - .map(|field| { - let pattern = field.identifier.to_string(); - quote! { - #pattern => true - } - }) - .collect() -} - -fn generate_field_chains(fields: &[&Field]) -> Vec { - fields - .iter() - .map(|field| { - let name_string = field.identifier.to_string(); - quote! { - fields.insert(format!("{prefix}{}", #name_string)); - } - }) - .collect() -} - -fn generate_path_field_chains(fields: &[&Field]) -> Vec { - fields - .iter() - .filter(|field| !field.attributes.contains(&FieldAttribute::Leaf)) - .map(|field| { - let field_name = &field.identifier.to_string(); - let ty = &field.ty; - quote! { - <#ty as serialize_hierarchy::SerializeHierarchy>::fill_fields(fields, &format!("{prefix}{}.", #field_name)); - } - }) - .collect() -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -enum TypeAttribute { - AsJpeg, - Bounds { predicates: Vec }, -} - -fn parse_attributes(attrs: &[syn::Attribute]) -> HashSet { - attrs - .iter() - .flat_map(parse_meta_items) - .map(|meta| match meta { - NestedMeta::Meta(Meta::Path(word)) if word.is_ident("as_jpeg") => TypeAttribute::AsJpeg, - NestedMeta::Meta(Meta::NameValue(MetaNameValue { - path, lit: literal, .. - })) if path.is_ident("bound") => { - let string = match literal { - Lit::Str(literal) => literal, - _ => abort!( - literal, - "expected bound attribute to be a string: `bound = \"...\"`" - ), - }; - let predicates = match string - .parse_with(Punctuated::::parse_terminated) - { - Ok(predicates) => Vec::from_iter(predicates), - Err(error) => { - abort!(error.span(), error.to_string()) - } - }; - TypeAttribute::Bounds { predicates } - } - NestedMeta::Meta(meta_item) => { - let path = meta_item - .path() - .into_token_stream() - .to_string() - .replace(' ', ""); - abort!(meta_item.path(), "unknown attribute `{}`", path) - } - NestedMeta::Lit(lit) => { - abort!(lit, "unexpected literal in attribute") - } - }) - .collect() -} - -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] -enum FieldAttribute { - Skip, - Leaf, -} - -#[derive(Debug)] -struct Field { - attributes: HashSet, - identifier: Ident, - ty: Type, -} - -fn parse_meta_items(attribute: &syn::Attribute) -> Vec { - if !attribute.path.is_ident("serialize_hierarchy") { - return Vec::new(); - } - match attribute.parse_meta() { - Ok(Meta::List(meta)) => meta.nested.into_iter().collect(), - Ok(other) => abort!(other, "expected `#[serialize_hierarchy(...)]`",), - Err(error) => abort!(error.span(), error.to_string()), - } -} - -fn read_fields(input: &DataStruct) -> Vec { - input - .fields - .iter() - .map(|field| { - let attributes = field - .attrs - .iter() - .flat_map(parse_meta_items) - .map(|meta| match meta { - NestedMeta::Meta(Meta::Path(word)) if word.is_ident("skip") => { - FieldAttribute::Skip - } - NestedMeta::Meta(Meta::Path(word)) if word.is_ident("leaf") => { - FieldAttribute::Leaf - } - NestedMeta::Meta(meta_item) => { - let path = meta_item - .path() - .into_token_stream() - .to_string() - .replace(' ', ""); - abort!(meta_item.path(), "unknown attribute `{}`", path) - } - - NestedMeta::Lit(lit) => { - abort!(lit, "unexpected literal in attribute") - } - }) - .collect(); - let identifier = field - .ident - .clone() - .unwrap_or_else(|| abort!(field, "field has to be named")); - let ty = field.ty.clone(); - Field { - attributes, - identifier, - ty, - } - }) - .collect() -} diff --git a/crates/source_analyzer/src/contexts.rs b/crates/source_analyzer/src/contexts.rs index 8e2af21467..5b3faf09dd 100644 --- a/crates/source_analyzer/src/contexts.rs +++ b/crates/source_analyzer/src/contexts.rs @@ -36,8 +36,7 @@ impl Contexts { if item .attrs .iter() - .filter_map(|attribute| attribute.path.get_ident()) - .any(|identifier| identifier == "context") => + .any(|attribute| attribute.path().is_ident("context")) => { Some(item) } @@ -82,8 +81,7 @@ fn exactly_one_context_struct_with_name_exists(file: &File, name: &str) -> bool Item::Struct(item) if item .attrs .iter() - .filter_map(|attribute| attribute.path.get_ident()) - .any(|identifier| identifier == "context") + .any(|attribute| attribute.path().is_ident("context")) ) }) .filter(|item| { diff --git a/crates/source_analyzer/src/node.rs b/crates/source_analyzer/src/node.rs index b472b1b04e..94188ccd91 100644 --- a/crates/source_analyzer/src/node.rs +++ b/crates/source_analyzer/src/node.rs @@ -84,9 +84,9 @@ fn has_new_and_cycle_method(implementation: &ItemImpl) -> bool { implementation .items .iter() - .any(|item| matches!(item, ImplItem::Method(method) if method.sig.ident == "new")) + .any(|item| matches!(item, ImplItem::Fn(method) if method.sig.ident == "new")) && implementation .items .iter() - .any(|item| matches!(item, ImplItem::Method(method) if method.sig.ident == "cycle")) + .any(|item| matches!(item, ImplItem::Fn(method) if method.sig.ident == "cycle")) } diff --git a/crates/source_analyzer/src/to_absolute.rs b/crates/source_analyzer/src/to_absolute.rs index cefa48a781..b513b86d70 100644 --- a/crates/source_analyzer/src/to_absolute.rs +++ b/crates/source_analyzer/src/to_absolute.rs @@ -16,9 +16,6 @@ impl ToAbsolute for PathArguments { GenericArgument::Type(argument_type) => { *argument_type = argument_type.to_absolute(uses); } - GenericArgument::Binding(binding) => { - binding.ty = binding.ty.to_absolute(uses); - } GenericArgument::Constraint(constraint) => { for bound in constraint.bounds.iter_mut() { if let TypeParamBound::Trait(trait_bound) = bound { @@ -27,6 +24,11 @@ impl ToAbsolute for PathArguments { } } GenericArgument::Const(_) => {} + GenericArgument::AssocType(assoc_type) => { + assoc_type.ty = assoc_type.ty.to_absolute(uses); + } + GenericArgument::AssocConst(_) => {} + _ => todo!(), } } } diff --git a/crates/spl_network_messages/Cargo.toml b/crates/spl_network_messages/Cargo.toml index dc86aacb3c..3c05166a07 100644 --- a/crates/spl_network_messages/Cargo.toml +++ b/crates/spl_network_messages/Cargo.toml @@ -16,8 +16,8 @@ linear_algebra = { workspace = true } nalgebra = { workspace = true } num-derive = {workspace = true} num-traits = {workspace = true} +path_serde = { workspace = true } serde = { workspace = true } -serialize_hierarchy = { workspace = true } [dev-dependencies] bincode = { workspace = true } diff --git a/crates/spl_network_messages/src/game_controller_state_message.rs b/crates/spl_network_messages/src/game_controller_state_message.rs index 97f4d06326..00d3af845a 100644 --- a/crates/spl_network_messages/src/game_controller_state_message.rs +++ b/crates/spl_network_messages/src/game_controller_state_message.rs @@ -7,8 +7,8 @@ use std::{ }; use color_eyre::{eyre::bail, Report, Result}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::{ bindings::{ @@ -29,7 +29,7 @@ use crate::{ PlayerNumber, HULKS_TEAM_NUMBER, }; -#[derive(Clone, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive(Clone, Debug, Deserialize, Serialize, PathSerialize, PathIntrospect)] pub struct GameControllerStateMessage { pub competition_phase: CompetitionPhase, pub competition_type: CompetitionType, @@ -197,7 +197,9 @@ impl TryFrom for GameControllerStateMessage { } } -#[derive(Clone, Copy, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub enum CompetitionPhase { RoundRobin, PlayOff, @@ -213,7 +215,9 @@ impl CompetitionPhase { } } -#[derive(Clone, Copy, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub enum CompetitionType { Normal, SharedAutonomy, @@ -229,7 +233,17 @@ impl CompetitionType { } } -#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum GamePhase { #[default] Normal, @@ -257,7 +271,18 @@ impl GamePhase { } } -#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + Eq, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum GameState { Initial, Ready, @@ -280,7 +305,17 @@ impl GameState { } #[derive( - Default, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, SerializeHierarchy, + Default, + Clone, + Copy, + Debug, + Deserialize, + Eq, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, )] pub enum Team { Hulks, @@ -314,7 +349,17 @@ impl SubState { } } -#[derive(Default, Clone, Copy, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Default, + Clone, + Copy, + Debug, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum SubState { #[default] GoalKick, @@ -324,7 +369,18 @@ pub enum SubState { PenaltyKick, } -#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + Eq, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum Half { First, Second, @@ -342,7 +398,7 @@ impl TryFrom for Half { } } -#[derive(Clone, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive(Clone, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect)] pub struct TeamState { pub team_number: u8, pub field_player_color: TeamColor, @@ -355,7 +411,7 @@ pub struct TeamState { pub players: Vec, } -#[derive(Clone, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive(Clone, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect)] pub enum TeamColor { Blue, Red, @@ -411,7 +467,9 @@ impl TryFrom for Player { } } -#[derive(Clone, Copy, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub enum Penalty { IllegalBallContact { remaining: Duration }, PlayerPushing { remaining: Duration }, diff --git a/crates/spl_network_messages/src/lib.rs b/crates/spl_network_messages/src/lib.rs index f3a9d985c4..5f960c60ff 100644 --- a/crates/spl_network_messages/src/lib.rs +++ b/crates/spl_network_messages/src/lib.rs @@ -10,6 +10,7 @@ use std::{ use coordinate_systems::Field; use linear_algebra::{Point2, Pose2}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; pub use game_controller_return_message::GameControllerReturnMessage; @@ -17,7 +18,6 @@ pub use game_controller_state_message::{ GameControllerStateMessage, GamePhase, GameState, Half, Penalty, PenaltyShoot, Player, SubState, Team, TeamColor, TeamState, }; -use serialize_hierarchy::SerializeHierarchy; pub use visual_referee_message::{VisualRefereeDecision, VisualRefereeMessage}; #[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)] @@ -30,7 +30,17 @@ pub struct HulkMessage { pub time_to_reach_kick_position: Option, } -#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + PathDeserialize, + PathIntrospect, + PathSerialize, + Serialize, +)] pub struct BallPosition { pub position: Point2, pub age: Duration, @@ -39,7 +49,18 @@ pub struct BallPosition { pub const HULKS_TEAM_NUMBER: u8 = 24; #[derive( - Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, SerializeHierarchy, + Clone, + Copy, + Debug, + Default, + Deserialize, + Eq, + Hash, + PartialEq, + PathDeserialize, + PathIntrospect, + PathSerialize, + Serialize, )] pub enum PlayerNumber { One, diff --git a/crates/spl_network_messages/src/visual_referee_message.rs b/crates/spl_network_messages/src/visual_referee_message.rs index cf4a1946ea..3e31e124af 100644 --- a/crates/spl_network_messages/src/visual_referee_message.rs +++ b/crates/spl_network_messages/src/visual_referee_message.rs @@ -1,8 +1,8 @@ use std::{ffi::c_char, mem::size_of, slice::from_raw_parts, time::Duration}; use num_derive::FromPrimitive; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::{ bindings::{ @@ -35,7 +35,9 @@ use crate::{ FromPrimitive, PartialEq, Serialize, - SerializeHierarchy, + PathSerialize, + PathDeserialize, + PathIntrospect, )] #[repr(u8)] pub enum VisualRefereeDecision { diff --git a/crates/types/Cargo.toml b/crates/types/Cargo.toml index c972449410..be50591221 100644 --- a/crates/types/Cargo.toml +++ b/crates/types/Cargo.toml @@ -16,12 +16,7 @@ image = { workspace = true } linear_algebra = { workspace = true } nalgebra = { workspace = true } ordered-float = { workspace = true } +path_serde = { workspace = true } serde = { workspace = true } -serialize_hierarchy = { workspace = true } spl_network_messages = { workspace = true } splines = { workspace = true } - -[build-dependencies] -petgraph = { workspace = true } -proc-macro2 = { workspace = true } -quote = { workspace = true } diff --git a/crates/types/src/action.rs b/crates/types/src/action.rs index 64e4ca51c0..6a6e24bb65 100644 --- a/crates/types/src/action.rs +++ b/crates/types/src/action.rs @@ -1,7 +1,9 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Debug, Clone, Copy, SerializeHierarchy, Serialize, Deserialize)] +#[derive( + Debug, Clone, Copy, PathSerialize, PathDeserialize, PathIntrospect, Serialize, Deserialize, +)] pub enum Action { Calibrate, DefendGoal, diff --git a/crates/types/src/ball.rs b/crates/types/src/ball.rs index 479bed044a..3bba317838 100644 --- a/crates/types/src/ball.rs +++ b/crates/types/src/ball.rs @@ -4,9 +4,9 @@ use approx_derive::{AbsDiffEq, RelativeEq}; use coordinate_systems::{Ground, Pixel}; use geometry::circle::Circle; use linear_algebra::Point2; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, SerializeHierarchy)] +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PathSerialize, PathIntrospect)] pub struct CandidateEvaluation { pub candidate_circle: Circle, pub preclassifier_confidence: f32, @@ -16,9 +16,18 @@ pub struct CandidateEvaluation { } #[derive( - Clone, Debug, Deserialize, Serialize, SerializeHierarchy, AbsDiffEq, RelativeEq, PartialEq, + Clone, + Debug, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, + AbsDiffEq, + RelativeEq, + PartialEq, )] -#[abs_diff_eq(epsilon = "f32")] +#[abs_diff_eq(epsilon_type = f32)] pub struct Ball { pub position: Point2, pub image_location: Circle, diff --git a/crates/types/src/ball_filter.rs b/crates/types/src/ball_filter.rs index b5eb5785e8..5c688fdf8d 100644 --- a/crates/types/src/ball_filter.rs +++ b/crates/types/src/ball_filter.rs @@ -1,17 +1,16 @@ use std::time::SystemTime; -use serde::{Deserialize, Serialize}; - use coordinate_systems::Ground; use linear_algebra::{vector, Point}; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; +use serde::{Deserialize, Serialize}; use crate::{ ball_position::BallPosition, multivariate_normal_distribution::MultivariateNormalDistribution, parameters::BallFilterParameters, }; -#[derive(Clone, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive(Clone, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect)] pub struct Hypothesis { pub moving_state: MultivariateNormalDistribution<4>, pub resting_state: MultivariateNormalDistribution<4>, diff --git a/crates/types/src/ball_position.rs b/crates/types/src/ball_position.rs index 38494a04cc..a58adc59bc 100644 --- a/crates/types/src/ball_position.rs +++ b/crates/types/src/ball_position.rs @@ -1,11 +1,13 @@ use std::time::{SystemTime, UNIX_EPOCH}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use linear_algebra::{Point2, Vector2}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; -#[derive(Clone, Copy, Serialize, Deserialize, SerializeHierarchy, Debug)] +#[derive( + Clone, Copy, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, Debug, +)] pub struct BallPosition { pub position: Point2, pub velocity: Vector2, @@ -22,7 +24,9 @@ impl Default for BallPosition { } } -#[derive(Clone, Copy, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct HypotheticalBallPosition { pub position: Point2, pub validity: f32, diff --git a/crates/types/src/bounding_box.rs b/crates/types/src/bounding_box.rs index c8f45fe05f..db08e859d0 100644 --- a/crates/types/src/bounding_box.rs +++ b/crates/types/src/bounding_box.rs @@ -1,9 +1,11 @@ use coordinate_systems::Pixel; use geometry::rectangle::Rectangle; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Debug, Clone, Copy, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Debug, Clone, Copy, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct BoundingBox { pub area: Rectangle, pub score: f32, diff --git a/crates/types/src/buttons.rs b/crates/types/src/buttons.rs index 67a9b9b095..5086cb535d 100644 --- a/crates/types/src/buttons.rs +++ b/crates/types/src/buttons.rs @@ -1,7 +1,9 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Default, Clone, Serialize, Deserialize, SerializeHierarchy, Debug)] +#[derive( + Default, Clone, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, Debug, +)] pub struct Buttons { pub is_chest_button_pressed: bool, pub head_buttons_touched: bool, diff --git a/crates/types/src/camera_position.rs b/crates/types/src/camera_position.rs index 8e1c87d04a..675bd0cec6 100644 --- a/crates/types/src/camera_position.rs +++ b/crates/types/src/camera_position.rs @@ -1,8 +1,18 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; #[derive( - Default, Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize, SerializeHierarchy, + Default, + Debug, + Clone, + Copy, + Eq, + PartialEq, + Serialize, + Deserialize, + PathSerialize, + PathDeserialize, + PathIntrospect, )] pub enum CameraPosition { #[default] diff --git a/crates/types/src/color.rs b/crates/types/src/color.rs index 935b42dc43..d924ca4cb0 100644 --- a/crates/types/src/color.rs +++ b/crates/types/src/color.rs @@ -1,8 +1,18 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; #[derive( - Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, SerializeHierarchy, + Clone, + Copy, + Debug, + Default, + Deserialize, + Eq, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, )] #[repr(C)] pub struct YCbCr422 { @@ -109,7 +119,17 @@ pub enum Intensity { } #[derive( - Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, SerializeHierarchy, + Clone, + Copy, + Debug, + Default, + Deserialize, + Eq, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, )] pub struct Rgb { pub r: u8, diff --git a/crates/types/src/condition_input.rs b/crates/types/src/condition_input.rs index 4f1ebfd28d..514b25b566 100644 --- a/crates/types/src/condition_input.rs +++ b/crates/types/src/condition_input.rs @@ -1,10 +1,12 @@ use nalgebra::Vector3; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::fall_state::FallState; -#[derive(Default, Debug, Clone, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Default, Debug, Clone, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct ConditionInput { pub filtered_angular_velocity: Vector3, pub fall_state: FallState, diff --git a/crates/types/src/cycle_time.rs b/crates/types/src/cycle_time.rs index a3ba224ffd..f16972ad2a 100644 --- a/crates/types/src/cycle_time.rs +++ b/crates/types/src/cycle_time.rs @@ -1,9 +1,11 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Clone, Copy, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct CycleTime { pub start_time: SystemTime, pub last_cycle_duration: Duration, diff --git a/crates/types/src/detected_feet.rs b/crates/types/src/detected_feet.rs index 7cc8b5f065..ecc05cfb93 100644 --- a/crates/types/src/detected_feet.rs +++ b/crates/types/src/detected_feet.rs @@ -1,21 +1,27 @@ use linear_algebra::Point2; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use coordinate_systems::{Ground, Pixel}; -#[derive(Default, Clone, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Default, Clone, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct DetectedFeet { pub positions: Vec>, } -#[derive(Default, Clone, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Default, Clone, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct ClusterPoint { pub pixel_coordinates: Point2, pub position_in_ground: Point2, } -#[derive(Default, Clone, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Default, Clone, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct CountedCluster { pub mean: Point2, pub samples: usize, diff --git a/crates/types/src/fall_state.rs b/crates/types/src/fall_state.rs index 399a2d9b03..96a05701db 100644 --- a/crates/types/src/fall_state.rs +++ b/crates/types/src/fall_state.rs @@ -1,28 +1,69 @@ use std::time::SystemTime; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum Side { Left, Right, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum Direction { Forward { side: Side }, Backward { side: Side }, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum Kind { FacingDown, FacingUp, Sitting, } -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum FallState { #[default] Upright, diff --git a/crates/types/src/field_border.rs b/crates/types/src/field_border.rs index 89de2db016..bd293d686c 100644 --- a/crates/types/src/field_border.rs +++ b/crates/types/src/field_border.rs @@ -3,9 +3,11 @@ use serde::{Deserialize, Serialize}; use coordinate_systems::Pixel; use linear_algebra::Point2; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct FieldBorder { pub border_lines: Vec>, } diff --git a/crates/types/src/field_color.rs b/crates/types/src/field_color.rs index 2438f7ef09..6055ed51fa 100644 --- a/crates/types/src/field_color.rs +++ b/crates/types/src/field_color.rs @@ -1,9 +1,11 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::color::{Intensity, Rgb, RgbChannel, YCbCr444}; -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct FieldColor { pub red_chromaticity_threshold: f32, pub blue_chromaticity_threshold: f32, diff --git a/crates/types/src/field_dimensions.rs b/crates/types/src/field_dimensions.rs index aca258ce40..57c17ac7e0 100644 --- a/crates/types/src/field_dimensions.rs +++ b/crates/types/src/field_dimensions.rs @@ -1,11 +1,13 @@ use serde::{Deserialize, Serialize}; use linear_algebra::Point2; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use coordinate_systems::Field; -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct FieldDimensions { pub ball_radius: f32, pub length: f32, diff --git a/crates/types/src/field_lines.rs b/crates/types/src/field_lines.rs index c7b1e09fbf..acaafea66b 100644 --- a/crates/types/src/field_lines.rs +++ b/crates/types/src/field_lines.rs @@ -1,9 +1,11 @@ use coordinate_systems::Pixel; use geometry::line::Line2; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct ProjectedFieldLines { pub top: Vec>, pub bottom: Vec>, diff --git a/crates/types/src/filtered_game_controller_state.rs b/crates/types/src/filtered_game_controller_state.rs index 00aa878d28..696d51a22e 100644 --- a/crates/types/src/filtered_game_controller_state.rs +++ b/crates/types/src/filtered_game_controller_state.rs @@ -1,10 +1,20 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use spl_network_messages::{GamePhase, Penalty, SubState, Team}; use crate::{filtered_game_state::FilteredGameState, players::Players}; -#[derive(Default, Clone, Copy, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Default, + Clone, + Copy, + Debug, + Serialize, + Deserialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct FilteredGameControllerState { pub game_state: FilteredGameState, pub opponent_game_state: FilteredGameState, diff --git a/crates/types/src/filtered_game_state.rs b/crates/types/src/filtered_game_state.rs index dd6b74375f..141f67bbb4 100644 --- a/crates/types/src/filtered_game_state.rs +++ b/crates/types/src/filtered_game_state.rs @@ -1,9 +1,19 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use spl_network_messages::Team; #[derive( - Clone, Copy, Debug, Default, Serialize, Deserialize, SerializeHierarchy, PartialEq, Eq, + Clone, + Copy, + Debug, + Default, + Serialize, + Deserialize, + PathSerialize, + PathDeserialize, + PathIntrospect, + PartialEq, + Eq, )] pub enum FilteredGameState { #[default] diff --git a/crates/types/src/filtered_segments.rs b/crates/types/src/filtered_segments.rs index 026af3537c..9f7f6189ae 100644 --- a/crates/types/src/filtered_segments.rs +++ b/crates/types/src/filtered_segments.rs @@ -1,9 +1,11 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use super::image_segments::ScanGrid; -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct FilteredSegments { pub scan_grid: ScanGrid, } diff --git a/crates/types/src/filtered_whistle.rs b/crates/types/src/filtered_whistle.rs index 79290e07f6..5241fc38f2 100644 --- a/crates/types/src/filtered_whistle.rs +++ b/crates/types/src/filtered_whistle.rs @@ -1,11 +1,14 @@ use std::time::SystemTime; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct FilteredWhistle { pub is_detected: bool, pub started_this_cycle: bool, + #[path_serde(leaf)] pub last_detection: Option, } diff --git a/crates/types/src/foot_bumper_obstacle.rs b/crates/types/src/foot_bumper_obstacle.rs index 502600d120..0cec38dfbd 100644 --- a/crates/types/src/foot_bumper_obstacle.rs +++ b/crates/types/src/foot_bumper_obstacle.rs @@ -2,9 +2,19 @@ use serde::{Deserialize, Serialize}; use coordinate_systems::Ground; use linear_algebra::Point2; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; -#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Copy, + Clone, + Debug, + Default, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct FootBumperObstacle { pub position: Point2, } diff --git a/crates/types/src/foot_bumper_values.rs b/crates/types/src/foot_bumper_values.rs index 6cdada64f3..dd2e9f2fe8 100644 --- a/crates/types/src/foot_bumper_values.rs +++ b/crates/types/src/foot_bumper_values.rs @@ -1,7 +1,9 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Default, Debug, Clone, SerializeHierarchy, Serialize, Deserialize)] +#[derive( + Default, Debug, Clone, PathSerialize, PathDeserialize, PathIntrospect, Serialize, Deserialize, +)] pub struct FootBumperValues { pub left_foot_bumper_count: i32, pub right_foot_bumper_count: i32, diff --git a/crates/types/src/game_controller_state.rs b/crates/types/src/game_controller_state.rs index f4b6e02ca2..b61b9934c0 100644 --- a/crates/types/src/game_controller_state.rs +++ b/crates/types/src/game_controller_state.rs @@ -1,12 +1,14 @@ use std::time::SystemTime; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use spl_network_messages::{GamePhase, GameState, Penalty, SubState, Team}; use crate::players::Players; -#[derive(Clone, Copy, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct GameControllerState { pub game_state: GameState, pub game_phase: GamePhase, diff --git a/crates/types/src/grayscale_image.rs b/crates/types/src/grayscale_image.rs index f1475b4838..51ef931ccc 100644 --- a/crates/types/src/grayscale_image.rs +++ b/crates/types/src/grayscale_image.rs @@ -1,14 +1,12 @@ use std::sync::Arc; -use image::{ - codecs::jpeg::JpegEncoder, load_from_memory_with_format, ImageBuffer, ImageError, ImageFormat, - Luma, -}; +use path_serde::{PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::{DecodeJpeg, EncodeJpeg, SerializeHierarchy}; -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] -#[serialize_hierarchy(as_jpeg)] +use crate::jpeg::JpegImage; + +#[derive(Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathIntrospect)] +#[path_serde(add_leaf(jpeg: JpegImage))] pub struct GrayscaleImage { width: u32, height: u32, @@ -36,34 +34,3 @@ impl GrayscaleImage { self.height } } - -impl EncodeJpeg for GrayscaleImage { - const DEFAULT_QUALITY: u8 = 40; - type Error = ImageError; - - fn encode_as_jpeg(&self, quality: u8) -> Result, Self::Error> { - let gray_image = ImageBuffer::, &[u8]>::from_raw( - self.width, - self.height, - self.buffer.as_slice(), - ) - .unwrap(); - let mut jpeg_image_buffer = vec![]; - let mut encoder = JpegEncoder::new_with_quality(&mut jpeg_image_buffer, quality); - encoder.encode_image(&gray_image)?; - Ok(jpeg_image_buffer) - } -} - -impl DecodeJpeg for GrayscaleImage { - type Error = ImageError; - - fn decode_from_jpeg(jpeg: Vec) -> Result { - let luma_image = load_from_memory_with_format(&jpeg, ImageFormat::Jpeg)?.into_luma8(); - Ok(Self { - width: luma_image.width(), - height: luma_image.height(), - buffer: luma_image.into_vec().into(), - }) - } -} diff --git a/crates/types/src/image_segments.rs b/crates/types/src/image_segments.rs index ce5013074b..9c2486b7dc 100644 --- a/crates/types/src/image_segments.rs +++ b/crates/types/src/image_segments.rs @@ -1,14 +1,18 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::color::{Intensity, YCbCr444}; -#[derive(Default, Clone, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Default, Clone, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct ImageSegments { pub scan_grid: ScanGrid, } -#[derive(Default, Clone, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Default, Clone, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct ScanGrid { pub vertical_scan_lines: Vec, } diff --git a/crates/types/src/initial_look_around.rs b/crates/types/src/initial_look_around.rs index 874fbb2405..4ec5fc0787 100644 --- a/crates/types/src/initial_look_around.rs +++ b/crates/types/src/initial_look_around.rs @@ -1,9 +1,11 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::support_foot::Side; -#[derive(Debug, Clone, Copy, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Debug, Clone, Copy, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub enum Mode { Center { moving_towards: Side }, Left, diff --git a/crates/types/src/initial_pose.rs b/crates/types/src/initial_pose.rs index 82583e6e8c..a00282beb8 100644 --- a/crates/types/src/initial_pose.rs +++ b/crates/types/src/initial_pose.rs @@ -1,9 +1,11 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::support_foot::Side; -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct InitialPose { pub center_line_offset_x: f32, pub side: Side, diff --git a/crates/types/src/interpolated.rs b/crates/types/src/interpolated.rs index e9d58f43e1..b25d19d1ed 100644 --- a/crates/types/src/interpolated.rs +++ b/crates/types/src/interpolated.rs @@ -2,12 +2,22 @@ use std::f32::consts::PI; use linear_algebra::Isometry2; use nalgebra::{matrix, point, Point2}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use coordinate_systems::{Field, Ground}; -#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct Interpolated { pub first_half_own_half_towards_own_goal: f32, pub first_half_own_half_away_own_goal: f32, diff --git a/crates/types/src/joints.rs b/crates/types/src/joints.rs index 25d2c910a6..f73480727d 100644 --- a/crates/types/src/joints.rs +++ b/crates/types/src/joints.rs @@ -11,8 +11,8 @@ use std::{ ops::{Add, Div, Index, IndexMut, Mul, Sub}, }; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use splines::impl_Interpolate; use self::{ @@ -23,7 +23,18 @@ use self::{ mirror::Mirror, }; -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + PartialEq, + Eq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum JointsName { Head(HeadJoint), LeftArm(ArmJoint), @@ -33,9 +44,18 @@ pub enum JointsName { } #[derive( - Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq, Serialize, SerializeHierarchy, + Clone, + Copy, + Debug, + Default, + Deserialize, + PartialEq, + Eq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, )] -#[serialize_hierarchy(bound = "T: SerializeHierarchy + Serialize, for<'de> T: Deserialize<'de>")] pub struct Joints { pub head: HeadJoints, pub left_arm: ArmJoints, diff --git a/crates/types/src/joints/arm.rs b/crates/types/src/joints/arm.rs index 63842ba3fe..c3e2b0418b 100644 --- a/crates/types/src/joints/arm.rs +++ b/crates/types/src/joints/arm.rs @@ -4,13 +4,24 @@ use std::{ time::Duration, }; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use splines::impl_Interpolate; use super::mirror::Mirror; -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + PartialEq, + Eq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum ArmJoint { ShoulderPitch, ShoulderRoll, @@ -21,9 +32,18 @@ pub enum ArmJoint { } #[derive( - Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq, Serialize, SerializeHierarchy, + Clone, + Copy, + Debug, + Default, + Deserialize, + PartialEq, + Eq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, )] -#[serialize_hierarchy(bound = "T: SerializeHierarchy + Serialize, for<'de> T: Deserialize<'de>")] pub struct ArmJoints { pub shoulder_pitch: T, pub shoulder_roll: T, diff --git a/crates/types/src/joints/body.rs b/crates/types/src/joints/body.rs index 6ab15545df..dfb624547b 100644 --- a/crates/types/src/joints/body.rs +++ b/crates/types/src/joints/body.rs @@ -1,7 +1,7 @@ use std::ops::{Add, Div, Mul, Sub}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use super::{ arm::{ArmJoint, ArmJoints}, @@ -17,9 +17,18 @@ pub enum BodyJointsName { } #[derive( - Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq, Serialize, SerializeHierarchy, + Clone, + Copy, + Debug, + Default, + Deserialize, + PartialEq, + Eq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, )] -#[serialize_hierarchy(bound = "T: SerializeHierarchy + Serialize, for<'de> T: Deserialize<'de>")] pub struct BodyJoints { pub left_arm: ArmJoints, pub right_arm: ArmJoints, @@ -138,9 +147,18 @@ impl Div for BodyJoints { } #[derive( - Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq, Serialize, SerializeHierarchy, + Clone, + Copy, + Debug, + Default, + Deserialize, + PartialEq, + Eq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, )] -#[serialize_hierarchy(bound = "T: SerializeHierarchy + Serialize, for<'de> T: Deserialize<'de>")] pub struct LowerBodyJoints { pub left_leg: LegJoints, pub right_leg: LegJoints, @@ -159,9 +177,18 @@ where } #[derive( - Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq, Serialize, SerializeHierarchy, + Clone, + Copy, + Debug, + Default, + Deserialize, + PartialEq, + Eq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, )] -#[serialize_hierarchy(bound = "T: SerializeHierarchy + Serialize, for<'de> T: Deserialize<'de>")] pub struct UpperBodyJoints { pub left_arm: ArmJoints, pub right_arm: ArmJoints, diff --git a/crates/types/src/joints/head.rs b/crates/types/src/joints/head.rs index 120ebb698c..aad7999eb3 100644 --- a/crates/types/src/joints/head.rs +++ b/crates/types/src/joints/head.rs @@ -3,21 +3,41 @@ use std::{ time::Duration, }; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use super::mirror::Mirror; -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + PartialEq, + Eq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum HeadJoint { Yaw, Pitch, } #[derive( - Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq, Serialize, SerializeHierarchy, + Clone, + Copy, + Debug, + Default, + Deserialize, + PartialEq, + Eq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, )] -#[serialize_hierarchy(bound = "T: SerializeHierarchy + Serialize, for<'de> T: Deserialize<'de>")] pub struct HeadJoints { pub yaw: T, pub pitch: T, diff --git a/crates/types/src/joints/leg.rs b/crates/types/src/joints/leg.rs index fa42ceaa30..7d8d1d721c 100644 --- a/crates/types/src/joints/leg.rs +++ b/crates/types/src/joints/leg.rs @@ -3,12 +3,23 @@ use std::{ time::Duration, }; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use super::mirror::Mirror; -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + PartialEq, + Eq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum LegJoint { AnklePitch, AnkleRoll, @@ -19,9 +30,18 @@ pub enum LegJoint { } #[derive( - Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq, Serialize, SerializeHierarchy, + Clone, + Copy, + Debug, + Default, + Deserialize, + PartialEq, + Eq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, )] -#[serialize_hierarchy(bound = "T: SerializeHierarchy + Serialize, for<'de> T: Deserialize<'de>")] pub struct LegJoints { pub ankle_pitch: T, pub ankle_roll: T, diff --git a/crates/types/src/jpeg.rs b/crates/types/src/jpeg.rs new file mode 100644 index 0000000000..d6820098d8 --- /dev/null +++ b/crates/types/src/jpeg.rs @@ -0,0 +1,38 @@ +use image::{codecs::jpeg::JpegEncoder, ImageBuffer, ImageError, Luma, RgbImage}; +use serde::{Deserialize, Serialize}; + +use crate::{grayscale_image::GrayscaleImage, ycbcr422_image::YCbCr422Image}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct JpegImage { + data: Vec, +} + +impl TryFrom<&GrayscaleImage> for JpegImage { + type Error = ImageError; + + fn try_from(image: &GrayscaleImage) -> Result { + let gray_image = + ImageBuffer::, &[u8]>::from_raw(image.width(), image.height(), image.buffer()) + .unwrap(); + let mut jpeg_buffer = vec![]; + let quality = 40; + let mut encoder = JpegEncoder::new_with_quality(&mut jpeg_buffer, quality); + encoder.encode_image(&gray_image)?; + + Ok(Self { data: jpeg_buffer }) + } +} + +impl TryFrom<&YCbCr422Image> for JpegImage { + type Error = ImageError; + + fn try_from(image: &YCbCr422Image) -> Result { + let rgb_image = RgbImage::from(image); + let mut jpeg_buffer = vec![]; + let quality = 40; + let mut encoder = JpegEncoder::new_with_quality(&mut jpeg_buffer, quality); + encoder.encode_image(&rgb_image)?; + Ok(Self { data: jpeg_buffer }) + } +} diff --git a/crates/types/src/kick_decision.rs b/crates/types/src/kick_decision.rs index 0868ea6d11..4fb2c9feff 100644 --- a/crates/types/src/kick_decision.rs +++ b/crates/types/src/kick_decision.rs @@ -1,11 +1,13 @@ use coordinate_systems::Ground; use linear_algebra::Pose2; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::{motion_command::KickVariant, support_foot::Side}; -#[derive(Debug, Clone, Copy, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Debug, Clone, Copy, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct KickDecision { pub variant: KickVariant, pub kicking_side: Side, diff --git a/crates/types/src/led.rs b/crates/types/src/led.rs index c35889c854..d81b92ff99 100644 --- a/crates/types/src/led.rs +++ b/crates/types/src/led.rs @@ -1,9 +1,19 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::color::Rgb; -#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Serialize, + Deserialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct Leds { pub left_ear: Ear, pub right_ear: Ear, @@ -14,7 +24,17 @@ pub struct Leds { pub right_eye: Eye, } -#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Serialize, + Deserialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct Eye { pub color_at_0: Rgb, pub color_at_45: Rgb, @@ -41,7 +61,17 @@ impl From for Eye { } } -#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Serialize, + Deserialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct Ear { pub intensity_at_0: f32, pub intensity_at_36: f32, diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 6ee9b68be5..572655bda5 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -32,6 +32,7 @@ pub mod initial_pose; pub mod interpolated; pub mod joints; pub mod joints_velocity; +pub mod jpeg; pub mod kick_decision; pub mod kick_target; pub mod led; diff --git a/crates/types/src/limb.rs b/crates/types/src/limb.rs index c5d26ec7a4..a92322363f 100644 --- a/crates/types/src/limb.rs +++ b/crates/types/src/limb.rs @@ -5,9 +5,11 @@ use serde::{Deserialize, Serialize}; use coordinate_systems::Pixel; use linear_algebra::{point, Point2}; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; -#[derive(Clone, Debug, Default, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Limb { pub pixel_polygon: Vec>, } @@ -30,7 +32,9 @@ pub fn is_above_limbs(pixel_position: Point2, projected_limbs: &[Limb]) - }) } -#[derive(Clone, Debug, Default, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct ProjectedLimbs { pub limbs: Vec, } diff --git a/crates/types/src/line_data.rs b/crates/types/src/line_data.rs index cc33dac1b0..91f9efd2de 100644 --- a/crates/types/src/line_data.rs +++ b/crates/types/src/line_data.rs @@ -3,16 +3,18 @@ use std::collections::HashSet; use coordinate_systems::{Ground, Pixel}; use geometry::line::Line2; use linear_algebra::Point2; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Clone, Default, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Default, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct LineData { pub lines: Vec>, pub used_segments: HashSet>, } -#[derive(Clone, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive(Clone, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect)] pub enum LineDiscardReason { TooFewPoints, LineTooShort, diff --git a/crates/types/src/localization.rs b/crates/types/src/localization.rs index c694441718..65c8c60acd 100644 --- a/crates/types/src/localization.rs +++ b/crates/types/src/localization.rs @@ -3,11 +3,13 @@ use serde::{Deserialize, Serialize}; use coordinate_systems::{Field, Ground}; use linear_algebra::{Isometry2, Point2, Pose2}; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use crate::multivariate_normal_distribution::MultivariateNormalDistribution; -#[derive(Clone, Copy, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Update { pub ground_to_field: Isometry2, pub line_center_point: Point2, @@ -17,7 +19,9 @@ pub struct Update { pub line_length_weight: f32, } -#[derive(Clone, Copy, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct ScoredPose { pub state: MultivariateNormalDistribution<3>, pub score: f32, diff --git a/crates/types/src/messages.rs b/crates/types/src/messages.rs index 216e3dea46..d71cbcd557 100644 --- a/crates/types/src/messages.rs +++ b/crates/types/src/messages.rs @@ -2,12 +2,12 @@ use std::net::SocketAddr; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use spl_network_messages::{ GameControllerReturnMessage, GameControllerStateMessage, HulkMessage, VisualRefereeMessage, }; -#[derive(Clone, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive(Clone, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect)] pub enum IncomingMessage { GameController(SocketAddr, GameControllerStateMessage), Spl(HulkMessage), @@ -19,7 +19,7 @@ impl Default for IncomingMessage { } } -#[derive(Clone, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive(Clone, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect)] pub enum OutgoingMessage { GameController(SocketAddr, GameControllerReturnMessage), Spl(HulkMessage), diff --git a/crates/types/src/motion_command.rs b/crates/types/src/motion_command.rs index 9843262cf6..7bfdc7bd9d 100644 --- a/crates/types/src/motion_command.rs +++ b/crates/types/src/motion_command.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use coordinate_systems::Ground; use linear_algebra::{Orientation2, Point2}; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use crate::{ camera_position::CameraPosition, @@ -17,7 +17,9 @@ pub enum OrientationMode { Override(Orientation2), } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub enum MotionCommand { ArmsUpSquat, FallProtection { @@ -99,7 +101,17 @@ impl MotionCommand { } } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum HeadMotion { ZeroAngles, Center, @@ -116,20 +128,53 @@ pub enum HeadMotion { Unstiff, } -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum ImageRegion { Bottom, #[default] Center, } -#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + Eq, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum ArmMotion { Swing, PullTight, } -#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + Eq, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum KickDirection { Back, Front, @@ -137,21 +182,53 @@ pub enum KickDirection { Right, } -#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + Eq, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum KickVariant { Forward, Turn, Side, } -#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + Eq, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum JumpDirection { Left, Right, } #[derive( - Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, SerializeHierarchy, + Clone, + Copy, + Debug, + Default, + Deserialize, + Eq, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, )] pub enum GlanceDirection { #[default] diff --git a/crates/types/src/motion_selection.rs b/crates/types/src/motion_selection.rs index d91d4c564f..f5f70c3dad 100644 --- a/crates/types/src/motion_selection.rs +++ b/crates/types/src/motion_selection.rs @@ -1,15 +1,28 @@ use std::ops::{Index, IndexMut}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Clone, Debug, Default, Serialize, SerializeHierarchy, Deserialize)] +#[derive( + Clone, Debug, Default, Serialize, PathSerialize, PathDeserialize, PathIntrospect, Deserialize, +)] pub struct MotionSelection { pub current_motion: MotionType, pub dispatching_motion: Option, } -#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + Eq, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum MotionType { ArmsUpSquat, Dispatching, @@ -33,7 +46,7 @@ impl Default for MotionType { } } -#[derive(Clone, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive(Clone, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect)] pub struct MotionSafeExits { arms_up_squat: bool, dispatching: bool, diff --git a/crates/types/src/motor_commands.rs b/crates/types/src/motor_commands.rs index fb495dfac1..963d38a48c 100644 --- a/crates/types/src/motor_commands.rs +++ b/crates/types/src/motor_commands.rs @@ -8,56 +8,63 @@ use crate::joints::{ mirror::Mirror, Joints, }; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use splines::impl_Interpolate; #[derive( - Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq, Serialize, SerializeHierarchy, + Clone, + Copy, + Debug, + Default, + Deserialize, + PartialEq, + Eq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, )] -#[serialize_hierarchy( - bound = "Joints: SerializeHierarchy + Serialize, for<'de> Joints: Deserialize<'de>" -)] -pub struct MotorCommands { - pub positions: Joints, - pub stiffnesses: Joints, +pub struct MotorCommands { + pub positions: T, + pub stiffnesses: T, } impl_Interpolate!(f32, MotorCommands>, PI); -impl Mirror for MotorCommands +impl Mirror for MotorCommands where - Joints: Mirror, + T: Mirror, { fn mirrored(self) -> Self { Self { - positions: Joints::mirrored(self.positions), - stiffnesses: Joints::mirrored(self.stiffnesses), + positions: T::mirrored(self.positions), + stiffnesses: T::mirrored(self.stiffnesses), } } } -impl Mul for MotorCommands +impl Mul for MotorCommands where - Joints: Mul, + T: Mul, { - type Output = MotorCommands; + type Output = MotorCommands; fn mul(self, right: f32) -> Self::Output { Self::Output { - positions: Joints::mul(self.positions, right), + positions: T::mul(self.positions, right), stiffnesses: self.stiffnesses * right, } } } -impl Add> for MotorCommands +impl Add> for MotorCommands where - Joints: Add, + T: Add, { - type Output = MotorCommands; + type Output = MotorCommands; - fn add(self, right: MotorCommands) -> Self::Output { + fn add(self, right: MotorCommands) -> Self::Output { Self::Output { positions: self.positions + right.positions, stiffnesses: self.stiffnesses + right.stiffnesses, @@ -65,13 +72,13 @@ where } } -impl Sub> for MotorCommands +impl Sub> for MotorCommands where - Joints: Sub, + T: Sub, { - type Output = MotorCommands; + type Output = MotorCommands; - fn sub(self, right: MotorCommands) -> Self::Output { + fn sub(self, right: MotorCommands) -> Self::Output { Self::Output { positions: self.positions - right.positions, stiffnesses: self.stiffnesses - right.stiffnesses, @@ -79,11 +86,11 @@ where } } -impl Div for MotorCommands +impl Div for MotorCommands where - Joints: Div, + T: Div, { - type Output = MotorCommands; + type Output = MotorCommands; fn div(self, right: f32) -> Self::Output { Self::Output { diff --git a/crates/types/src/multivariate_normal_distribution.rs b/crates/types/src/multivariate_normal_distribution.rs index a20ccc4fad..a0a9e94568 100644 --- a/crates/types/src/multivariate_normal_distribution.rs +++ b/crates/types/src/multivariate_normal_distribution.rs @@ -1,11 +1,12 @@ use nalgebra::{SMatrix, SVector}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Clone, Copy, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct MultivariateNormalDistribution { - #[serialize_hierarchy(leaf)] pub mean: SVector, - #[serialize_hierarchy(leaf)] + #[path_serde(leaf)] pub covariance: SMatrix, } diff --git a/crates/types/src/obstacle_avoiding_arms.rs b/crates/types/src/obstacle_avoiding_arms.rs index 5149625ab4..9ab5b5c87f 100644 --- a/crates/types/src/obstacle_avoiding_arms.rs +++ b/crates/types/src/obstacle_avoiding_arms.rs @@ -1,12 +1,14 @@ use std::f32::consts::FRAC_PI_2; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use splines::Interpolate; use crate::joints::{arm::ArmJoints, mirror::Mirror}; -#[derive(Clone, Debug, Default, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub enum ArmCommand { #[default] Swing, @@ -50,7 +52,9 @@ impl ArmCommand { } } -#[derive(Clone, Debug, Default, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct ArmCommands { pub left_arm: ArmCommand, pub right_arm: ArmCommand, diff --git a/crates/types/src/obstacles.rs b/crates/types/src/obstacles.rs index 38ec9abe7d..77a051272d 100644 --- a/crates/types/src/obstacles.rs +++ b/crates/types/src/obstacles.rs @@ -1,11 +1,21 @@ use serde::{Deserialize, Serialize}; use linear_algebra::Point2; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use coordinate_systems::Ground; -#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum ObstacleKind { Ball, GoalPost, @@ -14,7 +24,9 @@ pub enum ObstacleKind { Unknown, } -#[derive(Clone, Copy, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Obstacle { pub kind: ObstacleKind, pub position: Point2, diff --git a/crates/types/src/orientation_filter.rs b/crates/types/src/orientation_filter.rs index 7908290a5a..40cde66acb 100644 --- a/crates/types/src/orientation_filter.rs +++ b/crates/types/src/orientation_filter.rs @@ -1,8 +1,10 @@ use nalgebra::{UnitComplex, UnitQuaternion, Vector3}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Clone, Debug, Default, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Parameters { pub acceleration_threshold: f32, pub delta_angular_velocity_threshold: f32, @@ -12,7 +14,9 @@ pub struct Parameters { pub force_sensitive_resistor_threshold: f32, } -#[derive(Clone, Debug, Default, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct State { pub previous_angular_velocity: Vector3, pub angular_velocity_bias: Vector3, diff --git a/crates/types/src/parameters.rs b/crates/types/src/parameters.rs index 0d1d835b1e..166d3967f9 100644 --- a/crates/types/src/parameters.rs +++ b/crates/types/src/parameters.rs @@ -3,8 +3,8 @@ use std::{path::PathBuf, time::Duration}; use coordinate_systems::{Field, Ground, NormalizedPixel}; use linear_algebra::{Point2, Vector2}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::{ joints::head::HeadJoints, @@ -13,7 +13,9 @@ use crate::{ step_plan::Step, }; -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct WhistleDetectionParameters { pub detection_band: Range, pub background_noise_scaling: f32, @@ -21,7 +23,9 @@ pub struct WhistleDetectionParameters { pub number_of_chunks: usize, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct StepPlannerParameters { pub injected_step: Option, pub max_step_size: Step, @@ -30,7 +34,9 @@ pub struct StepPlannerParameters { pub rotation_exponent: f32, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct BehaviorParameters { pub injected_motion_command: Option, pub lost_ball: LostBallParameters, @@ -45,7 +51,17 @@ pub struct BehaviorParameters { pub initial_lookaround_duration: Duration, } -#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Copy, + Clone, + Debug, + Default, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct LookActionParameters { pub angle_threshold: f32, pub distance_threshold: f32, @@ -53,7 +69,9 @@ pub struct LookActionParameters { pub position_of_interest_switch_interval: Duration, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct RolePositionsParameters { pub defender_aggressive_ring_radius: f32, pub defender_passive_ring_radius: f32, @@ -72,20 +90,26 @@ pub struct RolePositionsParameters { pub striker_set_position: Point2, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct SearchParameters { pub position_reached_distance: f32, pub rotation_per_step: f32, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct InWalkKicksParameters { pub forward: InWalkKickInfoParameters, pub turn: InWalkKickInfoParameters, pub side: InWalkKickInfoParameters, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct FindKickTargetsParameters { pub distance_from_corner: f32, pub corner_kick_target_distance_to_goal: f32, @@ -106,7 +130,9 @@ impl Index for InWalkKicksParameters { } } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct InWalkKickInfoParameters { pub position: nalgebra::Point2, pub orientation: f32, @@ -115,7 +141,9 @@ pub struct InWalkKickInfoParameters { pub enabled: bool, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct DribblingParameters { pub hybrid_align_distance: f32, pub distance_to_be_aligned: f32, @@ -123,7 +151,9 @@ pub struct DribblingParameters { pub ignore_robot_when_near_ball_radius: f32, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct WalkAndStandParameters { pub hysteresis: nalgebra::Vector2, pub target_reached_thresholds: nalgebra::Vector2, @@ -131,12 +161,24 @@ pub struct WalkAndStandParameters { pub distance_to_be_aligned: f32, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct LostBallParameters { pub offset_to_last_ball_location: Vector2, } -#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Copy, + Clone, + Debug, + Default, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct InterceptBallParameters { pub maximum_ball_distance: f32, pub minimum_ball_velocity: f32, @@ -145,7 +187,9 @@ pub struct InterceptBallParameters { pub maximum_intercept_distance: f32, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct PathPlanningParameters { pub arc_walking_speed: f32, pub ball_obstacle_radius: f32, @@ -158,7 +202,9 @@ pub struct PathPlanningParameters { pub half_rotation: Duration, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct GameStateFilterParameters { pub game_controller_controller_delay: Duration, pub playing_message_delay: Duration, @@ -169,13 +215,25 @@ pub struct GameStateFilterParameters { pub whistle_acceptance_goal_distance: Vector2, } -#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct ImageRegionParameters { pub bottom: Point2, pub center: Point2, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct LookAroundParameters { pub look_around_timeout: Duration, pub quick_search_timeout: Duration, @@ -186,7 +244,9 @@ pub struct LookAroundParameters { pub halfway_right_positions: HeadJoints, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct SplNetworkParameters { pub game_controller_return_message_interval: Duration, pub remaining_amount_of_messages_to_stop_sending: u16, @@ -196,7 +256,17 @@ pub struct SplNetworkParameters { pub striker_trusts_team_ball: Duration, } -#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum MedianModeParameters { #[default] Disabled, @@ -204,14 +274,26 @@ pub enum MedianModeParameters { FivePixels, } -#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum EdgeDetectionSourceParameters { #[default] Luminance, GreenChromaticity, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct BallDetectionParameters { pub minimal_radius: f32, pub preclassifier_neural_network: PathBuf, @@ -227,7 +309,9 @@ pub struct BallDetectionParameters { pub ball_radius_enlargement_factor: f32, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct BallFilterParameters { pub hypothesis_timeout: Duration, pub measurement_matching_distance: f32, @@ -244,7 +328,9 @@ pub struct BallFilterParameters { pub resting_ball_velocity_threshold: f32, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct ObstacleFilterParameters { pub hypothesis_timeout: Duration, pub network_robot_measurement_matching_distance: f32, @@ -268,7 +354,9 @@ pub struct ObstacleFilterParameters { pub goal_post_obstacle_radius: f32, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct CameraMatrixParameters { pub camera_pitch: f32, pub extrinsic_rotations: nalgebra::Vector3, @@ -276,7 +364,9 @@ pub struct CameraMatrixParameters { pub cc_optical_center: nalgebra::Point2, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct SearchSuggestorParameters { pub cells_per_meter: f32, pub heatmap_decay_factor: f32, diff --git a/crates/types/src/path_obstacles.rs b/crates/types/src/path_obstacles.rs index aac57d8a84..43198793d5 100644 --- a/crates/types/src/path_obstacles.rs +++ b/crates/types/src/path_obstacles.rs @@ -1,12 +1,14 @@ use std::collections::HashSet; use geometry::{arc::Arc, circle::Circle, direction::Direction, line_segment::LineSegment}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use coordinate_systems::Ground; -#[derive(Clone, Copy, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub enum PathObstacleShape { Circle(Circle), LineSegment(LineSegment), @@ -46,7 +48,7 @@ impl PathObstacleShape { } } -#[derive(Clone, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive(Clone, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect)] pub struct PathObstacle { pub shape: PathObstacleShape, pub nodes: Vec, diff --git a/crates/types/src/penalty_shot_direction.rs b/crates/types/src/penalty_shot_direction.rs index 555ce5f8e1..c1759ce390 100644 --- a/crates/types/src/penalty_shot_direction.rs +++ b/crates/types/src/penalty_shot_direction.rs @@ -1,8 +1,19 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Clone, Copy, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Default, + Debug, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum PenaltyShotDirection { + #[default] NotMoving, Left, Right, diff --git a/crates/types/src/perspective_grid_candidates.rs b/crates/types/src/perspective_grid_candidates.rs index 89b7e97403..601e3dfc11 100644 --- a/crates/types/src/perspective_grid_candidates.rs +++ b/crates/types/src/perspective_grid_candidates.rs @@ -1,17 +1,29 @@ use approx::{AbsDiffEq, RelativeEq}; use geometry::circle::Circle; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use coordinate_systems::Pixel; -#[derive(Default, Clone, Copy, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Default, + Clone, + Copy, + Debug, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct Row { pub circle_radius: f32, pub center_y: f32, } -#[derive(Default, Clone, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Default, Clone, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct PerspectiveGridCandidates { pub candidates: Vec>, } diff --git a/crates/types/src/planned_path.rs b/crates/types/src/planned_path.rs index 65b4cb79ae..ef50e5c01f 100644 --- a/crates/types/src/planned_path.rs +++ b/crates/types/src/planned_path.rs @@ -1,12 +1,14 @@ use approx::{AbsDiffEq, RelativeEq}; use geometry::{arc::Arc, direction::Direction, line_segment::LineSegment}; use linear_algebra::Point2; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use coordinate_systems::Ground; -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, SerializeHierarchy)] +#[derive( + Clone, Debug, Serialize, Deserialize, PartialEq, PathSerialize, PathDeserialize, PathIntrospect, +)] pub enum PathSegment { LineSegment(LineSegment), Arc(Arc, Direction), @@ -75,7 +77,9 @@ impl PathSegment { } } -#[derive(Clone, Debug, Default, Serialize, SerializeHierarchy, Deserialize)] +#[derive( + Clone, Debug, Default, Serialize, PathSerialize, PathDeserialize, PathIntrospect, Deserialize, +)] pub struct PlannedPath { pub path: Option>, } diff --git a/crates/types/src/players.rs b/crates/types/src/players.rs index 18e892e5c9..12bbcc9608 100644 --- a/crates/types/src/players.rs +++ b/crates/types/src/players.rs @@ -1,12 +1,21 @@ use std::ops::{Index, IndexMut}; use color_eyre::Result; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use spl_network_messages::{Penalty, PlayerNumber, TeamState}; -#[derive(Clone, Copy, Default, Debug, Deserialize, Serialize, SerializeHierarchy)] -#[serialize_hierarchy(bound = "T: SerializeHierarchy + Serialize, for<'de> T: Deserialize<'de>")] +#[derive( + Clone, + Copy, + Default, + Debug, + Deserialize, + Serialize, + PathSerialize, + PathIntrospect, + PathDeserialize, +)] pub struct Players { pub one: T, pub two: T, diff --git a/crates/types/src/point_of_interest.rs b/crates/types/src/point_of_interest.rs index 484135fc0d..18dbb2b69a 100644 --- a/crates/types/src/point_of_interest.rs +++ b/crates/types/src/point_of_interest.rs @@ -1,11 +1,21 @@ use serde::{Deserialize, Serialize}; use linear_algebra::Point2; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use coordinate_systems::Field; -#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum PointOfInterest { #[default] Forward, diff --git a/crates/types/src/pose_detection.rs b/crates/types/src/pose_detection.rs index 1c17854f88..7b466ab7c5 100644 --- a/crates/types/src/pose_detection.rs +++ b/crates/types/src/pose_detection.rs @@ -4,16 +4,20 @@ use crate::bounding_box::BoundingBox; use color_eyre::Result; use coordinate_systems::Pixel; use linear_algebra::{point, Point2}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Debug, Clone, Copy, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Debug, Clone, Copy, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Keypoint { pub point: Point2, pub confidence: f32, } -#[derive(Debug, Clone, Copy, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Debug, Clone, Copy, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Keypoints { pub left_eye: Keypoint, pub right_eye: Keypoint, @@ -112,7 +116,9 @@ impl From for [Keypoint; 17] { } } -#[derive(Debug, Clone, Copy, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Debug, Clone, Copy, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct HumanPose { pub bounding_box: BoundingBox, pub keypoints: Keypoints, @@ -127,7 +133,9 @@ impl HumanPose { } } -#[derive(Debug, Clone, Copy, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Debug, Clone, Copy, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct RefereePoseCandidate { pub pose: HumanPose, pub distance_to_referee_position: f32, diff --git a/crates/types/src/pose_kinds.rs b/crates/types/src/pose_kinds.rs index efd4ca69a4..3e5880f97e 100644 --- a/crates/types/src/pose_kinds.rs +++ b/crates/types/src/pose_kinds.rs @@ -1,14 +1,24 @@ use linear_algebra::Point2; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Debug, Clone, Serialize, Deserialize, SerializeHierarchy, PartialEq, Eq)] +#[derive( + Debug, + Clone, + Serialize, + Deserialize, + PathSerialize, + PathDeserialize, + PathIntrospect, + PartialEq, + Eq, +)] pub enum PoseKind { AboveHeadArms, ArmsBySide, } -#[derive(Debug, Clone, Serialize, Deserialize, SerializeHierarchy)] +#[derive(Debug, Clone, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect)] pub struct PoseKindPosition { pub pose_kind: PoseKind, pub position: Point2, diff --git a/crates/types/src/primary_state.rs b/crates/types/src/primary_state.rs index beab3bb4f5..d03fe58e03 100644 --- a/crates/types/src/primary_state.rs +++ b/crates/types/src/primary_state.rs @@ -1,8 +1,19 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; #[derive( - Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, SerializeHierarchy, + Clone, + Copy, + Debug, + Default, + Deserialize, + Eq, + Hash, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, )] pub enum PrimaryState { #[default] diff --git a/crates/types/src/robot_kinematics.rs b/crates/types/src/robot_kinematics.rs index f64d45753b..61c936d951 100644 --- a/crates/types/src/robot_kinematics.rs +++ b/crates/types/src/robot_kinematics.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use linear_algebra::Isometry3; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use coordinate_systems::{ Head, LeftAnkle, LeftElbow, LeftFoot, LeftForearm, LeftHip, LeftPelvis, LeftShoulder, LeftSole, @@ -10,18 +10,24 @@ use coordinate_systems::{ RightUpperArm, RightWrist, Robot, Torso, }; -#[derive(Debug, Clone, Default, SerializeHierarchy, Serialize, Deserialize)] +#[derive( + Debug, Clone, Default, PathSerialize, PathDeserialize, PathIntrospect, Serialize, Deserialize, +)] pub struct RobotHeadKinematics { pub neck_to_robot: Isometry3, pub head_to_robot: Isometry3, } -#[derive(Debug, Clone, Default, SerializeHierarchy, Serialize, Deserialize)] +#[derive( + Debug, Clone, Default, PathSerialize, PathDeserialize, PathIntrospect, Serialize, Deserialize, +)] pub struct RobotTorsoKinematics { pub torso_to_robot: Isometry3, } -#[derive(Debug, Clone, Default, SerializeHierarchy, Serialize, Deserialize)] +#[derive( + Debug, Clone, Default, PathSerialize, PathDeserialize, PathIntrospect, Serialize, Deserialize, +)] pub struct RobotLeftArmKinematics { pub shoulder_to_robot: Isometry3, pub upper_arm_to_robot: Isometry3, @@ -30,7 +36,9 @@ pub struct RobotLeftArmKinematics { pub wrist_to_robot: Isometry3, } -#[derive(Debug, Clone, Default, SerializeHierarchy, Serialize, Deserialize)] +#[derive( + Debug, Clone, Default, PathSerialize, PathDeserialize, PathIntrospect, Serialize, Deserialize, +)] pub struct RobotRightArmKinematics { pub shoulder_to_robot: Isometry3, pub upper_arm_to_robot: Isometry3, @@ -39,7 +47,9 @@ pub struct RobotRightArmKinematics { pub wrist_to_robot: Isometry3, } -#[derive(Debug, Clone, Default, SerializeHierarchy, Serialize, Deserialize)] +#[derive( + Debug, Clone, Default, PathSerialize, PathDeserialize, PathIntrospect, Serialize, Deserialize, +)] pub struct RobotLeftLegKinematics { pub pelvis_to_robot: Isometry3, pub hip_to_robot: Isometry3, @@ -50,7 +60,9 @@ pub struct RobotLeftLegKinematics { pub sole_to_robot: Isometry3, } -#[derive(Debug, Clone, Default, SerializeHierarchy, Serialize, Deserialize)] +#[derive( + Debug, Clone, Default, PathSerialize, PathDeserialize, PathIntrospect, Serialize, Deserialize, +)] pub struct RobotRightLegKinematics { pub pelvis_to_robot: Isometry3, pub hip_to_robot: Isometry3, @@ -61,7 +73,9 @@ pub struct RobotRightLegKinematics { pub sole_to_robot: Isometry3, } -#[derive(Debug, Clone, Default, SerializeHierarchy, Serialize, Deserialize)] +#[derive( + Debug, Clone, Default, PathSerialize, PathDeserialize, PathIntrospect, Serialize, Deserialize, +)] pub struct RobotKinematics { pub head: RobotHeadKinematics, pub torso: RobotTorsoKinematics, diff --git a/crates/types/src/roles.rs b/crates/types/src/roles.rs index 6641fb1ad2..019dc10f2b 100644 --- a/crates/types/src/roles.rs +++ b/crates/types/src/roles.rs @@ -1,8 +1,18 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; #[derive( - Default, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, SerializeHierarchy, + Default, + Clone, + Copy, + Debug, + Deserialize, + Eq, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, )] pub enum Role { DefenderLeft, diff --git a/crates/types/src/rule_obstacles.rs b/crates/types/src/rule_obstacles.rs index 8539694fd0..00d037a8c5 100644 --- a/crates/types/src/rule_obstacles.rs +++ b/crates/types/src/rule_obstacles.rs @@ -1,10 +1,12 @@ use geometry::{circle::Circle, rectangle::Rectangle}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use coordinate_systems::Field; -#[derive(Clone, Copy, Debug, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub enum RuleObstacle { Circle(Circle), Rectangle(Rectangle), diff --git a/crates/types/src/samples.rs b/crates/types/src/samples.rs index 442b8e1af5..0465a44aae 100644 --- a/crates/types/src/samples.rs +++ b/crates/types/src/samples.rs @@ -1,10 +1,13 @@ use std::sync::Arc; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Samples { pub rate: u32, + #[path_serde(leaf)] pub channels_of_samples: Arc>>, } diff --git a/crates/types/src/sensor_data.rs b/crates/types/src/sensor_data.rs index dea64043b0..81364a9ca7 100644 --- a/crates/types/src/sensor_data.rs +++ b/crates/types/src/sensor_data.rs @@ -1,11 +1,21 @@ use coordinate_systems::Robot; use linear_algebra::{Vector2, Vector3}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::joints::Joints; -#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct InertialMeasurementUnitData { // Linear acceleration is coming from a left handed coordinate system pub linear_acceleration: Vector3, @@ -13,13 +23,17 @@ pub struct InertialMeasurementUnitData { pub roll_pitch: Vector2, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct SonarSensors { pub left: f32, pub right: f32, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Foot { pub front_left: f32, pub front_right: f32, @@ -33,13 +47,17 @@ impl Foot { } } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct ForceSensitiveResistors { pub left: Foot, pub right: Foot, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct TouchSensors { pub chest_button: bool, pub head_front: bool, @@ -57,7 +75,9 @@ pub struct TouchSensors { pub right_hand_right: bool, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct SensorData { pub positions: Joints, pub inertial_measurement_unit: InertialMeasurementUnitData, diff --git a/crates/types/src/sole_pressure.rs b/crates/types/src/sole_pressure.rs index e03c7600ce..67806e34c9 100644 --- a/crates/types/src/sole_pressure.rs +++ b/crates/types/src/sole_pressure.rs @@ -1,7 +1,9 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct SolePressure { pub left: f32, pub right: f32, diff --git a/crates/types/src/sonar_obstacle.rs b/crates/types/src/sonar_obstacle.rs index 4f54f2e238..6bf11ff53c 100644 --- a/crates/types/src/sonar_obstacle.rs +++ b/crates/types/src/sonar_obstacle.rs @@ -1,11 +1,21 @@ use serde::{Deserialize, Serialize}; use linear_algebra::Point2; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use coordinate_systems::Ground; -#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Copy, + Clone, + Debug, + Default, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct SonarObstacle { pub position: Point2, } diff --git a/crates/types/src/sonar_values.rs b/crates/types/src/sonar_values.rs index d7392f04af..12180d99df 100644 --- a/crates/types/src/sonar_values.rs +++ b/crates/types/src/sonar_values.rs @@ -1,7 +1,9 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Default, Debug, Clone, SerializeHierarchy, Serialize, Deserialize)] +#[derive( + Default, Debug, Clone, PathSerialize, PathDeserialize, PathIntrospect, Serialize, Deserialize, +)] pub struct SonarValues { pub left_sonar: bool, pub right_sonar: bool, diff --git a/crates/types/src/step_plan.rs b/crates/types/src/step_plan.rs index 50476c4644..2f250e7570 100644 --- a/crates/types/src/step_plan.rs +++ b/crates/types/src/step_plan.rs @@ -1,10 +1,20 @@ use std::ops::{Add, Sub}; use nalgebra::Vector2; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Clone, Copy, Debug, Serialize, Deserialize, SerializeHierarchy, Default)] +#[derive( + Clone, + Copy, + Debug, + Serialize, + Deserialize, + PathSerialize, + PathDeserialize, + PathIntrospect, + Default, +)] pub struct Step { pub forward: f32, pub left: f32, diff --git a/crates/types/src/support_foot.rs b/crates/types/src/support_foot.rs index ee84ccb0f4..60dd76d21d 100644 --- a/crates/types/src/support_foot.rs +++ b/crates/types/src/support_foot.rs @@ -1,7 +1,18 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, SerializeHierarchy)] +#[derive( + Clone, + Copy, + Debug, + Deserialize, + Eq, + PartialEq, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum Side { Left, Right, @@ -22,7 +33,9 @@ impl Default for Side { } } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct SupportFoot { pub support_side: Option, pub changed_this_cycle: bool, diff --git a/crates/types/src/walk_command.rs b/crates/types/src/walk_command.rs index 2298f0328a..6896e21083 100644 --- a/crates/types/src/walk_command.rs +++ b/crates/types/src/walk_command.rs @@ -1,9 +1,19 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use crate::{motion_command::KickVariant, step_plan::Step, support_foot::Side}; -#[derive(Default, Clone, Copy, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Default, + Clone, + Copy, + Debug, + Serialize, + Deserialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub enum WalkCommand { #[default] Stand, diff --git a/crates/types/src/whistle.rs b/crates/types/src/whistle.rs index 15544bac6a..cc51cab3f6 100644 --- a/crates/types/src/whistle.rs +++ b/crates/types/src/whistle.rs @@ -1,12 +1,16 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Whistle { pub is_detected: Vec, } -#[derive(Debug, Default, Clone, SerializeHierarchy, Serialize, Deserialize)] +#[derive( + Debug, Default, Clone, PathSerialize, PathDeserialize, PathIntrospect, Serialize, Deserialize, +)] pub struct DetectionInfo { pub overall_mean: f32, pub std_deviation: f32, diff --git a/crates/types/src/world_state.rs b/crates/types/src/world_state.rs index dd616df2b6..607ac48cab 100644 --- a/crates/types/src/world_state.rs +++ b/crates/types/src/world_state.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use coordinate_systems::{Field, Ground}; use linear_algebra::{Isometry2, Point2, Vector2}; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use spl_network_messages::PlayerNumber; use crate::{ @@ -14,7 +14,7 @@ use crate::{ roles::Role, rule_obstacles::RuleObstacle, support_foot::Side, }; -#[derive(Clone, Debug, Default, Serialize, Deserialize, SerializeHierarchy)] +#[derive(Clone, Debug, Default, Serialize, Deserialize, PathSerialize, PathIntrospect)] pub struct WorldState { pub ball: Option, pub rule_ball: Option, @@ -29,7 +29,9 @@ pub struct WorldState { pub robot: RobotState, } -#[derive(Clone, Copy, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct BallState { pub ball_in_ground: Point2, pub ball_in_field: Point2, @@ -39,6 +41,19 @@ pub struct BallState { pub field_side: Side, } +impl Default for BallState { + fn default() -> Self { + Self { + ball_in_ground: Point2::origin(), + ball_in_field: Point2::origin(), + ball_in_ground_velocity: Vector2::zeros(), + last_seen_ball: UNIX_EPOCH, + penalty_shot_direction: Default::default(), + field_side: Side::Left, + } + } +} + impl BallState { pub fn new_at_center(ground_to_field: Isometry2) -> Self { Self { @@ -52,7 +67,9 @@ impl BallState { } } -#[derive(Clone, Debug, Default, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct RobotState { pub ground_to_field: Option>, pub role: Role, diff --git a/crates/types/src/ycbcr422_image.rs b/crates/types/src/ycbcr422_image.rs index 7e622a9a62..cade49131b 100644 --- a/crates/types/src/ycbcr422_image.rs +++ b/crates/types/src/ycbcr422_image.rs @@ -7,23 +7,26 @@ use std::{ }; use color_eyre::eyre::{self, WrapErr}; -use image::{ - codecs::jpeg::JpegEncoder, io::Reader, load_from_memory_with_format, ImageError, ImageFormat, - RgbImage, -}; +use image::{io::Reader, RgbImage}; use serde::{Deserialize, Serialize}; use coordinate_systems::Pixel; use linear_algebra::Point2; -use serialize_hierarchy::{DecodeJpeg, EncodeJpeg, SerializeHierarchy}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; -use crate::color::{Rgb, YCbCr422, YCbCr444}; +use crate::{ + color::{Rgb, YCbCr422, YCbCr444}, + jpeg::JpegImage, +}; -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] -#[serialize_hierarchy(as_jpeg)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathIntrospect, PathDeserialize, +)] +#[path_serde(add_leaf(jpeg: JpegImage))] pub struct YCbCr422Image { width_422: u32, height: u32, + #[path_serde(leaf)] buffer: Arc>, } @@ -104,28 +107,6 @@ impl From for RgbImage { } } -impl EncodeJpeg for YCbCr422Image { - const DEFAULT_QUALITY: u8 = 40; - type Error = ImageError; - - fn encode_as_jpeg(&self, quality: u8) -> Result, Self::Error> { - let rgb_image: RgbImage = self.into(); - let mut jpeg_buffer = vec![]; - let mut encoder = JpegEncoder::new_with_quality(&mut jpeg_buffer, quality); - encoder.encode_image(&rgb_image)?; - Ok(jpeg_buffer) - } -} - -impl DecodeJpeg for YCbCr422Image { - type Error = ImageError; - - fn decode_from_jpeg(jpeg: Vec) -> Result { - let rgb_image = load_from_memory_with_format(&jpeg, ImageFormat::Jpeg)?.into_rgb8(); - Ok(rgb_image.into()) - } -} - impl YCbCr422Image { pub fn buffer(&self) -> &[YCbCr422] { &self.buffer diff --git a/crates/walking_engine/Cargo.toml b/crates/walking_engine/Cargo.toml index c1f5d486ff..8f2e7a398b 100644 --- a/crates/walking_engine/Cargo.toml +++ b/crates/walking_engine/Cargo.toml @@ -6,13 +6,13 @@ license.workspace = true homepage.workspace = true [dependencies] -serde = { workspace = true } -types = { workspace = true } -linear_algebra = { workspace = true } -nalgebra = { workspace = true } coordinate_systems = { workspace = true } -serialize_hierarchy = { workspace = true } -splines = { workspace = true } -kinematics = { workspace = true } itertools = { workspace = true } +kinematics = { workspace = true } +linear_algebra = { workspace = true } motionfile = { workspace = true } +nalgebra = { workspace = true } +path_serde = { workspace = true } +serde = { workspace = true } +splines = { workspace = true } +types = { workspace = true } diff --git a/crates/walking_engine/src/feet.rs b/crates/walking_engine/src/feet.rs index a05f536409..2804fe303d 100644 --- a/crates/walking_engine/src/feet.rs +++ b/crates/walking_engine/src/feet.rs @@ -1,13 +1,15 @@ use coordinate_systems::{Robot, Walk}; use kinematics::forward::{left_sole_to_robot, right_sole_to_robot}; use linear_algebra::{point, Isometry3, Orientation3, Pose3, Vector2, Vector3}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::{joints::body::BodyJoints, step_plan::Step, support_foot::Side}; use crate::parameters::Parameters; -#[derive(Clone, Copy, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Feet { pub support_sole: Pose3, pub swing_sole: Pose3, diff --git a/crates/walking_engine/src/foot_leveling.rs b/crates/walking_engine/src/foot_leveling.rs index 60c679e1c5..44adfc0df7 100644 --- a/crates/walking_engine/src/foot_leveling.rs +++ b/crates/walking_engine/src/foot_leveling.rs @@ -1,12 +1,22 @@ use coordinate_systems::Robot; use linear_algebra::Orientation3; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::{joints::body::LowerBodyJoints, support_foot::Side}; use crate::Context; -#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, SerializeHierarchy)] +#[derive( + Debug, + Clone, + Copy, + Serialize, + Deserialize, + Default, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct FootLeveling { pub roll: f32, pub pitch: f32, diff --git a/crates/walking_engine/src/gyro_balancing.rs b/crates/walking_engine/src/gyro_balancing.rs index cfbd02010a..481d2b61d4 100644 --- a/crates/walking_engine/src/gyro_balancing.rs +++ b/crates/walking_engine/src/gyro_balancing.rs @@ -1,5 +1,5 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::{ joints::{body::LowerBodyJoints, leg::LegJoints}, support_foot::Side, @@ -7,7 +7,17 @@ use types::{ use crate::Context; -#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, SerializeHierarchy)] +#[derive( + Debug, + Clone, + Copy, + Serialize, + Deserialize, + Default, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct GyroBalancing { balancing: LegJoints, } diff --git a/crates/walking_engine/src/kick_state.rs b/crates/walking_engine/src/kick_state.rs index 7f1c888d20..edd541746b 100644 --- a/crates/walking_engine/src/kick_state.rs +++ b/crates/walking_engine/src/kick_state.rs @@ -1,6 +1,6 @@ use itertools::Itertools; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use splines::Interpolate; use std::time::Duration; use types::{ @@ -13,7 +13,9 @@ use crate::kick_steps::{JointOverride, KickStep, KickSteps}; use super::step_state::StepState; -#[derive(Debug, Copy, Clone, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Debug, Copy, Clone, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct KickState { pub variant: KickVariant, /// the foot that is kicking the ball diff --git a/crates/walking_engine/src/kick_steps.rs b/crates/walking_engine/src/kick_steps.rs index 768b4a66a7..bb28938ef6 100644 --- a/crates/walking_engine/src/kick_steps.rs +++ b/crates/walking_engine/src/kick_steps.rs @@ -1,7 +1,7 @@ use std::time::Duration; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::{motion_command::KickVariant, step_plan::Step}; #[derive(Clone, Copy, Debug, Serialize, Deserialize)] @@ -20,7 +20,9 @@ pub struct KickStep { pub ankle_pitch_overrides: Option>, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct KickSteps { pub forward: Vec, pub turn: Vec, diff --git a/crates/walking_engine/src/lib.rs b/crates/walking_engine/src/lib.rs index e657e21512..681b572470 100644 --- a/crates/walking_engine/src/lib.rs +++ b/crates/walking_engine/src/lib.rs @@ -7,8 +7,8 @@ use mode::{ stopping::Stopping, walking::Walking, Mode, }; use parameters::Parameters; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::{ cycle_time::CycleTime, joints::body::BodyJoints, motion_command::KickVariant, motor_commands::MotorCommands, obstacle_avoiding_arms::ArmCommands, sensor_data::SensorData, @@ -53,7 +53,7 @@ pub trait WalkTransition { fn kick(self, context: &Context, variant: KickVariant, side: Side, strength: f32) -> Mode; } -#[derive(Debug, Clone, Serialize, Deserialize, SerializeHierarchy)] +#[derive(Debug, Clone, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect)] pub struct Engine { pub mode: Mode, } diff --git a/crates/walking_engine/src/mode.rs b/crates/walking_engine/src/mode.rs index 3cf4085eaa..b8915fcd2d 100644 --- a/crates/walking_engine/src/mode.rs +++ b/crates/walking_engine/src/mode.rs @@ -1,5 +1,5 @@ +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::{ joints::body::BodyJoints, motion_command::KickVariant, motor_commands::MotorCommands, step_plan::Step, support_foot::Side, @@ -19,7 +19,9 @@ pub mod starting; pub mod stopping; pub mod walking; -#[derive(Copy, Clone, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Copy, Clone, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub enum Mode { Standing(Standing), Starting(Starting), diff --git a/crates/walking_engine/src/mode/catching.rs b/crates/walking_engine/src/mode/catching.rs index 56ee4c0b4e..a5652b5ae9 100644 --- a/crates/walking_engine/src/mode/catching.rs +++ b/crates/walking_engine/src/mode/catching.rs @@ -16,14 +16,16 @@ use super::{ use coordinate_systems::{Ground, Robot}; use kinematics::forward::{left_sole_to_robot, right_sole_to_robot}; use linear_algebra::{point, Isometry3, Point3}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::{ joints::body::BodyJoints, motion_command::KickVariant, motor_commands::MotorCommands, step_plan::Step, support_foot::Side, }; -#[derive(Clone, Copy, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Catching { pub step: StepState, } diff --git a/crates/walking_engine/src/mode/kicking.rs b/crates/walking_engine/src/mode/kicking.rs index 0d31519ad9..e47111f200 100644 --- a/crates/walking_engine/src/mode/kicking.rs +++ b/crates/walking_engine/src/mode/kicking.rs @@ -10,14 +10,16 @@ use crate::{ }; use super::{stopping::Stopping, walking::Walking, Mode, WalkTransition}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::{ joints::body::BodyJoints, motion_command::KickVariant, motor_commands::MotorCommands, step_plan::Step, support_foot::Side, }; -#[derive(Clone, Copy, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Kicking { pub kick: KickState, pub step: StepState, diff --git a/crates/walking_engine/src/mode/standing.rs b/crates/walking_engine/src/mode/standing.rs index fbe19794b1..dad426db20 100644 --- a/crates/walking_engine/src/mode/standing.rs +++ b/crates/walking_engine/src/mode/standing.rs @@ -1,7 +1,7 @@ use std::time::Duration; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::{ joints::body::BodyJoints, motion_command::KickVariant, motor_commands::MotorCommands, step_plan::Step, support_foot::Side, @@ -14,7 +14,17 @@ use crate::{ use super::{starting::Starting, Mode}; -#[derive(Default, Clone, Copy, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Default, + Clone, + Copy, + Debug, + Serialize, + Deserialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct Standing {} impl WalkTransition for Standing { diff --git a/crates/walking_engine/src/mode/starting.rs b/crates/walking_engine/src/mode/starting.rs index 43833f9ed9..612114c44b 100644 --- a/crates/walking_engine/src/mode/starting.rs +++ b/crates/walking_engine/src/mode/starting.rs @@ -4,14 +4,16 @@ use crate::{ }; use super::{kicking::Kicking, standing::Standing, Mode, WalkTransition, Walking}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::{ joints::body::BodyJoints, motion_command::KickVariant, motor_commands::MotorCommands, step_plan::Step, support_foot::Side, }; -#[derive(Clone, Copy, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Starting { pub step: StepState, } diff --git a/crates/walking_engine/src/mode/stopping.rs b/crates/walking_engine/src/mode/stopping.rs index 51f1eb7a86..25f4ef22cf 100644 --- a/crates/walking_engine/src/mode/stopping.rs +++ b/crates/walking_engine/src/mode/stopping.rs @@ -4,14 +4,16 @@ use crate::{ }; use super::{kicking::Kicking, standing::Standing, walking::Walking, Mode, WalkTransition}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::{ joints::body::BodyJoints, motion_command::KickVariant, motor_commands::MotorCommands, step_plan::Step, support_foot::Side, }; -#[derive(Clone, Copy, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Stopping { pub step: StepState, } diff --git a/crates/walking_engine/src/mode/walking.rs b/crates/walking_engine/src/mode/walking.rs index b644204499..85673a29b4 100644 --- a/crates/walking_engine/src/mode/walking.rs +++ b/crates/walking_engine/src/mode/walking.rs @@ -1,6 +1,6 @@ use super::{kicking::Kicking, stopping::Stopping, Mode, WalkTransition}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::{ joints::body::BodyJoints, motion_command::KickVariant, motor_commands::MotorCommands, step_plan::Step, support_foot::Side, @@ -11,7 +11,9 @@ use crate::{ Context, }; -#[derive(Clone, Copy, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Walking { pub step: StepState, pub requested_step: Step, diff --git a/crates/walking_engine/src/parameters.rs b/crates/walking_engine/src/parameters.rs index 21f11ab12e..99f90d32bf 100644 --- a/crates/walking_engine/src/parameters.rs +++ b/crates/walking_engine/src/parameters.rs @@ -2,14 +2,16 @@ use std::time::Duration; use coordinate_systems::Walk; use linear_algebra::Vector3; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::{ joints::{arm::ArmJoints, leg::LegJoints}, step_plan::Step, }; -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Parameters { pub base: Base, pub catching_steps: CatchingStepsParameters, @@ -28,7 +30,9 @@ pub struct Parameters { pub max_rotation_speed: f32, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Base { pub foot_lift_apex: f32, pub foot_lift_apex_increase: Step, @@ -42,27 +46,43 @@ pub struct Base { pub walk_height: f32, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct StartingStepParameters { pub foot_lift_apex: f32, pub step_duration: Duration, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Stiffnesses { pub arm_stiffness: f32, pub leg_stiffness_walk: f32, pub leg_stiffness_stand: f32, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct GyroBalancingParameters { pub balance_factors: LegJoints, pub low_pass_factor: f32, pub max_delta: LegJoints, } -#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Copy, + Clone, + Debug, + Default, + Deserialize, + Serialize, + PathSerialize, + PathDeserialize, + PathIntrospect, +)] pub struct CatchingStepsParameters { pub toe_offset: f32, pub heel_offset: f32, @@ -72,7 +92,9 @@ pub struct CatchingStepsParameters { pub additional_foot_lift: f32, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct SwingingArmsParameters { pub default_roll: f32, pub roll_factor: f32, diff --git a/crates/walking_engine/src/step_plan.rs b/crates/walking_engine/src/step_plan.rs index 1dcd3afa7b..57b7785bc8 100644 --- a/crates/walking_engine/src/step_plan.rs +++ b/crates/walking_engine/src/step_plan.rs @@ -2,15 +2,17 @@ use std::time::Duration; use coordinate_systems::Walk; use linear_algebra::Vector2; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use types::{step_plan::Step, support_foot::Side}; use crate::Context; use super::{anatomic_constraints::AnatomicConstraints, feet::Feet}; -#[derive(Clone, Copy, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct StepPlan { pub step_duration: Duration, pub start_feet: Feet, diff --git a/crates/walking_engine/src/step_state.rs b/crates/walking_engine/src/step_state.rs index 5252561bc3..ab9a7e6aae 100644 --- a/crates/walking_engine/src/step_state.rs +++ b/crates/walking_engine/src/step_state.rs @@ -3,8 +3,8 @@ use std::{f32::consts::FRAC_PI_2, time::Duration}; use coordinate_systems::{LeftSole, RightSole, Walk}; use kinematics::inverse::leg_angles; use linear_algebra::{point, Isometry3, Orientation3, Point3, Pose3, Rotation3}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use splines::Interpolate; use types::{ joints::{arm::ArmJoints, body::BodyJoints, leg::LegJoints, mirror::Mirror}, @@ -24,7 +24,9 @@ use super::{ step_plan::StepPlan, }; -#[derive(Clone, Copy, Debug, Serialize, Deserialize, SerializeHierarchy)] +#[derive( + Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct StepState { pub plan: StepPlan, pub time_since_start: Duration, diff --git a/docs/framework/directory_structure.md b/docs/framework/directory_structure.md index a07d05c127..0c4bd928c0 100644 --- a/docs/framework/directory_structure.md +++ b/docs/framework/directory_structure.md @@ -9,8 +9,8 @@ The directory structure is organized as follows, only touching parts relevant fo - `context_attribute/`: Contains the proc-macro `#[context]` used in our nodes to augment and prepare them for the execution in the framework - `framework/`: Some basic building blocks (future queue and multiple buffers) and other framework types - `parameters/`: Functionality for de/serializing a parameter directory - - `serialize_hierarchy/`: Traits needed for all types available via Communication - - `serialize_hierarchy_derive/`: Derive macro for the `SerializeHierarchy` trait + - `path_serde/`: Traits needed for all types available via Communication + - `path_serde_derive/`: Derive macro for the `PathSerialize, PathDeserialize, PathIntrospect` trait - `etc/`: All additional files necessary when deploying the code to a robot - `parameters/`: Parameter files that are deployed to NAOs and are read during startup - `tools/`: Miscellaneous projects and tools more or less related to the code diff --git a/docs/framework/macros.md b/docs/framework/macros.md index da7a43b9fa..c54cbb57dc 100644 --- a/docs/framework/macros.md +++ b/docs/framework/macros.md @@ -30,17 +30,5 @@ TODO: Elaborate - `require_some!` TODO: `required` flag? - Extracts data from cycle context and returns none for all main outputs if the input was none - `require_some!(...) => match ... { Some(...) => ..., None => return MainOutputs::none() }` - - SerializeHierarchy - - Trait - - Mostly used by Communication for (de-)serialization - - Adds support for field paths - - Allows to (de-)serialize into/from field paths: `fn serialize_hierarchy(field_path)`, `fn deserialize_hierarchy(field_path, data)` - - Allows to check if a field paths exists - - Allows to generate a hierarchy object - - Implemented for all databases and configuration - - Macro `#[derive(SerializeHierarchy)]` - - Attached to structs - - Generates `impl SerializeHierarchy for ... { ... }` - - Iterates over all fields and delegates function calls to the fields - 3rd-party macros: `nalgebra::point` or `nalgebra::matrix` - Link to 3rd-party documentation diff --git a/docs/framework/path_serde.md b/docs/framework/path_serde.md new file mode 100644 index 0000000000..f002fae0b7 --- /dev/null +++ b/docs/framework/path_serde.md @@ -0,0 +1,138 @@ +# Path Serialization and Deserialization + +The `path_serde` crate introduces essential interfaces for serializing and deserializing specific parts of types by providing paths to their internals. +This functionality is mainly used by *Communication* to serialize data and provide it to connected debugging applications. + +## Traits + +The crate provides three distinct traits: `PathSerialize`, `PathDeserialize`, and `PathIntrospect`. + +### `PathSerialize` + +The PathSerialize trait enables the serialization of specific parts of types by accepting a path to the desired internal data. +This is particularly useful when only certain portions of a data structure need to be serialized. + +```rust +trait PathSerialize { + fn serialize_path(&self, path: &str, serializer: S) -> Result> + where + S: Serializer; +} +``` + +For instance a user is only interested in the position angle value of the ankle pitch joint, a serialization of the path `Control.main.sensor_data.positions.ankle_pitch` results in serializing only this specific float value. + +### `PathDeserialize` + +Conversely, the `PathDeserialize` trait facilitates the deserialization of data into types given a specified path. + +```rust +trait PathDeserialize { + fn deserialize_path<'de, D>( + &mut self, + path: &str, + deserializer: D, + ) -> Result<(), Error> + where + D: Deserializer<'de>; +} +``` + +This functionality is used when changing only parts of parameters. + +## `PathIntrospect` + +The `PathIntrospect` trait enables type introspection, allowing the user to generate a set of available paths to fields of a type. +This functionality is valuable for dynamically exploring the structure of data types and determining the paths that can be utilized for serialization and deserialization. +For instance, tooling may use these paths to autocomplete available paths when subscribing data from the robot. + +## Macro + +`path_serde` also provides derive macros, automatically generating the implementation of the three traits. +The source of an annotated type is analyzed and implementation is generated for each field, delegating the call to sub-types. + +### Attributes + +Types and fields can be additionally annotated with attributes to modify code generation. +Each attribute is prefixed with `#[path_serde(<...>)` to identify attributes to the `path_serde` macros. +We define the following attributes: + +#### Container: `bound` + +This attribute is attached to a container type and defines generic where bounds to the implementation. + +```rust +#[derive(Serialize, PathSerialize)] +#[path_serde(bound = T: PathSerialize + Serialize)] +struct MyStruct { + foo: T, +} +``` + +#### Container: `add_leaf` + +The `add_leaf` attribute adds an additional leaf to the children of a type by specifying a leaf name and a type. +This type is required to implement a `TryFrom` to generate the data for this field when requested. +Additionally, this type must be serializable or deserializable. + +```rust +#[derive(Serialize, PathSerialize)] +#[path_serde(add_leaf(bar: MyIntoType)] +struct MyStruct { + foo: i32, +} +``` + +#### Field: `leaf` + +This attributes tags a field to be a leaf of the tree. +That means, it is not expected to have further children, and path delegation ends at this field. + +```rust +#[derive(Serialize, PathSerialize)] +pub struct MultivariateNormalDistribution { + pub mean: f32, + #[path_serde(leaf)] + pub covariance: FancyType, +} +``` + +#### Field: `skip` + +This attributes tags a field to be skipped for the implementation. +It is neither considered for (de-)serialization, nor included in the available paths. + +```rust +#[derive(Serialize, PathSerialize)] +pub struct MultivariateNormalDistribution { + pub mean: f32, + #[path_serde(skip)] + pub covariance: FancyType, +} +``` + +## Example Usage + +```rust +#[derive(PathSerialize, PathDeserialize, PathIntrospect)] +struct ExampleStruct { + foo: u32, + bar: String, +} + +fn main() { + let example = ExampleStruct { + foo: 42, + bar: String::from("example"), + }; + + // Serialize data using path + let serialized_data = example.serialize_path("foo", /* serializer */); + + // Deserialize data from a specified path + let deserialized_data = example.deserialize_path("bar", /* deserializer */); + + // Generate a set of all available paths within ExampleStruct + let available_paths = ExampleStruct::get_fields(); +} +``` diff --git a/docs/setup/configure_team.md b/docs/setup/configure_team.md new file mode 100644 index 0000000000..b437613862 --- /dev/null +++ b/docs/setup/configure_team.md @@ -0,0 +1,31 @@ +# Configuring Team Specific Data + +!!! todo + + This page has to be improved. + +## HULKs Members + +There is nothing to do, all the configuration should be ready to go if you cloned the `hulks/hulk` repository. + +## Non HULKs Members + +### Set up Team Number + +In the HULKs code release, the SPL team number is hardcoded in a few places. Change this to your own team number before continuing. + +- `crates/spl_network/src/lib.rs` contains a constant called `HULKS_TEAM_NUMBER`. You may also wish to rename this constant. +- `tools/pepsi` contains a bunch of `24`s, however most of them are in comments or CLI command help text. + - `tools/pepsi/src/parsers.rs` has a default and a check value that use 24 literals. +- `tools/twix/src/completion_edit.rs` generates IP address suggestions with a hardcoded team number. +- `etc/parameters/hardware.json` has an attribute called spl for team communication hardcoded to 10024 (10000 + team number). + +### Set up Hardware IDs + +The tooling around our framework expects each NAO robot to have a number associated with it's hardware IDs. +This number also determines the last octet of a robot's IP addresses. +For example robot number `21` will always have the IPv4 addresses `10.0.X.21` (wireless) and `10.1.X.21` (ethernet) where X is the team number. + +For each robot you must determine it's head and body IDs and enter them in `etc/parameters/hardware_ids.json`. +This file is used by [pepsi](../tooling/pepsi.md) and other tools to find the hardware ids belonging to a robot number. + diff --git a/docs/setup/development_environment.md b/docs/setup/development_environment.md new file mode 100644 index 0000000000..bf76fad3dc --- /dev/null +++ b/docs/setup/development_environment.md @@ -0,0 +1,97 @@ +# Setup Development Environment + + +This section will guide you through the setup of your development environment to build software for the NAO robot and test your algorithms using our various tools. + +## Installing Rust + +We require a latest stable release of the Rust toolchain to build our tools. +Visit [https://rustup.rs/](https://rustup.rs/) for up to date instructions on how to install `rustup` for your machine. + +## Installing Dependencies + +Our software requires a few dependencies to be installed before you can compile, upload, and run our code. +Most of these dependencies are needed for the compilation of local tools. +All dependencies needed for a cross-compilation for the NAO are included in the NAO SDK. +Use your distribution's package manager to install the following dependencies: + +- [Git](https://git-scm.com/), [Git LFS](https://git-lfs.com/) +- [clang](https://clang.llvm.org/) +- [python3](https://www.python.org/) +- [which](https://carlowood.github.io/which/) +- [zstd](http://www.zstd.net/) +- [xz](https://tukaani.org/xz/) +- [file](https://darwinsys.com/file/) +- [rsync](https://rsync.samba.org/) + +=== "Arch Linux" + + ```sh + sudo pacman -S git git-lfs clang python3 which zstd xz file rsync + ``` + +=== "Fedora" + + ```sh + sudo dnf install git git-lfs clang python3 which zstd xz file rsync + ``` + +=== "Ubuntu" + + ```sh + sudo apt install git git-lfs clang python3 zstd xz-utils file rsync + ``` + +## Cloning the Repository + +We use Git to manage all our software. + +??? info "Git Setup: If you haven't used Git before" + + Git is a free and open source distributed version control system. + + **First**, install Git (see above). + + The **second** thing you should is to set your user name and email address. + This is important because every Git commit uses this information, and it’s baked into the commits you start creating: + + ``` + git config --global user.name "" + git config --global user.email "" + ``` + + And **third**, setup authentication with GitHub + You can access and write data in repositories on GitHub.com using SSH (Secure Shell Protocol). + When you connect via SSH, you authenticate using a private key file on your local machine. + You can follow this [guide](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent) to generate and add a key to GitHub. + If you already have a key, you can skip the part about generating a new one, and simply add your existing key to GitHub. + +```sh +git clone https://github.com/hulks/hulk.git +``` + +## Build Pepsi + +Pepsi is our main tool to interact with the repository, configure NAOs, and upload the software to the robot. +For a more in depth overview and introduction to Pepsi, consult [../tooling/pepsi.md]. + +For now, it is sufficient to know that Pepsi takes care of building the source code and also uploading it to the NAO. +This includes downloading and installing the SDK. + +To build and run Pepsi from source, use + +```sh +./pepsi +``` + +This downloads and builds all dependencies for the workspace and displays the help page of Pepsi. + +!!! tip + + You can also install Pepsi into your local system to conviniently use it without rebuilding: + + ``` + cargo install --path tools/pepsi + ``` + + Pepsi is subsequently installed at `~/.cargo/bin/pepsi`. diff --git a/docs/setup/git_setup.md b/docs/setup/git_setup.md deleted file mode 100644 index 424f550df5..0000000000 --- a/docs/setup/git_setup.md +++ /dev/null @@ -1,20 +0,0 @@ -# GitHub Setup - -If you haven't set up Git before, follow this guide. - -## Configuring Username and Email - -The first thing you should do when you install Git is to set your user name and email address. -This is important because every Git commit uses this information, and it’s immutably baked into the commits you start creating: - -``` -git config --global user.name "" -git config --global user.email "" -``` - -## Creating and Adding a SSH-Key - -You can access and write data in repositories on GitHub.com using SSH (Secure Shell Protocol). -When you connect via SSH, you authenticate using a private key file on your local machine. -You can follow this [guide](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent) to generate and add a key to GitHub. -If you already have a key, you can skip the part about generating a new one, and simply add your existing key to GitHub. diff --git a/docs/setup/main_setup.md b/docs/setup/main_setup.md deleted file mode 100644 index de896bee32..0000000000 --- a/docs/setup/main_setup.md +++ /dev/null @@ -1,111 +0,0 @@ -# Main Setup and Compiling for Webots - -This section will guide you through the installation of dependencies and compiling the code for the [Webots](https://www.cyberbotics.com/) simulator. -We recommend using [Arch Linux](https://archlinux.org/) or one of it's derivatives such as [Manjaro](https://manjaro.org/). - -## Installing Dependencies - -Some packages are required to be installed before you can compile and run our code. -Use your distribution's package manager to install the following dependencies: - -=== "Arch Linux/Manjaro" - - 1. Install dependencies - - ```sh - yay -S git git-lfs base-devel rustup rsync cmake clang hdf5 opusfile python webots - ``` - `yay` is used because `webots` is an [AUR](https://aur.archlinux.org/) package. - Optionally substitute `yay` with your favorite AUR helper. - - 1. Install rust toolchain - - ```sh - rustup default stable - ``` - -=== "Ubuntu" - - 1. Install dependencies - - ```sh - sudo apt install git git-lfs build-essential libssl-dev pkg-config libclang-dev rsync cmake libhdf5-dev libopusfile-dev python3 libasound2-dev libluajit-5.1-dev libudev-dev - ``` - - 1. Install Webots - Download webots from [https://cyberbotics.com/](https://cyberbotics.com/) the XXXX.deb file and install it with - - ```sh - sudo dpkg -i XXXX.deb - ``` - - 1. Install rust toolchain - - Visit [https://rustup.rs/](https://rustup.rs/) for up to date instructions. - -=== "Fedora" - - 1. Install dependencies - - ```sh - sudo dnf install git git-lfs hdf5-devel clang-devel rsync cmake python luajit-devel libudev-devel opusfile-devel zstd alsa-lib-devel - ``` - - 1. Install Webots - - At the moment there are no official Fedora packages, but the archive for Ubuntu has worked out fine in our experience. - Download webots from [https://cyberbotics.com/](https://cyberbotics.com/) the XXXX.tar.bz (Ubuntu Archive) file and install to a local directory. - - ```sh - mkdir ~/tools/ # example install location - cd ~/tools - tar -xf ...tar.bz # creates a directory named `webots` - - # symlink to be accessible from the command line - ln -s ~/tools/webots/webots ~/.local/bin/webots - sudo dnf install mesa-libGLU - ``` - - 1. Install rust toolchain - - Visit [https://rustup.rs/](https://rustup.rs/) for up to date instructions. - -## Acquiring the code - -Clone our [HULKs/hulk](https://github.com/HULKs/hulk) repository from GitHub: - -```sh -git clone git@github.com:HULKs/hulk -``` - -## Compiling for Webots - -In the root of our repository is a script called `pepsi`. See [pepsi](../tooling/pepsi.md) for details. -Simply execute the build command in the repository root to build a binary for use with Webots. -This will first build the pepsi binary and then start the build process. - -```sh -./pepsi build -``` - -## Running Webots - -Once the compilation step is complete, open webots and load the scene at `webots/worlds/penalized.wbt` from the repository. - -## Running Webots in external Mode - -To not be forced to reload the scene in Webots when rebuilding the controller, you can run in webots `webots/worlds/penalized_extern.wbt` and starting the controller with: - -```sh -./pepsi run -``` - -## Running Behavior Simulator - -To be able to run the current behavior simulator files, you have to install lua ```ìnspect``` package, either by downloading and saving it to the lua path (e.g., you hulk repo) or by using a lua package manager. - -Afterwards you can run the simulator by executing the following command in your hulk project root folder: -```sh -cargo run --manifest-path=tools/behavior_simulator/Cargo.toml serve tests/behavior/golden_goal.lua -``` -The results can be inspected in twix. diff --git a/docs/setup/nao_image_and_sdk.md b/docs/setup/nao_image_and_sdk.md index 59f4861bc8..b235e4eb04 100644 --- a/docs/setup/nao_image_and_sdk.md +++ b/docs/setup/nao_image_and_sdk.md @@ -1,109 +1,74 @@ # NAO Image & SDK -TODO: decide whether to backtick all "meta-nao", "meta-hulks", "kas", "BitBake" names -TODO: "code release" or "code-release" or "coderelease"? -TODO: Set up id map json first -TODO: Change team number in meta-hulks +The HULKs use the [Yocto Project](https://yoctoproject.org) for creating a custom linux distribution, we call HULKs-OS. +The toolchain compiles all necessary dependencies, tools, and kernel to produce flashable OPN images for the NAO. +Additionally, Yocto provides means to construct a corresponding software development kit (SDK) containing a complete cross-compilation toolchain. -The HULKs use the [Yocto Project](https://yoctoproject.org) for creating flashable OPN images for the NAO and a corresponding software development kit (SDK) for local development targeting the NAO. -The SDK contains a full cross-compilation toolchain that is self-contained and can be easily used on development machines. +Team HULKs automatically releases the latest HULKs-OS publicly on GitHub [here](https://github.com/hulks/meta-nao/releases). +If you're looking to use these images or SDKs for flashing and deploying software onto your robot, you can opt for the pre-built versions and do not need to build your own image and SDK. -## Use an Existing Yocto SDK with the HULKs Code +Upon booting, the image automatically configures both wired and wireless network devices for the NAO. +Each robot is identified by its unique Head-ID, which is used to assign a distinct IP address. +The mapping between Head-IDs and IP addresses is configured in the image ([here](https://github.com/HULKs/meta-nao/blob/main/meta-hulks/recipes-hulks/network-config/network-config/id_map.json)). +All HULKs robots come pre-configured in the released images, via the `configure_network` service ([here](https://github.com/HULKs/meta-nao/blob/main/meta-hulks/recipes-hulks/network-config/network-config/configure_network)). +But if you're flashing a new or non-HULKs robot, you'll need to add its head ID to the map and generate a new image. -You can just use [pepsi](../tooling/pepsi.md) to compile and upload to a booted NAO. -Within the HULKs repository, use the following command to e.g. upload to NAO 42: - -```sh -./pepsi upload 42 -``` - -Pepsi will automatically download the SDK from the BigHULK (internal server only accessible in the HULKs lab network) or GitHub and ask you to install it during the compilation process. +For robots not listed, the image falls back to configuring its wired network device via DHCP. +Thus, you're free to flash the HULKs-OS image onto a robot and find its IP address by inspecting your DHCP leases or asking your IT administrator. ## Image & SDK Creation The Yocto Project leverages [BitBake](https://en.wikipedia.org/wiki/BitBake) as task execution engine and offers an abstraction layer to modify and extend existing build configurations. -Combined with [OpenEmbedded](https://www.openembedded.org/wiki/Main_Page), the entire worktree is structured in several layers (the HULKs use the meta-nao and meta-hulks layers). +Combined with [OpenEmbedded](https://www.openembedded.org/wiki/Main_Page), the entire worktree is structured in several layers configuring the distribution and providing support for dependencies or services. +Basic NAO support to construct a distribution for a minimal NAO robot operating system for use in SPL is configured with the root `meta`-layer in the [`meta-nao`](https://github.com/hulks/meta-nao) repository. +The HULKs overlay this configuration with an additional `meta-hulks` layer to target the special HULKs usecase. ### Setup of the Working Directory -For creating the image and SDK, make sure there is at least 100 GB empty disk space available. -Start by cloning the code (if not done before) and setting up a Yocto working directory. -This working directory will contain the layers [HULKs/meta-nao](https://github.com/HULKs/meta-nao) and meta-hulks, a script for running BitBake commands, and the HULKs nao repository. -It will be called `yocto`. -The new `yocto` working directory must have at least 100 GB of empty space available and should not be part of a Git repository. +Start by cloning the code and setting up a Yocto working directory. +This working directory will contain the yocto configuration layers, including [HULKs/meta-nao](https://github.com/HULKs/meta-nao) and meta-hulks. ```sh mkdir yocto/ cd yocto/ ``` -=== "HULKs Members" - - HULKs members need the [HULKs/hulk](https://github.com/HULKs/hulk) repository, and the [HULKs/meta-nao](https://github.com/HULKs/meta-nao) and [HULKs/meta-hulks](https://github.com/HULKs/meta-hulks) layer. - The rest should already be set up. - - ```sh - # working directory is still `yocto` - git clone git@github.com:HULKs/hulk - git clone git@github.com:HULKs/meta-nao - git clone git@github.com:HULKs/meta-hulks - ``` +!!! danger -=== "Non HULKs Members" + For creating the image and SDK, make sure there is at least 100 GB empty disk space available. - Non HULKs members need the [HULKs/meta-nao](https://github.com/HULKs/meta-nao) layer and the meta-hulks layer from [HULKs/CodeRelease](https://github.com/HULKs/HULKsCodeRelease) (in the subdirectory `yocto/meta-hulks`). - - ```sh - # working directory is still `yocto` - git clone git@github.com:HULKs/HULKsCodeRelease - mv HULKsCodeRelease hulk - #ln -s nao/yocto/meta-hulks meta-hulks - #sed -i 's|path: "patches|path: "yocto/meta-hulks/patches|' meta-hulks/kas-project.yml - cp -r nao/yocto/meta-hulks meta-hulks - git clone git@github.com:HULKs/meta-nao - ``` - - During the HULKs code release generation, some cryptographic keys are replaced. - If you want to e.g. connect to a NAO via SSH the following steps need to be done to recreate the keys: - - ```sh - # working directory is still `yocto` - ssh-keygen -t ed25519 -C nao@hulk -f nao/scripts/ssh_key - # Answer `y` when asked to overwrite - cat nao/scripts/ssh_key.pub > meta-hulks/recipes-connectivity/openssh/openssh/authorized_keys - ``` - If you wondered, as a non HULKs member you don't need the `meta-hulks/ssh-dir` populated with keys. +Continue by cloning the `meta-nao` repository: - In addition to the SSH keys, also the NAO hardware IDs and wireless network configurations need to be adjusted. - The hardware IDs can be configured in `meta-hulks/recipes-hulks/network-config/network-config/id_map.json`. - Wireless networks can be configured at `meta-hulks/recipes-conf/nao-wifi-conf/nao-wifi-conf/*.psk` ([iwd](https://iwd.wiki.kernel.org/) is used). - If networks are added/removed or names change, the recipe `meta-hulks/recipes-conf/nao-wifi-conf.bb` also needs adjustmenst. +```sh +git clone git@github.com:HULKs/meta-nao +``` -For project setup the [siemens/kas](https://github.com/siemens/kas) framework is used. -To setup kas use the containerized version (podman or docker) via the [kas-container script](https://github.com/siemens/kas/blob/master/kas-container) and store it inside the `yocto` directory. +For project setup we use [siemens/kas](https://github.com/siemens/kas), a setup tool for bitbake based projects. +To run kas, either install it locally ([see here](https://kas.readthedocs.io/en/latest/userguide/getting-started.html)), or use the containerized version via the [kas-container script](https://github.com/siemens/kas/blob/master/kas-container). +We prefer the containarized solution, as the container comes with all batteries included. +The `kas-container` script makes it easy to spin a container (via podman or docker). ```sh -wget https://github.com/siemens/kas/raw/master/kas-container -chmod +x kas-container +wget https://raw.githubusercontent.com/siemens/kas/master/kas-container +chmod u+x kas-container ``` -Alternatively setup kas via a python-pip installation, follow the installation steps in the [user guide](https://kas.readthedocs.io/en/latest/userguide.html). - -The meta-hulks layer ships a `kas-project.yml` project description file. -This file defines the project structure kas has to setup for the Yocto build phase. -The next step is to download all the referenced repositories in the `kas-project.yml`. +Subsequently, you can clone all necessary layers, we specify in our `kas-project.yml`. +This file defines the project structure `kas` has to setup for the Yocto build phase. ```sh ./kas-container checkout meta-hulks/kas-project.yml ``` -The NAO v6 uses LoLA and HAL for communication with the chestboard. -All these binaries and libraries necessary to operate the NAO properly are shipped with the `.opn` RoboCupper image and are **not** included in this repository. -For HULKs members contact our dev-leads and for non HULKs members contact the RoboCup SPL Technical Committee to get this image. -To extract the necessary binaries the `extract_binaries.sh` script is used. -This script fetches all binaries from inside the RoboCupper image and collects them in an archive for the upcoming build phase. -To generate the archive containing the aldebaran binaries run (with root privileges): +The last step is to populate the working directory with the proprietary and closed source software by aldebaran. +This mainly is LoLA and HAL for communication with the chestboard. +We do **not** provide these binaries, but rather extract them from the `.opn` files shipped with the RoboCupper image. +To get the Robocupper image, HULKs members can ask our dev-leads, and non HULKs members should contact the RoboCup SPL Technical Committee. + +To extract the necessary binaries we provide a helper script called `extract_binaries.sh`. +This script mounts the file system contained in the OPN image, fetches all binaries from inside the RoboCupper image, and collects them in an archive for the upcoming build phase. +Mounting the OPN file system may require root privileges. ```sh cd meta-nao/recipes-support/aldebaran/ @@ -111,104 +76,91 @@ mkdir -p aldebaran-binaries ./extract_binaries.sh -o aldebaran-binaries/aldebaran_binaries.tar.gz nao-2.8.5.11_ROBOCUP_ONLY_with_root.opn ``` -### Starting a Build Shell +Now your working directory is ready to build your own NAO image and SDK. +At this point, you may adjust the distribution to your liking. +This includes adding hardware IDs, configuring network, installing additional dependencies, and much more. -kas is able to start a shell inside of the build environment. -The `kas-project.yml` of meta-hulks needs to be referenced: +!!! todo -```sh -# working directory is `yocto` -./kas-container shell meta-hulks/kas-project.yml -``` + Explain what to do when configuring a new robot. -All BitBake and Devtool commands shall be executed from this shell. - -### Preparing the Build +### Starting a Build Shell -The NAO image contains the HULA binary (TODO: link to HULA) which is built from [HULKs/hulk](https://github.com/HULKs/hulk) or [HULKs/CodeRelease](https://github.com/HULKs/HULKsCodeRelease) (depending -on whether you are a HULKs member or not). -The HULA source code is located in `tools/hula`. -The meta-hulks layer is set up to clone the private [HULKs/hulk](https://github.com/HULKs/hulk) repository and check out a specific version. -This only works if the kas-container has SSH correctly set up and uses a SSH key that has access to the repository. -Ensure that the SSH private key has appropriate permissions, usually `600`. -Most often it is easier to clone the repository manually and point BitBake to use it. -The following command can be executed within the build environment to do that: +`kas` is able to start a shell inside of the build environment. +The `kas-project.yml` of meta-nao needs to be referenced: ```sh -devtool modify --no-extract hula /work/nao +# working directory is `yocto` +./kas-container shell meta-nao/kas-project.yml ``` -This must be executed at any restart of the build shell. +All BitBake and Devtool commands must be executed from inside this shell. ### Building the Image -Inside of the build shell, the following command will build the NAO image. -The initial build may take multiple hours depending on your hardware and internet access. -BitBake provides advanced caching of the build artifacts which means that future builds are done in minutes depending on the changes. -The cache relies in the `build/sstate-cache` which can be copied from another build directory or shared between machines ( -see [Yocto Documentation about Shared State Cache](https://docs.yoctoproject.org/overview-manual/concepts.html#shared-state-cache)). -To build the image run the following command in the build shell: +Inside of the build shell, you can build a NAO OPN image and SDK via BitBake. +The initial build may take multiple hours depending on your computing performance and download speed. +Remember, you are building an entire linux distribution. +BitBake provides advanced caching of the build artifacts which means that future builds are done in minutes or even seconds depending on the changes. +The cache relies in the `build/sstate-cache` which can be copied from another build directory or even shared between machines, see [Yocto Documentation about Shared State Cache](https://docs.yoctoproject.org/overview-manual/concepts.html#shared-state-cache) for further explanation. +To build the image, run the following command from inside the build shell: ```sh bitbake nao-image ``` This generates and executes all necessary tasks and targets to construct a proper `.opn` file. -The initial build phase might take several hours depending on the performance of your build machine and your internet connection. -BitBake uses a very elaborated caching strategy to speed up following builds of targets. -Thus small changes afterwards might only take a few minutes. - -As soon as the build has successfully finished, the image can be deployed. -After BitBake ran all tasks up to nao-image, a new `.opn` file is generated in `build/tmp/deploy/images/nao-v6/nao-image-HULKs-OS-[...].ext3.gz.opn`. -The image can now be flashed to a NAO as described in the [NAO setup section](./nao_setup.md#flashing-the-firmware). - -Make sure a RoboCupper image has been flashed before flashing the first Yocto image, since the latter does not flash the chestboard (which needs up-to-date software). This step is not required for flashing subsequent Yocto images. +After BitBake finishes the `nao-image` task, the image file can be found at `build/tmp/deploy/images/nao-v6/nao-image-HULKs-OS-[...].ext3.gz.opn`. +The image can directly be flashed to a NAO as described in the [NAO setup section](./nao_setup.md#flashing-the-firmware). ### Building the SDK -To be able to compile the HULKs robotics code targeting the NAO platform, the code needs to be cross compiled for the NAO target. -Within the build shell, the following command will build the SDK: +To be able to compile software targeting the NAO platform, the code needs to be cross compiled for the NAO target. +When you only change configuration for the NAO image, you may still maintain compatibility with the publicly released SDK at [meta-nao](https://github.com/hulks/meta-nao/releases) and opt for this SDK instead of building your own. + +Within the build shell, the following command will build a full SDK: ```sh bitbake -c populate_sdk nao-image ``` -This build phase may take several hours. +Again, this build phase may take several hours. After a successful build, the SDK is located at `build/tmp/deploy/sdk/HULKs-OS-toolchain-[...].sh`. To install the SDK run the script and follow the instructions. Afterwards, you are able to source the build environment and use the respective cross compilers. -### Advanced: Upgrade other Yocto Layers +### Advanced: + +#### Upgrade other Yocto Layers The Yocto Project and the Poky reference distribution provide a Linux kernel, userland programs, libraries, and other tooling. All these things are updated in the regular Yocto releases. -To ensure deterministic builds the HULKs freeze versions of all used layers in the `kas-project.yml` files of meta-nao and meta-hulks. +To ensure deterministic builds the HULKs freeze versions of all used layers in the `kas-project.yml` files of meta-nao. -### Advanced: Upgrade Image/SDK Versions and Semantic Versioning +#### Upgrade Image/SDK Versions and Semantic Versioning The HULKs use semantic versioning for the Yocto images and SDKs. This means that versions are increased depending on the severity of changes. The following policy exists for the HULKs: -- Both images and SDKs have major, minor, and patch version numbers (e.g. 4.2.3) -- Images and SDKs with the same major and minor version number are compatible with each other -- Major changes, refactorings, implementations result in the increase of the major version number -- Minor changes, additions and iterations result in the increase of the minor version number -- Changes in the image that do not require SDK recreation, result in the increase of the patch version number (which only requires to create a new image) +- Both images and SDKs have major, minor, and patch version numbers (e.g. 4.2.3). +- Images and SDKs with the same major and minor version number are compatible with each other. +- Major changes, refactorings, or implementations result in the increase of the major version number. +- Minor changes, additions, and iterations result in the increase of the minor version number. +- Changes in the image that do not require SDK recreation, result in the increase of the patch version number. This consequently only requires creating a new image and not necessarily a redistribution of new SDKs. -Before building new images, the version number needs to be set in `meta-hulks/conf/distro/HULKsOS.conf`. +Before building new images, the version number needs to be set in `meta-nao/conf/distro/HULKsOS.conf`. Only change the `DISTRO_VERSION`, the `SDK_VERSION` is automatically derived from the `DISTRO_VERSION`. Once a new image and/or SDK is released, pepsi needs to know the new version numbers. Therefore update the variables `OS_VERSION` and/or `SDK_VERSION` in `crates/constants/src/lib.rs`. Successive builds with pepsi will use the new version. -### Advanced: Upgrade Rust Version +#### Upgrade Rust Version Since upgrading the Rust version often requires manual steps, this section describes the approach on how to upgrade and generate the needed patch files. These instructions can be followed e.g. if a new Rust version is available and a new image/SDK should be created with this new version. Users that just want to use the current version that we upgraded to should skip this section. -The latest patch set for is included in the meta-hulks layer (in `patches/`) or HULKs code release (in `yocto/meta-hulks/patches/`). Rust is provided by the poky repository. The recipes are located in `meta/recipes-devtools/{cargo,rust}`. @@ -260,4 +212,4 @@ A patch file can be created after applying these instructions and saved to the c git commit # ... git format-patch HEAD~ # this generates 0001-....patch ``` - - Copy the patch file into `meta-hulks/patches/0001....patch` and fix the patch path in `meta-hulks/kas-project.yml` + - Copy the patch file into `meta-nao/patches/0001....patch` and fix the patch path in `meta-nao/kas-project.yml` diff --git a/docs/setup/nao_setup.md b/docs/setup/nao_setup.md index 1c5881be51..27dbf1cc0e 100644 --- a/docs/setup/nao_setup.md +++ b/docs/setup/nao_setup.md @@ -1,85 +1,67 @@ # NAO Setup -This section assumes you have a working SDK installed. -See [Nao Image and SDK](./nao_image_and_sdk.md) to learn how to acquire or build one. +This section assumes you have a working development environment, and can successfully run `pepsi --help`. +See [Development Environment](./development_environment.md) to learn how to setup your environment. -## Configuring Team Specific Data +!!! warning -=== "HULKs Members" + Make sure a RoboCupper image has been flashed before flashing the first Yocto image, since the latter does not flash the chestboard (which needs up-to-date firmware). + This step is not required for flashing subsequent Yocto images. - There is nothing to do, all the configuration should be ready to if you cloned the `hulks/nao` repository. - -=== "Non HULKs Members" - - ### SSH Keys - - If you built your own SDK, you should have created an SSH key pair. - The public key is used during image creation and registered as an authorized key in the openssh configuration. - All of our tools expect the private key to be located at `scripts/ssh_key`. - If you did not create the SDK yourself, ask your teammates for the key. - - ### Set up Team Number - - In the HULKs code release, the SPL team number is hardcoded in a few places. Change this to your own team number before continuing. - - - `crates/spl_network/src/lib.rs` contains a constant called HULKS_TEAM_NUMBER. You may also wish to rename this constant. - - `tools/pepsi` contains a bunch of `24`s, however most of them are in comments or CLI command help text. - - `tools/pepsi/src/parsers.rs` has a default and a check value that use 24 literals. - - `tools/twix/src/completion_edit.rs` generates IP address suggestions with a hardcoded team number. - - `etc/parameters/hardware.json` has an attribute called spl for team communication hardcoded to 10024 (10000 + team number). +## Flashing the Firmware - ### Set up Hardware IDs +You can flash the firmware both using [pepsi](../tooling/pepsi.md) or manually with a USB stick. +Flashing with pepsi is the preferred option. - The tooling around our framework expects each NAO robot to have a number associated with it's hardware IDs. - This number also determines the last octet of a robot's IP addresses. - For example robot number `21` will always have the IPv4 addresses `10.0.X.21` (wireless) and `10.1.X.21` (ethernet) where X is the team number. +### Using `pepsi gammaray` - For each robot you must determine it's head and body IDs and enter them in `etc/parameters/hardware_ids.json`. - This file is used by [pepsi](../tooling/pepsi.md) and other tools to find the hardware ids belonging to a robot number. +Pepsi automatically downloads the latest configured release of the HULKs-OS image. +To flash a robot use: -## Flashing the Firmware +```sh +pepsi gammaray +``` -You can flash the firmware both using [pepsi](../tooling/pepsi.md) or manually using an USB stick. +Where `` is any configured NAO number or a full IP address. -Flashing with pepsi is done using the `gammaray` subcommand and is the preferred option. The following steps are only necessary for manual flashing with an USB stick. +??? info "Alternatively: Using an USB Stick" -### Preparing a Flash-Stick + #### Preparing the Stick -First, the firmware image has to be flashed to a USB stick. -Use `lsblk` to make sure you are overwriting the correct device. -```sh -lsblk -``` + First, the firmware image has to be written to the USB stick. + Use `lsblk` to find the device that represents the USB stick. -All existing data on the target device will be wiped! -Replace `sdX` with the USB device. -```sh -dd if=path-to-nao-image.opn of=/dev/sdX status=progress -``` + ```sh + lsblk + ``` -Finally, run `sync` to make sure all data has actually been written to the stick before unplugging it. -```sh -sync -``` + All existing data on the target device will be wiped! + Replace `sdX` with the USB device. -### Flashing the NAO + ```sh + dd if=path-to-nao-image.opn of=/dev/sdX status=progress + ``` -- Make sure the robot is turned off and a charger is plugged in to prevent a sudden loss of power during the process. -- Plug the prepared USB stick into the back of the NAO's head. -- Hold the chest button for about 5 seconds until it starts glowing, then release immediately. - The chest button LED should now be flashing rapidly. -- Wait for the flashing process to finish -- The new firmare should be installed now. + Finally, run `sync` to make sure all data has actually been written to the stick before unplugging it. + ```sh + sync + ``` -## Compiling for NAO + #### Flashing the NAO -`./pepsi build --target nao` will compile the code for use on the NAO with the `incremental` cargo profile. + - Make sure the robot is turned off and a charger is plugged in to prevent a sudden loss of power during the process. + - Plug the prepared USB stick into the back of the NAO's head. + - Hold the chest button for about 5 seconds until it starts glowing blue, then release immediately. + The chest button LED should now be flashing rapidly. + - Wait for the flashing process to finish + - The robot reboots at the end of the flashing process. -## Uploading to the NAO +### Checking for success -`./pepsi upload ` will first compile the code with the same `incremental` cargo profile and the upload the binary and configuration files to the robot with the specified number. +When the flash process was successfull, the robot boots up and presents with red [Knight Rider](https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExYmloOHd2NDJtcjkzaWFqZ2t2c2xjeWZuZjZlZGdueTNxOGUzdXA5byZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/4ViH9IuRZO2wo/giphy.gif) eyes. +The new HULKs-OS is now installed and the NAO is waiting for the robotics software. ## Remote Shell Access -`./pepsi shell ` establishes an SSH connection and presents an interactive shell to the user. +`./pepsi shell ` establishes an SSH connection and presents an interactive shell to the user. diff --git a/docs/setup/overview.md b/docs/setup/overview.md index 2634c55eec..3a9283612b 100644 --- a/docs/setup/overview.md +++ b/docs/setup/overview.md @@ -1,5 +1,14 @@ # Overview -TODO: Symbolbild HULK mit pepsi +!!! todo -This section describes the necessary steps to download the code, compile for the Webots simulator, how to prepare the NAO SDK and image using Yocto and finally how to compile and upload the software to a real NAO robot. + High-Level visualization of the Software Architecture: NAO, SDK, HULKs-Robotics code, Pepsi, etc. + + +This section describes the steps required to set up and get started with our framework. +The following pages include documentation to + +- setup the [Development Environment](./development_environment.md), +- acquire or build the latest [NAO operating system image](./nao_image_and_sdk.md) and Software Development Toolkit (SDK) to cross-compile for the NAO, +- [setup the NAO](./nao_setup.md) by flashing the operating system image to the NAO, +- and [compile, upload, and run](./upload.md) the HULKs robotics software on the robot diff --git a/docs/setup/upload.md b/docs/setup/upload.md new file mode 100644 index 0000000000..9eeeffa213 --- /dev/null +++ b/docs/setup/upload.md @@ -0,0 +1,23 @@ +# Uploading HULK + +This section assumes that you have set up your development environment and flashed a Yocto image to the NAO. + +Uploading the software to a NAO is done with Pepsi. +See `pepsi --help` for details on the respective commands. +To upload the robotics software to the NAO, just run: + +```sh +pepsi upload +``` + +Pepsi takes care of downloading and installing the SDK, calling `cargo` to trigger compilation, and uploading the software to the robot. +When successful, you are presented with a green tick in your shell, and the robot is showing rotating rainbow eyes. + +## SDK Management + +Pepsi automatically checks for the latest SDK configured in the repository and installs it if necessary. +To manually manage your SDK installation, use the `sdk` subcommand. + +```sh +pepsi sdk install --help +``` diff --git a/mkdocs.yml b/mkdocs.yml index 6473ac7a3d..94a7ff98dd 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -26,10 +26,11 @@ nav: - Introduction: index.md - Setup: - Overview: setup/overview.md - - Main Setup & Webots: setup/main_setup.md + - Development Environment: setup/development_environment.md + - Configure Team: setup/configure_team.md - NAO Image & SDK: setup/nao_image_and_sdk.md - NAO Setup: setup/nao_setup.md - - Git Setup: setup/git_setup.md + - Upload HULK: setup/upload.md - Framework: - Overview: framework/overview.md - Directory Structure: framework/directory_structure.md @@ -44,6 +45,7 @@ nav: - Thread Communication: framework/thread_communication.md - Filtering: framework/filtering.md - Macros: framework/macros.md + - Path SerDe: framework/path_serde.md - Error Handling: framework/error_handling.md - Logging: framework/logging.md - Tooling: @@ -88,6 +90,8 @@ nav: - GitHub Webhooks: workflow/github_webhooks.md - Leadership: workflow/leadership.md markdown_extensions: + - admonition + - pymdownx.details - pymdownx.highlight: anchor_linenums: true - pymdownx.inlinehilite diff --git a/tools/behavior_simulator/Cargo.toml b/tools/behavior_simulator/Cargo.toml index def8c12f98..aebed0780d 100644 --- a/tools/behavior_simulator/Cargo.toml +++ b/tools/behavior_simulator/Cargo.toml @@ -28,9 +28,9 @@ mlua = { workspace = true } nalgebra = { workspace = true } parameters = { workspace = true } parking_lot = { workspace = true } +path_serde = { workspace = true } projection = { workspace = true } serde = { workspace = true } -serialize_hierarchy = { workspace = true } spl_network = { workspace = true } spl_network_messages = { workspace = true } tokio = { workspace = true } diff --git a/tools/behavior_simulator/src/cycler.rs b/tools/behavior_simulator/src/cycler.rs index 0cb5b2140f..bc1dd23fda 100644 --- a/tools/behavior_simulator/src/cycler.rs +++ b/tools/behavior_simulator/src/cycler.rs @@ -15,8 +15,8 @@ use control::{ }; use framework::{AdditionalOutput, PerceptionInput}; +use path_serde::{PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use tokio::sync::Notify; use types::messages::IncomingMessage; @@ -28,7 +28,7 @@ use crate::{ }, }; -#[derive(Clone, Default, Serialize, Deserialize, SerializeHierarchy)] +#[derive(Clone, Default, Deserialize, Serialize, PathSerialize, PathIntrospect)] pub struct Database { pub main_outputs: MainOutputs, pub additional_outputs: AdditionalOutputs, diff --git a/tools/behavior_simulator/src/server.rs b/tools/behavior_simulator/src/server.rs index 4fdd56c720..29e343002f 100644 --- a/tools/behavior_simulator/src/server.rs +++ b/tools/behavior_simulator/src/server.rs @@ -12,27 +12,27 @@ use crate::{ }; use color_eyre::{eyre::bail, owo_colors::OwoColorize, Result}; use framework::{multiple_buffer_with_slots, Reader, Writer}; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use serde::{Deserialize, Serialize}; -use serialize_hierarchy::SerializeHierarchy; use tokio::{net::ToSocketAddrs, select, sync::Notify, time::interval}; use tokio_util::sync::CancellationToken; use types::{field_dimensions::FieldDimensions, players::Players}; -#[derive(Clone, Serialize, Deserialize, SerializeHierarchy)] +#[derive(Clone, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect)] struct Parameters { selected_frame: usize, selected_robot: usize, field_dimensions: FieldDimensions, } -#[derive(Clone, Default, Serialize, Deserialize, SerializeHierarchy)] +#[derive(Clone, Default, Serialize, PathSerialize, PathIntrospect)] struct MainOutputs { frame_count: usize, ball: Option, databases: Players>, } -#[derive(Clone, Default, Serialize, Deserialize, SerializeHierarchy)] +#[derive(Clone, Default, Serialize, PathSerialize, PathIntrospect)] struct BehaviorSimulatorDatabase { main_outputs: MainOutputs, } diff --git a/tools/behavior_simulator/src/state.rs b/tools/behavior_simulator/src/state.rs index 77c9d516fc..5bc707c436 100644 --- a/tools/behavior_simulator/src/state.rs +++ b/tools/behavior_simulator/src/state.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; use coordinate_systems::{Field, Head}; use geometry::line_segment::LineSegment; use linear_algebra::{vector, Isometry2, Orientation2, Point2, Rotation2, Vector2}; -use serialize_hierarchy::SerializeHierarchy; +use path_serde::{PathDeserialize, PathIntrospect, PathSerialize}; use spl_network_messages::{GamePhase, HulkMessage, PlayerNumber, Team}; use types::{ ball_position::BallPosition, @@ -36,7 +36,9 @@ pub enum Event { Goal, } -#[derive(Default, Clone, Deserialize, Serialize, SerializeHierarchy)] +#[derive( + Default, Clone, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect, +)] pub struct Ball { pub position: Point2, pub velocity: Vector2,