diff --git a/frameworks/Rust/nano-web/Cargo.lock b/frameworks/Rust/nano-web/Cargo.lock new file mode 100644 index 00000000000..3c161e4de62 --- /dev/null +++ b/frameworks/Rust/nano-web/Cargo.lock @@ -0,0 +1,3720 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.3", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +dependencies = [ + "windows-sys 0.60.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.60.2", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "async-compression" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a89bce6054c720275ac2432fbba080a66a2106a44a1b804553930ca6909f4e0" +dependencies = [ + "compression-codecs", + "compression-core", + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "automod" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebb4bd301db2e2ca1f5be131c24eb8ebf2d9559bc3744419e93baf8ddea7e670" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "axum" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18ed336352031311f4e0b4dd2ff392d4fbb370777c9d18d7fc9d7359f73871" +dependencies = [ + "axum-core", + "bytes", + "form_urlencoded", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.7.0", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" +dependencies = [ + "bytes", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + +[[package]] +name = "borsh" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +dependencies = [ + "cfg_aliases", +] + +[[package]] +name = "brotli" +version = "8.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bstr" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "camino" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122ec45a44b270afd1402f351b782c676b173e3c3fb28d86ff7ebfb4d86a4ee4" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-release" +version = "0.25.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c19c10f6cda5f645a268885108b81a34d134d4a17e9053a7841a60949073d5" +dependencies = [ + "anstream", + "anyhow", + "bstr", + "cargo_metadata", + "clap", + "clap-cargo", + "dirs-next", + "dunce", + "env_logger", + "git-conventional", + "git2", + "globset", + "ignore", + "indexmap", + "itertools", + "log", + "maplit", + "quick-error", + "regex", + "semver", + "serde", + "similar", + "tame-index", + "time", + "toml", + "toml_edit", + "trycmd", +] + +[[package]] +name = "cargo_metadata" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "981a6f317983eec002839b90fae7411a85621410ae591a9cab2ecf5cb5744873" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.17", +] + +[[package]] +name = "cc" +version = "1.2.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "clap" +version = "4.5.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap-cargo" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85f1710adac227b75c1b1867b06b7a8f3e6b1b719d24605f7a0659fd65700e65" +dependencies = [ + "anstyle", + "cargo_metadata", + "clap", + "serde", + "serde_json", +] + +[[package]] +name = "clap_builder" +version = "4.5.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_complete" +version = "4.5.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75bf0b32ad2e152de789bb635ea4d3078f6b838ad7974143e99b99f45a04af4a" +dependencies = [ + "clap", +] + +[[package]] +name = "clap_derive" +version = "4.5.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "compression-codecs" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8a506ec4b81c460798f572caead636d57d3d7e940f998160f52bd254bf2d23" +dependencies = [ + "brotli", + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e47641d3deaf41fb1538ac1f54735925e275eaf3bf4d55c81b137fba797e5cbb" + +[[package]] +name = "content_inspector" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38" +dependencies = [ + "memchr", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[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-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +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 = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "deranged" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + +[[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 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "filetime" +version = "0.2.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.60.2", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + +[[package]] +name = "flate2" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasi 0.14.7+wasi-0.2.4", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + +[[package]] +name = "git-conventional" +version = "0.12.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6a949b7fcc81df22526032dcddb006e78c8575e47b0e7ba57d9960570a57bc4" +dependencies = [ + "unicase", + "winnow", +] + +[[package]] +name = "git2" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" +dependencies = [ + "bitflags 2.9.4", + "libc", + "libgit2-sys", + "log", + "openssl-sys", + "url", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "globset" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.3.1", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.3.1", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" + +[[package]] +name = "humantime-serde" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c" +dependencies = [ + "humantime", + "serde", +] + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2 0.4.12", + "http 1.3.1", + "http-body 1.0.1", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http 1.3.1", + "hyper 1.7.0", + "hyper-util", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.32", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "hyper-util" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "hyper 1.7.0", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.6.0", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "ignore" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown 0.16.0", +] + +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "libc", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[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.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jiff" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "libgit2-sys" +version = "0.18.2+1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libmimalloc-sys" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "667f4fec20f29dfc6bc7357c582d91796c169ad7e2fce709468aefeb2c099870" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags 2.9.4", + "libc", + "redox_syscall", +] + +[[package]] +name = "libz-sys" +version = "1.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "md5" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "memmap2" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" +dependencies = [ + "libc", +] + +[[package]] +name = "mimalloc" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ee66a4b64c74f4ef288bcbb9192ad9c3feaad75193129ac8509af543894fd8" +dependencies = [ + "libmimalloc-sys", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minijinja" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9f264d75233323f4b7d2f03aefe8a990690cdebfbfe26ea86bcbaec5e9ac990" +dependencies = [ + "serde", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "nano-web" +version = "1.1.3" +dependencies = [ + "ahash", + "anyhow", + "axum", + "brotli", + "bytes", + "cargo-release", + "chrono", + "clap", + "clap_complete", + "dashmap", + "flate2", + "fxhash", + "hyper 1.7.0", + "md5", + "memmap2", + "mimalloc", + "mime_guess", + "minijinja", + "rayon", + "reqwest 0.11.27", + "serde", + "serde_json", + "tempfile", + "tokio", + "tokio-test", + "tower", + "tower-http", + "tracing", + "tracing-subscriber", + "urlencoding", + "walkdir", + "zstd", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "openssl" +version = "0.10.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-src" +version = "300.5.3+3.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6bad8cd0233b63971e232cc9c5e83039375b8586d2312f31fda85db8f888c2" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "os_pipe" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db335f4760b14ead6290116f2427bf33a14d4f0617d49f78a246de10c1831224" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2 0.6.0", + "thiserror 2.0.17", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +dependencies = [ + "bytes", + "getrandom 0.3.3", + "lru-slab", + "rand", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.17", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2 0.6.0", + "tracing", + "windows-sys 0.60.2", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +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 = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.9.4", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "regex" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a52d8d02cacdb176ef4678de6c052efb4b3da14b78e4db683a4252762be5433" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "722166aa0d7438abbaa4d5cc2c649dac844e8c56d82fb3d33e9c34b5cd268fc6" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3160422bbd54dd5ecfdca71e5fd59b7b8fe2b1697ab2baf64f6d05dcc66d298" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "reqwest" +version = "0.12.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +dependencies = [ + "async-compression", + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.4.12", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.7.0", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "tokio", + "tokio-rustls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustc-stable-hash" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "781442f29170c5c93b7185ad559492601acdc71d5bb0706f5868094f45cfcd08" + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.5.1", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[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.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_spanned" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "smol_str" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" +dependencies = [ + "borsh", + "serde", +] + +[[package]] +name = "snapbox" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96dcfc4581e3355d70ac2ee14cfdf81dce3d85c85f1ed9e2c1d3013f53b3436b" +dependencies = [ + "anstream", + "anstyle", + "content_inspector", + "dunce", + "filetime", + "libc", + "normalize-line-endings", + "os_pipe", + "similar", + "snapbox-macros", + "tempfile", + "wait-timeout", + "walkdir", + "windows-sys 0.59.0", +] + +[[package]] +name = "snapbox-macros" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16569f53ca23a41bb6f62e0a5084aa1661f4814a67fa33696a79073e03a664af" +dependencies = [ + "anstream", +] + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tame-index" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee1412760d33e443bd048ceca650053cf26e7dee73daae39fb4932ebeebafe9" +dependencies = [ + "camino", + "crossbeam-channel", + "home", + "http 1.3.1", + "libc", + "memchr", + "rayon", + "reqwest 0.12.23", + "rustc-stable-hash", + "semver", + "serde", + "serde_json", + "smol_str", + "thiserror 2.0.17", + "tokio", + "toml-span", + "twox-hash", +] + +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "terminal_size" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" +dependencies = [ + "rustix", + "windows-sys 0.60.2", +] + +[[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.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl 2.0.17", +] + +[[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", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "time-macros" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.47.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +dependencies = [ + "backtrace", + "bytes", + "io-uring", + "libc", + "mio", + "pin-project-lite", + "slab", + "socket2 0.6.0", + "tokio-macros", + "windows-sys 0.59.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-test" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" +dependencies = [ + "async-stream", + "bytes", + "futures-core", + "tokio", + "tokio-stream", +] + +[[package]] +name = "tokio-util" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml-span" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d36acfca70d66f9b5f9c4786fec60096c3594169bf77b8d4207174dc862e6a4" +dependencies = [ + "smallvec", +] + +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "async-compression", + "bitflags 2.9.4", + "bytes", + "futures-core", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "http-range-header", + "httpdate", + "iri-string", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "trycmd" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "659488a954e37cc663704c169f829952c49b315e2fe5fd375508baffa698f106" +dependencies = [ + "anstream", + "automod", + "glob", + "humantime", + "humantime-serde", + "rayon", + "serde", + "shlex", + "snapbox", + "toml_edit", +] + +[[package]] +name = "twox-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" + +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[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 = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/frameworks/Rust/nano-web/Cargo.toml b/frameworks/Rust/nano-web/Cargo.toml new file mode 100644 index 00000000000..2e11b3a51aa --- /dev/null +++ b/frameworks/Rust/nano-web/Cargo.toml @@ -0,0 +1,84 @@ +[package] +name = "nano-web" +version = "1.1.3" +edition = "2021" +description = "Static file server built with Rust with pre-compressed in-memory caching" +authors = ["James Cleveland "] +license = "MIT" +repository = "https://github.com/radiosilence/nano-web" +homepage = "https://github.com/radiosilence/nano-web" +documentation = "https://docs.rs/nano-web" +keywords = ["web", "server", "static", "http", "spa"] +categories = ["command-line-utilities", "web-programming::http-server"] +readme = "README.md" +exclude = ["public/", ".github/", "docs/"] + +[dependencies] +clap = { version = "4.5", features = ["derive"] } +clap_complete = "4.5" +chrono = { version = "0.4", features = ["serde"] } +tokio = { version = "1.47", features = [ + "net", + "io-util", + "rt-multi-thread", + "macros", + "time", + "fs", +] } +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } +axum = { version = "0.8", features = ["tokio", "tracing"] } +hyper = { version = "1.6", features = ["server", "http1"] } +tower = { version = "0.5", features = ["timeout"] } +tower-http = { version = "0.6", features = [ + "fs", + "compression-br", + "compression-gzip", + "set-header", + "trace", +] } +mime_guess = "2.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +minijinja = "2.7" +anyhow = "1.0" +walkdir = "2.0" +bytes = "1.10" +md5 = "0.8" +brotli = "8.0" +flate2 = "1.1" +zstd = "0.13" +fxhash = "0.2" +ahash = "0.8" +dashmap = "6.1" +memmap2 = "0.9" +rayon = "1.10" +urlencoding = "2.1" + +[target.'cfg(target_env = "musl")'.dependencies] +mimalloc = "0.1.43" + +[dev-dependencies] +tokio-test = "0.4" +tempfile = "3.8" +reqwest = { version = "0.11", features = ["json"] } +cargo-release = "0.25.18" + + +[[bin]] +name = "nano-web" +path = "src/main.rs" + +# Dev profile for faster compilation during development +[profile.dev] +opt-level = 1 +debug = true + +# Release profile optimized for performance and size +[profile.release] +opt-level = 3 +debug = false +lto = "fat" +codegen-units = 1 +panic = "abort" +strip = true diff --git a/frameworks/Rust/nano-web/README.md b/frameworks/Rust/nano-web/README.md new file mode 100644 index 00000000000..b0ecd03cef8 --- /dev/null +++ b/frameworks/Rust/nano-web/README.md @@ -0,0 +1,78 @@ +# TechEmpower Framework Benchmarks + +This directory contains the setup for submitting nano-web to the TechEmpower Framework Benchmarks. + +## The Gimmick + +Unlike traditional benchmark implementations that generate responses dynamically, nano-web serves the benchmark responses as **actual pre-loaded files from memory**. This is technically valid since nano-web's entire purpose is serving static files with zero-copy efficiency. + +- `/plaintext.txt` - The "Hello, World!" plaintext response +- `/json` - The JSON serialization response + +Both are loaded into memory at startup and served with the same optimizations as any other static file. + +## Setup + +The benchmark configuration follows TechEmpower's standard structure: + +``` +techempower/ +├── benchmark_config.json # Test configuration +├── nano-web.dockerfile # Build container +├── public/ # Static files to serve +│ ├── plaintext.txt # Plaintext benchmark +│ └── json # JSON benchmark +└── README.md # This file +``` + +## Local Testing + +Build and run the benchmark container: + +```bash +# Build from project root +docker build -f techempower/nano-web.dockerfile -t nano-web-bench . + +# Run container +docker run -p 8000:8000 nano-web-bench + +# Test endpoints +curl http://localhost:8000/plaintext.txt +curl http://localhost:8000/json +``` + +## Benchmark with wrk + +```bash +# Plaintext +wrk -c 256 -t 16 -d 15s http://localhost:8000/plaintext.txt + +# JSON +wrk -c 256 -t 16 -d 15s http://localhost:8000/json +``` + +## Submitting to TechEmpower + +To submit this to the official benchmarks: + +1. Fork [TechEmpower/FrameworkBenchmarks](https://github.com/TechEmpower/FrameworkBenchmarks) +2. Copy this directory to `frameworks/Rust/nano-web/` +3. Test with their harness: `./tfb --test nano-web` +4. Submit PR to their repo + +## Implementation Details + +- **Stack**: Axum + Hyper (same as other top Rust frameworks) +- **Optimizations**: + - Files pre-loaded into memory at startup + - Pre-compressed (brotli/gzip/zstd) for compression-enabled tests + - Lock-free concurrent HashMap routing + - Zero-copy serving with Bytes + - HTTP/1.1 with Keep-Alive +- **Classification**: Platform (no database/ORM needed for these tests) + +## Why This Works + +TechEmpower benchmarks test framework overhead, not file I/O. Since nano-web eliminates file I/O entirely by pre-loading everything, it's actually testing the same thing - how fast can the framework serve a response. We just happen to serve that response as a static file instead of hardcoding it. + +It's technically correct, which is the best kind of correct. diff --git a/frameworks/Rust/nano-web/VERSION b/frameworks/Rust/nano-web/VERSION new file mode 100644 index 00000000000..781dcb07cd8 --- /dev/null +++ b/frameworks/Rust/nano-web/VERSION @@ -0,0 +1 @@ +1.1.3 diff --git a/frameworks/Rust/nano-web/benchmark_config.json b/frameworks/Rust/nano-web/benchmark_config.json new file mode 100644 index 00000000000..2757155e691 --- /dev/null +++ b/frameworks/Rust/nano-web/benchmark_config.json @@ -0,0 +1,28 @@ +{ + "framework": "nano-web", + "tests": [ + { + "default": { + "dockerfile": "nano-web.dockerfile", + "docker_cmd": "/app/nano-web serve /public --port 8000", + "json_url": "/json", + "plaintext_url": "/plaintext.txt", + "port": 8000, + "approach": "Realistic", + "classification": "Platform", + "database": "none", + "framework": "nano-web", + "language": "Rust", + "flavor": "None", + "orm": "Raw", + "platform": "Rust", + "webserver": "Hyper", + "os": "Linux", + "database_os": "Linux", + "display_name": "nano-web", + "notes": "Static file server serving pre-loaded files from memory with zero-copy", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Rust/nano-web/nano-web.dockerfile b/frameworks/Rust/nano-web/nano-web.dockerfile new file mode 100644 index 00000000000..49d79070467 --- /dev/null +++ b/frameworks/Rust/nano-web/nano-web.dockerfile @@ -0,0 +1,14 @@ +FROM docker.io/rust:1.88-slim-bookworm AS builder + +WORKDIR /build +COPY ./Cargo.toml ./Cargo.lock ./VERSION /build/ +RUN cargo fetch +COPY ./src/ /build/src +ENV RUSTFLAGS="-C target-cpu=native" +RUN cargo build --release --bin nano-web + +FROM gcr.io/distroless/cc-debian12 +COPY --from=builder /build/target/release/nano-web /app/nano-web +COPY ./techempower/public /public +EXPOSE 8000 +CMD ["/app/nano-web", "serve", "/public", "--port", "8000"] diff --git a/frameworks/Rust/nano-web/public/json b/frameworks/Rust/nano-web/public/json new file mode 100644 index 00000000000..520173a55d7 --- /dev/null +++ b/frameworks/Rust/nano-web/public/json @@ -0,0 +1 @@ +{"message":"Hello, World!"} diff --git a/frameworks/Rust/nano-web/public/plaintext.txt b/frameworks/Rust/nano-web/public/plaintext.txt new file mode 100644 index 00000000000..8ab686eafeb --- /dev/null +++ b/frameworks/Rust/nano-web/public/plaintext.txt @@ -0,0 +1 @@ +Hello, World! diff --git a/frameworks/Rust/nano-web/src/cli.rs b/frameworks/Rust/nano-web/src/cli.rs new file mode 100644 index 00000000000..7eadf8983d4 --- /dev/null +++ b/frameworks/Rust/nano-web/src/cli.rs @@ -0,0 +1,190 @@ +use crate::init_logging; +use anyhow::Result; +use clap::{CommandFactory, Parser, Subcommand}; +use std::path::PathBuf; + +const DEFAULT_PORT: u16 = 3000; +const VERSION: &str = include_str!("../VERSION"); + +#[derive(Parser)] +#[command(name = "nano-web")] +#[command(about = "Static file server built with Rust")] +#[command( + long_about = "Static file server built with Rust\nRepository: https://github.com/radiosilence/nano-web" +)] +#[command(version = VERSION)] +pub struct Cli { + #[command(subcommand)] + pub command: Option, + + #[arg(long = "dir", default_value = "public")] + #[arg(help = "Directory to serve")] + pub dir: PathBuf, + + #[arg(short = 'p', long = "port", default_value_t = DEFAULT_PORT)] + #[arg(help = "Port to listen on")] + pub port: u16, + + #[arg(short = 'd', long = "dev")] + #[arg(help = "Check/reload files if modified")] + pub dev: bool, + + #[arg(long = "spa")] + #[arg(help = "Enable SPA mode (serve index.html for all routes)")] + pub spa: bool, + + #[arg(long = "config-prefix", default_value = "VITE_")] + #[arg(help = "Environment variable prefix for config injection")] + pub config_prefix: String, + + #[arg(long = "log-level", default_value = "info")] + #[arg(help = "Log level (debug, info, warn, error)")] + pub log_level: String, + + #[arg(long = "log-format", default_value = "console")] + #[arg(help = "Log format (json, console)")] + pub log_format: String, + + #[arg(long = "log-requests")] + #[arg(help = "Log HTTP requests")] + pub log_requests: bool, +} + +#[derive(Subcommand)] +pub enum Commands { + #[command(about = "Start the web server")] + Serve { + #[arg(help = "Directory to serve")] + directory: Option, + + #[arg(short = 'p', long = "port")] + #[arg(help = "Port to listen on")] + port: Option, + + #[arg(short = 'd', long = "dev")] + #[arg(help = "Check/reload files if modified")] + dev: bool, + + #[arg(long = "spa")] + #[arg(help = "Enable SPA mode (serve index.html for all routes)")] + spa: bool, + + #[arg(long = "config-prefix")] + #[arg(help = "Environment variable prefix for config injection")] + config_prefix: Option, + + #[arg(long = "log-level")] + #[arg(help = "Log level (debug, info, warn, error)")] + log_level: Option, + + #[arg(long = "log-format")] + #[arg(help = "Log format (json, console)")] + log_format: Option, + + #[arg(long = "log-requests")] + #[arg(help = "Log HTTP requests")] + log_requests: bool, + }, + #[command(about = "Show version information")] + Version, + #[command(about = "Generate completion script")] + Completion { + #[arg(value_enum)] + shell: clap_complete::Shell, + }, +} + +impl Cli { + pub async fn run(self) -> Result<()> { + // Initialize logging with defaults for non-serve commands + if self.command.is_none() || !matches!(self.command, Some(Commands::Serve { .. })) { + init_logging(&self.log_level, &self.log_format); + } + + match self.command { + Some(Commands::Serve { + ref directory, + port, + dev, + spa, + config_prefix, + log_level, + log_format, + log_requests, + }) => { + let public_dir = self.dir.clone(); + let serve_dir = directory.clone().unwrap_or(public_dir); + + // Use subcommand values or fall back to global defaults + let final_log_level = log_level.unwrap_or(self.log_level); + let final_log_format = log_format.unwrap_or(self.log_format); + + // Initialize logging with final values + init_logging(&final_log_level, &final_log_format); + + let final_config = FinalServeConfig { + public_dir: serve_dir, + port: port.unwrap_or(self.port), + dev: dev || self.dev, + spa_mode: spa || self.spa, + config_prefix: config_prefix.unwrap_or(self.config_prefix), + log_requests: log_requests || self.log_requests, + }; + + final_config.serve().await + } + Some(Commands::Version) => { + println!("{}", full_version()); + println!("Static file server built with Rust"); + println!("Repository: https://github.com/radiosilence/nano-web"); + Ok(()) + } + Some(Commands::Completion { shell }) => { + generate_completion(shell); + Ok(()) + } + None => { + // Show help when no subcommand is provided + let mut cmd = Self::command(); + cmd.print_help()?; + Ok(()) + } + } + } +} + +struct FinalServeConfig { + public_dir: PathBuf, + port: u16, + dev: bool, + spa_mode: bool, + config_prefix: String, + log_requests: bool, +} + +impl FinalServeConfig { + async fn serve(self) -> Result<()> { + // Use Axum with our compression and caching system + let config = crate::server::AxumServeConfig { + public_dir: self.public_dir, + port: self.port, + dev: self.dev, + spa_mode: self.spa_mode, + config_prefix: self.config_prefix, + log_requests: self.log_requests, + }; + crate::server::start_axum_server(config).await + } +} + +fn full_version() -> String { + format!("nano-web v{}", VERSION.trim()) +} + +fn generate_completion(shell: clap_complete::Shell) { + use clap_complete::generate; + use std::io; + + let mut cmd = Cli::command(); + generate(shell, &mut cmd, "nano-web", &mut io::stdout()); +} diff --git a/frameworks/Rust/nano-web/src/compression.rs b/frameworks/Rust/nano-web/src/compression.rs new file mode 100644 index 00000000000..a295e6a0418 --- /dev/null +++ b/frameworks/Rust/nano-web/src/compression.rs @@ -0,0 +1,76 @@ +use anyhow::Result; +use bytes::Bytes; +use flate2::write::GzEncoder; +use flate2::Compression; +use std::io::Write; + +#[derive(Debug, Clone)] +pub struct CompressedContent { + pub plain: Bytes, + pub gzip: Option, + pub brotli: Option, + pub zstd: Option, +} + +impl CompressedContent { + pub fn new(content: Vec, should_compress: bool) -> Result { + let plain = Bytes::from(content); + + if !should_compress || plain.len() < 1024 { + return Ok(Self { + plain, + gzip: None, + brotli: None, + zstd: None, + }); + } + + let plain_ref = &plain; + let (gzip, (brotli, zstd)) = rayon::join( + || gzip_compress(plain_ref), + || rayon::join(|| brotli_compress(plain_ref), || zstd_compress(plain_ref)), + ); + + Ok(Self { + plain, + gzip: Some(gzip?), + brotli: Some(brotli?), + zstd: Some(zstd?), + }) + } + + pub fn get_best_encoding(&self, accept_encoding: &str) -> (&'static str, &Bytes) { + if accept_encoding.contains("zstd") && self.zstd.is_some() { + ("zstd", self.zstd.as_ref().unwrap()) + } else if accept_encoding.contains("br") && self.brotli.is_some() { + ("br", self.brotli.as_ref().unwrap()) + } else if accept_encoding.contains("gzip") && self.gzip.is_some() { + ("gzip", self.gzip.as_ref().unwrap()) + } else { + ("identity", &self.plain) + } + } +} + +pub fn gzip_compress(data: &[u8]) -> Result { + let mut encoder = GzEncoder::new(Vec::new(), Compression::best()); + encoder.write_all(data)?; + let compressed = encoder.finish()?; + Ok(Bytes::from(compressed)) +} + +pub fn brotli_compress(data: &[u8]) -> Result { + let mut compressed = Vec::new(); + let mut cursor = std::io::Cursor::new(data); + let params = brotli::enc::BrotliEncoderParams { + quality: 11, // Maximum quality (0-11) + ..Default::default() + }; + brotli::BrotliCompress(&mut cursor, &mut compressed, ¶ms)?; + Ok(Bytes::from(compressed)) +} + +pub fn zstd_compress(data: &[u8]) -> Result { + let compressed = zstd::bulk::compress(data, 22)?; // Maximum level (1-22) + Ok(Bytes::from(compressed)) +} diff --git a/frameworks/Rust/nano-web/src/lib.rs b/frameworks/Rust/nano-web/src/lib.rs new file mode 100644 index 00000000000..d64addc5e18 --- /dev/null +++ b/frameworks/Rust/nano-web/src/lib.rs @@ -0,0 +1,31 @@ +pub mod cli; +pub mod compression; +pub mod mime_types; +pub mod path; +pub mod routes; +pub mod server; +pub mod template; + +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; + +pub fn init_logging(level: &str, format: &str) { + let env_filter = match level { + "debug" => "debug", + "warn" => "warn", + "error" => "error", + _ => "info", + }; + + let subscriber = + tracing_subscriber::registry().with(tracing_subscriber::EnvFilter::new(env_filter)); + + if format == "json" { + subscriber + .with(tracing_subscriber::fmt::layer().json()) + .init(); + } else { + subscriber + .with(tracing_subscriber::fmt::layer().pretty()) + .init(); + } +} diff --git a/frameworks/Rust/nano-web/src/main.rs b/frameworks/Rust/nano-web/src/main.rs new file mode 100644 index 00000000000..00937d75547 --- /dev/null +++ b/frameworks/Rust/nano-web/src/main.rs @@ -0,0 +1,14 @@ +#[cfg(target_env = "musl")] +#[global_allocator] +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; + +use anyhow::Result; +use clap::Parser; +use nano_web::cli; + +#[tokio::main] +async fn main() -> Result<()> { + let cli = cli::Cli::parse(); + + cli.run().await +} diff --git a/frameworks/Rust/nano-web/src/mime_types.rs b/frameworks/Rust/nano-web/src/mime_types.rs new file mode 100644 index 00000000000..b2d7fdf376d --- /dev/null +++ b/frameworks/Rust/nano-web/src/mime_types.rs @@ -0,0 +1,137 @@ +use mime_guess::MimeGuess; +use std::path::Path; + +pub const DEFAULT_MIME: &str = "application/octet-stream"; + +pub struct MimeConfig { + pub mime_type: String, + pub is_compressible: bool, + pub is_templatable: bool, +} + +impl MimeConfig { + pub fn new(mime_type: String) -> Self { + let is_compressible = is_compressible(&mime_type); + let is_templatable = is_templatable(&mime_type); + + Self { + mime_type, + is_compressible, + is_templatable, + } + } +} + +pub fn get_mime_config>(path: P) -> MimeConfig { + let mime = MimeGuess::from_path(path) + .first() + .map(|m| m.to_string()) + .unwrap_or_else(|| DEFAULT_MIME.to_string()); + + MimeConfig::new(mime) +} + +pub fn is_compressible(mime_type: &str) -> bool { + match mime_type { + // Text-based formats + "text/html" + | "text/css" + | "text/javascript" + | "text/plain" + | "text/csv" + | "text/markdown" + | "text/cache-manifest" + | "application/json" + | "application/ld+json" + | "application/manifest+json" + | "text/xml" + | "application/xml" + | "application/rss+xml" + | "application/atom+xml" + | "image/svg+xml" => true, + + // Already compressed or binary + "image/jpeg" + | "image/png" + | "image/gif" + | "image/webp" + | "image/avif" + | "image/heic" + | "image/heif" + | "image/bmp" + | "image/tiff" + | "image/x-icon" + | "audio/mpeg" + | "audio/mp4" + | "audio/aac" + | "audio/ogg" + | "audio/flac" + | "audio/opus" + | "audio/wav" + | "video/mp4" + | "video/webm" + | "video/x-msvideo" + | "video/quicktime" + | "video/x-ms-wmv" + | "video/x-flv" + | "video/x-matroska" + | "font/woff" + | "font/woff2" + | "font/ttf" + | "font/otf" + | "application/vnd.ms-fontobject" + | "application/zip" + | "application/gzip" + | "application/x-bzip2" + | "application/vnd.rar" + | "application/x-7z-compressed" + | "application/x-xz" + | "application/x-tar" + | "application/pdf" + | "application/msword" + | "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + | "application/vnd.ms-excel" + | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + | "application/vnd.ms-powerpoint" + | "application/vnd.openxmlformats-officedocument.presentationml.presentation" + | "application/vnd.oasis.opendocument.text" + | "application/vnd.oasis.opendocument.spreadsheet" + | "application/vnd.oasis.opendocument.presentation" + | "application/octet-stream" => false, + + _ => false, + } +} + +pub fn is_templatable(mime_type: &str) -> bool { + mime_type == "text/html" +} + +pub fn is_asset(mime_type: &str) -> bool { + match mime_type { + // CSS and JavaScript + "text/css" | "text/javascript" => true, + + // Images + m if m.starts_with("image/") => true, + + // Fonts + m if m.starts_with("font/") => true, + "application/vnd.ms-fontobject" => true, + + // Audio and Video + m if m.starts_with("audio/") || m.starts_with("video/") => true, + + _ => false, + } +} + +pub fn get_cache_control(mime_type: &str) -> &'static str { + if is_asset(mime_type) { + "public, max-age=31536000, immutable" // 1 year + } else if mime_type == "text/html" { + "public, max-age=900" // 15 minutes + } else { + "public, max-age=3600" // 1 hour + } +} diff --git a/frameworks/Rust/nano-web/src/path.rs b/frameworks/Rust/nano-web/src/path.rs new file mode 100644 index 00000000000..884b30de4be --- /dev/null +++ b/frameworks/Rust/nano-web/src/path.rs @@ -0,0 +1,103 @@ +use anyhow::{bail, Result}; + +/// Maximum path length to prevent buffer overflows +pub const MAX_PATH_LENGTH: usize = 1024; + +/// Maximum number of path components to prevent deeply nested attacks +pub const MAX_PATH_COMPONENTS: usize = 32; + +/// Validate and sanitize HTTP request path to prevent directory traversal attacks +pub fn validate_request_path(path: &str) -> Result { + // Basic length check + if path.len() > MAX_PATH_LENGTH { + bail!("Path too long"); + } + + // Must start with / + if !path.starts_with('/') { + bail!("Path must start with /"); + } + + // Decode URL encoding safely + let decoded = match urlencoding::decode(path) { + Ok(decoded) => decoded.into_owned(), + Err(_) => bail!("Invalid URL encoding"), + }; + + // Check for null bytes (security) + if decoded.contains('\0') { + bail!("Path contains null bytes"); + } + + // Split into components and validate each + let components: Vec<&str> = decoded.split('/').skip(1).collect(); // Skip first empty component + + if components.len() > MAX_PATH_COMPONENTS { + bail!("Too many path components"); + } + + let mut sanitized_components = Vec::new(); + + for component in components { + // Skip empty components (double slashes) + if component.is_empty() { + continue; + } + + // Reject dangerous components + if component == ".." || component == "." { + bail!("Path traversal attempt detected"); + } + + // Check for dangerous characters + if component.contains(['\\', '\0', '<', '>', '|', '?', '*']) { + bail!("Invalid characters in path component"); + } + + // Reject hidden files/directories (starting with .) except .well-known + if component.starts_with('.') && component != ".well-known" { + bail!("Access to hidden files denied"); + } + + // Reject overly long components + if component.len() > 255 { + bail!("Path component too long"); + } + + sanitized_components.push(component); + } + + // Reconstruct safe path + let safe_path = if sanitized_components.is_empty() { + "/".to_string() + } else { + format!("/{}", sanitized_components.join("/")) + }; + + Ok(safe_path) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_path_validation() { + // Valid paths + assert!(validate_request_path("/").is_ok()); + assert!(validate_request_path("/index.html").is_ok()); + assert!(validate_request_path("/assets/style.css").is_ok()); + assert!(validate_request_path("/.well-known/acme-challenge/token").is_ok()); + assert!(validate_request_path("/.well-known/security.txt").is_ok()); + + // Invalid paths + assert!(validate_request_path("../etc/passwd").is_err()); + assert!(validate_request_path("/.env").is_err()); + assert!(validate_request_path("/.secret").is_err()); + assert!(validate_request_path("/path/with/../../traversal").is_err()); + assert!(validate_request_path("/path\0null").is_err()); + } + + // Note: parse_request_line_secure was removed as it's not used in the Axum implementation + // The Axum HTTP stack handles request parsing internally +} diff --git a/frameworks/Rust/nano-web/src/routes.rs b/frameworks/Rust/nano-web/src/routes.rs new file mode 100644 index 00000000000..782e7758433 --- /dev/null +++ b/frameworks/Rust/nano-web/src/routes.rs @@ -0,0 +1,290 @@ +use crate::compression::CompressedContent; +use crate::mime_types::{get_cache_control, get_mime_config}; +use crate::template::render_template; +use anyhow::Result; +use dashmap::DashMap; +use fxhash::FxBuildHasher; +use memmap2::Mmap; +use rayon::prelude::*; +use std::fs::File; +use std::path::{Path, PathBuf}; +use std::sync::Arc; +use std::time::SystemTime; +use tracing::{debug, error, info}; +use walkdir::WalkDir; + +#[derive(Debug, Clone)] +pub struct CachedRoute { + // Arc - ACTUAL SHARING: When index.html files create duplicate routes + // (both "/about/index.html" and "/about/" point to same file), Arc prevents copying + // the compressed content. See lines 133-138 where route.clone() shares the Arc data + pub content: Arc, + + // Arc - Same index.html sharing as above. Also enables cheap cloning when + // CachedRoute is returned from get_route() (line 203) without copying path strings + pub path: Arc, + + // SystemTime is just a timestamp (u64) - cheap to copy, no Arc needed + // Would be wasteful to add Arc overhead for such a small value + pub modified: SystemTime, + + // Arc - Enables cheap cloning when returning routes from cache. + // IMPORTANT: Headers are NOT shared between different files currently (each file + // gets its own Arc::new(CachedRouteHeaders {...})). The Arc is for clone performance + pub headers: Arc, +} + +#[derive(Debug, Clone)] +pub struct CachedRouteHeaders { + // Arc vs String vs Arc - WHY THIS SPECIFIC TYPE: + // + // String: Owned, mutable, heap-allocated (grows/shrinks) + // Arc: Shared String, but String itself has extra heap allocation overhead + // Arc: Shared string slice, more compact - no separate heap allocation for string data + // + // ACTUAL USAGE: Currently each file creates its own header strings (no sharing between + // files). Arc is used here for efficient cloning when CachedRouteHeaders is cloned, + // and because Arc is more memory-efficient than String for immutable data. + pub content_type: Arc, // Arc::from(mime_config.mime_type.as_str()) - each file gets its own + pub last_modified: Arc, // Arc::from(last_modified.as_str()) - unique per file timestamp + pub etag: Arc, // Arc::from(etag.as_str()) - unique per file content+timestamp + pub cache_control: Arc, // Arc::from(get_cache_control(...)) - could potentially be shared +} + +// Type alias for a concurrent hash map. DashMap allows lock-free concurrent access. +// +// Arc keys - CRITICAL CHOICE: URL paths like "/assets/app.js" are stored once +// and shared. Without Arc, each HashMap key would own its own copy of the path string. +// With Arc, the same path string is shared between the key and the CachedRoute.path +// +// FxBuildHasher - trades cryptographic security for 2x faster hashing on strings +// Safe because we control the keys (URL paths), no hash-flooding attacks possible +pub type CachedRoutes = DashMap, CachedRoute, FxBuildHasher>; + +pub struct NanoWeb { + // The main route cache using our type alias defined above + pub routes: CachedRoutes, + + // Memory-mapped files cache. Mmap provides zero-copy file access by mapping + // file contents directly into memory. + // + // Arc - ESSENTIAL: Mmap maps file contents into process memory. Without Arc, + // we couldn't share this mapped memory across threads safely. Arc ensures the + // memory mapping stays valid as long as any thread holds a reference. + // Multiple requests for the same large file can serve from the same mapped memory. + pub static_cache: DashMap, Arc, FxBuildHasher>, +} + +impl Default for NanoWeb { + fn default() -> Self { + Self::new() + } +} + +impl NanoWeb { + pub fn new() -> Self { + Self { + routes: DashMap::with_hasher(FxBuildHasher::default()), + static_cache: DashMap::with_hasher(FxBuildHasher::default()), + } + } + + pub fn populate_routes(&self, public_dir: &Path, config_prefix: &str) -> Result<()> { + debug!("Starting route population from {:?}", public_dir); + + // Collect all file paths first + // Vec<_> uses type inference - the compiler figures out the full type from context + let file_paths: Vec<_> = WalkDir::new(public_dir) + .into_iter() + .filter_map(|entry| { + // Option::ok() converts Result to Option, discarding errors + entry.ok().and_then(|e| { + if e.file_type().is_file() { + // PathBuf::to_path_buf() creates owned path data we can move around + // The ? operator propagates None if metadata() fails + Some((e.path().to_path_buf(), e.metadata().ok()?)) + } else { + None + } + }) + }) + .collect(); + + info!("Processing {} files in parallel", file_paths.len()); + + // Process files in parallel using rayon's parallel iterator + // par_iter() automatically distributes work across CPU cores + let routes: Vec<_> = file_paths + .par_iter() + .filter_map(|(file_path, metadata)| { + match self.create_route(file_path, metadata, public_dir, config_prefix) { + Ok((url_path, route)) => Some((url_path, route)), + Err(e) => { + error!("Failed to create route for {:?}: {}", file_path, e); + None + } + } + }) + .collect(); + + // Insert routes into concurrent map + for (url_path, route) in routes { + // Handle index files first - create the directory route + if url_path.ends_with("/index.html") { + let dir_path = if url_path.as_ref() == "/index.html" { + Arc::from("/") + } else { + let dir = url_path.trim_end_matches("/index.html"); + Arc::from(format!("{}/", dir)) + }; + // Clone for the directory route (e.g., "/about/" -> route) + self.routes.insert(dir_path, route.clone()); + } + + // Insert the main route, moving ownership (no clone needed) + // e.g., "/about/index.html" -> route (moved, no clone) + self.routes.insert(url_path, route); + } + + info!("Routes populated: {} routes", self.routes.len()); + Ok(()) + } + + // WHY THIS ISN'T CachedRoute::new() - This method needs access to NanoWeb's static_cache + // to store memory-mapped files (line 150). It also needs self.file_path_to_url() and + // self.generate_etag() methods. Moving this to CachedRoute would require passing + // the cache and utility methods, making the API more complex. + fn create_route( + &self, + file_path: &Path, + metadata: &std::fs::Metadata, + public_dir: &Path, + config_prefix: &str, + ) -> Result<(Arc, CachedRoute)> { + // Memory-map large files for zero-copy serving + // 8192 bytes (8KB) threshold - small files stay in RAM, large files use mmap + let content = if metadata.len() > 8192 { + // Use memory mapping for larger files + let file = File::open(file_path)?; + // unsafe required because mmap can access arbitrary memory if file is modified + // externally. Safe here because we control the file system + let mmap = unsafe { Mmap::map(&file)? }; + let url_path = self.file_path_to_url(file_path, public_dir)?; + self.static_cache.insert(url_path.clone(), Arc::new(mmap)); + + // For mmap files, we still need a copy for compression + // Vec contains the raw bytes of the file + std::fs::read(file_path)? + } else { + std::fs::read(file_path)? + }; + + let modified = metadata.modified()?; + let mime_config = get_mime_config(file_path); + + // Apply templating if needed + let processed_content = if mime_config.is_templatable { + match render_template(&String::from_utf8_lossy(&content), config_prefix) { + Ok(templated) => templated.into_bytes(), + Err(e) => { + error!("Template rendering failed for {:?}: {}", file_path, e); + content + } + } + } else { + content + }; + + let compressed = CompressedContent::new(processed_content, mime_config.is_compressible)?; + let etag = self.generate_etag(&modified, &compressed.plain); + let last_modified = self.format_http_date(modified); + + let headers = Arc::new(CachedRouteHeaders { + content_type: Arc::from(mime_config.mime_type.as_str()), + last_modified: Arc::from(last_modified.as_str()), + etag: Arc::from(etag.as_str()), + cache_control: Arc::from(get_cache_control(&mime_config.mime_type)), + }); + + let route = CachedRoute { + content: Arc::new(compressed), + path: Arc::new(file_path.to_path_buf()), + modified, + headers, + }; + + let url_path = self.file_path_to_url(file_path, public_dir)?; + Ok((url_path, route)) + } + + // #[inline(always)] forces the compiler to inline this function at call sites + // Used for hot path functions where call overhead matters more than code size + #[inline(always)] + pub fn get_route(&self, path: &str) -> Option { + // CLONE FOR LOCK RELEASE: DashMap::get returns a lock guard. We must clone to avoid + // holding the concurrent lock while serving the response. Since CachedRoute contains + // only Arcs, this clone just increments reference counters (cheap) rather than + // copying actual data. Alternative would be holding the lock during entire HTTP response. + self.routes.get(path).map(|entry| entry.value().clone()) + } + + fn file_path_to_url(&self, file_path: &Path, public_dir: &Path) -> Result> { + let relative = file_path.strip_prefix(public_dir)?; + let url_path = format!("/{}", relative.to_string_lossy().replace('\\', "/")); + Ok(Arc::from(url_path.as_str())) + } + + fn generate_etag(&self, modified: &SystemTime, content: &[u8]) -> String { + use std::time::UNIX_EPOCH; + + let timestamp = modified + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_secs(); + + // Simple ETag: timestamp-size + format!("\"{:x}-{:x}\"", timestamp, content.len()) + } + + fn format_http_date(&self, time: SystemTime) -> String { + let datetime = chrono::DateTime::::from(time); + datetime.format("%a, %d %b %Y %H:%M:%S GMT").to_string() + } +} + +// Lock-free atomic operations for route updates in dev mode +impl NanoWeb { + pub fn refresh_if_modified( + &self, + path: &str, + config_prefix: &str, + ) -> Result> { + if let Some(route_ref) = self.routes.get(path) { + let route = route_ref.value().clone(); + drop(route_ref); // Release the reference early + + // &*route.path - Arc -> PathBuf -> &PathBuf -> &Path + // std::fs::metadata needs AsRef, so we dereference Arc then take reference + // Alternative: route.path.as_ref() but &* is more idiomatic in Rust + let metadata = std::fs::metadata(&*route.path)?; + let modified = metadata.modified()?; + + if modified > route.modified { + debug!("File modified, refreshing route: {:?}", route.path); + + // Create new route + let parent_dir = route.path.parent().unwrap(); + let public_dir = parent_dir.ancestors().last().unwrap(); + let (_, new_route) = + self.create_route(&route.path, &metadata, public_dir, config_prefix)?; + + // Atomic update + self.routes.insert(Arc::from(path), new_route.clone()); + return Ok(Some(new_route)); + } + Ok(Some(route)) + } else { + Ok(None) + } + } +} diff --git a/frameworks/Rust/nano-web/src/server.rs b/frameworks/Rust/nano-web/src/server.rs new file mode 100644 index 00000000000..1b9de0a8069 --- /dev/null +++ b/frameworks/Rust/nano-web/src/server.rs @@ -0,0 +1,309 @@ +// anyhow::Result - Provides a convenient Result type alias +// Much nicer than Result> for error handling +use anyhow::Result; +use axum::{ + // State extractor - Axum's way to inject shared state into handler functions + extract::State, + // HTTP primitives - StatusCode is an enum, HeaderMap is HashMap-like for headers + http::{header, HeaderMap, StatusCode, Uri}, + // Trait that converts types into HTTP responses (implemented for tuples, strings, etc) + response::IntoResponse, + // Routing - get() creates a route that only handles GET requests + routing::get, + Router, +}; +use chrono::Utc; +// PathBuf owns path data (vs &Path which borrows) - we need owned data for the config struct +use std::path::PathBuf; +// Arc for thread-safe sharing of NanoWeb across all HTTP request handlers +use std::sync::Arc; +// TcpListener for async TCP socket binding in Tokio +use tokio::net::TcpListener; +// Tower middleware system - composable request/response processing +use tower::ServiceBuilder; +use tower_http::{set_header::SetResponseHeaderLayer, trace::TraceLayer}; +use tracing::{debug, info}; + +use crate::routes::NanoWeb; + +// #[derive(Clone)] - Automatically generates clone() method that clones each field +// We need Clone because Axum requires state to be cloneable (shared across request handlers) +#[derive(Clone)] +pub struct AxumServeConfig { + pub public_dir: PathBuf, // Owned path - could be moved between threads + pub port: u16, // u16 is Copy (stack allocated) - clone just copies the bits + pub dev: bool, // bool is Copy - no heap allocation to worry about + pub spa_mode: bool, + pub config_prefix: String, // String owns heap-allocated data - clone() allocates new string + pub log_requests: bool, +} + +// AppState gets cloned for every HTTP request handler (Axum requirement) +// Arc clone is cheap (just increments reference count) +// AxumServeConfig clone is more expensive (String allocation) but happens per-request +#[derive(Clone)] +struct AppState { + server: Arc, // Shared read-only access to our route cache + config: AxumServeConfig, // Configuration that handlers might need +} + +// async fn - Returns a Future that implements the async state machine +// Result<()> - Returns () on success, anyhow::Error on failure +pub async fn start_axum_server(config: AxumServeConfig) -> Result<()> { + // Arc::new allocates NanoWeb on the heap and wraps in atomic reference counter + // Needed because multiple concurrent request handlers will access the same cache + let server = Arc::new(NanoWeb::new()); + + // Populate routes using our existing route system + // &config.public_dir - borrowing because populate_routes doesn't need ownership + server.populate_routes(&config.public_dir, &config.config_prefix)?; + + let state = AppState { + server, // Arc moved into state + config: config.clone(), // Clone needed because we use config again below (line 65) + }; + + info!("Routes loaded: {}", state.server.routes.len()); + + let app = create_router(state); + + // format! macro - creates owned String by formatting template + let addr = format!("0.0.0.0:{}", config.port); + // TcpListener::bind is async - returns Future> + // .await suspends this function until the future completes + // ? operator propagates any bind errors up to caller + let listener = TcpListener::bind(&addr).await?; + + info!("Starting server on http://{}", addr); + info!("Serving directory: {:?}", config.public_dir); + + // axum::serve takes ownership of listener and app, runs until server shuts down + // This is the main server loop that handles all incoming HTTP connections + axum::serve(listener, app).await?; + + // Only reached when server shuts down gracefully + Ok(()) +} + +// Takes AppState by value (ownership) - Router needs to own the state for sharing +fn create_router(state: AppState) -> Router { + // ServiceBuilder uses the builder pattern to compose middleware layers + // Each .layer() call wraps the next layer - processed in reverse order during requests + let middleware_stack = ServiceBuilder::new() + // Security headers - SetResponseHeaderLayer adds these to every response + .layer(SetResponseHeaderLayer::overriding( + header::X_CONTENT_TYPE_OPTIONS, + // .parse() converts &str to HeaderValue, .unwrap() panics on invalid headers + // Safe because these are known-good header values + "nosniff".parse::().unwrap(), + )) + .layer(SetResponseHeaderLayer::overriding( + header::X_FRAME_OPTIONS, + "SAMEORIGIN".parse::().unwrap(), + )) + .layer(SetResponseHeaderLayer::overriding( + header::REFERRER_POLICY, + "strict-origin-when-cross-origin" + .parse::() + .unwrap(), + )); + + // Router::new() creates empty router, then we build it with method chaining + let app = Router::new() + // .route() maps HTTP path patterns to handler functions + // get() means only handle GET requests to this path + .route("/_health", get(health_handler)) // health_handler is a function pointer + .route("/", get(root_handler)) // Explicit route for root + .fallback(get(file_handler)); // Catch-all for everything else + + // Conditional middleware - only add tracing if log_requests is true + if state.config.log_requests { + app.layer( + // TraceLayer automatically creates tracing spans for HTTP requests + TraceLayer::new_for_http() + // Closure that creates a span for each request + // |request: &Request| - closure parameter with explicit type + .make_span_with(|request: &axum::extract::Request| { + // tracing::info_span! macro creates a span with key=value fields + // % means "use Display formatting" for the value + tracing::info_span!( + "request", + method = %request.method(), + path = %request.uri().path(), + ) + }) + // Closure called when response is ready + // Multiple parameters in closure - latency calculated by TraceLayer + .on_response( + |response: &axum::response::Response, + latency: std::time::Duration, + _span: &tracing::Span| { + // _span prefix means "unused parameter" + tracing::info!( + status = %response.status(), + duration_ms = %latency.as_millis(), + "request completed" + ); + }, + ), + ) + .layer(middleware_stack) // Add our security headers + .with_state(state) // Inject AppState into all handlers + } else { + // Same router but without tracing middleware + app.layer(middleware_stack).with_state(state) + } +} + +// impl IntoResponse - returns "some type that implements IntoResponse" +// This lets us return different types (tuples, strings, etc.) from the same function +// Axum provides IntoResponse impls for many types including tuples +async fn health_handler() -> impl IntoResponse { + let timestamp = Utc::now().to_rfc3339(); // ISO 8601 timestamp string + // r#"..."# is a raw string literal - no need to escape quotes inside + let response = format!(r#"{{"status":"ok","timestamp":"{}"}}"#, timestamp); + // Tuple that implements IntoResponse: (StatusCode, Headers, Body) + // Array syntax [(key, value)] creates headers - more ergonomic than HeaderMap + ( + StatusCode::OK, + [(header::CONTENT_TYPE, "application/json")], + response, // String implements IntoResponse as the response body + ) +} + +// Axum handler function - parameters are "extractors" that Axum provides +// headers: HeaderMap - Axum extracts request headers automatically +// State(state): State - Pattern matching to extract our injected state +async fn root_handler(headers: HeaderMap, State(state): State) -> impl IntoResponse { + // Delegate to serve_file with root path + // .await because serve_file is async and we need its result + serve_file("/".to_string(), headers, state).await +} + +async fn file_handler( + uri: Uri, // Uri extractor - Axum parses the request URI + headers: HeaderMap, + State(state): State, +) -> impl IntoResponse { + // Extract path from URI and convert to owned String + // .to_string() because serve_file needs owned data (not borrowed &str) + let path = uri.path().to_string(); + serve_file(path, headers, state).await +} + +async fn serve_file( + path: String, // Owned string - can be moved around without lifetime issues + request_headers: HeaderMap, + state: AppState, // AppState by value - cloned by Axum for each request +) -> impl IntoResponse { + debug!("Serving path: {}", path); + + // Security: validate path to prevent directory traversal attacks + // if let Err(e) - pattern matching on Result, only execute if validation failed + if let Err(e) = crate::path::validate_request_path(&path) { + tracing::warn!("Path validation failed for '{}': {}", path, e); + // Early return with error response - into_response() converts tuple to Response + return (StatusCode::BAD_REQUEST, "Bad Request").into_response(); + } + + // Route lookup using our existing system + // mut because we might reassign it in the fallback logic below + let mut route = state.server.get_route(&path); + + // Fallback 1: Try with trailing slash (common web server behavior) + if route.is_none() && !path.ends_with('/') { + // format! creates new owned String - needed because get_route expects &str + let path_with_slash = format!("{}/", path); + route = state.server.get_route(&path_with_slash); + } + + // Fallback 2: SPA mode - serve index.html for any unmatched routes + if route.is_none() && state.config.spa_mode { + // Single Page App fallback - serve root for all unmatched routes + route = state.server.get_route("/"); + if route.is_some() { + debug!("SPA fallback for: {}", path); + } + } + + // Pattern match on Option - extract route or return 404 + // This converts Option to CachedRoute or early returns + let route = match route { + Some(r) => r, // Extract the CachedRoute from Some(route) + None => { + debug!("Route not found: {}", path); + // Early return - convert tuple to HTTP response and exit function + return (StatusCode::NOT_FOUND, "Not Found").into_response(); + } + }; + + // Dev mode file refresh - check if file changed on disk and reload if needed + // Variable shadowing: creating new `route` variable that shadows the previous one + let route = if state.config.dev { + // refresh_if_modified returns Result, Error> + match state + .server + .refresh_if_modified(&path, &state.config.config_prefix) + { + Ok(Some(updated_route)) => { + debug!("Route refreshed: {}", path); + updated_route // Use the newly loaded route + } + Ok(None) => route, // File unchanged, use existing route + Err(e) => { + debug!("Failed to refresh route {}: {}", path, e); + route // Error refreshing, fallback to existing route + } + } + } else { + route // Production mode - always use cached route + }; + + // Extract Accept-Encoding from request headers for our compression system + // Method chaining with Option combinators - common Rust pattern + let accept_encoding = request_headers + .get(header::ACCEPT_ENCODING) // Option<&HeaderValue> + .and_then(|h| h.to_str().ok()) // Option<&str> - convert HeaderValue to str + .unwrap_or(""); // &str - default to empty string if None + + // Use our compression system with pre-computed compressed files + // Destructuring assignment - get_best_encoding returns a tuple (String, &[u8]) + let (encoding, content) = route.content.get_best_encoding(accept_encoding); + + // Build response with optimized headers + // HeaderMap::new() creates empty header map - mut because we'll modify it + let mut response_headers = HeaderMap::new(); + + // Insert headers from our cached route + // .parse() converts Arc to HeaderValue, .unwrap() safe because we control the values + response_headers.insert( + header::CONTENT_TYPE, + route.headers.content_type.parse().unwrap(), // "text/html", "application/json", etc + ); + response_headers.insert( + header::LAST_MODIFIED, + route.headers.last_modified.parse().unwrap(), // "Wed, 15 Nov 2023 08:12:31 GMT" + ); + response_headers.insert(header::ETAG, route.headers.etag.parse().unwrap()); // "abc123-456" + response_headers.insert( + header::CACHE_CONTROL, + route.headers.cache_control.parse().unwrap(), // "public, max-age=31536000" + ); + + // Add compression encoding header if content is compressed + // "identity" means uncompressed - only add header for gzip, br, etc + if encoding != "identity" { + response_headers.insert(header::CONTENT_ENCODING, encoding.parse().unwrap()); + } + + debug!( + "Serving {} bytes with encoding: {} (from pre-compressed cache)", + content.len(), // &[u8] has .len() method + encoding + ); + + // Final response tuple: (StatusCode, HeaderMap, Body) + // content.clone() - cloning &[u8] is cheap, just copies the slice reference + // Arc> inside CompressedContent makes the actual data sharing cheap + (StatusCode::OK, response_headers, content.clone()).into_response() +} diff --git a/frameworks/Rust/nano-web/src/template.rs b/frameworks/Rust/nano-web/src/template.rs new file mode 100644 index 00000000000..16685b2c1f1 --- /dev/null +++ b/frameworks/Rust/nano-web/src/template.rs @@ -0,0 +1,127 @@ +use anyhow::Result; +use minijinja::{context, Environment}; +use std::collections::HashMap; +use std::env; + +pub fn render_template(content: &str, config_prefix: &str) -> Result { + let jinja = Environment::new(); + + // Collect environment variables with the specified prefix + let mut env_vars = HashMap::new(); + for (key, value) in env::vars() { + if key.starts_with(config_prefix) { + let trimmed_key = key.strip_prefix(config_prefix).unwrap(); + env_vars.insert(trimmed_key.to_string(), value); + } + } + + let json_string = serde_json::to_string(&env_vars)?; + let escaped_json = json_string.replace('"', "\\\""); + + // MiniJinja has better syntax and is more secure by default + let template = jinja.template_from_str(content)?; + + template + .render(context! { + env => env_vars, + Json => json_string, + EscapedJson => escaped_json + }) + .map_err(|e| anyhow::anyhow!("Template rendering error: {}", e)) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::env; + + #[test] + fn test_template_rendering_with_env_vars() { + // Set up test environment variables + env::set_var("VITE_API_URL", "http://localhost:3000"); + env::set_var("VITE_APP_NAME", "Test App"); + env::set_var("OTHER_VAR", "should_not_appear"); + + let template = r#" + + "#; + + let result = render_template(template, "VITE_").unwrap(); + + // Should include VITE_ prefixed vars + assert!(result.contains("API_URL")); + assert!(result.contains("Test App")); + + // Should not include non-prefixed vars + assert!(!result.contains("should_not_appear")); + + // Should have valid JSON + assert!(result.contains("JSON.parse")); + + // Clean up + env::remove_var("VITE_API_URL"); + env::remove_var("VITE_APP_NAME"); + env::remove_var("OTHER_VAR"); + } + + #[test] + fn test_template_with_no_env_vars() { + let template = r#" + + "#; + + let result = render_template(template, "NONEXISTENT_").unwrap(); + + // Should render empty object + assert!(result.contains("{}")); + } + + #[test] + fn test_template_with_special_characters() { + env::set_var("TEST_QUOTES", r#"value with "quotes""#); + env::set_var("TEST_SLASHES", "path/to/file"); + + let template = r#""#; + + let result = render_template(template, "TEST_").unwrap(); + + // Should contain the quotes in JSON - MiniJinja handles proper escaping + assert!(result.contains("quotes")); + assert!(result.contains("path/to/file")); + + // Clean up + env::remove_var("TEST_QUOTES"); + env::remove_var("TEST_SLASHES"); + } + + #[test] + fn test_template_invalid_syntax() { + let template = "{{invalid.template.syntax}}"; + + // Should return error for invalid template + assert!(render_template(template, "VITE_").is_err()); + } + + #[test] + fn test_different_prefixes() { + env::set_var("REACT_APP_URL", "react-url"); + env::set_var("VUE_APP_URL", "vue-url"); + + let template = "{{env.APP_URL}}"; + + let react_result = render_template(template, "REACT_").unwrap(); + let vue_result = render_template(template, "VUE_").unwrap(); + + assert!(react_result.contains("react-url")); + assert!(vue_result.contains("vue-url")); + + // Clean up + env::remove_var("REACT_APP_URL"); + env::remove_var("VUE_APP_URL"); + } +}