diff --git a/Cargo.lock b/Cargo.lock index 8ca27a4..a4f6013 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,12 +22,6 @@ 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" @@ -124,15 +118,6 @@ 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" @@ -204,35 +189,12 @@ dependencies = [ "inout", ] -[[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 = "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" @@ -254,48 +216,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -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.2.1" @@ -305,71 +225,6 @@ dependencies = [ "hybrid-array", ] -[[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 = "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.11.2" @@ -381,54 +236,12 @@ dependencies = [ "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 = "downcast-rs" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys", -] - -[[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" @@ -441,12 +254,6 @@ 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 = "getrandom" version = "0.4.2" @@ -467,7 +274,7 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "foldhash 0.1.5", + "foldhash", ] [[package]] @@ -475,11 +282,6 @@ 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" @@ -544,12 +346,6 @@ 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" @@ -562,15 +358,6 @@ 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" @@ -581,28 +368,6 @@ 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" @@ -619,23 +384,6 @@ 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 = "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" @@ -648,27 +396,6 @@ 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" @@ -684,33 +411,12 @@ 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 = "memchr" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" -[[package]] -name = "mio" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys", -] - [[package]] name = "munge" version = "0.4.7" @@ -731,24 +437,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "nix" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" -dependencies = [ - "bitflags 2.11.1", - "cfg-if", - "cfg_aliases 0.1.1", - "libc", -] - -[[package]] -name = "num-conv" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" - [[package]] name = "num-traits" version = "0.2.19" @@ -758,15 +446,6 @@ 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" @@ -796,39 +475,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "portable-atomic" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" - -[[package]] -name = "portable-pty" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a596a2b3d2752d94f51fac2d4a96737b8705dddd311a32b9af47211f08671e" -dependencies = [ - "anyhow", - "bitflags 1.3.2", - "downcast-rs", - "filedescriptor", - "lazy_static", - "libc", - "log", - "nix", - "serial2", - "shared_library", - "shell-words", - "winapi", - "winreg", -] - -[[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" @@ -909,69 +555,6 @@ 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-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-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" @@ -1049,40 +632,12 @@ 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" @@ -1137,17 +692,6 @@ dependencies = [ "zmij", ] -[[package]] -name = "serial2" -version = "0.2.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdbc46aa3882ec3d48ec2b5abcb4f0d863a13d7599265f3faa6d851f23c12f3" -dependencies = [ - "cfg-if", - "libc", - "winapi", -] - [[package]] name = "sha2" version = "0.11.0" @@ -1159,59 +703,12 @@ dependencies = [ "digest", ] -[[package]] -name = "shared_library" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" -dependencies = [ - "lazy_static", - "libc", -] - -[[package]] -name = "shell-words" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" - [[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] - [[package]] name = "simdutf8" version = "0.1.5" @@ -1224,12 +721,6 @@ 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" @@ -1258,33 +749,6 @@ 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" @@ -1307,33 +771,13 @@ dependencies = [ "unicode-ident", ] -[[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 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", + "thiserror-impl", ] [[package]] @@ -1347,27 +791,6 @@ 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" @@ -1383,17 +806,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" -[[package]] -name = "treetest" -version = "0.1.0" -dependencies = [ - "crossbeam-channel", - "crossterm", - "ratatui", - "thiserror 2.0.18", - "unshell", -] - [[package]] name = "typenum" version = "1.20.0" @@ -1406,29 +818,6 @@ 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" @@ -1440,34 +829,10 @@ name = "unshell" version = "0.1.0" dependencies = [ "chrono", - "crossbeam-channel", "rkyv", "static_init", - "thiserror 2.0.18", - "unshell-leaves", - "unshell-macros", + "thiserror", "unshell-protocol", - "unshell-runtime", -] - -[[package]] -name = "unshell-leaves" -version = "0.1.0" -dependencies = [ - "crossbeam-channel", - "portable-pty", - "rkyv", - "unshell-macros", - "unshell-protocol", -] - -[[package]] -name = "unshell-macros" -version = "0.1.0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", ] [[package]] @@ -1475,14 +840,6 @@ name = "unshell-protocol" version = "0.1.0" dependencies = [ "rkyv", - "unshell-macros", -] - -[[package]] -name = "unshell-runtime" -version = "0.1.0" -dependencies = [ - "unshell-protocol", ] [[package]] @@ -1511,12 +868,6 @@ dependencies = [ "wasm-bindgen", ] -[[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" @@ -1695,24 +1046,6 @@ 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 = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - [[package]] name = "wit-bindgen" version = "0.51.0" diff --git a/Cargo.toml b/Cargo.toml index e6245df..a33bee8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,11 +4,11 @@ cargo-features = ["trim-paths", "panic-immediate-abort"] members = [ "ush-obfuscate", "base62", - "unshell-macros", + # "unshell-macros", "unshell-protocol", - "unshell-runtime", - "unshell-leaves", - "treetest", + # "unshell-runtime", + # "unshell-leaves", + # "treetest", ] resolver = "2" @@ -32,9 +32,9 @@ portable-pty = "0.9.0" crossbeam-channel = "0.5.15" unshell = { path = "." } unshell-protocol = { path = "./unshell-protocol" } -unshell-runtime = { path = "./unshell-runtime" } -unshell-leaves = { path = "./unshell-leaves" } -unshell-macros = { path = "./unshell-macros" } +# unshell-runtime = { path = "./unshell-runtime" } +# unshell-leaves = { path = "./unshell-leaves" } +# unshell-macros = { path = "./unshell-macros" } # ush-obfuscate = { path = "./ush-obfuscate" } # base62 = { path = "./base62" } @@ -51,8 +51,8 @@ log = [] log_debug = ["log", "dep:chrono"] # Leaf features -leaf_endpoint = ["unshell-leaves/leaf_endpoint"] -leaf_tui = ["unshell-leaves/leaf_tui"] +# leaf_endpoint = ["unshell-leaves/leaf_endpoint"] +# leaf_tui = ["unshell-leaves/leaf_tui"] # obfuscate_aes = ["ush-obfuscate/obfuscate_aes"] # obfuscate_ref = ["ush-obfuscate/obfuscate_ref"] @@ -63,64 +63,10 @@ thiserror = { workspace = true, optional = true } chrono = { workspace = true, optional = true } # ush-obfuscate = { workspace = true } static_init = { workspace = true } -unshell-macros = { workspace = true } +# unshell-macros = { workspace = true } unshell-protocol = { workspace = true } -unshell-runtime = { workspace = true } -unshell-leaves = { workspace = true } - -[dev-dependencies] -crossbeam-channel = { workspace = true } - -[[example]] -name = "leaf_derive" -path = "examples/protocol/leaf_derive.rs" - -[[example]] -name = "crossbeam_channel_leaf" -path = "examples/protocol/crossbeam_channel_leaf.rs" - -[[example]] -name = "runtime_leaf_actions" -path = "examples/protocol/runtime_leaf_actions.rs" - -[[example]] -name = "remote_shell_endpoint" -path = "examples/protocol/remote_shell_endpoint.rs" -required-features = ["leaf_endpoint"] - -[[example]] -name = "remote_shell_receive" -path = "examples/protocol/remote_shell_receive.rs" -required-features = ["leaf_endpoint"] - -[[example]] -name = "remote_shell_single_endpoint" -path = "examples/protocol/remote_shell_single_endpoint.rs" -required-features = ["leaf_endpoint"] - -[[example]] -name = "bench" -path = "examples/protocol/bench/bench.rs" - -[[example]] -name = "op_encode_call" -path = "examples/protocol/bench/op_encode_call.rs" - -[[example]] -name = "op_decode_call" -path = "examples/protocol/bench/op_decode_call.rs" - -[[example]] -name = "op_forward_call_receive" -path = "examples/protocol/bench/op_forward_call_receive.rs" - -[[example]] -name = "op_local_call_receive" -path = "examples/protocol/bench/op_local_call_receive.rs" - -[[example]] -name = "op_hook_data_receive" -path = "examples/protocol/bench/op_hook_data_receive.rs" +# unshell-runtime = { workspace = true } +# unshell-leaves = { workspace = true } [profile.minimize] inherits = "release" @@ -143,4 +89,4 @@ unsafe_op_in_unsafe_fn = "warn" unused_import_braces = "warn" unused_lifetimes = "warn" trivial_casts = "allow" -missing_docs = "warn" +# missing_docs = "warn" diff --git a/src/lib.rs b/src/lib.rs index 8554e0e..781d470 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,12 +24,12 @@ pub mod logger; pub use unshell_protocol as protocol; /// Re-export the leaf library crate behind the historical `unshell::leaves` path -pub use unshell_leaves as leaves; +// pub use unshell_leaves as leaves; /// Re-export the runtime crate behind the `unshell::runtime` path. -pub use unshell_runtime as runtime; +// pub use unshell_runtime as runtime; -pub use unshell_macros::{Procedure, leaf, procedures}; +// pub use unshell_macros::{Procedure, leaf, procedures}; /// Creates a root-assumed endpoint from one local identifier plus any number of leaf hosts. /// @@ -40,21 +40,21 @@ pub use unshell_macros::{Procedure, leaf, procedures}; /// Why it exists: the common bootstrap case should not require callers to manually construct an /// empty path, `Vec`, and a `Vec` when they already have leaf host values. /// -/// # Example -/// ```rust -/// use unshell::{create_endpoint, leaf}; -/// use unshell::protocol::tree::Endpoint; -/// -/// #[derive(Default)] -/// struct DemoLeaf; -/// -/// #[leaf(id = "org.example.v1.demo", procedures = ["ping"], endpoint_struct = DemoLeaf)] -/// struct Demo; -/// -/// let endpoint = create_endpoint!("demo", DemoLeaf::default()); -/// assert!(endpoint.path().is_empty()); -/// assert_eq!(endpoint.local_id(), Some("demo")); -/// ``` +// # Example +// ```rust +// use unshell::{create_endpoint, leaf}; +// use unshell::protocol::tree::Endpoint; + +// #[derive(Default)] +// struct DemoLeaf; + +// #[leaf(id = "org.example.v1.demo", procedures = ["ping"], endpoint_struct = DemoLeaf)] +// struct Demo; + +// let endpoint = create_endpoint!("demo", DemoLeaf::default()); +// assert!(endpoint.path().is_empty()); +// assert_eq!(endpoint.local_id(), Some("demo")); +// ``` #[macro_export] macro_rules! create_endpoint { ($id:expr $(, $leaf:expr )* $(,)?) => {{ diff --git a/unshell-protocol/Cargo.toml b/unshell-protocol/Cargo.toml index a357429..bd4d2fb 100644 --- a/unshell-protocol/Cargo.toml +++ b/unshell-protocol/Cargo.toml @@ -9,7 +9,7 @@ doctest = false [dependencies] rkyv = { workspace = true } -unshell-macros = { path = "../unshell-macros" } +# unshell-macros = { path = "../unshell-macros" } [lints.rust] elided_lifetimes_in_paths = "warn" @@ -22,4 +22,4 @@ unsafe_op_in_unsafe_fn = "warn" unused_import_braces = "warn" unused_lifetimes = "warn" trivial_casts = "allow" -missing_docs = "warn" +# missing_docs = "warn" diff --git a/unshell-protocol/src/lib.rs b/unshell-protocol/src/lib.rs index ebe2a98..0e46874 100644 --- a/unshell-protocol/src/lib.rs +++ b/unshell-protocol/src/lib.rs @@ -1,20 +1,6 @@ -//! # UnShell Protocol -//! -//! The protocol crate owns the wire types, framing, validation helpers, and the -//! small tree runtime used by endpoint implementations. - #![no_std] pub extern crate alloc; -#[allow(unused_extern_crates)] -extern crate self as unshell; -/// Keep the historical nested path so existing imports and proc-macro output can -/// continue to target `unshell::protocol::...` while the implementation lives in -/// its own crate. -pub mod protocol; - -pub use protocol::*; - -#[cfg(test)] -pub use unshell_macros::{Procedure, leaf, procedures}; +pub mod packet; +pub mod utils; diff --git a/unshell-protocol/src/packet/mod.rs b/unshell-protocol/src/packet/mod.rs new file mode 100644 index 0000000..6491b60 --- /dev/null +++ b/unshell-protocol/src/packet/mod.rs @@ -0,0 +1,167 @@ +#[cfg(test)] +mod tests; + +extern crate alloc; + +use alloc::string::String; +use alloc::vec::Vec; + +#[derive(Debug)] +pub struct Packet { + pub hook_id: u16, + pub is_upwards_call: bool, + pub end_hook: bool, + pub path: String, + // ── body (routers never read below this line) ── + pub procedure_id: String, + pub data: Vec, +} + +/// Returned by `deserialize_header` — only what a router needs. +/// `body_remainder` is a raw slice into the original buffer so the +/// entire body can be forwarded without touching it. +#[derive(Debug)] +pub struct HeaderRef<'buf> { + pub hook_id: u16, + pub is_upwards_call: bool, + pub end_hook: bool, + pub path: &'buf str, + pub body_remainder: &'buf [u8], +} + +#[derive(Debug)] +pub enum SerializeError { + PathTooLarge, + ProcIdTooLarge, + BodyTooLarge, +} + +#[derive(Debug, PartialEq)] +pub enum DeserializeError { + BufferTooShort, + BodyLengthMismatch, + PathTooLong, + ProcIdTooLong, + InvalidUtf8, +} + +impl Packet { + pub fn serialize(&self) -> Result, SerializeError> { + let path_bytes = self.path.as_bytes(); + let proc_id_bytes = self.procedure_id.as_bytes(); + + let path_len = u32::try_from(path_bytes.len()).map_err(|_| SerializeError::PathTooLarge)?; + let proc_id_len = + u32::try_from(proc_id_bytes.len()).map_err(|_| SerializeError::ProcIdTooLarge)?; + + // body = proc_id_len field + proc_id bytes + data bytes + let body_payload_len = 4usize + .checked_add(proc_id_bytes.len()) + .and_then(|n| n.checked_add(self.data.len())) + .ok_or(SerializeError::BodyTooLarge)?; + let body_len = u32::try_from(body_payload_len).map_err(|_| SerializeError::BodyTooLarge)?; + + let total = 8 + path_bytes.len() + 4 + body_payload_len; + let mut buf = Vec::with_capacity(total); + + // ── header ──────────────────────────────────────────────────────────── + let flags = (self.is_upwards_call as u8) | ((self.end_hook as u8) << 1); + buf.extend_from_slice(&self.hook_id.to_le_bytes()); + buf.push(flags); + buf.push(0u8); // padding + buf.extend_from_slice(&path_len.to_le_bytes()); + buf.extend_from_slice(path_bytes); + + // ── body ────────────────────────────────────────────────────────────── + buf.extend_from_slice(&body_len.to_le_bytes()); + buf.extend_from_slice(&proc_id_len.to_le_bytes()); + buf.extend_from_slice(proc_id_bytes); + buf.extend_from_slice(&self.data); + + Ok(buf) + } + + /// Deserialize only the header — O(path_len), body bytes are never read. + /// A router can inspect `HeaderRef` then forward the original buffer as-is. + pub fn deserialize_header(buf: &[u8]) -> Result, DeserializeError> { + // fixed prefix: hook_id (2) + flags (1) + padding (1) + path_len (4) + if buf.len() < 8 { + return Err(DeserializeError::BufferTooShort); + } + + let hook_id = u16::from_le_bytes([buf[0], buf[1]]); + let flags = buf[2]; + let is_upwards_call = flags & 0b0000_0001 != 0; + let end_hook = flags & 0b0000_0010 != 0; + let path_len = u32::from_le_bytes([buf[4], buf[5], buf[6], buf[7]]) as usize; + + let path_start = 8usize; + let path_end = path_start + .checked_add(path_len) + .ok_or(DeserializeError::PathTooLong)?; + + if buf.len() < path_end { + return Err(DeserializeError::BufferTooShort); + } + + let path = core::str::from_utf8(&buf[path_start..path_end]) + .map_err(|_| DeserializeError::InvalidUtf8)?; + + Ok(HeaderRef { + hook_id, + is_upwards_call, + end_hook, + path, + body_remainder: &buf[path_end..], + }) + } + + /// Full deserialization. Parses the header then the body. + pub fn deserialize(buf: &[u8]) -> Result { + let header = Self::deserialize_header(buf)?; + let body_buf = header.body_remainder; + + // body_len prefix + if body_buf.len() < 4 { + return Err(DeserializeError::BufferTooShort); + } + let body_len = + u32::from_le_bytes([body_buf[0], body_buf[1], body_buf[2], body_buf[3]]) as usize; + + let body_end = 4usize + .checked_add(body_len) + .ok_or(DeserializeError::BodyLengthMismatch)?; + if body_buf.len() < body_end { + return Err(DeserializeError::BodyLengthMismatch); + } + + // proc_id_len + proc_id + let inner = &body_buf[4..body_end]; + if inner.len() < 4 { + return Err(DeserializeError::BufferTooShort); + } + let proc_id_len = u32::from_le_bytes([inner[0], inner[1], inner[2], inner[3]]) as usize; + + let proc_id_start = 4usize; + let proc_id_end = proc_id_start + .checked_add(proc_id_len) + .ok_or(DeserializeError::ProcIdTooLong)?; + if inner.len() < proc_id_end { + return Err(DeserializeError::BufferTooShort); + } + + let procedure_id = core::str::from_utf8(&inner[proc_id_start..proc_id_end]) + .map_err(|_| DeserializeError::InvalidUtf8)?; + + let data = inner[proc_id_end..].to_vec(); + + Ok(Self { + hook_id: header.hook_id, + is_upwards_call: header.is_upwards_call, + end_hook: header.end_hook, + path: header.path.into(), + procedure_id: procedure_id.into(), + data, + }) + } +} diff --git a/unshell-protocol/src/packet/tests.rs b/unshell-protocol/src/packet/tests.rs new file mode 100644 index 0000000..fd4eb0d --- /dev/null +++ b/unshell-protocol/src/packet/tests.rs @@ -0,0 +1,264 @@ +use super::*; +use alloc::string::ToString; +use alloc::vec; + +// ── Helpers ─────────────────────────────────────────────────────────────── + +fn make_packet() -> Packet { + Packet { + hook_id: 42, + is_upwards_call: true, + end_hook: false, + path: "my/service/path".to_string(), + procedure_id: "my.service.Method".to_string(), + data: vec![0xDE, 0xAD, 0xBE, 0xEF], + } +} + +fn make_packet_flags(is_upwards_call: bool, end_hook: bool) -> Packet { + Packet { + is_upwards_call, + end_hook, + ..make_packet() + } +} + +// ── Round-trip ──────────────────────────────────────────────────────────── + +#[test] +fn full_round_trip() { + let packet = make_packet(); + let buf = packet.serialize().unwrap(); + let result = Packet::deserialize(&buf).unwrap(); + + assert_eq!(result.hook_id, packet.hook_id); + assert_eq!(result.is_upwards_call, packet.is_upwards_call); + assert_eq!(result.end_hook, packet.end_hook); + assert_eq!(result.path, packet.path); + assert_eq!(result.procedure_id, packet.procedure_id); + assert_eq!(result.data, packet.data); +} + +#[test] +fn header_round_trip() { + let packet = make_packet(); + let buf = packet.serialize().unwrap(); + let header = Packet::deserialize_header(&buf).unwrap(); + + assert_eq!(header.hook_id, packet.hook_id); + assert_eq!(header.is_upwards_call, packet.is_upwards_call); + assert_eq!(header.end_hook, packet.end_hook); + assert_eq!(header.path, packet.path); +} + +// ── Flags ───────────────────────────────────────────────────────────────── + +#[test] +fn flags_both_false() { + let packet = make_packet_flags(false, false); + let buf = packet.serialize().unwrap(); + let header = Packet::deserialize_header(&buf).unwrap(); + assert!(!header.is_upwards_call); + assert!(!header.end_hook); +} + +#[test] +fn flags_both_true() { + let packet = make_packet_flags(true, true); + let buf = packet.serialize().unwrap(); + let header = Packet::deserialize_header(&buf).unwrap(); + assert!(header.is_upwards_call); + assert!(header.end_hook); +} + +#[test] +fn flags_upwards_only() { + let packet = make_packet_flags(true, false); + let buf = packet.serialize().unwrap(); + let header = Packet::deserialize_header(&buf).unwrap(); + assert!(header.is_upwards_call); + assert!(!header.end_hook); +} + +#[test] +fn flags_end_hook_only() { + let packet = make_packet_flags(false, true); + let buf = packet.serialize().unwrap(); + let header = Packet::deserialize_header(&buf).unwrap(); + assert!(!header.is_upwards_call); + assert!(header.end_hook); +} + +// ── Empty fields ────────────────────────────────────────────────────────── + +#[test] +fn empty_path() { + let packet = Packet { + path: "".to_string(), + ..make_packet() + }; + let buf = packet.serialize().unwrap(); + let header = Packet::deserialize_header(&buf).unwrap(); + assert_eq!(header.path, ""); +} + +#[test] +fn empty_procedure_id() { + let packet = Packet { + procedure_id: "".to_string(), + ..make_packet() + }; + let buf = packet.serialize().unwrap(); + let result = Packet::deserialize(&buf).unwrap(); + assert_eq!(result.procedure_id, ""); +} + +#[test] +fn empty_data() { + let packet = Packet { + data: vec![], + ..make_packet() + }; + let buf = packet.serialize().unwrap(); + let result = Packet::deserialize(&buf).unwrap(); + assert_eq!(result.data, &[] as &[u8]); +} + +#[test] +fn all_fields_empty() { + let packet = Packet { + hook_id: 0, + is_upwards_call: false, + end_hook: false, + path: "".to_string(), + procedure_id: "".to_string(), + data: vec![], + }; + let buf = packet.serialize().unwrap(); + let result = Packet::deserialize(&buf).unwrap(); + assert_eq!(result.hook_id, 0); + assert_eq!(result.path, ""); + assert_eq!(result.procedure_id, ""); + assert_eq!(result.data, &[] as &[u8]); +} + +// ── Zero-copy: borrows point into the original buffer ───────────────────── + +#[test] +fn header_path_is_borrowed_from_buffer() { + let buf = make_packet().serialize().unwrap(); + let header = Packet::deserialize_header(&buf).unwrap(); + + let path_ptr = header.path.as_ptr(); + let buf_range = buf.as_ptr_range(); + assert!( + buf_range.contains(&path_ptr), + "path must be a subslice of the input buffer, not a new allocation" + ); +} + +#[test] +fn body_remainder_is_borrowed_from_buffer() { + let buf = make_packet().serialize().unwrap(); + let header = Packet::deserialize_header(&buf).unwrap(); + + let remainder_ptr = header.body_remainder.as_ptr(); + let buf_range = buf.as_ptr_range(); + assert!( + buf_range.contains(&remainder_ptr), + "body_remainder must point into the input buffer" + ); +} + +// ── Partial deserialization: body is untouched by header parse ──────────── + +#[test] +fn deserialize_header_does_not_read_body() { + let buf = make_packet().serialize().unwrap(); + let header = Packet::deserialize_header(&buf).unwrap(); + + // Re-parse body from the remainder to confirm it's intact. + let body_buf = header.body_remainder; + let body_len = + u32::from_le_bytes([body_buf[0], body_buf[1], body_buf[2], body_buf[3]]) as usize; + assert!( + body_buf.len() >= 4 + body_len, + "body_remainder must contain the full body" + ); +} + +#[test] +fn can_forward_buffer_after_header_parse() { + // Simulates a router: parse the header, then forward the raw buffer + // without touching the body. + let original = make_packet().serialize().unwrap(); + let header = Packet::deserialize_header(&original).unwrap(); + + assert_eq!(header.path, "my/service/path"); + + // "Forward" by deserializing the full original buffer downstream. + let forwarded = Packet::deserialize(&original).unwrap(); + assert_eq!(forwarded.procedure_id, "my.service.Method"); + assert_eq!(forwarded.data, &[0xDE, 0xAD, 0xBE, 0xEF]); +} + +// ── Truncation / corruption ─────────────────────────────────────────────── + +#[test] +fn truncated_in_fixed_prefix() { + let buf = make_packet().serialize().unwrap(); + // Cut inside the fixed 8-byte prefix. + assert_eq!( + Packet::deserialize_header(&buf[..4]).unwrap_err(), + DeserializeError::BufferTooShort + ); +} + +#[test] +fn truncated_in_path() { + let buf = make_packet().serialize().unwrap(); + // Cut to just past the fixed prefix, mid-path. + assert_eq!( + Packet::deserialize_header(&buf[..9]).unwrap_err(), + DeserializeError::BufferTooShort + ); +} + +#[test] +fn truncated_in_body() { + let buf = make_packet().serialize().unwrap(); + // Remove last byte — well into the body. + assert!(Packet::deserialize(&buf[..buf.len() - 1]).is_err()); +} + +#[test] +fn empty_buffer_rejected() { + assert_eq!( + Packet::deserialize_header(&[]).unwrap_err(), + DeserializeError::BufferTooShort + ); +} + +#[test] +fn invalid_utf8_in_path() { + let mut buf = make_packet().serialize().unwrap(); + // Overwrite the first byte of the path (offset 8) with an invalid UTF-8 byte. + buf[8] = 0xFF; + assert_eq!( + Packet::deserialize_header(&buf).unwrap_err(), + DeserializeError::InvalidUtf8 + ); +} + +#[test] +fn invalid_utf8_in_procedure_id() { + let mut buf = make_packet().serialize().unwrap(); + // Find where procedure_id starts: 8 + path_len + 4 (body_len) + 4 (proc_id_len) + let path_len = u32::from_le_bytes([buf[4], buf[5], buf[6], buf[7]]) as usize; + let proc_id_offset = 8 + path_len + 4 + 4; + buf[proc_id_offset] = 0xFF; + assert_eq!( + Packet::deserialize(&buf).unwrap_err(), + DeserializeError::InvalidUtf8 + ); +} diff --git a/unshell-protocol/src/utils.rs b/unshell-protocol/src/utils.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/unshell-protocol/src/utils.rs @@ -0,0 +1 @@ +