diff --git a/Cargo.lock b/Cargo.lock index 1a49c1554fa..71bdd8c6072 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" dependencies = [ "memchr", ] @@ -22,9 +22,9 @@ dependencies = [ [[package]] name = "android_system_properties" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" dependencies = [ "libc", ] @@ -43,9 +43,9 @@ checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "argh" @@ -66,7 +66,7 @@ dependencies = [ "argh_shared", "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -77,15 +77,15 @@ checksum = "e5ade012bac4db278517a0132c8c10c6427025868dca16c801087c28d5a411f1" [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "cast" @@ -95,9 +95,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.58" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" +checksum = "86e055fa6e3e40ad6187ba25b6855eeb635d5271f8e0f0e1e9a5826b8d75bea0" dependencies = [ "find-msvc-tools", "jobserver", @@ -107,15 +107,15 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "iana-time-zone", "js-sys", @@ -153,18 +153,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.0" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.6.0" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ "anstyle", "clap_lex", @@ -172,9 +172,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" [[package]] name = "core-foundation-sys" @@ -219,9 +219,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -229,18 +229,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "crunchy" @@ -263,26 +263,49 @@ dependencies = [ [[package]] name = "either" -version = "1.15.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" [[package]] name = "find-msvc-tools" -version = "0.1.9" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48" + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] [[package]] name = "getrandom" -version = "0.3.4" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", "libc", "r-efi", - "wasip2", ] [[package]] @@ -322,9 +345,9 @@ dependencies = [ [[package]] name = "indoc" -version = "2.0.7" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +checksum = "a37b2691796cffeb8a8cd305ac66e65841559f147f4e63231d0eafa4db5384d1" dependencies = [ "rustversion", ] @@ -346,9 +369,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ "getrandom", "libc", @@ -356,25 +379,26 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.91" +version = "0.3.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5" dependencies = [ - "once_cell", + "cfg-if", + "futures-util", "wasm-bindgen", ] [[package]] name = "libc" -version = "0.2.183" +version = "0.2.191" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" [[package]] name = "log" -version = "0.4.29" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] name = "lsh" @@ -386,9 +410,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "num-traits" @@ -427,11 +451,17 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" [[package]] name = "plotters" @@ -463,33 +493,33 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.45" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" -version = "5.3.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rayon" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" dependencies = [ "either", "rayon-core", @@ -507,9 +537,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -519,9 +549,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ "aho-corasick", "memchr", @@ -530,24 +560,24 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "roxmltree" -version = "0.21.1" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1964b10c76125c36f8afe190065a4bf9a87bf324842c05701330bba9f1cacbb" +checksum = "9da7f59328b09405b181fee1018925fad50f157afb43c0c0f5c522c256dd5907" dependencies = [ "memchr", ] [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "same-file" @@ -560,9 +590,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -570,29 +600,29 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", ] [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ "itoa", "memchr", @@ -603,21 +633,38 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.1" +version = "1.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d5d4b1981b8bbbb7aed204cae5726d683d5d6ac7e74ec54122ea28f315e7c8" + +[[package]] +name = "syn" +version = "2.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] [[package]] name = "syn" -version = "2.0.117" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -636,9 +683,9 @@ dependencies = [ [[package]] name = "toml-span" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f22ba417d437b5fa5dcba6c27dbd6c14f38845315b724d89fed73b7a426451b7" +checksum = "ac7807845e399906fbe4e7f57369d284d5bf102836423073290b7c01948dbda3" dependencies = [ "smallvec", ] @@ -657,9 +704,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "version_check" @@ -677,20 +724,11 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "wasip2" -version = "1.0.2+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" -dependencies = [ - "wit-bindgen", -] - [[package]] name = "wasm-bindgen" -version = "0.2.114" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409" dependencies = [ "cfg-if", "once_cell", @@ -701,9 +739,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.114" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -711,31 +749,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.114" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 3.0.9", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.114" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.91" +version = "0.3.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +checksum = "88261b9deccee56594c11a3460c462c41f58d148598fe70ad77070126a68aba4" dependencies = [ "js-sys", "wasm-bindgen", @@ -793,7 +831,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -804,7 +842,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -842,68 +880,62 @@ dependencies = [ [[package]] name = "winresource" -version = "0.1.31" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0986a8b1d586b7d3e4fe3d9ea39fb451ae22869dcea4aa109d287a374d866087" +checksum = "a2bc6d36480b829272a5bdabf08e6dca8004761c1da7e35efef800540c66221b" dependencies = [ "version_check", ] -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" - [[package]] name = "zerocopy" -version = "0.8.47" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87" +checksum = "e5fe1f8f1b06191a00962174c61aa5005e0bb391a6d80d07e24d115c01a92ed8" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.47" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89" +checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" [[package]] name = "zstd" -version = "0.13.3" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +checksum = "db3ae9bf90af6e40197bef767eeefc46ad6397420fe873830bd85e5fbbfb3c70" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.2.4" +version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +checksum = "ded520f16b29e1a9b771c722221b2b0a0398c2316d9bb3c42b458a5414d7434b" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.16+zstd.1.5.7" +version = "2.1.2+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +checksum = "481ada9c543b2323cbb7bbdbb5249177fbf0188ed959ed2c15e4b22421c84ed3" dependencies = [ "cc", "pkg-config", diff --git a/crates/edit/Cargo.toml b/crates/edit/Cargo.toml index ffbdf347ed1..72f34e08131 100644 --- a/crates/edit/Cargo.toml +++ b/crates/edit/Cargo.toml @@ -51,4 +51,4 @@ features = [ [dev-dependencies] criterion = { version = "0.8", features = ["html_reports"] } -zstd = { version = "0.13", default-features = false } +zstd = { version = "0.14", default-features = false } diff --git a/crates/edit/src/bin/edit/main.rs b/crates/edit/src/bin/edit/main.rs index c1128c5b571..c3548176944 100644 --- a/crates/edit/src/bin/edit/main.rs +++ b/crates/edit/src/bin/edit/main.rs @@ -85,13 +85,13 @@ fn run() -> apperr::Result<()> { let mut vt_parser = vt::Parser::new(); let mut input_parser = input::Parser::new(); let mut tui = Tui::new()?; - tui.set_size(sys::get_window_size()?); // Switch the terminal to raw mode which prevents the user from pressing Ctrl+C. // `handle_args` may want to print a help message (must not fail), // and reads files (may hang; should be cancelable with Ctrl+C). // As such, we call this after `handle_args`. - sys::switch_modes()?; + let initial_size = sys::switch_modes()?; + tui.set_size(initial_size); let _restore = setup_terminal(&mut tui, &mut state, &mut vt_parser); diff --git a/crates/edit/src/sys/unix.rs b/crates/edit/src/sys/unix.rs index dccc56ee73e..9a3e7a1e23c 100644 --- a/crates/edit/src/sys/unix.rs +++ b/crates/edit/src/sys/unix.rs @@ -6,16 +6,19 @@ //! Read the `windows` module for reference. //! TODO: This reminds me that the sys API should probably be a trait. +// TODO: Get rid of that `State` global. +#![allow(static_mut_refs)] + use std::ffi::{c_char, c_int, c_void}; use std::fs::File; -use std::mem::{self, ManuallyDrop, MaybeUninit}; +use std::mem::{self, MaybeUninit}; use std::os::fd::FromRawFd as _; use std::os::unix::fs::MetadataExt as _; use std::path::Path; use std::ptr::{self, NonNull, null_mut}; use std::{io, time}; -use crate::arena::Arena; +use crate::arena::{Arena, scratch_arena}; use crate::collections::{BString, BVec}; use crate::helpers::*; @@ -38,7 +41,7 @@ pub unsafe fn virtual_reserve(size: usize) -> io::Result> { 0, ); if ptr.is_null() || ptr::eq(ptr, libc::MAP_FAILED) { - Err(io::Error::last_os_error()) + Err(last_os_error()) } else { Ok(NonNull::new_unchecked(ptr.cast())) } @@ -82,7 +85,7 @@ pub unsafe fn virtual_release(base: NonNull, size: usize) { pub unsafe fn virtual_commit(base: NonNull, size: usize) -> io::Result<()> { unsafe { let status = libc::mprotect(base.cast().as_ptr(), size, libc::PROT_READ | libc::PROT_WRITE); - if status != 0 { Err(io::Error::last_os_error()) } else { Ok(()) } + if status != 0 { Err(last_os_error()) } else { Ok(()) } } } @@ -90,7 +93,7 @@ struct State { stdin: libc::c_int, stdin_flags: libc::c_int, stdout_initial_termios: Option, - resize_pending: bool, + sigwinch: Pipe, // Buffer for incomplete UTF-8 sequences (max 4 bytes needed) utf8_buf: [u8; 4], utf8_len: usize, @@ -100,25 +103,35 @@ static mut STATE: State = State { stdin: libc::STDIN_FILENO, stdin_flags: -1, stdout_initial_termios: None, - resize_pending: false, + sigwinch: Pipe::default(), utf8_buf: [0; 4], utf8_len: 0, }; +/// We use a self-pipe trick to handle SIGWINCH + stdin polling. +/// +/// There are technically superior alternatives on Linux with epoll+signalfd and BSDs with kqueue. +/// I ran tests on Linux and epoll+signalfd improves startup CPU 1.03us -> 0.96us and memory use +/// 2.38KiB (+4KiB once a signal was delivered) -> 1.05KiB. CPU usage per delivery 7us -> 5us. +/// +/// This is certainly nice, but way way way too little difference relative to the sum of all +/// other operations in this editor. It is worth considering if we ever need our own mio/tokio. +/// (On that note, it is worth avoiding tokio, due to lack of support for rare platforms such as UEFI.) extern "C" fn sigwinch_handler(_: libc::c_int) { unsafe { - STATE.resize_pending = true; + let saved_errno = errno(); + let fd = STATE.sigwinch.writer; + + if fd >= 0 { + let b = 0u8; + while libc::write(fd, (&raw const b).cast(), 1) < 0 && errno() == libc::EINTR {} + } + + set_errno(saved_errno); } } pub fn init() -> io::Result { - unsafe { - // Set STATE.resize_pending to true whenever we get a SIGWINCH. - let mut sigwinch_action: libc::sigaction = mem::zeroed(); - sigwinch_action.sa_sigaction = sigwinch_handler as *const () as libc::sighandler_t; - check_int_return(libc::sigaction(libc::SIGWINCH, &sigwinch_action, null_mut()))?; - } - Ok(Deinit) } @@ -126,7 +139,7 @@ pub fn init() -> io::Result { pub fn reopen_stdin_if_redirected() -> io::Result> { unsafe { if libc::isatty(STATE.stdin) == 0 { - STATE.stdin = check_int_return(libc::open(c"/dev/tty".as_ptr(), libc::O_RDONLY))?; + STATE.stdin = libc::open(c"/dev/tty".as_ptr(), libc::O_RDONLY).check()?; Ok(Some(File::from_raw_fd(libc::STDIN_FILENO))) } else { Ok(None) @@ -134,14 +147,11 @@ pub fn reopen_stdin_if_redirected() -> io::Result> { } } -pub fn switch_modes() -> io::Result<()> { +pub fn switch_modes() -> io::Result { unsafe { - // Store the stdin flags so we can more easily toggle `O_NONBLOCK` later on. - STATE.stdin_flags = check_int_return(libc::fcntl(STATE.stdin, libc::F_GETFL))?; - // Get the original terminal modes so we can disable raw mode on exit. let mut termios = MaybeUninit::::uninit(); - check_int_return(libc::tcgetattr(libc::STDOUT_FILENO, termios.as_mut_ptr()))?; + libc::tcgetattr(libc::STDOUT_FILENO, termios.as_mut_ptr()).check()?; let mut termios = termios.assume_init(); STATE.stdout_initial_termios = Some(termios); @@ -201,7 +211,24 @@ pub fn switch_modes() -> io::Result<()> { termios.c_cc[libc::VMIN] = 1; termios.c_cc[libc::VTIME] = 0; - termios_setattr(libc::STDOUT_FILENO, &termios) + termios_setattr(libc::STDOUT_FILENO, &termios)?; + + // Set up the SIGWINCH self-pipe... + STATE.sigwinch = Pipe::new(libc::O_CLOEXEC | libc::O_NONBLOCK)?; + + // ...and the SIGWINCH handler. + let mut sigwinch_action: libc::sigaction = mem::zeroed(); + sigwinch_action.sa_sigaction = sigwinch_handler as *const () as libc::sighandler_t; + libc::sigemptyset(&mut sigwinch_action.sa_mask); + libc::sigaction(libc::SIGWINCH, &sigwinch_action, null_mut()).check()?; + + // Since we'll use poll(), stdin must be non-blocking. + STATE.stdin_flags = libc::fcntl(STATE.stdin, libc::F_GETFL).check()?; + libc::fcntl(STATE.stdin, libc::F_SETFL, STATE.stdin_flags | libc::O_NONBLOCK).check()?; + + // NOTE: It's crucial to get the initial window size AFTER + // setting up the signal handler to avoid missing an update. + get_window_size() } } @@ -235,7 +262,7 @@ impl Drop for Deinit { } } -pub fn get_window_size() -> io::Result { +fn get_window_size() -> io::Result { let mut winsz: libc::winsize = unsafe { mem::zeroed() }; let ret = unsafe { libc::ioctl(libc::STDOUT_FILENO, libc::TIOCGWINSZ, &raw mut winsz) }; if ret != 0 { @@ -257,12 +284,15 @@ pub fn read_stdin( mut timeout: time::Duration, ) -> Option<(Option, BString<'_>)> { unsafe { - if STATE.resize_pending { - timeout = time::Duration::ZERO; - } - - let read_poll = timeout != time::Duration::MAX; + let deadline = (timeout != time::Duration::MAX) + .then_some(timeout) + .and_then(|t| time::Instant::now().checked_add(t)); + let mut resized = false; let mut buf = BVec::empty(); + let mut fds = [ + libc::pollfd { fd: STATE.sigwinch.reader, events: libc::POLLIN, revents: 0 }, + libc::pollfd { fd: STATE.stdin, events: libc::POLLIN, revents: 0 }, + ]; // We don't know if the input is valid UTF8, so we first use a Vec and then // later turn it into UTF8 using `from_utf8_lossy_owned`. @@ -277,53 +307,114 @@ pub fn read_stdin( } loop { - if timeout != time::Duration::MAX { - let beg = time::Instant::now(); - - let mut pollfd = libc::pollfd { fd: STATE.stdin, events: libc::POLLIN, revents: 0 }; - let ret; - #[cfg(target_os = "linux")] - { - let ts = libc::timespec { - tv_sec: timeout.as_secs() as libc::time_t, + // Wait for stdin or SIGWINCH. + cfg_select! { + any( + target_os = "linux", // tier 1 + target_os = "android", // tier 2 + target_os = "freebsd", // tier 2 + target_os = "fuchsia", // tier 2 + target_os = "netbsd", // tier 2 + target_os = "cygwin", // tier 3 + target_os = "dragonfly", // tier 3 + target_os = "haiku", // tier 3 + target_os = "hurd", // tier 3 + target_os = "l4re", // tier 3 + target_os = "openbsd", // tier 3 + ) => { + let t = timeout.as_secs().try_into().ok().map(|tv_sec| libc::timespec { + tv_sec, tv_nsec: timeout.subsec_nanos() as libc::c_long, - }; - ret = libc::ppoll(&mut pollfd, 1, &ts, std::ptr::null()); - } - #[cfg(not(target_os = "linux"))] - { - ret = libc::poll(&mut pollfd, 1, timeout.as_millis() as libc::c_int); + }); + let ret = + libc::ppoll(fds.as_mut_ptr(), 2, opt_ptr(t.as_ref()), std::ptr::null()); } - if ret < 0 { - return None; // Error? Let's assume it's an EOF. + _ => { + let t = timeout.as_millis().try_into().unwrap_or(-1); + let ret = libc::poll(fds.as_mut_ptr(), 2, t); } - if ret == 0 { - break; // Timeout? We can stop reading. + } + + if ret == 0 { + break; // Timeout? We can stop reading. + } else if ret > 0 { + // Drain SIGWINCH events from the self-pipe. + if fds[0].revents & libc::POLLIN != 0 { + let scratch = scratch_arena(Some(arena)); + let buf = scratch.alloc_uninit_array::<256, u8>(); + + loop { + let ret = + libc::read(STATE.sigwinch.reader, buf.as_mut_ptr().cast(), buf.len()); + if ret > 0 { + resized = true; + } else if ret == 0 { + return None; // Unexpected error + } else { + #[allow( + unreachable_patterns, + reason = "On some platforms EAGAIN == EWOULDBLOCK" + )] + match errno() { + libc::EAGAIN | libc::EWOULDBLOCK => break, // finished draining the pipe + libc::EINTR => {} + _ => return None, // Unexpected error + } + } + } } - timeout = timeout.saturating_sub(beg.elapsed()); - }; + // Read from stdin if available. + if fds[1].revents & libc::POLLIN != 0 { + let spare = buf.spare_capacity_mut(); + let ret = libc::read(STATE.stdin, spare.as_mut_ptr().cast(), spare.len()); + if ret > 0 { + buf.set_len(buf.len() + ret as usize); + } else if ret == 0 { + return None; // EOF + } else { + #[allow( + unreachable_patterns, + reason = "On some platforms EAGAIN == EWOULDBLOCK" + )] + if !matches!(errno(), libc::EINTR | libc::EAGAIN | libc::EWOULDBLOCK) { + return None; // Unexpected error + } + } + } + } else { + // poll() can fail with EAGAIN if the kernel was OOM and we can retry. + // Linux returns ENOMEM, but I'm not sure if one is expected to retry that. + if !matches!(errno(), libc::EINTR | libc::EAGAIN) { + return None; // Unexpected error + } + } - // If we're asked for a non-blocking read we need - // to manipulate `O_NONBLOCK` and vice versa. - set_tty_nonblocking(read_poll); + // We got something? Great! + if resized || !buf.is_empty() { + break; + } - // Read from stdin. - let spare = buf.spare_capacity_mut(); - let ret = libc::read(STATE.stdin, spare.as_mut_ptr().cast(), spare.len()); + // Check for broken pipe events, etc. + // We do this after draining stdin to avoid missing out on trailing, buffered inputs + // after the TTY got closed. Technically we don't need to do that, reading that input + // should not be meaningful. But this is technically the right way to do it. if ret > 0 { - buf.set_len(buf.len() + ret as usize); - break; + for fd in &fds { + if fd.revents & (libc::POLLERR | libc::POLLHUP | libc::POLLNVAL) != 0 { + return None; // Unexpected error + } + } } - if ret == 0 { - return None; // EOF + + // Recalculate the remaining timeout if we need to retry. + if timeout.is_zero() { + break; } - if ret < 0 { - match errno() { - libc::EINTR if STATE.resize_pending => break, - libc::EAGAIN if timeout == time::Duration::ZERO => break, - libc::EINTR | libc::EAGAIN => {} - _ => return None, + if let Some(deadline) = deadline { + timeout = deadline.saturating_duration_since(time::Instant::now()); + if timeout.is_zero() { + break; } } } @@ -357,12 +448,7 @@ pub fn read_stdin( } } - let resize = if STATE.resize_pending { - STATE.resize_pending = false; - Some(get_window_size().ok()?) - } else { - None - }; + let resize = if resized { get_window_size().ok() } else { None }; Some((resize, BString::from_utf8_lossy(arena, buf))) } @@ -409,20 +495,6 @@ pub fn write_stdout(text: &str) { } } -/// Sets/Resets `O_NONBLOCK` on the TTY handle. -/// -/// Note that setting this flag applies to both stdin and stdout, because the -/// TTY is a bidirectional device and both handles refer to the same thing. -fn set_tty_nonblocking(nonblock: bool) { - unsafe { - let is_nonblock = (STATE.stdin_flags & libc::O_NONBLOCK) != 0; - if is_nonblock != nonblock { - STATE.stdin_flags ^= libc::O_NONBLOCK; - let _ = libc::fcntl(STATE.stdin, libc::F_SETFL, STATE.stdin_flags); - } - } -} - #[derive(Clone, PartialEq, Eq)] pub struct FileId { dev: u64, @@ -617,7 +689,7 @@ pub fn preferred_languages(arena: &Arena) -> BVec<'_, &'_ str> { pub fn memfd() -> io::Result { #[cfg(target_os = "linux")] unsafe { - let fd = check_int_return(libc::memfd_create(c"edit".as_ptr(), libc::MFD_CLOEXEC))?; + let fd = libc::memfd_create(c"edit".as_ptr(), libc::MFD_CLOEXEC).check()?; Ok(File::from_raw_fd(fd)) } #[cfg(not(target_os = "linux"))] @@ -628,9 +700,10 @@ pub fn memfd() -> io::Result { } // Duplicate the descriptor so that closing the C stream doesn't close our file. - let file = check_int_return(libc::fcntl(libc::fileno(stream), libc::F_DUPFD_CLOEXEC, 0)) + let file = libc::fcntl(libc::fileno(stream), libc::F_DUPFD_CLOEXEC, 0) + .check() .map(|fd| File::from_raw_fd(fd)); - let close = check_int_return(libc::fclose(stream)); + let close = libc::fclose(stream).check(); let file = file?; close?; @@ -638,16 +711,115 @@ pub fn memfd() -> io::Result { } } -#[inline] -#[cold] +/// Represents a classic unidirectional pipe. +#[repr(C)] +struct Pipe { + reader: c_int, + writer: c_int, +} + +impl Pipe { + #[inline(always)] + const fn default() -> Self { + Self { reader: -1, writer: -1 } + } + + fn new(flags: c_int) -> io::Result { + let mut fds = [-1, -1]; + + // Ironically, this is 1000% unneeded, because glibc, musl, etc., have shims for pipe2, + // *but as always*, the required extern_weak marker is an unstable feature. SINCE 2015. + // This repeated target-flaggery is a waste of everybody's time. + cfg_select! { + any( + target_os = "linux", // tier 1 + target_os = "android", // tier 2 + target_os = "emscripten", // tier 2 + target_os = "freebsd", // tier 2 + target_os = "fuchsia", // tier 2 + target_os = "netbsd", // tier 2 + target_os = "redox", // tier 2 + target_os = "solaris", // tier 2 + target_os = "cygwin", // tier 3 + target_os = "dragonfly", // tier 3 + target_os = "hurd", // tier 3 + target_os = "illumos", // tier 3 + target_os = "l4re", // tier 3 + target_os = "openbsd", // tier 3 + target_env = "newlib" // varies by target_os + ) => unsafe { + libc::pipe2(fds.as_mut_ptr(), flags).check()?; + }, + _ => unsafe { + libc::pipe(fds.as_mut_ptr()).check()?; + for fd in fds { + if flags & libc::O_CLOEXEC != 0 { + libc::fcntl(fd, libc::F_SETFD, libc::FD_CLOEXEC).check()?; + } + if flags & libc::O_NONBLOCK != 0 { + libc::fcntl(fd, libc::F_SETFL, libc::O_NONBLOCK).check()?; + } + } + }, + } + + Ok(Self { reader: fds[0], writer: fds[1] }) + } +} + +// "NIH syndrome can't be that bad." UNIX bros: +#[inline(always)] +fn errno_location() -> *mut c_int { + unsafe { + cfg_select! { + any( + target_os = "linux", // tier 1 + target_os = "emscripten", // tier 2 + target_os = "fuchsia", // tier 2 + target_os = "redox", // tier 2 + target_os = "dragonfly", // tier 3 + target_os = "hurd", // tier 3 + target_os = "l4re", // tier 3 + ) => libc::__errno_location(), + any( + target_os = "android", // tier 2 + target_os = "netbsd", // tier 2 + target_os = "cygwin", // tier 3 + target_os = "nuttx", // tier 3 + target_os = "openbsd", // tier 3 + target_env = "newlib", // varies by target_os + ) => libc::__errno(), + any( + target_os = "solaris", // tier 2 + target_os = "illumos", // tier 2 + ) => libc::___errno(), + any( + target_vendor = "apple", // tier 1 + target_os = "freebsd", // tier 2 + ) => libc::__error(), + any( + target_os = "haiku", // tier 3 + ) => libc::_errnop(), + any( + target_os = "aix", // tier 3 + ) => libc::_Errno(), + any( + target_os = "nto", // tier 3 + target_os = "qnx", // tier 3 + ) => libc::__get_errno_ptr(), + _ => compile_error!("unsupported platform"), + } + } +} + +#[inline(always)] fn errno() -> c_int { - // libc unfortunately doesn't export an alias for `errno` (WHY?). - // As such we (ab)use the stdlib and use its internal errno implementation. - // - // Under `-O -Copt-level=s` the 1.87 compiler fails to fully inline and - // remove the raw_os_error() call. This leaves us with the drop() call. - // ManuallyDrop fixes that and results in a direct `std::sys::os::errno` call. - ManuallyDrop::new(io::Error::last_os_error()).raw_os_error().unwrap_or(0) + unsafe { *errno_location() } +} + +#[inline(always)] +pub fn set_errno(e: c_int) { + unsafe { *errno_location() = e } } #[inline] @@ -662,6 +834,12 @@ fn from_raw_os_error(code: c_int) -> io::Error { io::Error::from_raw_os_error(code) } -fn check_int_return(ret: libc::c_int) -> io::Result { - if ret < 0 { Err(last_os_error()) } else { Ok(ret) } +trait CheckIntReturn { + fn check(self) -> io::Result; +} + +impl CheckIntReturn for c_int { + fn check(self) -> io::Result { + if self < 0 { Err(last_os_error()) } else { Ok(self) } + } } diff --git a/crates/edit/src/sys/windows.rs b/crates/edit/src/sys/windows.rs index 81ec12087eb..73c34079b36 100644 --- a/crates/edit/src/sys/windows.rs +++ b/crates/edit/src/sys/windows.rs @@ -195,7 +195,7 @@ pub fn reopen_stdin_if_redirected() -> io::Result> { } /// Switches the terminal into raw mode, etc. -pub fn switch_modes() -> io::Result<()> { +pub fn switch_modes() -> io::Result { unsafe { // `kernel32.dll` doesn't exist on OneCore variants of Windows. // NOTE: `kernelbase.dll` is NOT a stable API to rely on. In our case it's the best option though. @@ -253,7 +253,7 @@ pub fn switch_modes() -> io::Result<()> { check_bool_return(Console::SetConsoleCP(Globalization::CP_UTF8))?; check_bool_return(Console::SetConsoleOutputCP(Globalization::CP_UTF8))?; - Ok(()) + get_window_size() } } @@ -282,7 +282,7 @@ impl Drop for Deinit { } } -pub fn get_window_size() -> io::Result { +fn get_window_size() -> io::Result { unsafe { let mut info: Console::CONSOLE_SCREEN_BUFFER_INFOEX = mem::zeroed(); info.cbSize = mem::size_of::() as u32;