From 8182e671528fef17b660b42bb19efbefece7f573 Mon Sep 17 00:00:00 2001 From: lenn Date: Thu, 23 Apr 2026 23:54:33 +0800 Subject: [PATCH] trans to tokio --- .codex | 0 Cargo.lock | 1356 ++++++++++++++++++++++++++++++++++++- Cargo.toml | 3 + src/app.rs | 190 +++++- src/cmd.rs | 115 ++++ src/main.rs | 5 +- src/serial_core/mod.rs | 10 +- src/serial_core/model.rs | 500 -------------- src/serial_core/serial.rs | 42 +- 9 files changed, 1671 insertions(+), 550 deletions(-) create mode 100644 .codex create mode 100644 src/cmd.rs delete mode 100644 src/serial_core/model.rs diff --git a/.codex b/.codex new file mode 100644 index 0000000..e69de29 diff --git a/Cargo.lock b/Cargo.lock index cdc9701..e4747ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,10 +11,13 @@ dependencies = [ "chrono", "clap", "crc", + "crossterm", "csv", "fern", "humantime", "log", + "ratatui", + "ratatui-textarea", "serde", "serde_json", "tokio", @@ -22,6 +25,21 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -95,7 +113,16 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", +] + +[[package]] +name = "atomic" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" +dependencies = [ + "bytemuck", ] [[package]] @@ -104,6 +131,27 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -116,18 +164,42 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" + [[package]] name = "bytes" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + [[package]] name = "cc" version = "1.2.60" @@ -206,6 +278,29 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "compact_str" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "static_assertions", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -222,6 +317,15 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + [[package]] name = "crc" version = "3.4.0" @@ -237,6 +341,53 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +[[package]] +name = "crossterm" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" +dependencies = [ + "bitflags 2.11.1", + "crossterm_winapi", + "derive_more", + "document-features", + "mio", + "parking_lot", + "rustix", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "csscolorparser" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2a7d3066da2de787b7f032c736763eb7ae5d355f81a68bab2675a96008b0bf" +dependencies = [ + "lab", + "phf", +] + [[package]] name = "csv" version = "1.4.0" @@ -258,6 +409,108 @@ dependencies = [ "memchr", ] +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "deltae" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5729f5117e208430e437df2f4843f5e5952997175992d1414f94c57d61e270b4" + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.117", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "errno" version = "0.3.14" @@ -268,6 +521,25 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "euclid" +version = "0.22.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fancy-regex" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" +dependencies = [ + "bit-set", + "regex", +] + [[package]] name = "fern" version = "0.7.1" @@ -279,12 +551,53 @@ dependencies = [ "log", ] +[[package]] +name = "filedescriptor" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d" +dependencies = [ + "libc", + "thiserror 1.0.69", + "winapi", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "finl_unicode" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9844ddc3a6e533d62bba727eb6c28b5d360921d5175e9ff0f1e621a5c590a4d5" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "futures" version = "0.3.32" @@ -341,7 +654,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -373,6 +686,79 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "humantime" version = "2.3.0" @@ -403,6 +789,52 @@ dependencies = [ "cc", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.0", + "serde", + "serde_core", +] + +[[package]] +name = "indoc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] + +[[package]] +name = "instability" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb2d60ef19920a3a9193c3e371f726ec1dafc045dac788d0fb3704272458971" +dependencies = [ + "darling", + "indoc", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "io-kit-sys" version = "0.4.1" @@ -419,6 +851,15 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.18" @@ -435,18 +876,62 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kasuari" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde5057d6143cc94e861d90f591b9303d6716c6b9602309150bd068853c10899" +dependencies = [ + "hashbrown 0.16.1", + "portable-atomic", + "thiserror 2.0.18", +] + +[[package]] +name = "lab" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf36173d4167ed999940f804952e6b08197cae5ad5d572eb4db150ce8ad5d58f" + [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" +[[package]] +name = "line-clipping" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8" +dependencies = [ + "bitflags 2.11.1", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + [[package]] name = "lock_api" version = "0.4.14" @@ -462,6 +947,25 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "lru" +version = "0.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "mac_address" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0aeb26bf5e836cc1c341c8106051b573f1766dfa05aa87f0b98be5e51b02303" +dependencies = [ + "nix 0.29.0", + "winapi", +] + [[package]] name = "mach2" version = "0.4.3" @@ -477,6 +981,27 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "memmem" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "mio" version = "1.2.0" @@ -523,6 +1048,34 @@ dependencies = [ "cfg-if", "cfg_aliases", "libc", + "memoffset", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] @@ -534,6 +1087,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -546,6 +1108,15 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + [[package]] name = "parking_lot" version = "0.12.5" @@ -569,12 +1140,129 @@ dependencies = [ "windows-link", ] +[[package]] +name = "pest" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "pest_meta" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" +dependencies = [ + "pest", + "sha2", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -593,6 +1281,131 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "ratatui" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1ce67fb8ba4446454d1c8dbaeda0557ff5e94d39d5e5ed7f10a65eb4c8266bc" +dependencies = [ + "instability", + "ratatui-core", + "ratatui-crossterm", + "ratatui-macros", + "ratatui-termwiz", + "ratatui-widgets", +] + +[[package]] +name = "ratatui-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef8dea09a92caaf73bff7adb70b76162e5937524058a7e5bff37869cbbec293" +dependencies = [ + "bitflags 2.11.1", + "compact_str", + "hashbrown 0.16.1", + "indoc", + "itertools", + "kasuari", + "lru", + "strum", + "thiserror 2.0.18", + "unicode-segmentation", + "unicode-truncate", + "unicode-width", +] + +[[package]] +name = "ratatui-crossterm" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "577c9b9f652b4c121fb25c6a391dd06406d3b092ba68827e6d2f09550edc54b3" +dependencies = [ + "cfg-if", + "crossterm", + "instability", + "ratatui-core", +] + +[[package]] +name = "ratatui-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7f1342a13e83e4bb9d0b793d0ea762be633f9582048c892ae9041ef39c936f4" +dependencies = [ + "ratatui-core", + "ratatui-widgets", +] + +[[package]] +name = "ratatui-termwiz" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f76fe0bd0ed4295f0321b1676732e2454024c15a35d01904ddb315afd3d545c" +dependencies = [ + "ratatui-core", + "termwiz", +] + +[[package]] +name = "ratatui-textarea" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2950274c0e155944158cf766848dd87bd6db6dad27da1c23ee4a7c8de71dbf1f" +dependencies = [ + "ratatui-core", + "ratatui-crossterm", + "ratatui-widgets", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "ratatui-widgets" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7dbfa023cd4e604c2553483820c5fe8aa9d71a42eea5aa77c6e7f35756612db" +dependencies = [ + "bitflags 2.11.1", + "hashbrown 0.16.1", + "indoc", + "instability", + "itertools", + "line-clipping", + "ratatui-core", + "strum", + "time", + "unicode-segmentation", + "unicode-width", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -602,6 +1415,57 @@ dependencies = [ "bitflags 2.11.1", ] +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.11.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -620,6 +1484,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.228" @@ -647,7 +1517,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -681,12 +1551,44 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + [[package]] name = "signal-hook-registry" version = "1.4.8" @@ -697,6 +1599,12 @@ dependencies = [ "libc", ] +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + [[package]] name = "slab" version = "0.4.12" @@ -719,12 +1627,50 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.117" @@ -736,13 +1682,96 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "terminfo" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4ea810f0692f9f51b382fff5893887bb4580f5fa246fde546e0b13e7fcee662" +dependencies = [ + "fnv", + "nom", + "phf", + "phf_codegen", +] + +[[package]] +name = "termios" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b" +dependencies = [ + "libc", +] + +[[package]] +name = "termwiz" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" +dependencies = [ + "anyhow", + "base64", + "bitflags 2.11.1", + "fancy-regex", + "filedescriptor", + "finl_unicode", + "fixedbitset", + "hex", + "lazy_static", + "libc", + "log", + "memmem", + "nix 0.29.0", + "num-derive", + "num-traits", + "ordered-float", + "pest", + "pest_derive", + "phf", + "sha2", + "signal-hook", + "siphasher", + "terminfo", + "termios", + "thiserror 1.0.69", + "ucd-trie", + "unicode-segmentation", + "vtparse", + "wezterm-bidi", + "wezterm-blob-leases", + "wezterm-color-types", + "wezterm-dynamic", + "wezterm-input-types", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] @@ -753,9 +1782,30 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde_core", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + [[package]] name = "tokio" version = "1.52.1" @@ -781,7 +1831,7 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -811,13 +1861,25 @@ dependencies = [ "tokio", ] +[[package]] +name = "typenum" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "unescaper" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4064ed685c487dbc25bd3f0e9548f2e34bab9d18cefc700f9ec2dba74ba1138e" dependencies = [ - "thiserror", + "thiserror 2.0.18", ] [[package]] @@ -826,18 +1888,92 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-segmentation" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" + +[[package]] +name = "unicode-truncate" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b380a1238663e5f8a691f9039c73e1cdae598a30e9855f541d29b08b53e9a5" +dependencies = [ + "itertools", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +dependencies = [ + "atomic", + "getrandom 0.4.2", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vtparse" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9b2acfb050df409c972a37d3b8e08cdea3bddb0c09db9d53137e504cfabed0" +dependencies = [ + "utf8parse", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + [[package]] name = "wasm-bindgen" version = "0.2.118" @@ -870,7 +2006,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.117", "wasm-bindgen-shared", ] @@ -883,6 +2019,112 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.1", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "wezterm-bidi" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0a6e355560527dd2d1cf7890652f4f09bb3433b6aadade4c9b5ed76de5f3ec" +dependencies = [ + "log", + "wezterm-dynamic", +] + +[[package]] +name = "wezterm-blob-leases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692daff6d93d94e29e4114544ef6d5c942a7ed998b37abdc19b17136ea428eb7" +dependencies = [ + "getrandom 0.3.4", + "mac_address", + "sha2", + "thiserror 1.0.69", + "uuid", +] + +[[package]] +name = "wezterm-color-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de81ef35c9010270d63772bebef2f2d6d1f2d20a983d27505ac850b8c4b4296" +dependencies = [ + "csscolorparser", + "deltae", + "lazy_static", + "wezterm-dynamic", +] + +[[package]] +name = "wezterm-dynamic" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2ab60e120fd6eaa68d9567f3226e876684639d22a4219b313ff69ec0ccd5ac" +dependencies = [ + "log", + "ordered-float", + "strsim", + "thiserror 1.0.69", + "wezterm-dynamic-derive", +] + +[[package]] +name = "wezterm-dynamic-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c0cf2d539c645b448eaffec9ec494b8b19bd5077d9e58cb1ae7efece8d575b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "wezterm-input-types" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7012add459f951456ec9d6c7e6fc340b1ce15d6fc9629f8c42853412c029e57e" +dependencies = [ + "bitflags 1.3.2", + "euclid", + "lazy_static", + "serde", + "wezterm-dynamic", +] + [[package]] name = "winapi" version = "0.3.9" @@ -926,7 +2168,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -937,7 +2179,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1046,6 +2288,100 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.1", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + [[package]] name = "zmij" version = "1.0.21" diff --git a/Cargo.toml b/Cargo.toml index f005ee3..9c37ee7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,3 +18,6 @@ crc = "3.4.0" async-trait = "0.1.89" serde = { version = "1.0.228", features=["derive"]} serde_json = "1.0.149" +crossterm = "0.29.0" +ratatui = "0.30.0" +ratatui-textarea = "0.9.1" diff --git a/src/app.rs b/src/app.rs index 1d37329..1281b9b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,24 +1,86 @@ -use std::{sync::{Arc, Mutex}, thread::JoinHandle}; - +use log::error; +use std::{ + sync::{Arc, Mutex}, + time::{Duration, Instant}, +}; +use tokio::task::JoinHandle; +use tokio_serial::SerialPortBuilderExt; use tokio_util::sync::CancellationToken; -use crate::serial_core::{TactileARecording, error::SerialError}; +use crate::serial_core::{ + TactileARecording, + codecs::tactile_a::{TactileACodec, TactileAHandler}, + error::SerialError, + frame::TactileAFrame, + serial::{self, PollMode, SerialFrame, TactileAPollRequester}, +}; -struct SerialSession { +pub struct SerialSession { port: String, + current_record: Arc>, cancel: CancellationToken, - task: JoinHandle<()>, - current_record: Arc> + task: Mutex>>, +} + +impl SerialSession { + fn new( + port: String, + current_record: Arc>, + cancel: CancellationToken, + ) -> Self { + Self { + port, + current_record, + cancel, + task: Mutex::new(None), + } + } } pub struct SerialConnectionState { - session: Mutex>, - last_record: Mutex>>> + session: Mutex>>, + last_record: Mutex>>>, +} + +impl SerialConnectionState { + pub fn new() -> Self { + Self { + session: Mutex::new(None), + last_record: Mutex::new(None), + } + } + + pub fn current_port(&self) -> Result, SerialError> { + let session = self.session.lock().map_err(|_| SerialError::StateError)?; + Ok(session.as_ref().map(|session| session.port.clone())) + } + + pub fn current_record(&self) -> Result>>, SerialError> { + let session = self.session.lock().map_err(|_| SerialError::StateError)?; + Ok(session + .as_ref() + .map(|session| Arc::clone(&session.current_record))) + } +} + +impl Default for SerialConnectionState { + fn default() -> Self { + Self::new() + } +} + +impl SerialFrame for TactileAFrame { + fn dts_ms(&self) -> u64 { + match self { + TactileAFrame::Req(_) => 0, + TactileAFrame::Rep(frame) => frame.dts_ms, + } + } } pub async fn serial_connect( port: String, - state: Arc + state: Arc, ) -> Result<(), SerialError> { let port_name = port.trim().to_string(); if port_name.is_empty() { @@ -32,4 +94,112 @@ pub async fn serial_connect( } } -} \ No newline at end of file + let serial_port = tokio_serial::new(&port_name, 921500) + .open_native_async() + .map_err(|_| SerialError::OpenError)?; + + let cancel = CancellationToken::new(); + let current_record = Arc::new(Mutex::new(TactileARecording::new())); + let session_started_at = Instant::now(); + let session = Arc::new(SerialSession::new( + port_name, + Arc::clone(¤t_record), + cancel.clone(), + )); + + { + let mut active_session = state.session.lock().map_err(|_| SerialError::StateError)?; + *active_session = Some(Arc::clone(&session)); + } + { + let mut last_record = state + .last_record + .lock() + .map_err(|_| SerialError::StateError)?; + *last_record = None; + } + + let task_state = Arc::clone(&state); + let task_session = Arc::clone(&session); + let task_record = Arc::clone(¤t_record); + + let task = tokio::spawn(async move { + let codec = TactileACodec::new(7, 12); + let handler = TactileAHandler; + let poll_mode = PollMode::Enabled(Box::new(TactileAPollRequester::new( + Duration::from_millis(10), + 7, + 12, + Duration::from_millis(450), + ))); + + if let Err(err) = serial::run_serial_with_poll( + serial_port, + codec, + handler, + session_started_at, + Arc::clone(&task_record), + cancel, + poll_mode, + ) + .await + { + error!("serial task exited with error: {err}"); + } + + if let Ok(mut last_record) = task_state.last_record.lock() { + *last_record = Some(Arc::clone(&task_record)); + } + if let Ok(mut active_session) = task_state.session.lock() { + let should_clear = active_session + .as_ref() + .map(|session| Arc::ptr_eq(session, &task_session)) + .unwrap_or(false); + if should_clear { + *active_session = None; + } + } + if let Ok(mut task_slot) = task_session.task.lock() { + *task_slot = None; + } + }); + + let mut task_slot = session.task.lock().map_err(|_| SerialError::StateError)?; + *task_slot = Some(task); + + Ok(()) +} + +pub async fn serial_disconnect(state: Arc) -> Result<(), SerialError> { + shutdown_active_session(&state).await +} + +pub async fn shutdown_active_session(state: &SerialConnectionState) -> Result<(), SerialError> { + let session = { + let mut active_session = state.session.lock().map_err(|_| SerialError::StateError)?; + active_session.take() + }; + + let Some(session) = session else { + return Ok(()); + }; + + session.cancel.cancel(); + + let task = { + let mut task_slot = session.task.lock().map_err(|_| SerialError::StateError)?; + task_slot.take() + }; + + if let Some(task) = task { + task.await.map_err(|_| SerialError::CloseError)?; + } + + let mut last_record = state + .last_record + .lock() + .map_err(|_| SerialError::StateError)?; + *last_record = Some(Arc::clone(&session.current_record)); + + Ok(()) +} diff --git a/src/cmd.rs b/src/cmd.rs new file mode 100644 index 0000000..accab3b --- /dev/null +++ b/src/cmd.rs @@ -0,0 +1,115 @@ +use std::io::{self, Stdout, stdout}; + +use anyhow::Ok; +use crossterm::{ + event::KeyCode, + execute, + terminal::{ + self, EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode, + }, +}; +use ratatui::{ + Terminal, + backend::{self, CrosstermBackend}, + layout::{Constraint, Direction, Layout, Margin}, + style::{Modifier, Style}, + widgets::{Block, Borders, Paragraph, Wrap}, +}; +use ratatui_textarea::TextArea; + +#[derive(Debug, Default)] +struct App { + messages: Vec, + should_quit: bool, + input: TextArea<'static>, +} + +impl App { + fn new() -> Self { + let mut input = TextArea::default(); + input.set_block(Block::default().borders(Borders::ALL).title("Input")); + input.set_cursor_line_style(Style::default().add_modifier(Modifier::REVERSED)); + Self { + messages: vec!["Welcome to JE-Skin-Cli".to_string()], + should_quit: false, + input, + } + } + + fn on_key(&mut self, code: KeyCode) { + match code { + KeyCode::Esc => self.should_quit = true, + KeyCode::Enter => { + let text = self.input.lines().join("\n"); + if !text.trim().is_empty() { + self.messages.push(format!("You send: {}", text.trim())); + } + self.input = { + let mut ta = TextArea::default(); + ta.set_block(Block::default().borders(Borders::ALL).title("Input")); + ta.set_cursor_line_style(Style::default().add_modifier(Modifier::REVERSED)); + ta + }; + } + _ => { + self.input.input(match code { + KeyCode::Char(c) => c.into(), + KeyCode::Backspace => ratatui_textarea::Input { + key: ratatui_textarea::Key::Backspace, + ctrl: false, + alt: false, + shift: false, + }, + KeyCode::Left => ratatui_textarea::Input { + key: ratatui_textarea::Key::Left, + ctrl: false, + alt: false, + shift: false, + }, + KeyCode::Right => ratatui_textarea::Input { + key: ratatui_textarea::Key::Right, + ctrl: false, + alt: false, + shift: false, + }, + KeyCode::Up => ratatui_textarea::Input { + key: ratatui_textarea::Key::Up, + ctrl: false, + alt: false, + shift: false, + }, + KeyCode::Down => ratatui_textarea::Input { + key: ratatui_textarea::Key::Down, + ctrl: false, + alt: false, + shift: false, + }, + _ => return, + }); + } + } + } +} + +pub fn init_terminal() -> Result>> { + enable_raw_mode()?; + let mut stdout = io::stdout(); + execute!(stdout, EnterAlternateScreen)?; + let backend = CrosstermBackend::new(stdout); + let terminal = Terminal::new(backend)?; + Ok(terminal) +} + +pub fn restore_terminal(terminal: &mut Terminal>) -> Result<()> { + disable_raw_mode()?; + execute!(terminal.backend_mut(), LeaveAlternateScreen)?; + terminal.show_cursor()?; + Ok(()) +} + +fn run_app(terminal: &mut Terminal>) -> Result<()> { + let mut app = App::new(); + while !app.should_quit { + terminal.draw(|f| {}) + } +} diff --git a/src/main.rs b/src/main.rs index 39ed96a..89dafd0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ -pub mod serial_core; -pub mod flog; pub mod app; +pub mod cmd; +pub mod flog; +pub mod serial_core; fn main() { println!("Hello, world!"); } diff --git a/src/serial_core/mod.rs b/src/serial_core/mod.rs index 83b8fbc..05298ea 100644 --- a/src/serial_core/mod.rs +++ b/src/serial_core/mod.rs @@ -1,16 +1,17 @@ use tokio_serial::available_ports; use crate::serial_core::{ - error::SerialError, frame::{TactileAFrame, TestFrame}, record::Recording + error::SerialError, + frame::{TactileAFrame, TestFrame}, + record::Recording, }; pub mod codec; pub mod codecs; pub mod error; pub mod frame; -pub mod model; -pub mod serial; pub mod record; +pub mod serial; pub mod utils; pub type TestRecording = Recording; @@ -40,4 +41,5 @@ pub fn serial_enum() -> Result, SerialError> { .collect(); Ok(ports) -} \ No newline at end of file +} + diff --git a/src/serial_core/model.rs b/src/serial_core/model.rs deleted file mode 100644 index ce5b9e9..0000000 --- a/src/serial_core/model.rs +++ /dev/null @@ -1,500 +0,0 @@ -use crate::serial_core::frame::TestFrame; -use std::collections::HashMap; -use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; - -const MAX_POINTS: usize = 28; -const MAX_SUMMARY_POINTS: usize = 42; -const PANEL_STALE_AFTER: Duration = Duration::from_millis(2400); - -#[derive(serde::Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct HudPacket { - pub ts: u64, - pub panels: Vec, - pub summary: HudSummary, - pub pressure_matrix: Option>, -} - -#[derive(serde::Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct HudSummary { - pub label: String, - pub points: Vec, - pub latest: Option, - pub min: Option, - pub max: Option, -} - -#[derive(serde::Serialize, Clone, Copy)] -#[serde(rename_all = "lowercase")] -pub enum HudPanelSide { - Left, - Right, -} - -#[derive(serde::Serialize, Clone, Copy)] -#[serde(rename_all = "lowercase")] -pub enum HudTone { - Cyan, - Lime, - Orange, - Violet, - Gold, - Rose, -} - -#[derive(serde::Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct HudSignalPanel { - pub id: String, - pub code: String, - pub title: String, - pub side: HudPanelSide, - pub active: bool, - pub series: Vec, - pub icons: Vec, - pub latest: Option, - pub min: Option, - pub max: Option, -} - -#[derive(serde::Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct HudSignalSeries { - pub id: String, - pub tone: HudTone, - pub points: Vec, -} - -#[derive(serde::Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct HudSignalIcon { - pub id: String, - pub label: String, - pub tone: HudTone, -} - -struct HudPanelUpdate { - source_id: String, - values: Vec, -} - -struct PanelEntry { - panel: HudSignalPanel, - last_seen: Instant, -} - -pub struct HudChartState { - panels: HashMap, - order: Vec, - summary_points: Vec, - pressure_matrix: Option>, - last_frame_seen: Option, -} - -impl HudChartState { - pub fn new() -> Self { - Self { - panels: HashMap::new(), - order: Vec::new(), - summary_points: Vec::new(), - pressure_matrix: None, - last_frame_seen: None, - } - } - - pub fn record_summary(&mut self, value: f32) { - push_summary_point(&mut self.summary_points, value); - } - - pub fn record_pressure_matrix(&mut self, values: &[i32]) { - if values.is_empty() { - return; - } - - self.pressure_matrix = Some(values.iter().map(|value| *value as f32).collect()); - } - - pub fn apply_frame(&mut self, frame: &TestFrame, decoded_values: Option<&[i32]>) -> HudPacket { - let now = Instant::now(); - self.last_frame_seen = Some(now); - - for update in expand_frame_updates(frame, decoded_values) { - self.apply_update(update, now); - } - - self.prune_stale_at(now); - self.snapshot() - } - - pub fn prune_stale(&mut self) -> Option { - let before = self.panels.len(); - let summary_points_before = self.summary_points.len(); - self.prune_stale_at(Instant::now()); - - if before == self.panels.len() && summary_points_before == self.summary_points.len() { - return None; - } - - Some(self.snapshot()) - } - - fn apply_update(&mut self, update: HudPanelUpdate, now: Instant) { - if update.values.is_empty() { - return; - } - - if !self.panels.contains_key(&update.source_id) { - let next_side = side_for_index(self.order.len()); - self.order.push(update.source_id.clone()); - self.panels.insert( - update.source_id.clone(), - PanelEntry { - panel: build_panel(&update.source_id, next_side, update.values.len()), - last_seen: now, - }, - ); - } - - let entry = self - .panels - .get_mut(&update.source_id) - .expect("panel entry should exist after insertion"); - - entry.last_seen = now; - entry.panel.active = true; - ensure_panel_channels(&mut entry.panel, update.values.len()); - - for (index, value) in update.values.into_iter().enumerate() { - if let Some(series) = entry.panel.series.get_mut(index) { - push_point(&mut series.points, value); - } - } - - refresh_panel_stats(&mut entry.panel); - } - - fn prune_stale_at(&mut self, now: Instant) { - self.panels - .retain(|_, entry| now.duration_since(entry.last_seen) <= PANEL_STALE_AFTER); - self.order.retain(|id| self.panels.contains_key(id)); - - let summary_stale = self - .last_frame_seen - .map(|last_seen| now.duration_since(last_seen) > PANEL_STALE_AFTER) - .unwrap_or(false); - - if summary_stale { - self.summary_points.clear(); - self.pressure_matrix = None; - self.last_frame_seen = None; - } - } - - fn snapshot(&mut self) -> HudPacket { - self.rebalance_sides(); - - let panels = self - .order - .iter() - .filter_map(|id| self.panels.get(id).map(|entry| entry.panel.clone())) - .collect(); - - HudPacket { - ts: now_millis(), - panels, - summary: build_summary(&self.summary_points), - pressure_matrix: self.pressure_matrix.clone(), - } - } - - fn rebalance_sides(&mut self) { - for (index, id) in self.order.iter().enumerate() { - if let Some(entry) = self.panels.get_mut(id) { - entry.panel.side = side_for_index(index); - } - } - } -} - -impl Default for HudChartState { - fn default() -> Self { - Self::new() - } -} - -fn build_panel(source_id: &str, side: HudPanelSide, channel_count: usize) -> HudSignalPanel { - HudSignalPanel { - id: format!("panel-{source_id}"), - code: source_id.to_string(), - title: format!("Source {source_id}"), - side, - active: true, - series: build_panel_series(source_id, channel_count, &[]), - icons: build_panel_icons(source_id, channel_count), - latest: None, - min: None, - max: None, - } -} - -fn expand_frame_updates(frame: &TestFrame, decoded_values: Option<&[i32]>) -> Vec { - if let Some(values) = decoded_values { - if values.is_empty() { - return Vec::new(); - } - - return vec![HudPanelUpdate { - source_id: format_source_id(frame.cmd), - values: values.iter().map(|value| *value as f32).collect(), - }]; - } - - let chunks = frame.payload.chunks_exact(4); - - if !frame.payload.is_empty() && chunks.remainder().is_empty() { - return chunks.map(build_update_from_chunk).collect(); - } - - vec![HudPanelUpdate { - source_id: format_source_id(frame.cmd), - values: fallback_values(frame), - }] -} - -fn build_update_from_chunk(chunk: &[u8]) -> HudPanelUpdate { - HudPanelUpdate { - source_id: format_source_id(chunk[0]), - values: chunk[1..] - .iter() - .enumerate() - .map(|(index, byte)| normalize_value(*byte, tone_for_index(index))) - .collect(), - } -} - -fn fallback_values(frame: &TestFrame) -> Vec { - let mut bytes = frame.payload.clone(); - - if bytes.is_empty() { - bytes.extend([ - frame.cmd, - frame.length as u8, - frame.checksum, - frame.cmd.wrapping_add(frame.checksum), - ]); - } - - while bytes.len() < 3 { - let previous = *bytes.last().unwrap_or(&frame.cmd); - bytes.push( - previous - .wrapping_add(frame.cmd) - .wrapping_add(bytes.len() as u8), - ); - } - - bytes - .into_iter() - .enumerate() - .map(|(index, byte)| normalize_value(byte, tone_for_index(index))) - .collect() -} - -fn normalize_value(byte: u8, tone: HudTone) -> f32 { - let base = (byte as f32 / 255.0) * 100.0; - let offset = match tone { - HudTone::Cyan => 6.0, - HudTone::Lime => 0.0, - HudTone::Orange => -6.0, - HudTone::Violet => 10.0, - HudTone::Gold => -10.0, - HudTone::Rose => 3.0, - }; - - (base + offset).clamp(0.0, 100.0) -} - -fn format_source_id(byte: u8) -> String { - if byte.is_ascii_alphanumeric() { - (byte as char).to_ascii_uppercase().to_string() - } else { - format!("CH{:02X}", byte) - } -} - -fn side_for_index(index: usize) -> HudPanelSide { - if index % 2 == 0 { - HudPanelSide::Left - } else { - HudPanelSide::Right - } -} - -fn push_point(points: &mut Vec, value: f32) { - if points.len() >= MAX_POINTS { - points.remove(0); - } - - points.push((value * 10.0).round() / 10.0); -} - -fn build_panel_series( - source_id: &str, - channel_count: usize, - previous: &[HudSignalSeries], -) -> Vec { - (0..channel_count) - .map(|index| HudSignalSeries { - id: format!("{source_id}-series-{}", index + 1), - tone: tone_for_index(index), - points: previous - .get(index) - .map(|series| series.points.clone()) - .unwrap_or_default(), - }) - .collect() -} - -fn build_panel_icons(source_id: &str, channel_count: usize) -> Vec { - (0..channel_count) - .map(|index| HudSignalIcon { - id: format!("{source_id}-icon-{}", index + 1), - label: if channel_count == 1 { - "TOTAL".to_string() - } else { - format!("{source_id}-{}", index + 1) - }, - tone: tone_for_index(index), - }) - .collect() -} - -fn ensure_panel_channels(panel: &mut HudSignalPanel, channel_count: usize) { - if panel.series.len() == channel_count && panel.icons.len() == channel_count { - return; - } - - panel.series = build_panel_series(&panel.code, channel_count, &panel.series); - panel.icons = build_panel_icons(&panel.code, channel_count); -} - -fn refresh_panel_stats(panel: &mut HudSignalPanel) { - let latest_values: Vec = panel - .series - .iter() - .filter_map(|series| series.points.last().copied()) - .collect(); - - panel.latest = if latest_values.is_empty() { - None - } else { - Some(latest_values.iter().sum::() / latest_values.len() as f32) - }; - - panel.min = panel - .series - .iter() - .flat_map(|series| series.points.iter().copied()) - .reduce(f32::min); - - panel.max = panel - .series - .iter() - .flat_map(|series| series.points.iter().copied()) - .reduce(f32::max); -} - -fn tone_for_index(index: usize) -> HudTone { - match index % 6 { - 0 => HudTone::Cyan, - 1 => HudTone::Lime, - 2 => HudTone::Orange, - 3 => HudTone::Violet, - 4 => HudTone::Gold, - _ => HudTone::Rose, - } -} - -fn push_summary_point(points: &mut Vec, value: f32) { - if points.len() >= MAX_SUMMARY_POINTS { - points.remove(0); - } - - points.push((value * 10.0).round() / 10.0); -} - -fn build_summary(points: &[f32]) -> HudSummary { - HudSummary { - label: "TOTAL".to_string(), - points: points.to_vec(), - latest: points.last().copied(), - min: points.iter().copied().reduce(f32::min), - max: points.iter().copied().reduce(f32::max), - } -} - -fn now_millis() -> u64 { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .map(|duration| duration.as_millis() as u64) - .unwrap_or_default() -} - -// #[cfg(test)] -// mod tests { -// use super::*; -// -// fn sample_frame() -> TestFrame { -// TestFrame { -// header: [0xAA, 0x55], -// cmd: 0x01, -// length: 4, -// payload: vec![0x00, 0x0A, 0x00, 0x14], -// checksum: 0, -// -// } -// } -// -// #[test] -// fn prune_stale_clears_panels_and_summary_after_timeout() { -// let mut state = HudChartState::new(); -// let frame = sample_frame(); -// -// state.record_summary(30.0); -// let _ = state.apply_frame(&frame, Some(&[10, 20])); -// -// let stale_now = Instant::now(); -// let stale_seen = stale_now - PANEL_STALE_AFTER - Duration::from_millis(1); -// -// state.last_frame_seen = Some(stale_seen); -// -// for entry in state.panels.values_mut() { -// entry.last_seen = stale_seen; -// } -// -// let packet = state -// .prune_stale() -// .expect("stale data should emit an update"); -// -// assert!(packet.panels.is_empty()); -// assert!(packet.summary.points.is_empty()); -// assert!(state.panels.is_empty()); -// assert!(state.summary_points.is_empty()); -// } -// -// #[test] -// fn prune_stale_keeps_recent_summary_points() { -// let mut state = HudChartState::new(); -// let frame = sample_frame(); -// -// state.record_summary(30.0); -// let _ = state.apply_frame(&frame, Some(&[10, 20])); -// -// state.last_frame_seen = Some(Instant::now()); -// -// assert!(state.prune_stale().is_none()); -// assert_eq!(state.summary_points, vec![30.0]); -// assert_eq!(state.panels.len(), 1); -// } -// } diff --git a/src/serial_core/serial.rs b/src/serial_core/serial.rs index 89c33c7..4b9a90e 100644 --- a/src/serial_core/serial.rs +++ b/src/serial_core/serial.rs @@ -1,34 +1,26 @@ use crate::serial_core::codec::Codec; use crate::serial_core::codecs::tactile_a::TactileACodec; -use crate::serial_core::frame::{FrameHandler, TactileAFrame, TestFrame}; -use crate::serial_core::model::{HudChartState, HudPacket}; +use crate::serial_core::frame::{FrameHandler, TactileAFrame}; use crate::serial_core::record::Recording; +use crate::serial_core::record::{FrameTiming, RecordedFrame}; use anyhow::Result; +use std::future::pending; +use std::sync::{Arc, Mutex}; +use std::time::Instant; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::time::{self, Duration, MissedTickBehavior}; use tokio_serial::SerialStream; use tokio_util::sync::CancellationToken; -use std::future::pending; -use std::sync::{Arc, Mutex}; -use std::time::Instant; -use crate::serial_core::record::{FrameTiming, RecordedFrame}; pub enum PollMode { Disable, - Enabled(Box>) + Enabled(Box>), } pub trait SerialFrame: Clone + Send + 'static { fn dts_ms(&self) -> u64; - - fn to_hud_packet( - &self, - chart_state: &mut HudChartState, - display_values: Option<&[i32]>, - ) -> Option; } - pub trait PollRequester: Send { fn poll_interval(&self) -> Option { None @@ -122,11 +114,18 @@ where F: SerialFrame, C: Codec + Send + 'static, H: FrameHandler + Send + 'static, - T: Into + T: Into, { run_serial_with_poll( - port, codec, handler, session_started_at, recording, cancel, PollMode::Disable - ).await + port, + codec, + handler, + session_started_at, + recording, + cancel, + PollMode::Disable, + ) + .await } pub async fn run_serial_with_poll( @@ -136,7 +135,7 @@ pub async fn run_serial_with_poll( session_started_at: Instant, recording: Arc>>, cancel: CancellationToken, - poll_mode: PollMode + poll_mode: PollMode, ) -> Result<()> where F: SerialFrame, @@ -149,21 +148,16 @@ where PollMode::Enabled(r) => Some(r), }; - let mut poll_interval = requester - .as_ref() - .and_then(|r| r.poll_interval()) - .map(|d| { + let mut poll_interval = requester.as_ref().and_then(|r| r.poll_interval()).map(|d| { let mut it = time::interval(d); it.set_missed_tick_behavior(MissedTickBehavior::Skip); it }); - let mut chart_state = HudChartState::new(); let mut buffer = [0u8; 1024]; let mut prune_interval = time::interval(Duration::from_millis(450)); prune_interval.set_missed_tick_behavior(MissedTickBehavior::Delay); - loop { tokio::select! { _ = cancel.cancelled() => break,