From f595b5aa98a3d30c59706fd31c22c7d88102ac0c Mon Sep 17 00:00:00 2001 From: Michael Mikovsky <77305074+Astatin3@users.noreply.github.com> Date: Sun, 31 May 2026 10:26:57 -0600 Subject: [PATCH] Add "LeafMeta" struct to leaf --- Cargo.lock | 1120 +++++++++++++++++++++- Cargo.toml | 21 +- src/protocol/endpoint/mod.rs | 7 + src/protocol/leaf.rs | 351 +------ src/protocol/leaf_meta.rs | 8 + src/protocol/mod.rs | 8 +- src/protocol/procedure.rs | 66 ++ src/protocol/session.rs | 280 ++++++ src/protocol/tests/merkle_sync/leaves.rs | 33 + src/protocol/tests/oneshot/streams.rs | 23 + src/protocol/tests/oneshot/support.rs | 33 + 11 files changed, 1576 insertions(+), 374 deletions(-) create mode 100644 src/protocol/leaf_meta.rs create mode 100644 src/protocol/procedure.rs create mode 100644 src/protocol/session.rs diff --git a/Cargo.lock b/Cargo.lock index 8400a75..a6f4172 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,7 +10,7 @@ checksum = "66bd29a732b644c0431c6140f370d097879203d79b80c94a6747ba0872adaef8" dependencies = [ "cipher", "cpubits", - "cpufeatures", + "cpufeatures 0.3.0", ] [[package]] @@ -22,6 +22,12 @@ 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" @@ -37,6 +43,15 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "atomic" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" +dependencies = [ + "bytemuck", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -50,9 +65,30 @@ dependencies = [ "aes", "cbc", "regex", - "sha2", + "sha2 0.11.0", ] +[[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" @@ -65,6 +101,15 @@ 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 = "block-buffer" version = "0.12.0" @@ -112,12 +157,27 @@ dependencies = [ "syn 2.0.117", ] +[[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 = "cbc" version = "0.2.0" @@ -162,8 +222,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" dependencies = [ "cfg-if", - "cpufeatures", - "rand_core", + "cpufeatures 0.3.0", + "rand_core 0.10.1", ] [[package]] @@ -185,16 +245,39 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea" dependencies = [ - "crypto-common", + "crypto-common 0.2.1", "inout", ] +[[package]] +name = "compact_str" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "static_assertions", +] + [[package]] name = "const-oid" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" +[[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-sys" version = "0.8.7" @@ -207,6 +290,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ef0c543070d296ea414df2dd7625d1b24866ce206709d8a4a424f28377f5861" +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + [[package]] name = "cpufeatures" version = "0.3.0" @@ -231,6 +323,43 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[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 = "crypto-common" version = "0.2.1" @@ -240,35 +369,227 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "csscolorparser" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2a7d3066da2de787b7f032c736763eb7ae5d355f81a68bab2675a96008b0bf" +dependencies = [ + "lab", + "phf", +] + +[[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 0.10.4", + "crypto-common 0.1.7", +] + [[package]] name = "digest" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" dependencies = [ - "block-buffer", + "block-buffer 0.12.0", "const-oid", - "crypto-common", + "crypto-common 0.2.1", ] +[[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.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + [[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[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 = "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.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" +[[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 = "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" @@ -277,8 +598,8 @@ checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "libc", - "r-efi", - "rand_core", + "r-efi 6.0.0", + "rand_core 0.10.1", "wasip2", "wasip3", ] @@ -289,7 +610,7 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "foldhash", + "foldhash 0.1.5", ] [[package]] @@ -297,6 +618,11 @@ 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" @@ -361,6 +687,12 @@ 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.13.0" @@ -373,6 +705,15 @@ dependencies = [ "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 = "inout" version = "0.2.2" @@ -383,6 +724,28 @@ dependencies = [ "hybrid-array", ] +[[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 = "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" @@ -399,6 +762,29 @@ 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 = "leaf-pty" version = "0.1.0" @@ -418,6 +804,27 @@ 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" @@ -433,12 +840,64 @@ 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", + "winapi", +] + [[package]] name = "memchr" 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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + [[package]] name = "munge" version = "0.4.7" @@ -459,6 +918,46 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.11.1", + "cfg-if", + "cfg_aliases 0.2.1", + "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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[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]] name = "num-traits" version = "0.2.19" @@ -468,12 +967,30 @@ 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.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[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" @@ -497,6 +1014,113 @@ 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 0.10.9", +] + +[[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 0.8.6", +] + +[[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 = "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" @@ -545,6 +1169,12 @@ 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" @@ -560,6 +1190,15 @@ dependencies = [ "ptr_meta", ] +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.10.1" @@ -567,16 +1206,107 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ "chacha20", - "getrandom", - "rand_core", + "getrandom 0.4.2", + "rand_core 0.10.1", ] +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + [[package]] name = "rand_core" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" +[[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-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" @@ -654,12 +1384,40 @@ dependencies = [ "syn 2.0.117", ] +[[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", +] + [[package]] name = "rustversion" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "scopeguard" version = "1.2.0" @@ -679,6 +1437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", + "serde_derive", ] [[package]] @@ -714,6 +1473,17 @@ dependencies = [ "zmij", ] +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + [[package]] name = "sha2" version = "0.11.0" @@ -721,8 +1491,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.3.0", + "digest 0.11.2", ] [[package]] @@ -731,18 +1501,61 @@ 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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + [[package]] name = "simdutf8" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + [[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "static_init" version = "1.0.4" @@ -771,6 +1584,33 @@ dependencies = [ "syn 1.0.109", ] +[[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" @@ -793,13 +1633,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", + "num-derive", + "num-traits", + "ordered-float", + "pest", + "pest_derive", + "phf", + "sha2 0.10.9", + "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]] @@ -813,6 +1736,27 @@ dependencies = [ "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 = "tinyvec" version = "1.11.0" @@ -834,12 +1778,41 @@ 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 = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +[[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" @@ -852,9 +1825,10 @@ version = "0.1.0" dependencies = [ "chrono", "crossbeam-channel", + "ratatui", "rkyv", "static_init", - "thiserror", + "thiserror 2.0.18", "unshell-macros", ] @@ -880,26 +1854,55 @@ version = "0.1.0" dependencies = [ "base62", "block-padding", - "getrandom", + "getrandom 0.4.2", "hex", "hex-literal", "proc-macro2", "quote", - "rand", + "rand 0.10.1", "static_init", "syn 2.0.117", ] +[[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" @@ -997,6 +2000,78 @@ dependencies = [ "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 0.10.9", + "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" @@ -1078,6 +2153,15 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "wit-bindgen" version = "0.51.0" diff --git a/Cargo.toml b/Cargo.toml index b18814b..eb1a275 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,8 +7,6 @@ members = [ "unshell-macros-core", "unshell-macros", - # "unshell-protocol", - "unshell-leaves/leaf-pty", ] resolver = "2" @@ -32,6 +30,8 @@ proc-macro2 = "1.0.106" portable-pty = "0.9.0" crossbeam-channel = "0.5.15" +ratatui = "0.30.0" + unshell = { path = "." } # unshell-protocol = { path = "./unshell-protocol" } unshell-macros-core = { path = "./unshell-macros-core" } @@ -51,28 +51,23 @@ edition.workspace = true description = "Pure no_std implementation of the UnShell Protocol" [features] -default = [] +# default = ["interface_ratatui"] + log = [] log_debug = ["log", "dep:chrono"] -# Leaf features -# leaf_endpoint = ["unshell-leaves/leaf_endpoint"] -# leaf_tui = ["unshell-leaves/leaf_tui"] - -# obfuscate_aes = ["ush-obfuscate/obfuscate_aes"] -# obfuscate_ref = ["ush-obfuscate/obfuscate_ref"] +interface = [] +interface_ratatui = ["interface", "dep:ratatui"] [dependencies] rkyv = { workspace = true } thiserror = { workspace = true, optional = true } chrono = { workspace = true, optional = true } -# ush-obfuscate = { workspace = true } static_init = { workspace = true } +ratatui = { workspace = true, optional = true } + unshell-macros = { workspace = true } -# unshell-protocol = { workspace = true } -# unshell-runtime = { workspace = true } -# unshell-leaves = { workspace = true } [dev-dependencies] crossbeam-channel.workspace = true diff --git a/src/protocol/endpoint/mod.rs b/src/protocol/endpoint/mod.rs index eaac715..495c985 100644 --- a/src/protocol/endpoint/mod.rs +++ b/src/protocol/endpoint/mod.rs @@ -120,4 +120,11 @@ impl Endpoint { queue.clear(); } } + + pub fn iter_leaves(&mut self) -> core::slice::IterMut<'_, Box> + where + F: FnMut(&Packet), + { + self.leaves.iter_mut() + } } diff --git a/src/protocol/leaf.rs b/src/protocol/leaf.rs index dfd2646..872efd9 100644 --- a/src/protocol/leaf.rs +++ b/src/protocol/leaf.rs @@ -1,6 +1,7 @@ -use crate::protocol::{Endpoint, HookID, Packet, PacketQueue}; +use crate::protocol::Endpoint; -use alloc::vec::Vec; +#[cfg(feature = "interface")] +use crate::protocol::leaf_meta::LeafMeta; /// Application extension point hosted by an [`Endpoint`]. /// @@ -16,344 +17,10 @@ pub trait Leaf { /// Implementations normally drain matching inbound packets, mutate leaf-owned /// state, then enqueue outbound packets with [`Endpoint::add_outbound`]. fn update(&mut self, _: &mut Endpoint); -} - -/// Contract implemented by one hook-backed generated session family. -/// -/// A session family maps one outer `procedure_id` to many live hook instances. The -/// generated leaf owns packet grouping, retry-safe output flushing, and final cleanup; -/// the session implementation owns only application behavior. -/// -/// # Example -/// -/// ```rust,ignore -/// impl Session for MySession { -/// const PROCEDURE_ID: u32 = 7; -/// type State = MySessionState; -/// -/// fn reply_path(state: &Self::State) -> &[u32] { -/// &state.reply_path -/// } -/// -/// fn init( -/// leaf: &mut MyLeafState, -/// packet: Packet, -/// ctx: &mut SessionInit, -/// ) -> SessionInitResult { -/// SessionInitResult::Created(MySessionState::from_open(leaf, packet, ctx)) -/// } -/// -/// fn update( -/// leaf: &mut MyLeafState, -/// session: &mut Self::State, -/// incoming: &mut PacketQueue, -/// ctx: &mut SessionCtx<'_>, -/// ) -> SessionStatus { -/// while let Some(packet) = incoming.pop_front() { -/// session.apply(leaf, packet, ctx); -/// } -/// SessionStatus::Running -/// } -/// } -/// ``` -pub trait Session { - /// Outer packet procedure id used by every packet in this session family. - const PROCEDURE_ID: u32; - - /// Application state stored for one live hook. - type State; - - /// Returns the destination path for responses emitted by this session. - /// - /// `Packet` currently carries only a destination path, so protocols that need to - /// reply to a caller should capture a reply path during [`Self::init`]. The - /// generated leaf clones this path into [`SessionCtx`] before calling update so - /// session code can mutably borrow its state while emitting frames. - fn reply_path(session: &Self::State) -> &[u32]; - - /// Creates one session state from a packet whose hook has no active session. - /// - /// Returning [`SessionInitResult::RejectedWith`] lets the generated leaf route a - /// protocol-level failure response with the same retry guarantees as normal - /// output. Returning [`SessionInitResult::Rejected`] silently consumes the packet. - fn init(leaf: &mut L, packet: Packet, ctx: &mut SessionInit) -> SessionInitResult; - - /// Advances one active hook session. - /// - /// The generated leaf calls this for every live session on each update tick so - /// sessions can poll external workers even when no new packet arrived. Outbound - /// packets must be queued through `ctx`; direct endpoint routing would bypass the - /// generated retry rules. - fn update( - leaf: &mut L, - session: &mut Self::State, - incoming: &mut PacketQueue, - ctx: &mut SessionCtx<'_>, - ) -> SessionStatus; -} - -/// Contract implemented by one generated one-packet procedure handler. -/// -/// Procedures are for stateless or short-lived operations such as ping, capabilities, -/// or health checks. Long-running conversations should use [`Session`] so final -/// packet cleanup and retries remain tied to hook state. -pub trait Procedure { - /// Outer packet procedure id handled by this procedure. - const PROCEDURE_ID: u32; - - /// Handles one packet and optionally queues response packets in `out`. - fn handle(leaf: &mut L, endpoint: &mut Endpoint, packet: Packet, out: &mut ProcedureOut); -} - -/// Context passed to [`Session::init`]. -/// -/// This carries routing metadata that the generated leaf already knows before the -/// session state exists. Protocols that need source paths should encode them in the -/// packet payload; `packet_path` is the destination path that routed the packet here. -pub struct SessionInit { - hook_id: HookID, - packet_path: Vec, -} - -impl SessionInit { - /// Creates initialization metadata for a delivered packet. - pub fn new(hook_id: HookID, packet_path: Vec) -> Self { - Self { - hook_id, - packet_path, - } - } - - /// Returns the hook id that will identify the new session. - pub fn hook_id(&self) -> HookID { - self.hook_id - } - - /// Returns the destination path from the packet that reached this leaf. - pub fn packet_path(&self) -> &[u32] { - &self.packet_path - } -} - -/// Result of trying to create a session from a packet without an active hook entry. -pub enum SessionInitResult { - /// A new session was created and should be stored by the generated leaf. - Created(S), - - /// The packet was intentionally consumed without creating state or a response. - Rejected, - - /// The packet was rejected with a response that the generated leaf must route. - RejectedWith(Packet), -} - -/// Session lifecycle status returned from [`Session::update`]. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum SessionStatus { - /// The session is active and should receive future update ticks. - Running, - - /// The session is winding down but still needs future update ticks. - Closing, - - /// The session has finished application work. - /// - /// The generated leaf still retains the entry until every queued packet routes - /// successfully, which prevents a failed final frame from losing session cleanup. - Closed, -} - -/// Mutable output context passed to [`Session::update`]. -/// -/// The context queues packets only; it never routes them immediately. Centralizing -/// routing in generated code is what makes final-frame retries reliable. -pub struct SessionCtx<'a> { - hook_id: HookID, - reply_path: Vec, - procedure_id: u32, - outbox: &'a mut PacketQueue, -} - -impl<'a> SessionCtx<'a> { - /// Creates a context for one session update call. - pub fn new( - hook_id: HookID, - reply_path: Vec, - procedure_id: u32, - outbox: &'a mut PacketQueue, - ) -> Self { - Self { - hook_id, - reply_path, - procedure_id, - outbox, - } - } - - /// Returns the hook id used for packets emitted through this context. - pub fn hook_id(&self) -> HookID { - self.hook_id - } - - /// Returns the destination path used for packets emitted through this context. - pub fn reply_path(&self) -> &[u32] { - &self.reply_path - } - - /// Queues a one-byte-opcode frame without closing the hook. - pub fn send(&mut self, opcode: u8, data: &[u8]) { - self.send_frame(opcode, data, false); - } - - /// Queues a one-byte-opcode frame that closes the hook after successful routing. - pub fn send_final(&mut self, opcode: u8, data: &[u8]) { - self.send_frame(opcode, data, true); - } - - /// Queues a protocol-specific error frame without closing the hook. - /// - /// The `code` is used as the frame opcode because the protocol layer does not - /// reserve a universal error opcode. Leaves that have a dedicated error opcode can - /// pass that value here or call [`Self::send`] directly. - pub fn error(&mut self, code: u8, data: &[u8]) { - self.send(code, data); - } - - /// Queues a protocol-specific error frame that closes the hook after routing. - pub fn error_final(&mut self, code: u8, data: &[u8]) { - self.send_final(code, data); - } - - /// Queues raw packet data without adding an opcode byte. - pub fn send_raw(&mut self, data: &[u8]) { - self.send_raw_with_end(data, false); - } - - /// Queues raw packet data and closes the hook after successful routing. - pub fn send_raw_final(&mut self, data: &[u8]) { - self.send_raw_with_end(data, true); - } - - fn send_frame(&mut self, opcode: u8, data: &[u8], end_hook: bool) { - let mut frame = Vec::with_capacity(data.len() + 1); - frame.push(opcode); - frame.extend_from_slice(data); - self.enqueue_data(frame, end_hook); - } - - fn send_raw_with_end(&mut self, data: &[u8], end_hook: bool) { - self.enqueue_data(data.to_vec(), end_hook); - } - - fn enqueue_data(&mut self, data: Vec, end_hook: bool) { - self.outbox.push_back(Packet { - hook_id: self.hook_id, - end_hook, - path: self.reply_path.clone(), - procedure_id: self.procedure_id, - data, - }); - } -} - -/// Output accumulator passed to [`Procedure::handle`]. -pub struct ProcedureOut { - hook_id: HookID, - reply_path: Vec, - procedure_id: u32, - outbox: PacketQueue, -} - -impl ProcedureOut { - /// Creates an empty procedure output queue. - pub fn new(hook_id: HookID, reply_path: Vec, procedure_id: u32) -> Self { - Self { - hook_id, - reply_path, - procedure_id, - outbox: PacketQueue::new(), - } - } - - /// Replaces the response path used by later [`Self::send`] calls. - pub fn set_reply_path(&mut self, reply_path: Vec) { - self.reply_path = reply_path; - } - - /// Queues raw response data without closing the hook. - pub fn send(&mut self, data: &[u8]) { - self.send_with_end(data, false); - } - - /// Queues raw response data that closes the hook after successful routing. - pub fn send_final(&mut self, data: &[u8]) { - self.send_with_end(data, true); - } - - /// Consumes the output accumulator and returns packets for generated retry logic. - pub fn into_packets(self) -> PacketQueue { - self.outbox - } - - fn send_with_end(&mut self, data: &[u8], end_hook: bool) { - self.outbox.push_back(Packet { - hook_id: self.hook_id, - end_hook, - path: self.reply_path.clone(), - procedure_id: self.procedure_id, - data: data.to_vec(), - }); - } -} - -/// Storage entry used by macro-generated session stores. -/// -/// The fields are public so generated code in downstream crates can keep the update -/// loop straightforward and static. Handwritten leaves may also use this type, but it -/// is intentionally small rather than a full session framework. -pub struct SessionEntry { - /// Hook id associated with this live session. - pub hook_id: HookID, - - /// Application-owned session state. - pub state: S, - - /// Packets delivered for this hook but not yet consumed by the session. - pub inbox: PacketQueue, - - /// Packets emitted by the session but not yet accepted by endpoint routing. - pub outbox: PacketQueue, - - /// Whether application logic has finished and only retry flushing may remain. - pub closed: bool, -} - -impl SessionEntry { - /// Creates one active session entry for `hook_id`. - pub fn new(hook_id: HookID, state: S) -> Self { - Self { - hook_id, - state, - inbox: PacketQueue::new(), - outbox: PacketQueue::new(), - closed: false, - } - } -} - -/// Flushes a retry queue through [`Endpoint::add_outbound`]. -/// -/// The packet at the front is cloned for each attempt and removed only after routing -/// succeeds. This preserves final frames when a route is temporarily unavailable. -/// The return value is true when the queue was fully drained. -pub fn flush_packet_queue(endpoint: &mut Endpoint, outbox: &mut PacketQueue) -> bool { - while let Some(packet) = outbox.front().cloned() { - if endpoint.add_outbound(packet).is_err() { - return false; - } - - outbox.pop_front(); - } - - true + + #[cfg(feature = "interface")] + fn get_meta(&self) -> LeafMeta; + + #[cfg(feature = "interface_ratatui")] + fn render_ratatui(&mut self, _: &mut ratatui::Frame<'_>, _: ratatui::layout::Rect) {} } diff --git a/src/protocol/leaf_meta.rs b/src/protocol/leaf_meta.rs new file mode 100644 index 0000000..c74c9ac --- /dev/null +++ b/src/protocol/leaf_meta.rs @@ -0,0 +1,8 @@ +use alloc::vec::Vec; + +pub struct LeafMeta { + pub name: &'static str, + pub identifier: &'static str, + pub version: &'static str, + pub authors: Vec<&'static str>, +} diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index dbf6c80..fba9ffa 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -1,12 +1,18 @@ mod endpoint; mod error; mod leaf; +mod leaf_meta; mod packet; +mod procedure; +mod session; pub use endpoint::{Endpoint, HookID}; pub use error::*; -pub use leaf::*; +pub use leaf::Leaf; +pub use leaf_meta::LeafMeta; pub use packet::Packet; +pub use procedure::*; +pub use session::*; pub use unshell_macros::unshell_leaf; // Various named types used for brevity diff --git a/src/protocol/procedure.rs b/src/protocol/procedure.rs new file mode 100644 index 0000000..366a8d6 --- /dev/null +++ b/src/protocol/procedure.rs @@ -0,0 +1,66 @@ +use alloc::vec::Vec; + +use crate::protocol::{Endpoint, HookID, Packet, PacketQueue}; + +/// Contract implemented by one generated one-packet procedure handler. +/// +/// Procedures are for stateless or short-lived operations such as ping, capabilities, +/// or health checks. Long-running conversations should use [`Session`] so final +/// packet cleanup and retries remain tied to hook state. +pub trait Procedure { + /// Outer packet procedure id handled by this procedure. + const PROCEDURE_ID: u32; + + /// Handles one packet and optionally queues response packets in `out`. + fn handle(leaf: &mut L, endpoint: &mut Endpoint, packet: Packet, out: &mut ProcedureOut); +} + +/// Output accumulator passed to [`Procedure::handle`]. +pub struct ProcedureOut { + hook_id: HookID, + reply_path: Vec, + procedure_id: u32, + outbox: PacketQueue, +} + +impl ProcedureOut { + /// Creates an empty procedure output queue. + pub fn new(hook_id: HookID, reply_path: Vec, procedure_id: u32) -> Self { + Self { + hook_id, + reply_path, + procedure_id, + outbox: PacketQueue::new(), + } + } + + /// Replaces the response path used by later [`Self::send`] calls. + pub fn set_reply_path(&mut self, reply_path: Vec) { + self.reply_path = reply_path; + } + + /// Queues raw response data without closing the hook. + pub fn send(&mut self, data: &[u8]) { + self.send_with_end(data, false); + } + + /// Queues raw response data that closes the hook after successful routing. + pub fn send_final(&mut self, data: &[u8]) { + self.send_with_end(data, true); + } + + /// Consumes the output accumulator and returns packets for generated retry logic. + pub fn into_packets(self) -> PacketQueue { + self.outbox + } + + fn send_with_end(&mut self, data: &[u8], end_hook: bool) { + self.outbox.push_back(Packet { + hook_id: self.hook_id, + end_hook, + path: self.reply_path.clone(), + procedure_id: self.procedure_id, + data: data.to_vec(), + }); + } +} diff --git a/src/protocol/session.rs b/src/protocol/session.rs new file mode 100644 index 0000000..2ff94a2 --- /dev/null +++ b/src/protocol/session.rs @@ -0,0 +1,280 @@ +use alloc::vec::Vec; + +use crate::protocol::{Endpoint, HookID, Packet, PacketQueue}; + +/// Contract implemented by one hook-backed generated session family. +/// +/// A session family maps one outer `procedure_id` to many live hook instances. The +/// generated leaf owns packet grouping, retry-safe output flushing, and final cleanup; +/// the session implementation owns only application behavior. +/// +/// # Example +/// +/// ```rust,ignore +/// impl Session for MySession { +/// const PROCEDURE_ID: u32 = 7; +/// type State = MySessionState; +/// +/// fn reply_path(state: &Self::State) -> &[u32] { +/// &state.reply_path +/// } +/// +/// fn init( +/// leaf: &mut MyLeafState, +/// packet: Packet, +/// ctx: &mut SessionInit, +/// ) -> SessionInitResult { +/// SessionInitResult::Created(MySessionState::from_open(leaf, packet, ctx)) +/// } +/// +/// fn update( +/// leaf: &mut MyLeafState, +/// session: &mut Self::State, +/// incoming: &mut PacketQueue, +/// ctx: &mut SessionCtx<'_>, +/// ) -> SessionStatus { +/// while let Some(packet) = incoming.pop_front() { +/// session.apply(leaf, packet, ctx); +/// } +/// SessionStatus::Running +/// } +/// } +/// ``` +pub trait Session { + /// Outer packet procedure id used by every packet in this session family. + const PROCEDURE_ID: u32; + + /// Application state stored for one live hook. + type State; + + /// Returns the destination path for responses emitted by this session. + /// + /// `Packet` currently carries only a destination path, so protocols that need to + /// reply to a caller should capture a reply path during [`Self::init`]. The + /// generated leaf clones this path into [`SessionCtx`] before calling update so + /// session code can mutably borrow its state while emitting frames. + fn reply_path(session: &Self::State) -> &[u32]; + + /// Creates one session state from a packet whose hook has no active session. + /// + /// Returning [`SessionInitResult::RejectedWith`] lets the generated leaf route a + /// protocol-level failure response with the same retry guarantees as normal + /// output. Returning [`SessionInitResult::Rejected`] silently consumes the packet. + fn init(leaf: &mut L, packet: Packet, ctx: &mut SessionInit) -> SessionInitResult; + + /// Advances one active hook session. + /// + /// The generated leaf calls this for every live session on each update tick so + /// sessions can poll external workers even when no new packet arrived. Outbound + /// packets must be queued through `ctx`; direct endpoint routing would bypass the + /// generated retry rules. + fn update( + leaf: &mut L, + session: &mut Self::State, + incoming: &mut PacketQueue, + ctx: &mut SessionCtx<'_>, + ) -> SessionStatus; +} + +/// Context passed to [`Session::init`]. +/// +/// This carries routing metadata that the generated leaf already knows before the +/// session state exists. Protocols that need source paths should encode them in the +/// packet payload; `packet_path` is the destination path that routed the packet here. +pub struct SessionInit { + hook_id: HookID, + packet_path: Vec, +} + +impl SessionInit { + /// Creates initialization metadata for a delivered packet. + pub fn new(hook_id: HookID, packet_path: Vec) -> Self { + Self { + hook_id, + packet_path, + } + } + + /// Returns the hook id that will identify the new session. + pub fn hook_id(&self) -> HookID { + self.hook_id + } + + /// Returns the destination path from the packet that reached this leaf. + pub fn packet_path(&self) -> &[u32] { + &self.packet_path + } +} + +/// Result of trying to create a session from a packet without an active hook entry. +pub enum SessionInitResult { + /// A new session was created and should be stored by the generated leaf. + Created(S), + + /// The packet was intentionally consumed without creating state or a response. + Rejected, + + /// The packet was rejected with a response that the generated leaf must route. + RejectedWith(Packet), +} + +/// Session lifecycle status returned from [`Session::update`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SessionStatus { + /// The session is active and should receive future update ticks. + Running, + + /// The session is winding down but still needs future update ticks. + Closing, + + /// The session has finished application work. + /// + /// The generated leaf still retains the entry until every queued packet routes + /// successfully, which prevents a failed final frame from losing session cleanup. + Closed, +} + +/// Mutable output context passed to [`Session::update`]. +/// +/// The context queues packets only; it never routes them immediately. Centralizing +/// routing in generated code is what makes final-frame retries reliable. +pub struct SessionCtx<'a> { + hook_id: HookID, + reply_path: Vec, + procedure_id: u32, + outbox: &'a mut PacketQueue, +} + +impl<'a> SessionCtx<'a> { + /// Creates a context for one session update call. + pub fn new( + hook_id: HookID, + reply_path: Vec, + procedure_id: u32, + outbox: &'a mut PacketQueue, + ) -> Self { + Self { + hook_id, + reply_path, + procedure_id, + outbox, + } + } + + /// Returns the hook id used for packets emitted through this context. + pub fn hook_id(&self) -> HookID { + self.hook_id + } + + /// Returns the destination path used for packets emitted through this context. + pub fn reply_path(&self) -> &[u32] { + &self.reply_path + } + + /// Queues a one-byte-opcode frame without closing the hook. + pub fn send(&mut self, opcode: u8, data: &[u8]) { + self.send_frame(opcode, data, false); + } + + /// Queues a one-byte-opcode frame that closes the hook after successful routing. + pub fn send_final(&mut self, opcode: u8, data: &[u8]) { + self.send_frame(opcode, data, true); + } + + /// Queues a protocol-specific error frame without closing the hook. + /// + /// The `code` is used as the frame opcode because the protocol layer does not + /// reserve a universal error opcode. Leaves that have a dedicated error opcode can + /// pass that value here or call [`Self::send`] directly. + pub fn error(&mut self, code: u8, data: &[u8]) { + self.send(code, data); + } + + /// Queues a protocol-specific error frame that closes the hook after routing. + pub fn error_final(&mut self, code: u8, data: &[u8]) { + self.send_final(code, data); + } + + /// Queues raw packet data without adding an opcode byte. + pub fn send_raw(&mut self, data: &[u8]) { + self.send_raw_with_end(data, false); + } + + /// Queues raw packet data and closes the hook after successful routing. + pub fn send_raw_final(&mut self, data: &[u8]) { + self.send_raw_with_end(data, true); + } + + fn send_frame(&mut self, opcode: u8, data: &[u8], end_hook: bool) { + let mut frame = Vec::with_capacity(data.len() + 1); + frame.push(opcode); + frame.extend_from_slice(data); + self.enqueue_data(frame, end_hook); + } + + fn send_raw_with_end(&mut self, data: &[u8], end_hook: bool) { + self.enqueue_data(data.to_vec(), end_hook); + } + + fn enqueue_data(&mut self, data: Vec, end_hook: bool) { + self.outbox.push_back(Packet { + hook_id: self.hook_id, + end_hook, + path: self.reply_path.clone(), + procedure_id: self.procedure_id, + data, + }); + } +} + +/// Storage entry used by macro-generated session stores. +/// +/// The fields are public so generated code in downstream crates can keep the update +/// loop straightforward and static. Handwritten leaves may also use this type, but it +/// is intentionally small rather than a full session framework. +pub struct SessionEntry { + /// Hook id associated with this live session. + pub hook_id: HookID, + + /// Application-owned session state. + pub state: S, + + /// Packets delivered for this hook but not yet consumed by the session. + pub inbox: PacketQueue, + + /// Packets emitted by the session but not yet accepted by endpoint routing. + pub outbox: PacketQueue, + + /// Whether application logic has finished and only retry flushing may remain. + pub closed: bool, +} + +impl SessionEntry { + /// Creates one active session entry for `hook_id`. + pub fn new(hook_id: HookID, state: S) -> Self { + Self { + hook_id, + state, + inbox: PacketQueue::new(), + outbox: PacketQueue::new(), + closed: false, + } + } +} + +/// Flushes a retry queue through [`Endpoint::add_outbound`]. +/// +/// The packet at the front is cloned for each attempt and removed only after routing +/// succeeds. This preserves final frames when a route is temporarily unavailable. +/// The return value is true when the queue was fully drained. +pub fn flush_packet_queue(endpoint: &mut Endpoint, outbox: &mut PacketQueue) -> bool { + while let Some(packet) = outbox.front().cloned() { + if endpoint.add_outbound(packet).is_err() { + return false; + } + + outbox.pop_front(); + } + + true +} diff --git a/src/protocol/tests/merkle_sync/leaves.rs b/src/protocol/tests/merkle_sync/leaves.rs index 0c9ddcd..3a8d22f 100644 --- a/src/protocol/tests/merkle_sync/leaves.rs +++ b/src/protocol/tests/merkle_sync/leaves.rs @@ -5,6 +5,9 @@ use crossbeam_channel::{Receiver, Sender}; use crate::protocol::{Endpoint, Leaf, Packet}; +#[cfg(feature = "interface")] +use crate::protocol::LeafMeta; + use super::{ codec::{decode_block_chunk, decode_child_summary, decode_u32}, constants::{ @@ -96,6 +99,16 @@ impl Leaf for MockConnectionLeaf { LEAF_MOCK_CONNECTION } + #[cfg(feature = "interface")] + fn get_meta(&self) -> LeafMeta { + LeafMeta { + name: "Merke Connection Leaf", + identifier: "dev.unshell.test.merkle.connection", + version: "v0", + authors: vec!["ASTATIN3"], + } + } + fn update(&mut self, endpoint: &mut Endpoint) { if !self.started { endpoint @@ -126,6 +139,16 @@ impl Leaf for MerkleCallerLeaf { LEAF_MERKLE_CALLER } + #[cfg(feature = "interface")] + fn get_meta(&self) -> LeafMeta { + LeafMeta { + name: "Merke Caller Leaf", + identifier: "dev.unshell.test.merkle.caller", + version: "v0", + authors: vec!["ASTATIN3"], + } + } + fn update(&mut self, endpoint: &mut Endpoint) { self.receive_responses(endpoint); self.dispatch_next_request(endpoint); @@ -137,6 +160,16 @@ impl Leaf for MerkleRespondentLeaf { LEAF_MERKLE_RESPONDENT } + #[cfg(feature = "interface")] + fn get_meta(&self) -> LeafMeta { + LeafMeta { + name: "Merke Respondent Leaf", + identifier: "dev.unshell.test.merkle.respondent", + version: "v0", + authors: vec!["ASTATIN3"], + } + } + fn update(&mut self, endpoint: &mut Endpoint) { self.open_stream_from_request(endpoint); self.send_one_response_frame(endpoint); diff --git a/src/protocol/tests/oneshot/streams.rs b/src/protocol/tests/oneshot/streams.rs index b5d2180..ce3711d 100644 --- a/src/protocol/tests/oneshot/streams.rs +++ b/src/protocol/tests/oneshot/streams.rs @@ -1,5 +1,8 @@ use crate::protocol::{Endpoint, Leaf, Packet}; +#[cfg(feature = "interface")] +use crate::protocol::LeafMeta; + use alloc::{boxed::Box, format, vec, vec::Vec}; use super::support::{CommsLeaf, ENDPOINT_A, ENDPOINT_B, assert_hook_present, assert_hook_removed}; @@ -82,6 +85,16 @@ impl Leaf for StreamCallerLeaf { LEAF_STREAM_CALLER } + #[cfg(feature = "interface")] + fn get_meta(&self) -> LeafMeta { + LeafMeta { + name: "Stream Caller Leaf", + identifier: "dev.unshell.test.stream_caller_leaf", + version: "v0", + authors: vec!["ASTATIN3"], + } + } + fn update(&mut self, endpoint: &mut Endpoint) { if self.has_run { return; @@ -98,6 +111,16 @@ impl Leaf for StreamRespondentLeaf { LEAF_STREAM_RESPONDENT } + #[cfg(feature = "interface")] + fn get_meta(&self) -> LeafMeta { + LeafMeta { + name: "Stream Respondant Leaf", + identifier: "dev.unshell.test.stream_respondent_leaf", + version: "v0", + authors: vec!["ASTATIN3"], + } + } + fn update(&mut self, endpoint: &mut Endpoint) { self.open_stream_from_pending_request(endpoint); self.send_next_frame(endpoint); diff --git a/src/protocol/tests/oneshot/support.rs b/src/protocol/tests/oneshot/support.rs index 89fb069..2c1f19b 100644 --- a/src/protocol/tests/oneshot/support.rs +++ b/src/protocol/tests/oneshot/support.rs @@ -1,5 +1,8 @@ use crate::protocol::{Endpoint, Leaf, Packet}; +#[cfg(feature = "interface")] +use crate::protocol::LeafMeta; + use alloc::{vec, vec::Vec}; use crossbeam_channel::{Receiver, Sender}; @@ -112,6 +115,16 @@ impl Leaf for ControllerLeaf { LEAF_CONTROLLER } + #[cfg(feature = "interface")] + fn get_meta(&self) -> LeafMeta { + LeafMeta { + name: "Controller Leaf", + identifier: "dev.unshell.test.controller_leaf", + version: "v0", + authors: vec!["ASTATIN3"], + } + } + fn update(&mut self, endpoint: &mut Endpoint) { if !self.has_run { // The controller starts exactly one request so the end-to-end test can @@ -129,6 +142,16 @@ impl Leaf for CommsLeaf { LEAF_COMMS } + #[cfg(feature = "interface")] + fn get_meta(&self) -> LeafMeta { + LeafMeta { + name: "Comms Leaf", + identifier: "dev.unshell.test.comms_leaf", + version: "v0", + authors: vec!["ASTATIN3"], + } + } + fn update(&mut self, endpoint: &mut Endpoint) { if !self.started { endpoint @@ -160,6 +183,16 @@ impl Leaf for ResponderLeaf { LEAF_RESPONDER } + #[cfg(feature = "interface")] + fn get_meta(&self) -> LeafMeta { + LeafMeta { + name: "Responder Leaf", + identifier: "dev.unshell.test.responder_leaf", + version: "v0", + authors: vec!["ASTATIN3"], + } + } + fn update(&mut self, endpoint: &mut Endpoint) { let local_id = endpoint.path.last().cloned().unwrap_or(0); let mut packets = Vec::new();