From 80316498c7aa6712e72a7256f13c86f5a3af9e41 Mon Sep 17 00:00:00 2001 From: Sock <87631534+platonicsock@users.noreply.github.com> Date: Mon, 3 Aug 2026 13:26:50 -0400 Subject: [PATCH] [anneal] Add playground compiler backend gherrit-pr-id: Gklylrwoplohejnfq3oo4uymvshcq3o62 --- .../compiler/.gitignore | 1 + .../compiler/base/.dockerignore | 6 + .../compiler/base/Cargo.toml | 4251 +++++++++++++ .../compiler/base/Dockerfile | 169 + .../compiler/base/asm-cleanup/.gitignore | 2 + .../compiler/base/asm-cleanup/Cargo.toml | 11 + .../compiler/base/asm-cleanup/src/lib.rs | 282 + .../compiler/base/attach_notice.sh | 27 + .../cargo-anneal-alpha24-cache-manifest.patch | 623 ++ .../compiler/base/cargo-miri-playground | 7 + .../compiler/base/cargo-wasm | 35 + .../compiler/base/crate-information.json | 2382 ++++++++ .../compiler/base/entrypoint.sh | 7 + .../base/modify-cargo-toml/.gitignore | 2 + .../base/modify-cargo-toml/Cargo.toml | 11 + .../base/modify-cargo-toml/src/lib.rs | 131 + .../compiler/base/orchestrator/.gitignore | 1 + .../compiler/base/orchestrator/Cargo.lock | 1021 ++++ .../compiler/base/orchestrator/Cargo.toml | 37 + .../base/orchestrator/src/bin/worker.rs | 11 + .../base/orchestrator/src/coordinator.rs | 4282 +++++++++++++ .../orchestrator/src/coordinator/limits.rs | 327 + .../compiler/base/orchestrator/src/lib.rs | 35 + .../compiler/base/orchestrator/src/message.rs | 219 + .../compiler/base/orchestrator/src/worker.rs | 1264 ++++ .../compiler/base/security_notice.txt | 11 + .../rust-anneal-playground/compiler/build.sh | 24 + .../rust-anneal-playground/compiler/fetch.sh | 11 + .../top-crates/.gitignore | 1 + .../top-crates/Cargo.lock | 5351 +++++++++++++++++ .../top-crates/Cargo.toml | 24 + .../top-crates/crate-modifications.toml | 23 + .../top-crates/src/lib.rs | 718 +++ .../top-crates/src/main.rs | 125 + 34 files changed, 21432 insertions(+) create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/.gitignore create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/.dockerignore create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/Cargo.toml create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/Dockerfile create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/asm-cleanup/.gitignore create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/asm-cleanup/Cargo.toml create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/asm-cleanup/src/lib.rs create mode 100755 anneal/v1/playground/rust-anneal-playground/compiler/base/attach_notice.sh create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/cargo-anneal-alpha24-cache-manifest.patch create mode 100755 anneal/v1/playground/rust-anneal-playground/compiler/base/cargo-miri-playground create mode 100755 anneal/v1/playground/rust-anneal-playground/compiler/base/cargo-wasm create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/crate-information.json create mode 100755 anneal/v1/playground/rust-anneal-playground/compiler/base/entrypoint.sh create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/modify-cargo-toml/.gitignore create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/modify-cargo-toml/Cargo.toml create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/modify-cargo-toml/src/lib.rs create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/.gitignore create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/Cargo.lock create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/Cargo.toml create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/bin/worker.rs create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/coordinator.rs create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/coordinator/limits.rs create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/lib.rs create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/message.rs create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/worker.rs create mode 100644 anneal/v1/playground/rust-anneal-playground/compiler/base/security_notice.txt create mode 100755 anneal/v1/playground/rust-anneal-playground/compiler/build.sh create mode 100755 anneal/v1/playground/rust-anneal-playground/compiler/fetch.sh create mode 100644 anneal/v1/playground/rust-anneal-playground/top-crates/.gitignore create mode 100644 anneal/v1/playground/rust-anneal-playground/top-crates/Cargo.lock create mode 100644 anneal/v1/playground/rust-anneal-playground/top-crates/Cargo.toml create mode 100644 anneal/v1/playground/rust-anneal-playground/top-crates/crate-modifications.toml create mode 100644 anneal/v1/playground/rust-anneal-playground/top-crates/src/lib.rs create mode 100644 anneal/v1/playground/rust-anneal-playground/top-crates/src/main.rs diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/.gitignore b/anneal/v1/playground/rust-anneal-playground/compiler/.gitignore new file mode 100644 index 0000000000..f2dbd90499 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/.gitignore @@ -0,0 +1 @@ +*/channel-rust-*-date.txt diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/.dockerignore b/anneal/v1/playground/rust-anneal-playground/compiler/base/.dockerignore new file mode 100644 index 0000000000..8e23705a69 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/.dockerignore @@ -0,0 +1,6 @@ +.DS_Store +**/.DS_Store + +asm-cleanup/target +modify-cargo-toml/target +orchestrator/target diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/Cargo.toml b/anneal/v1/playground/rust-anneal-playground/compiler/base/Cargo.toml new file mode 100644 index 0000000000..e45b8da45b --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/Cargo.toml @@ -0,0 +1,4251 @@ +# This file is automatically @generated by the top-crates script. +# Do not edit it manually. Any pull requests changing this file will likely be closed. +# See https://github.com/rust-lang/rust-playground/blob/main/CRATE_POLICY.md for details. +# +[package] +name = "playground" +version = "0.0.1" +authors = ["The Rust Playground"] + +[workspace] +resolver = "2" + +[profile.dev] +codegen-units = 1 +incremental = false + +[profile.dev.build-override] +codegen-units = 1 +debug = true + +[profile.release] +codegen-units = 1 +incremental = false + +[profile.release.build-override] +codegen-units = 1 +debug = false + +[dependencies.addr2line] +package = "addr2line" +version = "=0.25.1" +default-features = false + +[dependencies.adler2] +package = "adler2" +version = "=2.0.1" +default-features = false + +[dependencies.ahash] +package = "ahash" +version = "=0.8.12" + +[dependencies.aho_corasick] +package = "aho-corasick" +version = "=1.1.4" +default-features = false + +[dependencies.aligned] +package = "aligned" +version = "=0.4.3" + +[dependencies.aligned_vec] +package = "aligned-vec" +version = "=0.6.4" + +[dependencies.alloc_no_stdlib] +package = "alloc-no-stdlib" +version = "=2.0.4" + +[dependencies.alloc_stdlib] +package = "alloc-stdlib" +version = "=0.2.2" + +[dependencies.allocator_api2] +package = "allocator-api2" +version = "=0.2.21" +features = ["alloc"] +default-features = false + +[dependencies.ansi_term] +package = "ansi_term" +version = "=0.12.1" + +[dependencies.anstream] +package = "anstream" +version = "=1.0.0" +features = ["wincon"] + +[dependencies.anstyle] +package = "anstyle" +version = "=1.0.14" + +[dependencies.anstyle_parse] +package = "anstyle-parse" +version = "=1.0.0" + +[dependencies.anstyle_query] +package = "anstyle-query" +version = "=1.1.5" + +[dependencies.anyhow] +package = "anyhow" +version = "=1.0.102" + +[dependencies.approx] +package = "approx" +version = "=0.5.1" +default-features = false + +[dependencies.arbitrary] +package = "arbitrary" +version = "=1.4.2" +default-features = false + +[dependencies.arc_swap] +package = "arc-swap" +version = "=1.9.1" + +[dependencies.arg_enum_proc_macro] +package = "arg_enum_proc_macro" +version = "=0.3.4" + +[dependencies.arrayvec] +package = "arrayvec" +version = "=0.7.6" + +[dependencies.as_slice] +package = "as-slice" +version = "=0.2.1" + +[dependencies.async_compression] +package = "async-compression" +version = "=0.4.42" +features = ["tokio"] + +[dependencies.async_trait] +package = "async-trait" +version = "=0.1.89" + +[dependencies.atomic] +package = "atomic" +version = "=0.6.1" +default-features = false + +[dependencies.atomic_waker] +package = "atomic-waker" +version = "=1.1.2" + +[dependencies.autocfg] +package = "autocfg" +version = "=1.5.1" + +[dependencies.av1_grain] +package = "av1-grain" +version = "=0.2.5" + +[dependencies.av_scenechange] +package = "av-scenechange" +version = "=0.14.1" +default-features = false + +[dependencies.avif_serialize] +package = "avif-serialize" +version = "=0.8.9" + +[dependencies.aws_lc_rs] +package = "aws-lc-rs" +version = "=1.17.0" +default-features = false + +[dependencies.aws_lc_sys] +package = "aws-lc-sys" +version = "=0.41.0" +default-features = false + +[dependencies.backtrace] +package = "backtrace" +version = "=0.3.76" + +[dependencies.base64] +package = "base64" +version = "=0.22.1" + +[dependencies.bit_field] +package = "bit_field" +version = "=0.10.3" + +[dependencies.bit_set] +package = "bit-set" +version = "=0.5.3" + +[dependencies.bit_vec] +package = "bit-vec" +version = "=0.6.3" +default-features = false + +[dependencies.bitflags] +package = "bitflags" +version = "=2.12.1" + +[dependencies.bitstream_io] +package = "bitstream-io" +version = "=4.10.0" + +[dependencies.bitvec] +package = "bitvec" +version = "=1.0.1" +default-features = false + +[dependencies.block_buffer] +package = "block-buffer" +version = "=0.12.0" + +[dependencies.block_buffer_0_10_4] +package = "block-buffer" +version = "=0.10.4" + +[dependencies.borsh] +package = "borsh" +version = "=1.6.1" +default-features = false + +[dependencies.brotli] +package = "brotli" +version = "=8.0.3" + +[dependencies.brotli_decompressor] +package = "brotli-decompressor" +version = "=5.0.1" +default-features = false + +[dependencies.built] +package = "built" +version = "=0.8.1" + +[dependencies.bumpalo] +package = "bumpalo" +version = "=3.20.3" + +[dependencies.bytecheck] +package = "bytecheck" +version = "=0.8.2" +default-features = false + +[dependencies.bytecheck_derive] +package = "bytecheck_derive" +version = "=0.8.2" +default-features = false + +[dependencies.bytemuck] +package = "bytemuck" +version = "=1.25.0" +features = ["extern_crate_alloc", "extern_crate_std", "latest_stable_rust"] + +[dependencies.bytemuck_derive] +package = "bytemuck_derive" +version = "=1.10.2" + +[dependencies.byteorder] +package = "byteorder" +version = "=1.5.0" + +[dependencies.byteorder_lite] +package = "byteorder-lite" +version = "=0.1.0" + +[dependencies.bytes] +package = "bytes" +version = "=1.11.1" + +[dependencies.bytes_0_4_12] +package = "bytes" +version = "=0.4.12" + +[dependencies.cc] +package = "cc" +version = "=1.2.63" +features = ["parallel"] + +[dependencies.cfg_aliases] +package = "cfg_aliases" +version = "=0.2.1" + +[dependencies.cfg_if] +package = "cfg-if" +version = "=1.0.4" + +[dependencies.chacha20] +package = "chacha20" +version = "=0.10.0" +features = ["rng"] +default-features = false + +[dependencies.chrono] +package = "chrono" +version = "=0.4.44" +features = ["clock", "serde"] + +[dependencies.clap] +package = "clap" +version = "=4.6.1" +features = ["unstable-doc"] + +[dependencies.clap_builder] +package = "clap_builder" +version = "=4.6.0" +features = ["unstable-doc"] + +[dependencies.clap_derive] +package = "clap_derive" +version = "=4.6.1" + +[dependencies.clap_lex] +package = "clap_lex" +version = "=1.1.0" + +[dependencies.cmake] +package = "cmake" +version = "=0.1.58" + +[dependencies.cmov] +package = "cmov" +version = "=0.5.4" + +[dependencies.color_quant] +package = "color_quant" +version = "=1.1.0" + +[dependencies.colorchoice] +package = "colorchoice" +version = "=1.0.5" + +[dependencies.compression_codecs] +package = "compression-codecs" +version = "=0.4.38" + +[dependencies.compression_core] +package = "compression-core" +version = "=0.4.32" + +[dependencies.const_default] +package = "const-default" +version = "=1.0.0" +default-features = false + +[dependencies.const_oid] +package = "const-oid" +version = "=0.10.2" + +[dependencies.convert_case] +package = "convert_case" +version = "=0.10.0" + +[dependencies.cookie] +package = "cookie" +version = "=0.18.1" +features = ["percent-encode"] + +[dependencies.cookie_store] +package = "cookie_store" +version = "=0.22.1" + +[dependencies.cpufeatures] +package = "cpufeatures" +version = "=0.3.0" + +[dependencies.crc32fast] +package = "crc32fast" +version = "=1.5.0" + +[dependencies.crossbeam] +package = "crossbeam" +version = "=0.8.4" + +[dependencies.crossbeam_channel] +package = "crossbeam-channel" +version = "=0.5.15" +default-features = false + +[dependencies.crossbeam_deque] +package = "crossbeam-deque" +version = "=0.8.6" + +[dependencies.crossbeam_epoch] +package = "crossbeam-epoch" +version = "=0.9.18" +default-features = false + +[dependencies.crossbeam_queue] +package = "crossbeam-queue" +version = "=0.3.12" +default-features = false + +[dependencies.crossbeam_utils] +package = "crossbeam-utils" +version = "=0.8.21" + +[dependencies.crypto_common] +package = "crypto-common" +version = "=0.2.2" + +[dependencies.crypto_common_0_1_7] +package = "crypto-common" +version = "=0.1.7" + +[dependencies.cssparser] +package = "cssparser" +version = "=0.31.2" + +[dependencies.cssparser_macros] +package = "cssparser-macros" +version = "=0.6.1" + +[dependencies.csv] +package = "csv" +version = "=1.4.0" + +[dependencies.csv_core] +package = "csv-core" +version = "=0.1.13" + +[dependencies.ctutils] +package = "ctutils" +version = "=0.4.2" + +[dependencies.data_encoding] +package = "data-encoding" +version = "=2.11.0" + +[dependencies.debug_unreachable] +package = "new_debug_unreachable" +version = "=1.0.6" + +[dependencies.deranged] +package = "deranged" +version = "=0.5.8" +features = ["powerfmt"] + +[dependencies.derive_more] +package = "derive_more" +version = "=2.1.1" +features = ["debug", "full", "std"] + +[dependencies.derive_more_0_99_20] +package = "derive_more" +version = "=0.99.20" +features = ["add", "add_assign"] +default-features = false + +[dependencies.derive_more_impl] +package = "derive_more-impl" +version = "=2.1.1" + +[dependencies.destructure_traitobject] +package = "destructure_traitobject" +version = "=0.2.0" + +[dependencies.digest] +package = "digest" +version = "=0.11.3" +features = ["mac"] + +[dependencies.digest_0_10_7] +package = "digest" +version = "=0.10.7" + +[dependencies.displaydoc] +package = "displaydoc" +version = "=0.2.6" +default-features = false + +[dependencies.document_features] +package = "document-features" +version = "=0.2.12" + +[dependencies.dtoa] +package = "dtoa" +version = "=1.0.11" + +[dependencies.dtoa_short] +package = "dtoa-short" +version = "=0.3.5" + +[dependencies.dunce] +package = "dunce" +version = "=1.0.5" + +[dependencies.ego_tree] +package = "ego-tree" +version = "=0.6.3" + +[dependencies.either] +package = "either" +version = "=1.16.0" +features = ["serde"] + +[dependencies.encoding_rs] +package = "encoding_rs" +version = "=0.8.35" + +[dependencies.env_filter] +package = "env_filter" +version = "=1.0.1" +default-features = false + +[dependencies.env_logger] +package = "env_logger" +version = "=0.11.10" + +[dependencies.equator] +package = "equator" +version = "=0.4.2" + +[dependencies.equator_macro] +package = "equator-macro" +version = "=0.4.2" + +[dependencies.equivalent] +package = "equivalent" +version = "=1.0.2" +default-features = false + +[dependencies.errno] +package = "errno" +version = "=0.3.14" + +[dependencies.exr] +package = "exr" +version = "=1.74.0" +default-features = false + +[dependencies.fallible_iterator] +package = "fallible-iterator" +version = "=0.3.0" + +[dependencies.fallible_iterator_0_2_0] +package = "fallible-iterator" +version = "=0.2.0" + +[dependencies.fallible_streaming_iterator] +package = "fallible-streaming-iterator" +version = "=0.1.9" + +[dependencies.faster_hex] +package = "faster-hex" +version = "=0.10.0" +default-features = false + +[dependencies.fastrand] +package = "fastrand" +version = "=2.4.1" + +[dependencies.fax] +package = "fax" +version = "=0.2.7" + +[dependencies.fdeflate] +package = "fdeflate" +version = "=0.3.7" + +[dependencies.filetime] +package = "filetime" +version = "=0.2.29" + +[dependencies.find_msvc_tools] +package = "find-msvc-tools" +version = "=0.1.9" + +[dependencies.fixedbitset] +package = "fixedbitset" +version = "=0.5.7" +default-features = false + +[dependencies.fixedbitset_0_4_2] +package = "fixedbitset" +version = "=0.4.2" +default-features = false + +[dependencies.flate2] +package = "flate2" +version = "=1.1.9" + +[dependencies.fnv] +package = "fnv" +version = "=1.0.7" + +[dependencies.foldhash] +package = "foldhash" +version = "=0.2.0" +default-features = false + +[dependencies.foldhash_0_1_5] +package = "foldhash" +version = "=0.1.5" +default-features = false + +[dependencies.form_urlencoded] +package = "form_urlencoded" +version = "=1.2.2" +features = ["alloc"] + +[dependencies.fs_extra] +package = "fs_extra" +version = "=1.3.0" + +[dependencies.funty] +package = "funty" +version = "=2.0.0" +default-features = false + +[dependencies.futf] +package = "futf" +version = "=0.1.5" + +[dependencies.futures] +package = "futures" +version = "=0.3.32" +features = ["async-await", "compat", "executor", "io-compat", "std", "thread-pool"] + +[dependencies.futures_0_1_31] +package = "futures" +version = "=0.1.31" + +[dependencies.futures_channel] +package = "futures-channel" +version = "=0.3.32" +features = ["sink", "std"] + +[dependencies.futures_core] +package = "futures-core" +version = "=0.3.32" + +[dependencies.futures_executor] +package = "futures-executor" +version = "=0.3.32" +default-features = false + +[dependencies.futures_io] +package = "futures-io" +version = "=0.3.32" +features = ["std"] + +[dependencies.futures_macro] +package = "futures-macro" +version = "=0.3.32" +default-features = false + +[dependencies.futures_sink] +package = "futures-sink" +version = "=0.3.32" + +[dependencies.futures_task] +package = "futures-task" +version = "=0.3.32" +default-features = false + +[dependencies.futures_util] +package = "futures-util" +version = "=0.3.32" +features = ["alloc", "sink"] + +[dependencies.fxhash] +package = "fxhash" +version = "=0.2.1" + +[dependencies.generic_array] +package = "generic-array" +version = "=1.4.3" +features = ["alloc", "arbitrary", "as_slice", "bitvec", "bytecheck-0_8", "bytemuck", "compat-0_14", "const-default", "faster-hex", "hybrid-array-0_4", "internals", "rkyv-0_8", "rkyv-0_8-full", "serde", "subtle", "zeroize"] + +[dependencies.generic_array_0_14_7] +package = "generic-array" +version = "=0.14.7" +features = ["more_lengths"] + +[dependencies.getopts] +package = "getopts" +version = "=0.2.24" + +[dependencies.getrandom] +package = "getrandom" +version = "=0.4.2" + +[dependencies.getrandom_0_2_17] +package = "getrandom" +version = "=0.2.17" + +[dependencies.getrandom_0_3_4] +package = "getrandom" +version = "=0.3.4" + +[dependencies.gif] +package = "gif" +version = "=0.14.2" + +[dependencies.gimli] +package = "gimli" +version = "=0.32.3" +features = ["read"] +default-features = false + +[dependencies.glob] +package = "glob" +version = "=0.3.3" + +[dependencies.h2] +package = "h2" +version = "=0.4.14" + +[dependencies.half] +package = "half" +version = "=2.7.1" + +[dependencies.hash32] +package = "hash32" +version = "=0.3.1" + +[dependencies.hashbrown] +package = "hashbrown" +version = "=0.17.1" +default-features = false + +[dependencies.hashbrown_0_15_5] +package = "hashbrown" +version = "=0.15.5" +features = ["default-hasher", "inline-more"] +default-features = false + +[dependencies.hashbrown_0_16_1] +package = "hashbrown" +version = "=0.16.1" +features = ["default-hasher"] +default-features = false + +[dependencies.hashlink] +package = "hashlink" +version = "=0.11.0" + +[dependencies.hdrhistogram] +package = "hdrhistogram" +version = "=7.5.4" +default-features = false + +[dependencies.heapless] +package = "heapless" +version = "=0.8.0" + +[dependencies.heck] +package = "heck" +version = "=0.5.0" + +[dependencies.hmac] +package = "hmac" +version = "=0.13.0" + +[dependencies.html5ever] +package = "html5ever" +version = "=0.27.0" + +[dependencies.html5ever_0_26_0] +package = "html5ever" +version = "=0.26.0" + +[dependencies.http] +package = "http" +version = "=1.4.1" + +[dependencies.http_body] +package = "http-body" +version = "=1.0.1" + +[dependencies.http_body_util] +package = "http-body-util" +version = "=0.1.3" + +[dependencies.http_range_header] +package = "http-range-header" +version = "=0.4.2" + +[dependencies.httparse] +package = "httparse" +version = "=1.10.1" + +[dependencies.httpdate] +package = "httpdate" +version = "=1.0.3" + +[dependencies.humantime] +package = "humantime" +version = "=2.3.0" + +[dependencies.hybrid_array] +package = "hybrid-array" +version = "=0.4.12" + +[dependencies.hyper] +package = "hyper" +version = "=1.10.1" +features = ["client", "full", "http1"] + +[dependencies.hyper_rustls] +package = "hyper-rustls" +version = "=0.27.9" +features = ["http1", "tls12"] +default-features = false + +[dependencies.hyper_util] +package = "hyper-util" +version = "=0.1.20" +features = ["client", "client-legacy", "client-proxy", "http1", "tokio"] + +[dependencies.iana_time_zone] +package = "iana-time-zone" +version = "=0.1.65" +features = ["fallback"] + +[dependencies.icu_collections] +package = "icu_collections" +version = "=2.2.0" +default-features = false + +[dependencies.icu_locale_core] +package = "icu_locale_core" +version = "=2.2.0" +features = ["zerovec"] +default-features = false + +[dependencies.icu_normalizer] +package = "icu_normalizer" +version = "=2.2.0" +default-features = false + +[dependencies.icu_normalizer_data] +package = "icu_normalizer_data" +version = "=2.2.0" +default-features = false + +[dependencies.icu_properties] +package = "icu_properties" +version = "=2.2.0" +default-features = false + +[dependencies.icu_properties_data] +package = "icu_properties_data" +version = "=2.2.0" +default-features = false + +[dependencies.icu_provider] +package = "icu_provider" +version = "=2.2.0" +default-features = false + +[dependencies.idna] +package = "idna" +version = "=1.1.0" +features = ["alloc", "compiled_data"] + +[dependencies.idna_adapter] +package = "idna_adapter" +version = "=1.2.2" + +[dependencies.image] +package = "image" +version = "=0.25.10" + +[dependencies.image_webp] +package = "image-webp" +version = "=0.2.4" + +[dependencies.imgref] +package = "imgref" +version = "=1.12.1" + +[dependencies.indexmap] +package = "indexmap" +version = "=2.14.0" +features = ["std"] + +[dependencies.iovec] +package = "iovec" +version = "=0.1.4" + +[dependencies.ipnet] +package = "ipnet" +version = "=2.12.0" + +[dependencies.is_terminal_polyfill] +package = "is_terminal_polyfill" +version = "=1.70.2" + +[dependencies.itertools] +package = "itertools" +version = "=0.14.0" + +[dependencies.itoa] +package = "itoa" +version = "=1.0.18" + +[dependencies.jiff] +package = "jiff" +version = "=0.2.28" +features = ["logging", "serde", "static", "std", "tzdb-bundle-always"] + +[dependencies.jiff_static] +package = "jiff-static" +version = "=0.2.28" + +[dependencies.jiff_tzdb] +package = "jiff-tzdb" +version = "=0.1.6" + +[dependencies.jobserver] +package = "jobserver" +version = "=0.1.34" +default-features = false + +[dependencies.lazy_static] +package = "lazy_static" +version = "=1.5.0" + +[dependencies.lebe] +package = "lebe" +version = "=0.5.3" + +[dependencies.libc] +package = "libc" +version = "=0.2.186" + +[dependencies.libm] +package = "libm" +version = "=0.2.16" + +[dependencies.libsqlite3_sys] +package = "libsqlite3-sys" +version = "=0.38.0" + +[dependencies.linux_raw_sys] +package = "linux-raw-sys" +version = "=0.12.1" +features = ["auxvec", "elf", "errno", "general", "ioctl", "no_std"] +default-features = false + +[dependencies.litemap] +package = "litemap" +version = "=0.8.2" +default-features = false + +[dependencies.litrs] +package = "litrs" +version = "=1.0.0" + +[dependencies.lock_api] +package = "lock_api" +version = "=0.4.14" + +[dependencies.log] +package = "log" +version = "=0.4.31" +features = ["std"] + +[dependencies.log4rs] +package = "log4rs" +version = "=1.4.0" + +[dependencies.log_mdc] +package = "log-mdc" +version = "=0.1.0" + +[dependencies.loop9] +package = "loop9" +version = "=0.1.5" + +[dependencies.mac] +package = "mac" +version = "=0.1.1" + +[dependencies.markup5ever] +package = "markup5ever" +version = "=0.12.1" + +[dependencies.markup5ever_0_11_0] +package = "markup5ever" +version = "=0.11.0" + +[dependencies.markup5ever_rcdom] +package = "markup5ever_rcdom" +version = "=0.2.0" + +[dependencies.matrixmultiply] +package = "matrixmultiply" +version = "=0.3.10" +features = ["cgemm"] + +[dependencies.maybe_rayon] +package = "maybe-rayon" +version = "=0.1.1" +default-features = false + +[dependencies.md5] +package = "md-5" +version = "=0.11.0" + +[dependencies.md5_0_10_6] +package = "md-5" +version = "=0.10.6" +default-features = false + +[dependencies.memchr] +package = "memchr" +version = "=2.8.1" + +[dependencies.memmap] +package = "memmap" +version = "=0.7.0" + +[dependencies.mime] +package = "mime" +version = "=0.3.17" + +[dependencies.mime_guess] +package = "mime_guess" +version = "=2.0.5" +default-features = false + +[dependencies.miniz_oxide] +package = "miniz_oxide" +version = "=0.9.1" + +[dependencies.miniz_oxide_0_8_9] +package = "miniz_oxide" +version = "=0.8.9" +features = ["simd", "with-alloc"] + +[dependencies.mio] +package = "mio" +version = "=1.2.1" +features = ["net", "os-ext", "os-poll"] + +[dependencies.mock_instant] +package = "mock_instant" +version = "=0.6.0" + +[dependencies.moxcms] +package = "moxcms" +version = "=0.8.1" + +[dependencies.munge] +package = "munge" +version = "=0.4.7" +default-features = false + +[dependencies.munge_macro] +package = "munge_macro" +version = "=0.4.7" +default-features = false + +[dependencies.nalgebra] +package = "nalgebra" +version = "=0.35.0" + +[dependencies.nalgebra_macros] +package = "nalgebra-macros" +version = "=0.3.0" + +[dependencies.ndarray] +package = "ndarray" +version = "=0.17.2" + +[dependencies.no_std_io2] +package = "no_std_io2" +version = "=0.9.4" + +[dependencies.nom] +package = "nom" +version = "=8.0.0" + +[dependencies.noop_proc_macro] +package = "noop_proc_macro" +version = "=0.3.0" + +[dependencies.nu_ansi_term] +package = "nu-ansi-term" +version = "=0.50.3" + +[dependencies.num] +package = "num" +version = "=0.4.3" + +[dependencies.num_bigint] +package = "num-bigint" +version = "=0.4.6" +default-features = false + +[dependencies.num_complex] +package = "num-complex" +version = "=0.4.6" +default-features = false + +[dependencies.num_conv] +package = "num-conv" +version = "=0.2.2" + +[dependencies.num_cpus] +package = "num_cpus" +version = "=1.17.0" + +[dependencies.num_derive] +package = "num-derive" +version = "=0.4.2" + +[dependencies.num_integer] +package = "num-integer" +version = "=0.1.46" +features = ["i128"] +default-features = false + +[dependencies.num_iter] +package = "num-iter" +version = "=0.1.45" +features = ["i128"] +default-features = false + +[dependencies.num_rational] +package = "num-rational" +version = "=0.4.2" + +[dependencies.num_traits] +package = "num-traits" +version = "=0.2.19" +features = ["i128", "libm"] + +[dependencies.object] +package = "object" +version = "=0.37.3" +features = ["archive", "elf", "macho", "pe", "read_core", "unaligned", "xcoff"] +default-features = false + +[dependencies.once_cell] +package = "once_cell" +version = "=1.21.4" +features = ["alloc", "race", "std"] + +[dependencies.openssl_probe] +package = "openssl-probe" +version = "=0.2.1" + +[dependencies.ordered_float] +package = "ordered-float" +version = "=2.10.1" + +[dependencies.parking_lot] +package = "parking_lot" +version = "=0.12.5" +features = ["arc_lock", "deadlock_detection", "serde"] + +[dependencies.parking_lot_core] +package = "parking_lot_core" +version = "=0.9.12" + +[dependencies.paste] +package = "paste" +version = "=1.0.15" + +[dependencies.pastey] +package = "pastey" +version = "=0.1.1" + +[dependencies.percent_encoding] +package = "percent-encoding" +version = "=2.3.2" +features = ["alloc"] + +[dependencies.petgraph] +package = "petgraph" +version = "=0.8.3" + +[dependencies.petgraph_0_6_5] +package = "petgraph" +version = "=0.6.5" + +[dependencies.phf] +package = "phf" +version = "=0.13.1" +features = ["macros"] + +[dependencies.phf_0_10_1] +package = "phf" +version = "=0.10.1" + +[dependencies.phf_0_11_3] +package = "phf" +version = "=0.11.3" +features = ["macros"] + +[dependencies.phf_codegen] +package = "phf_codegen" +version = "=0.11.3" + +[dependencies.phf_codegen_0_10_0] +package = "phf_codegen" +version = "=0.10.0" + +[dependencies.phf_generator] +package = "phf_generator" +version = "=0.13.1" + +[dependencies.phf_generator_0_10_0] +package = "phf_generator" +version = "=0.10.0" + +[dependencies.phf_generator_0_11_3] +package = "phf_generator" +version = "=0.11.3" + +[dependencies.phf_macros] +package = "phf_macros" +version = "=0.13.1" + +[dependencies.phf_macros_0_11_3] +package = "phf_macros" +version = "=0.11.3" + +[dependencies.phf_shared] +package = "phf_shared" +version = "=0.13.1" +default-features = false + +[dependencies.phf_shared_0_10_0] +package = "phf_shared" +version = "=0.10.0" + +[dependencies.phf_shared_0_11_3] +package = "phf_shared" +version = "=0.11.3" + +[dependencies.pin_project_lite] +package = "pin-project-lite" +version = "=0.2.17" + +[dependencies.pkg_config] +package = "pkg-config" +version = "=0.3.33" + +[dependencies.png] +package = "png" +version = "=0.18.1" + +[dependencies.postgres] +package = "postgres" +version = "=0.19.13" + +[dependencies.postgres_protocol] +package = "postgres-protocol" +version = "=0.6.11" + +[dependencies.postgres_types] +package = "postgres-types" +version = "=0.2.13" + +[dependencies.potential_utf] +package = "potential_utf" +version = "=0.1.5" +features = ["zerovec"] +default-features = false + +[dependencies.powerfmt] +package = "powerfmt" +version = "=0.2.0" +default-features = false + +[dependencies.ppv_lite86] +package = "ppv-lite86" +version = "=0.2.21" +features = ["simd"] +default-features = false + +[dependencies.precomputed_hash] +package = "precomputed-hash" +version = "=0.1.1" + +[dependencies.proc_macro2] +package = "proc-macro2" +version = "=1.0.106" +features = ["proc-macro", "span-locations"] + +[dependencies.profiling] +package = "profiling" +version = "=1.0.18" + +[dependencies.profiling_procmacros] +package = "profiling-procmacros" +version = "=1.0.18" + +[dependencies.psl_types] +package = "psl-types" +version = "=2.0.11" + +[dependencies.ptr_meta] +package = "ptr_meta" +version = "=0.3.1" +features = ["derive"] +default-features = false + +[dependencies.ptr_meta_derive] +package = "ptr_meta_derive" +version = "=0.3.1" +default-features = false + +[dependencies.publicsuffix] +package = "publicsuffix" +version = "=2.3.0" + +[dependencies.pxfm] +package = "pxfm" +version = "=0.1.29" + +[dependencies.qoi] +package = "qoi" +version = "=0.4.1" + +[dependencies.quick_error] +package = "quick-error" +version = "=2.0.1" + +[dependencies.quote] +package = "quote" +version = "=1.0.45" +features = ["proc-macro"] + +[dependencies.radium] +package = "radium" +version = "=0.7.0" + +[dependencies.rancor] +package = "rancor" +version = "=0.1.1" +default-features = false + +[dependencies.rand] +package = "rand" +version = "=0.10.1" +features = ["serde"] + +[dependencies.rand_0_8_6] +package = "rand" +version = "=0.8.6" +features = ["serde1", "small_rng"] + +[dependencies.rand_0_9_4] +package = "rand" +version = "=0.9.4" +features = ["serde", "small_rng"] + +[dependencies.rand_chacha] +package = "rand_chacha" +version = "=0.10.0" + +[dependencies.rand_chacha_0_3_1] +package = "rand_chacha" +version = "=0.3.1" +default-features = false + +[dependencies.rand_chacha_0_9_0] +package = "rand_chacha" +version = "=0.9.0" +default-features = false + +[dependencies.rand_core] +package = "rand_core" +version = "=0.10.1" + +[dependencies.rand_core_0_6_4] +package = "rand_core" +version = "=0.6.4" +features = ["alloc", "getrandom", "serde", "serde1", "std"] + +[dependencies.rand_core_0_9_5] +package = "rand_core" +version = "=0.9.5" +features = ["os_rng", "serde", "std"] + +[dependencies.rand_distr] +package = "rand_distr" +version = "=0.6.0" + +[dependencies.rav1e] +package = "rav1e" +version = "=0.8.1" +default-features = false + +[dependencies.ravif] +package = "ravif" +version = "=0.13.0" +default-features = false + +[dependencies.rawpointer] +package = "rawpointer" +version = "=0.2.1" + +[dependencies.rayon] +package = "rayon" +version = "=1.12.0" + +[dependencies.rayon_core] +package = "rayon-core" +version = "=1.13.0" + +[dependencies.regex] +package = "regex" +version = "=1.12.3" +features = ["perf", "std"] +default-features = false + +[dependencies.regex_automata] +package = "regex-automata" +version = "=0.4.14" +features = ["alloc", "meta", "nfa-pikevm", "syntax"] +default-features = false + +[dependencies.regex_syntax] +package = "regex-syntax" +version = "=0.8.10" +default-features = false + +[dependencies.rend] +package = "rend" +version = "=0.5.3" +default-features = false + +[dependencies.reqwest] +package = "reqwest" +version = "=0.13.4" +features = ["blocking", "cookies", "form", "json", "multipart", "query"] + +[dependencies.reqwest_0_12_28] +package = "reqwest" +version = "=0.12.28" +features = ["blocking", "cookies", "json", "multipart", "rustls-tls"] + +[dependencies.rgb] +package = "rgb" +version = "=0.8.53" +default-features = false + +[dependencies.ring] +package = "ring" +version = "=0.17.14" + +[dependencies.rkyv] +package = "rkyv" +version = "=0.8.16" +default-features = false + +[dependencies.rkyv_derive] +package = "rkyv_derive" +version = "=0.8.16" +default-features = false + +[dependencies.rusqlite] +package = "rusqlite" +version = "=0.40.0" +features = ["bundled-full"] + +[dependencies.rustc_demangle] +package = "rustc-demangle" +version = "=0.1.27" + +[dependencies.rustc_version] +package = "rustc_version" +version = "=0.4.1" + +[dependencies.rustix] +package = "rustix" +version = "=1.1.4" +features = ["fs", "std", "termios"] + +[dependencies.rustls] +package = "rustls" +version = "=0.23.40" +features = ["std", "tls12"] +default-features = false + +[dependencies.rustls_native_certs] +package = "rustls-native-certs" +version = "=0.8.4" + +[dependencies.rustls_pki_types] +package = "rustls-pki-types" +version = "=1.14.1" +features = ["alloc", "std"] + +[dependencies.rustls_platform_verifier] +package = "rustls-platform-verifier" +version = "=0.7.0" + +[dependencies.rustversion] +package = "rustversion" +version = "=1.0.22" + +[dependencies.ryu] +package = "ryu" +version = "=1.0.23" + +[dependencies.safe_arch] +package = "safe_arch" +version = "=1.0.0" +features = ["bytemuck"] + +[dependencies.same_file] +package = "same-file" +version = "=1.0.6" + +[dependencies.scopeguard] +package = "scopeguard" +version = "=1.2.0" +default-features = false + +[dependencies.scraper] +package = "scraper" +version = "=0.20.0" + +[dependencies.select] +package = "select" +version = "=0.6.1" + +[dependencies.selectors] +package = "selectors" +version = "=0.25.0" + +[dependencies.semver] +package = "semver" +version = "=1.0.28" +features = ["serde"] + +[dependencies.serde] +package = "serde" +version = "=1.0.228" +features = ["alloc", "derive", "rc"] + +[dependencies.serde_core] +package = "serde_core" +version = "=1.0.228" +features = ["alloc", "rc", "result"] + +[dependencies.serde_derive] +package = "serde_derive" +version = "=1.0.228" + +[dependencies.serde_json] +package = "serde_json" +version = "=1.0.150" +features = ["float_roundtrip", "raw_value", "unbounded_depth"] + +[dependencies.serde_spanned] +package = "serde_spanned" +version = "=1.1.1" +features = ["alloc"] +default-features = false + +[dependencies.serde_urlencoded] +package = "serde_urlencoded" +version = "=0.7.1" + +[dependencies.serde_value] +package = "serde-value" +version = "=0.7.0" + +[dependencies.serde_yaml] +package = "serde_yaml" +version = "=0.9.34" + +[dependencies.servo_arc] +package = "servo_arc" +version = "=0.3.0" + +[dependencies.sha1_smol] +package = "sha1_smol" +version = "=1.0.1" +default-features = false + +[dependencies.sha2] +package = "sha2" +version = "=0.11.0" + +[dependencies.sharded_slab] +package = "sharded-slab" +version = "=0.1.7" + +[dependencies.shlex] +package = "shlex" +version = "=2.0.1" + +[dependencies.signal_hook_registry] +package = "signal-hook-registry" +version = "=1.4.8" + +[dependencies.simba] +package = "simba" +version = "=0.10.0" +default-features = false + +[dependencies.simd_adler32] +package = "simd-adler32" +version = "=0.3.9" + +[dependencies.simd_helpers] +package = "simd_helpers" +version = "=0.1.0" + +[dependencies.siphasher] +package = "siphasher" +version = "=1.0.3" + +[dependencies.siphasher_0_3_11] +package = "siphasher" +version = "=0.3.11" + +[dependencies.slab] +package = "slab" +version = "=0.4.12" + +[dependencies.smallvec] +package = "smallvec" +version = "=1.15.1" +features = ["const_generics", "const_new"] + +[dependencies.socket2] +package = "socket2" +version = "=0.6.4" +features = ["all"] + +[dependencies.sptr] +package = "sptr" +version = "=0.3.2" + +[dependencies.stable_deref_trait] +package = "stable_deref_trait" +version = "=1.2.1" + +[dependencies.string_cache] +package = "string_cache" +version = "=0.8.9" + +[dependencies.string_cache_codegen] +package = "string_cache_codegen" +version = "=0.5.4" + +[dependencies.stringprep] +package = "stringprep" +version = "=0.1.5" + +[dependencies.strsim] +package = "strsim" +version = "=0.11.1" + +[dependencies.subtle] +package = "subtle" +version = "=2.6.1" +default-features = false + +[dependencies.syn] +package = "syn" +version = "=2.0.117" +features = ["clone-impls", "derive", "extra-traits", "fold", "full", "parsing", "printing", "proc-macro", "visit", "visit-mut"] + +[dependencies.syn_1_0_109] +package = "syn" +version = "=1.0.109" +features = ["extra-traits", "fold", "full", "visit", "visit-mut"] + +[dependencies.sync_wrapper] +package = "sync_wrapper" +version = "=1.0.2" +features = ["futures"] + +[dependencies.synstructure] +package = "synstructure" +version = "=0.13.2" + +[dependencies.tap] +package = "tap" +version = "=1.0.1" + +[dependencies.tar] +package = "tar" +version = "=0.4.46" + +[dependencies.tempfile] +package = "tempfile" +version = "=3.27.0" + +[dependencies.tendril] +package = "tendril" +version = "=0.4.3" + +[dependencies.terminal_size] +package = "terminal_size" +version = "=0.4.4" + +[dependencies.thiserror] +package = "thiserror" +version = "=2.0.18" + +[dependencies.thiserror_impl] +package = "thiserror-impl" +version = "=2.0.18" + +[dependencies.thread_id] +package = "thread-id" +version = "=5.1.0" + +[dependencies.thread_local] +package = "thread_local" +version = "=1.1.9" + +[dependencies.threadpool] +package = "threadpool" +version = "=1.8.1" + +[dependencies.tiff] +package = "tiff" +version = "=0.11.3" + +[dependencies.time] +package = "time" +version = "=0.3.47" +features = ["formatting", "macros", "parsing", "std"] + +[dependencies.time_core] +package = "time-core" +version = "=0.1.8" + +[dependencies.time_macros] +package = "time-macros" +version = "=0.2.27" + +[dependencies.tinystr] +package = "tinystr" +version = "=0.8.3" +default-features = false + +[dependencies.tinyvec] +package = "tinyvec" +version = "=1.11.0" +features = ["alloc", "borsh", "grab_spare_slice", "latest_stable_rust", "serde", "std"] + +[dependencies.tinyvec_macros] +package = "tinyvec_macros" +version = "=0.1.1" + +[dependencies.tokio] +package = "tokio" +version = "=1.52.3" +features = ["fs", "full", "io-util", "net", "rt", "rt-multi-thread", "sync", "test-util", "time"] + +[dependencies.tokio_io] +package = "tokio-io" +version = "=0.1.13" + +[dependencies.tokio_macros] +package = "tokio-macros" +version = "=2.7.0" + +[dependencies.tokio_postgres] +package = "tokio-postgres" +version = "=0.7.17" + +[dependencies.tokio_rustls] +package = "tokio-rustls" +version = "=0.26.4" +features = ["tls12"] +default-features = false + +[dependencies.tokio_stream] +package = "tokio-stream" +version = "=0.1.18" + +[dependencies.tokio_util] +package = "tokio-util" +version = "=0.7.18" +features = ["codec", "full", "io"] + +[dependencies.toml] +package = "toml" +version = "=1.1.2" + +[dependencies.toml_datetime] +package = "toml_datetime" +version = "=1.1.1" +features = ["alloc"] +default-features = false + +[dependencies.toml_parser] +package = "toml_parser" +version = "=1.1.2" +features = ["alloc"] +default-features = false + +[dependencies.toml_writer] +package = "toml_writer" +version = "=1.1.1" +features = ["alloc"] +default-features = false + +[dependencies.tower] +package = "tower" +version = "=0.5.3" +features = ["full", "retry", "timeout", "util"] + +[dependencies.tower_http] +package = "tower-http" +version = "=0.6.11" +features = ["follow-redirect", "full"] + +[dependencies.tower_layer] +package = "tower-layer" +version = "=0.3.3" + +[dependencies.tower_service] +package = "tower-service" +version = "=0.3.3" + +[dependencies.tracing] +package = "tracing" +version = "=0.1.44" +features = ["std"] +default-features = false + +[dependencies.tracing_attributes] +package = "tracing-attributes" +version = "=0.1.31" + +[dependencies.tracing_core] +package = "tracing-core" +version = "=0.1.36" + +[dependencies.tracing_log] +package = "tracing-log" +version = "=0.2.0" +features = ["log-tracer", "std"] +default-features = false + +[dependencies.tracing_subscriber] +package = "tracing-subscriber" +version = "=0.3.23" + +[dependencies.trpl] +package = "trpl" +version = "=0.3.0" + +[dependencies.try_lock] +package = "try-lock" +version = "=0.2.5" + +[dependencies.typemap_ors] +package = "typemap-ors" +version = "=1.0.0" + +[dependencies.typenum] +package = "typenum" +version = "=1.20.1" +features = ["const-generics", "i128"] + +[dependencies.unicase] +package = "unicase" +version = "=2.9.0" + +[dependencies.unicode_bidi] +package = "unicode-bidi" +version = "=0.3.18" + +[dependencies.unicode_ident] +package = "unicode-ident" +version = "=1.0.24" + +[dependencies.unicode_normalization] +package = "unicode-normalization" +version = "=0.1.25" + +[dependencies.unicode_properties] +package = "unicode-properties" +version = "=0.1.4" + +[dependencies.unicode_segmentation] +package = "unicode-segmentation" +version = "=1.13.3" + +[dependencies.unicode_width] +package = "unicode-width" +version = "=0.2.2" + +[dependencies.unicode_xid] +package = "unicode-xid" +version = "=0.2.6" + +[dependencies.unsafe_any_ors] +package = "unsafe-any-ors" +version = "=1.0.0" + +[dependencies.unsafe_libyaml] +package = "unsafe-libyaml" +version = "=0.2.11" + +[dependencies.untrusted] +package = "untrusted" +version = "=0.9.0" + +[dependencies.url] +package = "url" +version = "=2.5.8" +features = ["serde"] + +[dependencies.utf8] +package = "utf-8" +version = "=0.7.6" + +[dependencies.utf8_iter] +package = "utf8_iter" +version = "=1.0.4" + +[dependencies.utf8parse] +package = "utf8parse" +version = "=0.2.2" + +[dependencies.uuid] +package = "uuid" +version = "=1.23.2" +features = ["serde", "v1", "v3", "v4", "v5", "v6", "v7", "v8"] + +[dependencies.v_frame] +package = "v_frame" +version = "=0.3.9" + +[dependencies.vcpkg] +package = "vcpkg" +version = "=0.2.15" + +[dependencies.version_check] +package = "version_check" +version = "=0.9.5" + +[dependencies.walkdir] +package = "walkdir" +version = "=2.5.0" + +[dependencies.want] +package = "want" +version = "=0.3.1" + +[dependencies.wasm_bindgen] +package = "wasm-bindgen" +version = "=0.2.122" + +[dependencies.wasm_bindgen_macro] +package = "wasm-bindgen-macro" +version = "=0.2.122" + +[dependencies.wasm_bindgen_macro_support] +package = "wasm-bindgen-macro-support" +version = "=0.2.122" + +[dependencies.wasm_bindgen_shared] +package = "wasm-bindgen-shared" +version = "=0.2.122" + +[dependencies.webpki] +package = "rustls-webpki" +version = "=0.103.13" +features = ["alloc"] +default-features = false + +[dependencies.webpki_roots] +package = "webpki-roots" +version = "=1.0.7" + +[dependencies.weezl] +package = "weezl" +version = "=0.1.12" + +[dependencies.whoami] +package = "whoami" +version = "=2.1.2" + +[dependencies.wide] +package = "wide" +version = "=1.4.0" +default-features = false + +[dependencies.windows_aarch64_gnullvm] +package = "windows_aarch64_gnullvm" +version = "=0.53.1" + +[dependencies.windows_aarch64_msvc] +package = "windows_aarch64_msvc" +version = "=0.53.1" + +[dependencies.windows_i686_gnu] +package = "windows_i686_gnu" +version = "=0.53.1" + +[dependencies.windows_i686_msvc] +package = "windows_i686_msvc" +version = "=0.53.1" + +[dependencies.windows_link] +package = "windows-link" +version = "=0.2.1" +default-features = false + +[dependencies.windows_sys] +package = "windows-sys" +version = "=0.61.2" + +[dependencies.windows_targets] +package = "windows-targets" +version = "=0.53.5" +default-features = false + +[dependencies.windows_targets_0_52_6] +package = "windows-targets" +version = "=0.52.6" + +[dependencies.windows_x86_64_gnu] +package = "windows_x86_64_gnu" +version = "=0.53.1" + +[dependencies.windows_x86_64_gnu_0_52_6] +package = "windows_x86_64_gnu" +version = "=0.52.6" + +[dependencies.windows_x86_64_gnullvm] +package = "windows_x86_64_gnullvm" +version = "=0.53.1" + +[dependencies.windows_x86_64_msvc] +package = "windows_x86_64_msvc" +version = "=0.53.1" + +[dependencies.winnow] +package = "winnow" +version = "=1.0.3" +default-features = false + +[dependencies.writeable] +package = "writeable" +version = "=0.6.3" +default-features = false + +[dependencies.wyz] +package = "wyz" +version = "=0.5.1" +default-features = false + +[dependencies.xattr] +package = "xattr" +version = "=1.6.1" + +[dependencies.xml5ever] +package = "xml5ever" +version = "=0.17.0" + +[dependencies.y4m] +package = "y4m" +version = "=0.8.0" + +[dependencies.yoke] +package = "yoke" +version = "=0.8.2" +features = ["derive"] +default-features = false + +[dependencies.yoke_derive] +package = "yoke-derive" +version = "=0.8.2" +default-features = false + +[dependencies.zerocopy] +package = "zerocopy" +version = "=0.8.50" +features = ["__internal_use_only_features_that_work_on_stable", "derive", "simd"] + +[dependencies.zerocopy_derive] +package = "zerocopy-derive" +version = "=0.8.50" + +[dependencies.zerofrom] +package = "zerofrom" +version = "=0.1.8" +features = ["alloc", "derive"] + +[dependencies.zerofrom_derive] +package = "zerofrom-derive" +version = "=0.1.7" +default-features = false + +[dependencies.zeroize] +package = "zeroize" +version = "=1.8.2" + +[dependencies.zerotrie] +package = "zerotrie" +version = "=0.2.4" +features = ["yoke", "zerofrom"] +default-features = false + +[dependencies.zerovec] +package = "zerovec" +version = "=0.11.6" +features = ["derive", "yoke"] +default-features = false + +[dependencies.zerovec_derive] +package = "zerovec-derive" +version = "=0.11.3" +default-features = false + +[dependencies.zmij] +package = "zmij" +version = "=1.0.21" + +[dependencies.zstd] +package = "zstd" +version = "=0.13.3" +default-features = false + +[dependencies.zstd_safe] +package = "zstd-safe" +version = "=7.2.4" +features = ["std"] +default-features = false + +[dependencies.zstd_sys] +package = "zstd-sys" +version = "=2.0.16" +default-features = false + +[dependencies.zune_core] +package = "zune-core" +version = "=0.5.1" + +[dependencies.zune_inflate] +package = "zune-inflate" +version = "=0.2.54" +features = ["zlib"] +default-features = false + +[dependencies.zune_jpeg] +package = "zune-jpeg" +version = "=0.5.15" + +[build-dependencies.addr2line] +package = "addr2line" +version = "=0.25.1" +default-features = false + +[build-dependencies.adler2] +package = "adler2" +version = "=2.0.1" +default-features = false + +[build-dependencies.ahash] +package = "ahash" +version = "=0.8.12" + +[build-dependencies.aho_corasick] +package = "aho-corasick" +version = "=1.1.4" +default-features = false + +[build-dependencies.aligned] +package = "aligned" +version = "=0.4.3" + +[build-dependencies.aligned_vec] +package = "aligned-vec" +version = "=0.6.4" + +[build-dependencies.alloc_no_stdlib] +package = "alloc-no-stdlib" +version = "=2.0.4" + +[build-dependencies.alloc_stdlib] +package = "alloc-stdlib" +version = "=0.2.2" + +[build-dependencies.allocator_api2] +package = "allocator-api2" +version = "=0.2.21" +features = ["alloc"] +default-features = false + +[build-dependencies.ansi_term] +package = "ansi_term" +version = "=0.12.1" + +[build-dependencies.anstream] +package = "anstream" +version = "=1.0.0" +features = ["wincon"] + +[build-dependencies.anstyle] +package = "anstyle" +version = "=1.0.14" + +[build-dependencies.anstyle_parse] +package = "anstyle-parse" +version = "=1.0.0" + +[build-dependencies.anstyle_query] +package = "anstyle-query" +version = "=1.1.5" + +[build-dependencies.anyhow] +package = "anyhow" +version = "=1.0.102" + +[build-dependencies.approx] +package = "approx" +version = "=0.5.1" +default-features = false + +[build-dependencies.arbitrary] +package = "arbitrary" +version = "=1.4.2" +default-features = false + +[build-dependencies.arc_swap] +package = "arc-swap" +version = "=1.9.1" + +[build-dependencies.arg_enum_proc_macro] +package = "arg_enum_proc_macro" +version = "=0.3.4" + +[build-dependencies.arrayvec] +package = "arrayvec" +version = "=0.7.6" + +[build-dependencies.as_slice] +package = "as-slice" +version = "=0.2.1" + +[build-dependencies.async_compression] +package = "async-compression" +version = "=0.4.42" +features = ["tokio"] + +[build-dependencies.async_trait] +package = "async-trait" +version = "=0.1.89" + +[build-dependencies.atomic] +package = "atomic" +version = "=0.6.1" +default-features = false + +[build-dependencies.atomic_waker] +package = "atomic-waker" +version = "=1.1.2" + +[build-dependencies.autocfg] +package = "autocfg" +version = "=1.5.1" + +[build-dependencies.av1_grain] +package = "av1-grain" +version = "=0.2.5" + +[build-dependencies.av_scenechange] +package = "av-scenechange" +version = "=0.14.1" +default-features = false + +[build-dependencies.avif_serialize] +package = "avif-serialize" +version = "=0.8.9" + +[build-dependencies.aws_lc_rs] +package = "aws-lc-rs" +version = "=1.17.0" +default-features = false + +[build-dependencies.aws_lc_sys] +package = "aws-lc-sys" +version = "=0.41.0" +default-features = false + +[build-dependencies.backtrace] +package = "backtrace" +version = "=0.3.76" + +[build-dependencies.base64] +package = "base64" +version = "=0.22.1" + +[build-dependencies.bit_field] +package = "bit_field" +version = "=0.10.3" + +[build-dependencies.bit_set] +package = "bit-set" +version = "=0.5.3" + +[build-dependencies.bit_vec] +package = "bit-vec" +version = "=0.6.3" +default-features = false + +[build-dependencies.bitflags] +package = "bitflags" +version = "=2.12.1" + +[build-dependencies.bitstream_io] +package = "bitstream-io" +version = "=4.10.0" + +[build-dependencies.bitvec] +package = "bitvec" +version = "=1.0.1" +default-features = false + +[build-dependencies.block_buffer] +package = "block-buffer" +version = "=0.12.0" + +[build-dependencies.block_buffer_0_10_4] +package = "block-buffer" +version = "=0.10.4" + +[build-dependencies.borsh] +package = "borsh" +version = "=1.6.1" +default-features = false + +[build-dependencies.brotli] +package = "brotli" +version = "=8.0.3" + +[build-dependencies.brotli_decompressor] +package = "brotli-decompressor" +version = "=5.0.1" +default-features = false + +[build-dependencies.built] +package = "built" +version = "=0.8.1" + +[build-dependencies.bumpalo] +package = "bumpalo" +version = "=3.20.3" + +[build-dependencies.bytecheck] +package = "bytecheck" +version = "=0.8.2" +default-features = false + +[build-dependencies.bytecheck_derive] +package = "bytecheck_derive" +version = "=0.8.2" +default-features = false + +[build-dependencies.bytemuck] +package = "bytemuck" +version = "=1.25.0" +features = ["extern_crate_alloc", "extern_crate_std", "latest_stable_rust"] + +[build-dependencies.bytemuck_derive] +package = "bytemuck_derive" +version = "=1.10.2" + +[build-dependencies.byteorder] +package = "byteorder" +version = "=1.5.0" + +[build-dependencies.byteorder_lite] +package = "byteorder-lite" +version = "=0.1.0" + +[build-dependencies.bytes] +package = "bytes" +version = "=1.11.1" + +[build-dependencies.bytes_0_4_12] +package = "bytes" +version = "=0.4.12" + +[build-dependencies.cc] +package = "cc" +version = "=1.2.63" +features = ["parallel"] + +[build-dependencies.cfg_aliases] +package = "cfg_aliases" +version = "=0.2.1" + +[build-dependencies.cfg_if] +package = "cfg-if" +version = "=1.0.4" + +[build-dependencies.chacha20] +package = "chacha20" +version = "=0.10.0" +features = ["rng"] +default-features = false + +[build-dependencies.chrono] +package = "chrono" +version = "=0.4.44" +features = ["clock", "serde"] + +[build-dependencies.clap] +package = "clap" +version = "=4.6.1" +features = ["unstable-doc"] + +[build-dependencies.clap_builder] +package = "clap_builder" +version = "=4.6.0" +features = ["unstable-doc"] + +[build-dependencies.clap_derive] +package = "clap_derive" +version = "=4.6.1" + +[build-dependencies.clap_lex] +package = "clap_lex" +version = "=1.1.0" + +[build-dependencies.cmake] +package = "cmake" +version = "=0.1.58" + +[build-dependencies.cmov] +package = "cmov" +version = "=0.5.4" + +[build-dependencies.color_quant] +package = "color_quant" +version = "=1.1.0" + +[build-dependencies.colorchoice] +package = "colorchoice" +version = "=1.0.5" + +[build-dependencies.compression_codecs] +package = "compression-codecs" +version = "=0.4.38" + +[build-dependencies.compression_core] +package = "compression-core" +version = "=0.4.32" + +[build-dependencies.const_default] +package = "const-default" +version = "=1.0.0" +default-features = false + +[build-dependencies.const_oid] +package = "const-oid" +version = "=0.10.2" + +[build-dependencies.convert_case] +package = "convert_case" +version = "=0.10.0" + +[build-dependencies.cookie] +package = "cookie" +version = "=0.18.1" +features = ["percent-encode"] + +[build-dependencies.cookie_store] +package = "cookie_store" +version = "=0.22.1" + +[build-dependencies.cpufeatures] +package = "cpufeatures" +version = "=0.3.0" + +[build-dependencies.crc32fast] +package = "crc32fast" +version = "=1.5.0" + +[build-dependencies.crossbeam] +package = "crossbeam" +version = "=0.8.4" + +[build-dependencies.crossbeam_channel] +package = "crossbeam-channel" +version = "=0.5.15" +default-features = false + +[build-dependencies.crossbeam_deque] +package = "crossbeam-deque" +version = "=0.8.6" + +[build-dependencies.crossbeam_epoch] +package = "crossbeam-epoch" +version = "=0.9.18" +default-features = false + +[build-dependencies.crossbeam_queue] +package = "crossbeam-queue" +version = "=0.3.12" +default-features = false + +[build-dependencies.crossbeam_utils] +package = "crossbeam-utils" +version = "=0.8.21" + +[build-dependencies.crypto_common] +package = "crypto-common" +version = "=0.2.2" + +[build-dependencies.crypto_common_0_1_7] +package = "crypto-common" +version = "=0.1.7" + +[build-dependencies.cssparser] +package = "cssparser" +version = "=0.31.2" + +[build-dependencies.cssparser_macros] +package = "cssparser-macros" +version = "=0.6.1" + +[build-dependencies.csv] +package = "csv" +version = "=1.4.0" + +[build-dependencies.csv_core] +package = "csv-core" +version = "=0.1.13" + +[build-dependencies.ctutils] +package = "ctutils" +version = "=0.4.2" + +[build-dependencies.data_encoding] +package = "data-encoding" +version = "=2.11.0" + +[build-dependencies.debug_unreachable] +package = "new_debug_unreachable" +version = "=1.0.6" + +[build-dependencies.deranged] +package = "deranged" +version = "=0.5.8" +features = ["powerfmt"] + +[build-dependencies.derive_more] +package = "derive_more" +version = "=2.1.1" +features = ["debug", "full", "std"] + +[build-dependencies.derive_more_0_99_20] +package = "derive_more" +version = "=0.99.20" +features = ["add", "add_assign"] +default-features = false + +[build-dependencies.derive_more_impl] +package = "derive_more-impl" +version = "=2.1.1" + +[build-dependencies.destructure_traitobject] +package = "destructure_traitobject" +version = "=0.2.0" + +[build-dependencies.digest] +package = "digest" +version = "=0.11.3" +features = ["mac"] + +[build-dependencies.digest_0_10_7] +package = "digest" +version = "=0.10.7" + +[build-dependencies.displaydoc] +package = "displaydoc" +version = "=0.2.6" +default-features = false + +[build-dependencies.document_features] +package = "document-features" +version = "=0.2.12" + +[build-dependencies.dtoa] +package = "dtoa" +version = "=1.0.11" + +[build-dependencies.dtoa_short] +package = "dtoa-short" +version = "=0.3.5" + +[build-dependencies.dunce] +package = "dunce" +version = "=1.0.5" + +[build-dependencies.ego_tree] +package = "ego-tree" +version = "=0.6.3" + +[build-dependencies.either] +package = "either" +version = "=1.16.0" +features = ["serde"] + +[build-dependencies.encoding_rs] +package = "encoding_rs" +version = "=0.8.35" + +[build-dependencies.env_filter] +package = "env_filter" +version = "=1.0.1" +default-features = false + +[build-dependencies.env_logger] +package = "env_logger" +version = "=0.11.10" + +[build-dependencies.equator] +package = "equator" +version = "=0.4.2" + +[build-dependencies.equator_macro] +package = "equator-macro" +version = "=0.4.2" + +[build-dependencies.equivalent] +package = "equivalent" +version = "=1.0.2" +default-features = false + +[build-dependencies.errno] +package = "errno" +version = "=0.3.14" + +[build-dependencies.exr] +package = "exr" +version = "=1.74.0" +default-features = false + +[build-dependencies.fallible_iterator] +package = "fallible-iterator" +version = "=0.3.0" + +[build-dependencies.fallible_iterator_0_2_0] +package = "fallible-iterator" +version = "=0.2.0" + +[build-dependencies.fallible_streaming_iterator] +package = "fallible-streaming-iterator" +version = "=0.1.9" + +[build-dependencies.faster_hex] +package = "faster-hex" +version = "=0.10.0" +default-features = false + +[build-dependencies.fastrand] +package = "fastrand" +version = "=2.4.1" + +[build-dependencies.fax] +package = "fax" +version = "=0.2.7" + +[build-dependencies.fdeflate] +package = "fdeflate" +version = "=0.3.7" + +[build-dependencies.filetime] +package = "filetime" +version = "=0.2.29" + +[build-dependencies.find_msvc_tools] +package = "find-msvc-tools" +version = "=0.1.9" + +[build-dependencies.fixedbitset] +package = "fixedbitset" +version = "=0.5.7" +default-features = false + +[build-dependencies.fixedbitset_0_4_2] +package = "fixedbitset" +version = "=0.4.2" +default-features = false + +[build-dependencies.flate2] +package = "flate2" +version = "=1.1.9" + +[build-dependencies.fnv] +package = "fnv" +version = "=1.0.7" + +[build-dependencies.foldhash] +package = "foldhash" +version = "=0.2.0" +default-features = false + +[build-dependencies.foldhash_0_1_5] +package = "foldhash" +version = "=0.1.5" +default-features = false + +[build-dependencies.form_urlencoded] +package = "form_urlencoded" +version = "=1.2.2" +features = ["alloc"] + +[build-dependencies.fs_extra] +package = "fs_extra" +version = "=1.3.0" + +[build-dependencies.funty] +package = "funty" +version = "=2.0.0" +default-features = false + +[build-dependencies.futf] +package = "futf" +version = "=0.1.5" + +[build-dependencies.futures] +package = "futures" +version = "=0.3.32" +features = ["async-await", "compat", "executor", "io-compat", "std", "thread-pool"] + +[build-dependencies.futures_0_1_31] +package = "futures" +version = "=0.1.31" + +[build-dependencies.futures_channel] +package = "futures-channel" +version = "=0.3.32" +features = ["sink", "std"] + +[build-dependencies.futures_core] +package = "futures-core" +version = "=0.3.32" + +[build-dependencies.futures_executor] +package = "futures-executor" +version = "=0.3.32" +default-features = false + +[build-dependencies.futures_io] +package = "futures-io" +version = "=0.3.32" +features = ["std"] + +[build-dependencies.futures_macro] +package = "futures-macro" +version = "=0.3.32" +default-features = false + +[build-dependencies.futures_sink] +package = "futures-sink" +version = "=0.3.32" + +[build-dependencies.futures_task] +package = "futures-task" +version = "=0.3.32" +default-features = false + +[build-dependencies.futures_util] +package = "futures-util" +version = "=0.3.32" +features = ["alloc", "sink"] + +[build-dependencies.fxhash] +package = "fxhash" +version = "=0.2.1" + +[build-dependencies.generic_array] +package = "generic-array" +version = "=1.4.3" +features = ["alloc", "arbitrary", "as_slice", "bitvec", "bytecheck-0_8", "bytemuck", "compat-0_14", "const-default", "faster-hex", "hybrid-array-0_4", "internals", "rkyv-0_8", "rkyv-0_8-full", "serde", "subtle", "zeroize"] + +[build-dependencies.generic_array_0_14_7] +package = "generic-array" +version = "=0.14.7" +features = ["more_lengths"] + +[build-dependencies.getopts] +package = "getopts" +version = "=0.2.24" + +[build-dependencies.getrandom] +package = "getrandom" +version = "=0.4.2" + +[build-dependencies.getrandom_0_2_17] +package = "getrandom" +version = "=0.2.17" + +[build-dependencies.getrandom_0_3_4] +package = "getrandom" +version = "=0.3.4" + +[build-dependencies.gif] +package = "gif" +version = "=0.14.2" + +[build-dependencies.gimli] +package = "gimli" +version = "=0.32.3" +features = ["read"] +default-features = false + +[build-dependencies.glob] +package = "glob" +version = "=0.3.3" + +[build-dependencies.h2] +package = "h2" +version = "=0.4.14" + +[build-dependencies.half] +package = "half" +version = "=2.7.1" + +[build-dependencies.hash32] +package = "hash32" +version = "=0.3.1" + +[build-dependencies.hashbrown] +package = "hashbrown" +version = "=0.17.1" +default-features = false + +[build-dependencies.hashbrown_0_15_5] +package = "hashbrown" +version = "=0.15.5" +features = ["default-hasher", "inline-more"] +default-features = false + +[build-dependencies.hashbrown_0_16_1] +package = "hashbrown" +version = "=0.16.1" +features = ["default-hasher"] +default-features = false + +[build-dependencies.hashlink] +package = "hashlink" +version = "=0.11.0" + +[build-dependencies.hdrhistogram] +package = "hdrhistogram" +version = "=7.5.4" +default-features = false + +[build-dependencies.heapless] +package = "heapless" +version = "=0.8.0" + +[build-dependencies.heck] +package = "heck" +version = "=0.5.0" + +[build-dependencies.hmac] +package = "hmac" +version = "=0.13.0" + +[build-dependencies.html5ever] +package = "html5ever" +version = "=0.27.0" + +[build-dependencies.html5ever_0_26_0] +package = "html5ever" +version = "=0.26.0" + +[build-dependencies.http] +package = "http" +version = "=1.4.1" + +[build-dependencies.http_body] +package = "http-body" +version = "=1.0.1" + +[build-dependencies.http_body_util] +package = "http-body-util" +version = "=0.1.3" + +[build-dependencies.http_range_header] +package = "http-range-header" +version = "=0.4.2" + +[build-dependencies.httparse] +package = "httparse" +version = "=1.10.1" + +[build-dependencies.httpdate] +package = "httpdate" +version = "=1.0.3" + +[build-dependencies.humantime] +package = "humantime" +version = "=2.3.0" + +[build-dependencies.hybrid_array] +package = "hybrid-array" +version = "=0.4.12" + +[build-dependencies.hyper] +package = "hyper" +version = "=1.10.1" +features = ["client", "full", "http1"] + +[build-dependencies.hyper_rustls] +package = "hyper-rustls" +version = "=0.27.9" +features = ["http1", "tls12"] +default-features = false + +[build-dependencies.hyper_util] +package = "hyper-util" +version = "=0.1.20" +features = ["client", "client-legacy", "client-proxy", "http1", "tokio"] + +[build-dependencies.iana_time_zone] +package = "iana-time-zone" +version = "=0.1.65" +features = ["fallback"] + +[build-dependencies.icu_collections] +package = "icu_collections" +version = "=2.2.0" +default-features = false + +[build-dependencies.icu_locale_core] +package = "icu_locale_core" +version = "=2.2.0" +features = ["zerovec"] +default-features = false + +[build-dependencies.icu_normalizer] +package = "icu_normalizer" +version = "=2.2.0" +default-features = false + +[build-dependencies.icu_normalizer_data] +package = "icu_normalizer_data" +version = "=2.2.0" +default-features = false + +[build-dependencies.icu_properties] +package = "icu_properties" +version = "=2.2.0" +default-features = false + +[build-dependencies.icu_properties_data] +package = "icu_properties_data" +version = "=2.2.0" +default-features = false + +[build-dependencies.icu_provider] +package = "icu_provider" +version = "=2.2.0" +default-features = false + +[build-dependencies.idna] +package = "idna" +version = "=1.1.0" +features = ["alloc", "compiled_data"] + +[build-dependencies.idna_adapter] +package = "idna_adapter" +version = "=1.2.2" + +[build-dependencies.image] +package = "image" +version = "=0.25.10" + +[build-dependencies.image_webp] +package = "image-webp" +version = "=0.2.4" + +[build-dependencies.imgref] +package = "imgref" +version = "=1.12.1" + +[build-dependencies.indexmap] +package = "indexmap" +version = "=2.14.0" +features = ["std"] + +[build-dependencies.iovec] +package = "iovec" +version = "=0.1.4" + +[build-dependencies.ipnet] +package = "ipnet" +version = "=2.12.0" + +[build-dependencies.is_terminal_polyfill] +package = "is_terminal_polyfill" +version = "=1.70.2" + +[build-dependencies.itertools] +package = "itertools" +version = "=0.14.0" + +[build-dependencies.itoa] +package = "itoa" +version = "=1.0.18" + +[build-dependencies.jiff] +package = "jiff" +version = "=0.2.28" +features = ["logging", "serde", "static", "std", "tzdb-bundle-always"] + +[build-dependencies.jiff_static] +package = "jiff-static" +version = "=0.2.28" + +[build-dependencies.jiff_tzdb] +package = "jiff-tzdb" +version = "=0.1.6" + +[build-dependencies.jobserver] +package = "jobserver" +version = "=0.1.34" +default-features = false + +[build-dependencies.lazy_static] +package = "lazy_static" +version = "=1.5.0" + +[build-dependencies.lebe] +package = "lebe" +version = "=0.5.3" + +[build-dependencies.libc] +package = "libc" +version = "=0.2.186" + +[build-dependencies.libm] +package = "libm" +version = "=0.2.16" + +[build-dependencies.libsqlite3_sys] +package = "libsqlite3-sys" +version = "=0.38.0" + +[build-dependencies.linux_raw_sys] +package = "linux-raw-sys" +version = "=0.12.1" +features = ["auxvec", "elf", "errno", "general", "ioctl", "no_std"] +default-features = false + +[build-dependencies.litemap] +package = "litemap" +version = "=0.8.2" +default-features = false + +[build-dependencies.litrs] +package = "litrs" +version = "=1.0.0" + +[build-dependencies.lock_api] +package = "lock_api" +version = "=0.4.14" + +[build-dependencies.log] +package = "log" +version = "=0.4.31" +features = ["std"] + +[build-dependencies.log4rs] +package = "log4rs" +version = "=1.4.0" + +[build-dependencies.log_mdc] +package = "log-mdc" +version = "=0.1.0" + +[build-dependencies.loop9] +package = "loop9" +version = "=0.1.5" + +[build-dependencies.mac] +package = "mac" +version = "=0.1.1" + +[build-dependencies.markup5ever] +package = "markup5ever" +version = "=0.12.1" + +[build-dependencies.markup5ever_0_11_0] +package = "markup5ever" +version = "=0.11.0" + +[build-dependencies.markup5ever_rcdom] +package = "markup5ever_rcdom" +version = "=0.2.0" + +[build-dependencies.matrixmultiply] +package = "matrixmultiply" +version = "=0.3.10" +features = ["cgemm"] + +[build-dependencies.maybe_rayon] +package = "maybe-rayon" +version = "=0.1.1" +default-features = false + +[build-dependencies.md5] +package = "md-5" +version = "=0.11.0" + +[build-dependencies.md5_0_10_6] +package = "md-5" +version = "=0.10.6" +default-features = false + +[build-dependencies.memchr] +package = "memchr" +version = "=2.8.1" + +[build-dependencies.memmap] +package = "memmap" +version = "=0.7.0" + +[build-dependencies.mime] +package = "mime" +version = "=0.3.17" + +[build-dependencies.mime_guess] +package = "mime_guess" +version = "=2.0.5" +default-features = false + +[build-dependencies.miniz_oxide] +package = "miniz_oxide" +version = "=0.9.1" + +[build-dependencies.miniz_oxide_0_8_9] +package = "miniz_oxide" +version = "=0.8.9" +features = ["simd", "with-alloc"] + +[build-dependencies.mio] +package = "mio" +version = "=1.2.1" +features = ["net", "os-ext", "os-poll"] + +[build-dependencies.mock_instant] +package = "mock_instant" +version = "=0.6.0" + +[build-dependencies.moxcms] +package = "moxcms" +version = "=0.8.1" + +[build-dependencies.munge] +package = "munge" +version = "=0.4.7" +default-features = false + +[build-dependencies.munge_macro] +package = "munge_macro" +version = "=0.4.7" +default-features = false + +[build-dependencies.nalgebra] +package = "nalgebra" +version = "=0.35.0" + +[build-dependencies.nalgebra_macros] +package = "nalgebra-macros" +version = "=0.3.0" + +[build-dependencies.ndarray] +package = "ndarray" +version = "=0.17.2" + +[build-dependencies.no_std_io2] +package = "no_std_io2" +version = "=0.9.4" + +[build-dependencies.nom] +package = "nom" +version = "=8.0.0" + +[build-dependencies.noop_proc_macro] +package = "noop_proc_macro" +version = "=0.3.0" + +[build-dependencies.nu_ansi_term] +package = "nu-ansi-term" +version = "=0.50.3" + +[build-dependencies.num] +package = "num" +version = "=0.4.3" + +[build-dependencies.num_bigint] +package = "num-bigint" +version = "=0.4.6" +default-features = false + +[build-dependencies.num_complex] +package = "num-complex" +version = "=0.4.6" +default-features = false + +[build-dependencies.num_conv] +package = "num-conv" +version = "=0.2.2" + +[build-dependencies.num_cpus] +package = "num_cpus" +version = "=1.17.0" + +[build-dependencies.num_derive] +package = "num-derive" +version = "=0.4.2" + +[build-dependencies.num_integer] +package = "num-integer" +version = "=0.1.46" +features = ["i128"] +default-features = false + +[build-dependencies.num_iter] +package = "num-iter" +version = "=0.1.45" +features = ["i128"] +default-features = false + +[build-dependencies.num_rational] +package = "num-rational" +version = "=0.4.2" + +[build-dependencies.num_traits] +package = "num-traits" +version = "=0.2.19" +features = ["i128", "libm"] + +[build-dependencies.object] +package = "object" +version = "=0.37.3" +features = ["archive", "elf", "macho", "pe", "read_core", "unaligned", "xcoff"] +default-features = false + +[build-dependencies.once_cell] +package = "once_cell" +version = "=1.21.4" +features = ["alloc", "race", "std"] + +[build-dependencies.openssl_probe] +package = "openssl-probe" +version = "=0.2.1" + +[build-dependencies.ordered_float] +package = "ordered-float" +version = "=2.10.1" + +[build-dependencies.parking_lot] +package = "parking_lot" +version = "=0.12.5" +features = ["arc_lock", "deadlock_detection", "serde"] + +[build-dependencies.parking_lot_core] +package = "parking_lot_core" +version = "=0.9.12" + +[build-dependencies.paste] +package = "paste" +version = "=1.0.15" + +[build-dependencies.pastey] +package = "pastey" +version = "=0.1.1" + +[build-dependencies.percent_encoding] +package = "percent-encoding" +version = "=2.3.2" +features = ["alloc"] + +[build-dependencies.petgraph] +package = "petgraph" +version = "=0.8.3" + +[build-dependencies.petgraph_0_6_5] +package = "petgraph" +version = "=0.6.5" + +[build-dependencies.phf] +package = "phf" +version = "=0.13.1" +features = ["macros"] + +[build-dependencies.phf_0_10_1] +package = "phf" +version = "=0.10.1" + +[build-dependencies.phf_0_11_3] +package = "phf" +version = "=0.11.3" +features = ["macros"] + +[build-dependencies.phf_codegen] +package = "phf_codegen" +version = "=0.11.3" + +[build-dependencies.phf_codegen_0_10_0] +package = "phf_codegen" +version = "=0.10.0" + +[build-dependencies.phf_generator] +package = "phf_generator" +version = "=0.13.1" + +[build-dependencies.phf_generator_0_10_0] +package = "phf_generator" +version = "=0.10.0" + +[build-dependencies.phf_generator_0_11_3] +package = "phf_generator" +version = "=0.11.3" + +[build-dependencies.phf_macros] +package = "phf_macros" +version = "=0.13.1" + +[build-dependencies.phf_macros_0_11_3] +package = "phf_macros" +version = "=0.11.3" + +[build-dependencies.phf_shared] +package = "phf_shared" +version = "=0.13.1" +default-features = false + +[build-dependencies.phf_shared_0_10_0] +package = "phf_shared" +version = "=0.10.0" + +[build-dependencies.phf_shared_0_11_3] +package = "phf_shared" +version = "=0.11.3" + +[build-dependencies.pin_project_lite] +package = "pin-project-lite" +version = "=0.2.17" + +[build-dependencies.pkg_config] +package = "pkg-config" +version = "=0.3.33" + +[build-dependencies.png] +package = "png" +version = "=0.18.1" + +[build-dependencies.postgres] +package = "postgres" +version = "=0.19.13" + +[build-dependencies.postgres_protocol] +package = "postgres-protocol" +version = "=0.6.11" + +[build-dependencies.postgres_types] +package = "postgres-types" +version = "=0.2.13" + +[build-dependencies.potential_utf] +package = "potential_utf" +version = "=0.1.5" +features = ["zerovec"] +default-features = false + +[build-dependencies.powerfmt] +package = "powerfmt" +version = "=0.2.0" +default-features = false + +[build-dependencies.ppv_lite86] +package = "ppv-lite86" +version = "=0.2.21" +features = ["simd"] +default-features = false + +[build-dependencies.precomputed_hash] +package = "precomputed-hash" +version = "=0.1.1" + +[build-dependencies.proc_macro2] +package = "proc-macro2" +version = "=1.0.106" +features = ["proc-macro", "span-locations"] + +[build-dependencies.profiling] +package = "profiling" +version = "=1.0.18" + +[build-dependencies.profiling_procmacros] +package = "profiling-procmacros" +version = "=1.0.18" + +[build-dependencies.psl_types] +package = "psl-types" +version = "=2.0.11" + +[build-dependencies.ptr_meta] +package = "ptr_meta" +version = "=0.3.1" +features = ["derive"] +default-features = false + +[build-dependencies.ptr_meta_derive] +package = "ptr_meta_derive" +version = "=0.3.1" +default-features = false + +[build-dependencies.publicsuffix] +package = "publicsuffix" +version = "=2.3.0" + +[build-dependencies.pxfm] +package = "pxfm" +version = "=0.1.29" + +[build-dependencies.qoi] +package = "qoi" +version = "=0.4.1" + +[build-dependencies.quick_error] +package = "quick-error" +version = "=2.0.1" + +[build-dependencies.quote] +package = "quote" +version = "=1.0.45" +features = ["proc-macro"] + +[build-dependencies.radium] +package = "radium" +version = "=0.7.0" + +[build-dependencies.rancor] +package = "rancor" +version = "=0.1.1" +default-features = false + +[build-dependencies.rand] +package = "rand" +version = "=0.10.1" +features = ["serde"] + +[build-dependencies.rand_0_8_6] +package = "rand" +version = "=0.8.6" +features = ["serde1", "small_rng"] + +[build-dependencies.rand_0_9_4] +package = "rand" +version = "=0.9.4" +features = ["serde", "small_rng"] + +[build-dependencies.rand_chacha] +package = "rand_chacha" +version = "=0.10.0" + +[build-dependencies.rand_chacha_0_3_1] +package = "rand_chacha" +version = "=0.3.1" +default-features = false + +[build-dependencies.rand_chacha_0_9_0] +package = "rand_chacha" +version = "=0.9.0" +default-features = false + +[build-dependencies.rand_core] +package = "rand_core" +version = "=0.10.1" + +[build-dependencies.rand_core_0_6_4] +package = "rand_core" +version = "=0.6.4" +features = ["alloc", "getrandom", "serde", "serde1", "std"] + +[build-dependencies.rand_core_0_9_5] +package = "rand_core" +version = "=0.9.5" +features = ["os_rng", "serde", "std"] + +[build-dependencies.rand_distr] +package = "rand_distr" +version = "=0.6.0" + +[build-dependencies.rav1e] +package = "rav1e" +version = "=0.8.1" +default-features = false + +[build-dependencies.ravif] +package = "ravif" +version = "=0.13.0" +default-features = false + +[build-dependencies.rawpointer] +package = "rawpointer" +version = "=0.2.1" + +[build-dependencies.rayon] +package = "rayon" +version = "=1.12.0" + +[build-dependencies.rayon_core] +package = "rayon-core" +version = "=1.13.0" + +[build-dependencies.regex] +package = "regex" +version = "=1.12.3" +features = ["perf", "std"] +default-features = false + +[build-dependencies.regex_automata] +package = "regex-automata" +version = "=0.4.14" +features = ["alloc", "meta", "nfa-pikevm", "syntax"] +default-features = false + +[build-dependencies.regex_syntax] +package = "regex-syntax" +version = "=0.8.10" +default-features = false + +[build-dependencies.rend] +package = "rend" +version = "=0.5.3" +default-features = false + +[build-dependencies.reqwest] +package = "reqwest" +version = "=0.13.4" +features = ["blocking", "cookies", "form", "json", "multipart", "query"] + +[build-dependencies.reqwest_0_12_28] +package = "reqwest" +version = "=0.12.28" +features = ["blocking", "cookies", "json", "multipart", "rustls-tls"] + +[build-dependencies.rgb] +package = "rgb" +version = "=0.8.53" +default-features = false + +[build-dependencies.ring] +package = "ring" +version = "=0.17.14" + +[build-dependencies.rkyv] +package = "rkyv" +version = "=0.8.16" +default-features = false + +[build-dependencies.rkyv_derive] +package = "rkyv_derive" +version = "=0.8.16" +default-features = false + +[build-dependencies.rusqlite] +package = "rusqlite" +version = "=0.40.0" +features = ["bundled-full"] + +[build-dependencies.rustc_demangle] +package = "rustc-demangle" +version = "=0.1.27" + +[build-dependencies.rustc_version] +package = "rustc_version" +version = "=0.4.1" + +[build-dependencies.rustix] +package = "rustix" +version = "=1.1.4" +features = ["fs", "std", "termios"] + +[build-dependencies.rustls] +package = "rustls" +version = "=0.23.40" +features = ["std", "tls12"] +default-features = false + +[build-dependencies.rustls_native_certs] +package = "rustls-native-certs" +version = "=0.8.4" + +[build-dependencies.rustls_pki_types] +package = "rustls-pki-types" +version = "=1.14.1" +features = ["alloc", "std"] + +[build-dependencies.rustls_platform_verifier] +package = "rustls-platform-verifier" +version = "=0.7.0" + +[build-dependencies.rustversion] +package = "rustversion" +version = "=1.0.22" + +[build-dependencies.ryu] +package = "ryu" +version = "=1.0.23" + +[build-dependencies.safe_arch] +package = "safe_arch" +version = "=1.0.0" +features = ["bytemuck"] + +[build-dependencies.same_file] +package = "same-file" +version = "=1.0.6" + +[build-dependencies.scopeguard] +package = "scopeguard" +version = "=1.2.0" +default-features = false + +[build-dependencies.scraper] +package = "scraper" +version = "=0.20.0" + +[build-dependencies.select] +package = "select" +version = "=0.6.1" + +[build-dependencies.selectors] +package = "selectors" +version = "=0.25.0" + +[build-dependencies.semver] +package = "semver" +version = "=1.0.28" +features = ["serde"] + +[build-dependencies.serde] +package = "serde" +version = "=1.0.228" +features = ["alloc", "derive", "rc"] + +[build-dependencies.serde_core] +package = "serde_core" +version = "=1.0.228" +features = ["alloc", "rc", "result"] + +[build-dependencies.serde_derive] +package = "serde_derive" +version = "=1.0.228" + +[build-dependencies.serde_json] +package = "serde_json" +version = "=1.0.150" +features = ["float_roundtrip", "raw_value", "unbounded_depth"] + +[build-dependencies.serde_spanned] +package = "serde_spanned" +version = "=1.1.1" +features = ["alloc"] +default-features = false + +[build-dependencies.serde_urlencoded] +package = "serde_urlencoded" +version = "=0.7.1" + +[build-dependencies.serde_value] +package = "serde-value" +version = "=0.7.0" + +[build-dependencies.serde_yaml] +package = "serde_yaml" +version = "=0.9.34" + +[build-dependencies.servo_arc] +package = "servo_arc" +version = "=0.3.0" + +[build-dependencies.sha1_smol] +package = "sha1_smol" +version = "=1.0.1" +default-features = false + +[build-dependencies.sha2] +package = "sha2" +version = "=0.11.0" + +[build-dependencies.sharded_slab] +package = "sharded-slab" +version = "=0.1.7" + +[build-dependencies.shlex] +package = "shlex" +version = "=2.0.1" + +[build-dependencies.signal_hook_registry] +package = "signal-hook-registry" +version = "=1.4.8" + +[build-dependencies.simba] +package = "simba" +version = "=0.10.0" +default-features = false + +[build-dependencies.simd_adler32] +package = "simd-adler32" +version = "=0.3.9" + +[build-dependencies.simd_helpers] +package = "simd_helpers" +version = "=0.1.0" + +[build-dependencies.siphasher] +package = "siphasher" +version = "=1.0.3" + +[build-dependencies.siphasher_0_3_11] +package = "siphasher" +version = "=0.3.11" + +[build-dependencies.slab] +package = "slab" +version = "=0.4.12" + +[build-dependencies.smallvec] +package = "smallvec" +version = "=1.15.1" +features = ["const_generics", "const_new"] + +[build-dependencies.socket2] +package = "socket2" +version = "=0.6.4" +features = ["all"] + +[build-dependencies.sptr] +package = "sptr" +version = "=0.3.2" + +[build-dependencies.stable_deref_trait] +package = "stable_deref_trait" +version = "=1.2.1" + +[build-dependencies.string_cache] +package = "string_cache" +version = "=0.8.9" + +[build-dependencies.string_cache_codegen] +package = "string_cache_codegen" +version = "=0.5.4" + +[build-dependencies.stringprep] +package = "stringprep" +version = "=0.1.5" + +[build-dependencies.strsim] +package = "strsim" +version = "=0.11.1" + +[build-dependencies.subtle] +package = "subtle" +version = "=2.6.1" +default-features = false + +[build-dependencies.syn] +package = "syn" +version = "=2.0.117" +features = ["clone-impls", "derive", "extra-traits", "fold", "full", "parsing", "printing", "proc-macro", "visit", "visit-mut"] + +[build-dependencies.syn_1_0_109] +package = "syn" +version = "=1.0.109" +features = ["extra-traits", "fold", "full", "visit", "visit-mut"] + +[build-dependencies.sync_wrapper] +package = "sync_wrapper" +version = "=1.0.2" +features = ["futures"] + +[build-dependencies.synstructure] +package = "synstructure" +version = "=0.13.2" + +[build-dependencies.tap] +package = "tap" +version = "=1.0.1" + +[build-dependencies.tar] +package = "tar" +version = "=0.4.46" + +[build-dependencies.tempfile] +package = "tempfile" +version = "=3.27.0" + +[build-dependencies.tendril] +package = "tendril" +version = "=0.4.3" + +[build-dependencies.terminal_size] +package = "terminal_size" +version = "=0.4.4" + +[build-dependencies.thiserror] +package = "thiserror" +version = "=2.0.18" + +[build-dependencies.thiserror_impl] +package = "thiserror-impl" +version = "=2.0.18" + +[build-dependencies.thread_id] +package = "thread-id" +version = "=5.1.0" + +[build-dependencies.thread_local] +package = "thread_local" +version = "=1.1.9" + +[build-dependencies.threadpool] +package = "threadpool" +version = "=1.8.1" + +[build-dependencies.tiff] +package = "tiff" +version = "=0.11.3" + +[build-dependencies.time] +package = "time" +version = "=0.3.47" +features = ["formatting", "macros", "parsing", "std"] + +[build-dependencies.time_core] +package = "time-core" +version = "=0.1.8" + +[build-dependencies.time_macros] +package = "time-macros" +version = "=0.2.27" + +[build-dependencies.tinystr] +package = "tinystr" +version = "=0.8.3" +default-features = false + +[build-dependencies.tinyvec] +package = "tinyvec" +version = "=1.11.0" +features = ["alloc", "borsh", "grab_spare_slice", "latest_stable_rust", "serde", "std"] + +[build-dependencies.tinyvec_macros] +package = "tinyvec_macros" +version = "=0.1.1" + +[build-dependencies.tokio] +package = "tokio" +version = "=1.52.3" +features = ["fs", "full", "io-util", "net", "rt", "rt-multi-thread", "sync", "test-util", "time"] + +[build-dependencies.tokio_io] +package = "tokio-io" +version = "=0.1.13" + +[build-dependencies.tokio_macros] +package = "tokio-macros" +version = "=2.7.0" + +[build-dependencies.tokio_postgres] +package = "tokio-postgres" +version = "=0.7.17" + +[build-dependencies.tokio_rustls] +package = "tokio-rustls" +version = "=0.26.4" +features = ["tls12"] +default-features = false + +[build-dependencies.tokio_stream] +package = "tokio-stream" +version = "=0.1.18" + +[build-dependencies.tokio_util] +package = "tokio-util" +version = "=0.7.18" +features = ["codec", "full", "io"] + +[build-dependencies.toml] +package = "toml" +version = "=1.1.2" + +[build-dependencies.toml_datetime] +package = "toml_datetime" +version = "=1.1.1" +features = ["alloc"] +default-features = false + +[build-dependencies.toml_parser] +package = "toml_parser" +version = "=1.1.2" +features = ["alloc"] +default-features = false + +[build-dependencies.toml_writer] +package = "toml_writer" +version = "=1.1.1" +features = ["alloc"] +default-features = false + +[build-dependencies.tower] +package = "tower" +version = "=0.5.3" +features = ["full", "retry", "timeout", "util"] + +[build-dependencies.tower_http] +package = "tower-http" +version = "=0.6.11" +features = ["follow-redirect", "full"] + +[build-dependencies.tower_layer] +package = "tower-layer" +version = "=0.3.3" + +[build-dependencies.tower_service] +package = "tower-service" +version = "=0.3.3" + +[build-dependencies.tracing] +package = "tracing" +version = "=0.1.44" +features = ["std"] +default-features = false + +[build-dependencies.tracing_attributes] +package = "tracing-attributes" +version = "=0.1.31" + +[build-dependencies.tracing_core] +package = "tracing-core" +version = "=0.1.36" + +[build-dependencies.tracing_log] +package = "tracing-log" +version = "=0.2.0" +features = ["log-tracer", "std"] +default-features = false + +[build-dependencies.tracing_subscriber] +package = "tracing-subscriber" +version = "=0.3.23" + +[build-dependencies.trpl] +package = "trpl" +version = "=0.3.0" + +[build-dependencies.try_lock] +package = "try-lock" +version = "=0.2.5" + +[build-dependencies.typemap_ors] +package = "typemap-ors" +version = "=1.0.0" + +[build-dependencies.typenum] +package = "typenum" +version = "=1.20.1" +features = ["const-generics", "i128"] + +[build-dependencies.unicase] +package = "unicase" +version = "=2.9.0" + +[build-dependencies.unicode_bidi] +package = "unicode-bidi" +version = "=0.3.18" + +[build-dependencies.unicode_ident] +package = "unicode-ident" +version = "=1.0.24" + +[build-dependencies.unicode_normalization] +package = "unicode-normalization" +version = "=0.1.25" + +[build-dependencies.unicode_properties] +package = "unicode-properties" +version = "=0.1.4" + +[build-dependencies.unicode_segmentation] +package = "unicode-segmentation" +version = "=1.13.3" + +[build-dependencies.unicode_width] +package = "unicode-width" +version = "=0.2.2" + +[build-dependencies.unicode_xid] +package = "unicode-xid" +version = "=0.2.6" + +[build-dependencies.unsafe_any_ors] +package = "unsafe-any-ors" +version = "=1.0.0" + +[build-dependencies.unsafe_libyaml] +package = "unsafe-libyaml" +version = "=0.2.11" + +[build-dependencies.untrusted] +package = "untrusted" +version = "=0.9.0" + +[build-dependencies.url] +package = "url" +version = "=2.5.8" +features = ["serde"] + +[build-dependencies.utf8] +package = "utf-8" +version = "=0.7.6" + +[build-dependencies.utf8_iter] +package = "utf8_iter" +version = "=1.0.4" + +[build-dependencies.utf8parse] +package = "utf8parse" +version = "=0.2.2" + +[build-dependencies.uuid] +package = "uuid" +version = "=1.23.2" +features = ["serde", "v1", "v3", "v4", "v5", "v6", "v7", "v8"] + +[build-dependencies.v_frame] +package = "v_frame" +version = "=0.3.9" + +[build-dependencies.vcpkg] +package = "vcpkg" +version = "=0.2.15" + +[build-dependencies.version_check] +package = "version_check" +version = "=0.9.5" + +[build-dependencies.walkdir] +package = "walkdir" +version = "=2.5.0" + +[build-dependencies.want] +package = "want" +version = "=0.3.1" + +[build-dependencies.wasm_bindgen] +package = "wasm-bindgen" +version = "=0.2.122" + +[build-dependencies.wasm_bindgen_macro] +package = "wasm-bindgen-macro" +version = "=0.2.122" + +[build-dependencies.wasm_bindgen_macro_support] +package = "wasm-bindgen-macro-support" +version = "=0.2.122" + +[build-dependencies.wasm_bindgen_shared] +package = "wasm-bindgen-shared" +version = "=0.2.122" + +[build-dependencies.webpki] +package = "rustls-webpki" +version = "=0.103.13" +features = ["alloc"] +default-features = false + +[build-dependencies.webpki_roots] +package = "webpki-roots" +version = "=1.0.7" + +[build-dependencies.weezl] +package = "weezl" +version = "=0.1.12" + +[build-dependencies.whoami] +package = "whoami" +version = "=2.1.2" + +[build-dependencies.wide] +package = "wide" +version = "=1.4.0" +default-features = false + +[build-dependencies.windows_aarch64_gnullvm] +package = "windows_aarch64_gnullvm" +version = "=0.53.1" + +[build-dependencies.windows_aarch64_msvc] +package = "windows_aarch64_msvc" +version = "=0.53.1" + +[build-dependencies.windows_i686_gnu] +package = "windows_i686_gnu" +version = "=0.53.1" + +[build-dependencies.windows_i686_msvc] +package = "windows_i686_msvc" +version = "=0.53.1" + +[build-dependencies.windows_link] +package = "windows-link" +version = "=0.2.1" +default-features = false + +[build-dependencies.windows_sys] +package = "windows-sys" +version = "=0.61.2" + +[build-dependencies.windows_targets] +package = "windows-targets" +version = "=0.53.5" +default-features = false + +[build-dependencies.windows_targets_0_52_6] +package = "windows-targets" +version = "=0.52.6" + +[build-dependencies.windows_x86_64_gnu] +package = "windows_x86_64_gnu" +version = "=0.53.1" + +[build-dependencies.windows_x86_64_gnu_0_52_6] +package = "windows_x86_64_gnu" +version = "=0.52.6" + +[build-dependencies.windows_x86_64_gnullvm] +package = "windows_x86_64_gnullvm" +version = "=0.53.1" + +[build-dependencies.windows_x86_64_msvc] +package = "windows_x86_64_msvc" +version = "=0.53.1" + +[build-dependencies.winnow] +package = "winnow" +version = "=1.0.3" +default-features = false + +[build-dependencies.writeable] +package = "writeable" +version = "=0.6.3" +default-features = false + +[build-dependencies.wyz] +package = "wyz" +version = "=0.5.1" +default-features = false + +[build-dependencies.xattr] +package = "xattr" +version = "=1.6.1" + +[build-dependencies.xml5ever] +package = "xml5ever" +version = "=0.17.0" + +[build-dependencies.y4m] +package = "y4m" +version = "=0.8.0" + +[build-dependencies.yoke] +package = "yoke" +version = "=0.8.2" +features = ["derive"] +default-features = false + +[build-dependencies.yoke_derive] +package = "yoke-derive" +version = "=0.8.2" +default-features = false + +[build-dependencies.zerocopy] +package = "zerocopy" +version = "=0.8.50" +features = ["__internal_use_only_features_that_work_on_stable", "derive", "simd"] + +[build-dependencies.zerocopy_derive] +package = "zerocopy-derive" +version = "=0.8.50" + +[build-dependencies.zerofrom] +package = "zerofrom" +version = "=0.1.8" +features = ["alloc", "derive"] + +[build-dependencies.zerofrom_derive] +package = "zerofrom-derive" +version = "=0.1.7" +default-features = false + +[build-dependencies.zeroize] +package = "zeroize" +version = "=1.8.2" + +[build-dependencies.zerotrie] +package = "zerotrie" +version = "=0.2.4" +features = ["yoke", "zerofrom"] +default-features = false + +[build-dependencies.zerovec] +package = "zerovec" +version = "=0.11.6" +features = ["derive", "yoke"] +default-features = false + +[build-dependencies.zerovec_derive] +package = "zerovec-derive" +version = "=0.11.3" +default-features = false + +[build-dependencies.zmij] +package = "zmij" +version = "=1.0.21" + +[build-dependencies.zstd] +package = "zstd" +version = "=0.13.3" +default-features = false + +[build-dependencies.zstd_safe] +package = "zstd-safe" +version = "=7.2.4" +features = ["std"] +default-features = false + +[build-dependencies.zstd_sys] +package = "zstd-sys" +version = "=2.0.16" +default-features = false + +[build-dependencies.zune_core] +package = "zune-core" +version = "=0.5.1" + +[build-dependencies.zune_inflate] +package = "zune-inflate" +version = "=0.2.54" +features = ["zlib"] +default-features = false + +[build-dependencies.zune_jpeg] +package = "zune-jpeg" +version = "=0.5.15" diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/Dockerfile b/anneal/v1/playground/rust-anneal-playground/compiler/base/Dockerfile new file mode 100644 index 0000000000..b7e877933f --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/Dockerfile @@ -0,0 +1,169 @@ +#syntax=docker/dockerfile:1.5 + +FROM ubuntu:24.04 as toolchain + +ARG channel + +ENV DEBIAN_FRONTEND="noninteractive" + +# `build-essential` and `file` are needed for backtrace-sys +# `cmake`, `git`, `python` are needed for wasm tools +RUN apt-get update && apt-get install -y \ + build-essential \ + cmake \ + curl \ + file \ + gcc \ + git \ + libssl-dev \ + pkg-config \ + && rm -rf /var/lib/apt/lists/* + +RUN useradd -m playground -d /playground +RUN usermod -p '!!' root # Disable all passwords for root + +# Attach the security note +COPY --chown=playground attach_notice.sh security_notice.txt /playground/ +RUN /playground/attach_notice.sh /playground/security_notice.txt /etc/passwd && \ + /playground/attach_notice.sh /playground/security_notice.txt /etc/shadow && \ + rm -f /playground/attach_notice.sh + +USER playground +ENV USER=playground +ENV PATH=/playground/.cargo/bin:/playground/.elan/bin:$PATH +WORKDIR /playground + +# Ensure that we are using the latest stable version of rustup and the +# latest version of the current channel. A new manifest will trigger +# these lines to run again, forcing a new download of rustup and +# installation of Rust. +ADD --chown=playground https://static.rust-lang.org/rustup/release-stable.toml /playground/tools/rustup-manifest.toml +ADD --chown=playground https://static.rust-lang.org/dist/channel-rust-${channel}-date.txt /playground/tools/rust-channel-version +RUN curl https://sh.rustup.rs -sSf | sh -s -- \ + -y \ + --profile minimal \ + --default-toolchain "${channel}" \ + --target wasm32-unknown-unknown \ + --component rustfmt \ + --component clippy \ + --component rust-src +RUN if [ "${channel}" = 'nightly' ]; then rustup component add miri; fi + +COPY --chown=playground entrypoint.sh /playground/tools/ + +# Build wasm-tools + +FROM toolchain as wasm-tools + +RUN cargo install --locked wasm-tools + +# Fetch all the crate source files + +FROM toolchain as sources + +RUN mkdir /playground/src && echo 'fn main() {}' > /playground/src/main.rs +COPY --chown=playground Cargo.toml /playground/Cargo.toml +COPY --chown=playground crate-information.json /playground/crate-information.json +RUN cargo fetch + +# Set up cargo-chef for faster builds + +FROM toolchain as chef-available + +RUN cargo install --locked cargo-chef + +WORKDIR /orchestrator + +# Prepare the orchestrator's dependencies + +FROM chef-available as prepare-orchestrator + +COPY --chown=playground asm-cleanup /asm-cleanup +COPY --chown=playground modify-cargo-toml /modify-cargo-toml +COPY --chown=playground orchestrator /orchestrator +RUN cargo chef prepare + +# Build the orchestrator + +FROM chef-available as build-orchestrator + +COPY --chown=playground asm-cleanup /asm-cleanup +COPY --chown=playground modify-cargo-toml /modify-cargo-toml +COPY --chown=playground --from=prepare-orchestrator /orchestrator/recipe.json /orchestrator/recipe.json +RUN cargo chef cook --locked --release + +COPY --chown=playground orchestrator /orchestrator +RUN cargo install --locked --path . + +# Compiler and pre-compiled crates + +FROM sources + +ARG channel + +RUN cargo build +RUN cargo build --release +RUN cargo clippy +RUN if [ "${channel}" = 'nightly' ]; then cargo miri setup; cargo miri run; fi +COPY --chown=playground cargo-anneal-alpha24-cache-manifest.patch /playground/tools/ +RUN <<'EOF' +set -eu +tmp="$(mktemp -d)" +curl -L https://static.crates.io/crates/cargo-anneal/cargo-anneal-0.1.0-alpha.24.crate \ + -o "$tmp/cargo-anneal.crate" +mkdir "$tmp/src" +tar -xzf "$tmp/cargo-anneal.crate" -C "$tmp/src" --strip-components=1 +cd "$tmp/src" +git apply /playground/tools/cargo-anneal-alpha24-cache-manifest.patch +cargo install --locked --path . +rm -rf "$tmp" +EOF +RUN cargo anneal setup +RUN <<'EOF' +set -eu +mkdir -p /playground/anneal-workspace/src /playground/anneal-workspace/tmp + +cat > /playground/anneal-workspace/Cargo.toml <<'TOML' +[package] +name = "anneal-submission" +version = "0.0.0" +edition = "2021" + +[workspace] +TOML + +cat > /playground/anneal-workspace/src/main.rs <<'RS' +/// ```anneal, unsafe(axiom) +/// ``` +pub unsafe fn anneal_warmup_identity(x: u32) -> u32 { + x +} + +fn main() {} +RS + +cd /playground/anneal-workspace + +TMPDIR=/playground/anneal-workspace/tmp \ +TEMP=/playground/anneal-workspace/tmp \ +TMP=/playground/anneal-workspace/tmp \ +CARGO_BUILD_JOBS=2 cargo anneal verify --unsound-allow-is-valid + +# Keep reusable Cargo build artifacts, but do not bake Anneal's per-run Lean +# workspace into the image. At runtime, cargo-anneal regenerates that workspace +# and renames its old `.lake` directory into a fresh temporary tree; Docker +# overlayfs can reject that rename when the old tree lives in a read-only image +# layer with "Invalid cross-device link". +find /playground/anneal-workspace/target/anneal \ + -mindepth 1 \ + -maxdepth 1 \ + ! -name cargo_target \ + -exec rm -rf {} + +EOF +COPY --from=build-orchestrator /playground/.cargo/bin/worker /playground/.cargo/bin/worker +COPY --from=wasm-tools /playground/.cargo/bin/wasm-tools /playground/.cargo/bin +COPY --chown=playground cargo-wasm /playground/.cargo/bin +# `cargo-miri-playground` is vestigial and can be removed after a while +COPY --chown=playground cargo-miri-playground /playground/.cargo/bin + +ENTRYPOINT ["/playground/tools/entrypoint.sh"] diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/asm-cleanup/.gitignore b/anneal/v1/playground/rust-anneal-playground/compiler/base/asm-cleanup/.gitignore new file mode 100644 index 0000000000..1e7caa9ea8 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/asm-cleanup/.gitignore @@ -0,0 +1,2 @@ +Cargo.lock +target/ diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/asm-cleanup/Cargo.toml b/anneal/v1/playground/rust-anneal-playground/compiler/base/asm-cleanup/Cargo.toml new file mode 100644 index 0000000000..cdb6061914 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/asm-cleanup/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "asm-cleanup" +version = "0.1.0" +edition = "2018" + +[workspace] + +[dependencies] +petgraph = "0.8.1" +regex = "1.0.0" +rustc-demangle = "0.1.5" diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/asm-cleanup/src/lib.rs b/anneal/v1/playground/rust-anneal-playground/compiler/base/asm-cleanup/src/lib.rs new file mode 100644 index 0000000000..cba9ccd799 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/asm-cleanup/src/lib.rs @@ -0,0 +1,282 @@ +// Thanks to Matt Godbolt for creating the amazing Compiler Explorer https://www.godbolt.org +// This aims to provide similar assembly cleanup to what Godbolt does + +use petgraph::prelude::*; +use regex::{Captures, Regex}; +use rustc_demangle::demangle; +use std::{collections::HashSet, sync::LazyLock}; + +pub fn demangle_asm(block: &str) -> String { + static DEMANGLE_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"_[a-zA-Z0-9._$]*").unwrap()); + + DEMANGLE_REGEX + .replace_all(block, |caps: &Captures<'_>| { + format!("{:#}", demangle(caps.get(0).map_or("", |m| m.as_str()))) + }) + .to_string() +} + +enum LineType<'a> { + Opcode, + LabelDecl(&'a str), + Data(&'a str), + FunctionDecl, + Directive, + Blank, + Misc, +} + +// Removes unused labels and directives from assembly +pub fn filter_asm(block: &str) -> String { + use self::LineType::*; + + // Example: mov rax, rdx + // Always inlude in results + static OPCODE_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"^\s+[a-zA-Z]+.*[^:]$").unwrap()); + + // Example:.Lfunc_end7: + // Finds label declarations + // Include in results only if it is referenced by an opcode, or is a function + static LABEL_DECL_REGEX: LazyLock = LazyLock::new(|| { + Regex::new(r"^([a-zA-Z_.<][a-zA-Z0-9$&_.,<>\[\]{}:' ]*):(\s+#.*)?$").unwrap() + }); + + // Example: mov lea rdi, [rip + str.0] // str.0 is the referenced label + // Find labels used as operands for an opcode + static LABEL_REF_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"([a-zA-Z_.][a-zA-Z0-9$_.]*)").unwrap()); + + // Example: .string "Hello, world!" + // Note: this is a type of directive + // Include in results if it is part of a used label, may contain label references + static DATA_REGEX: LazyLock = LazyLock::new(|| { + Regex::new(r"^\s+\.(string|asciz|ascii|[1248]?byte|short|word|long|quad|value|zero)") + .unwrap() + }); + + // Example: .type main,@function + // Note: this is a type of directive + // Never include in results, but is used to find and include functions + static FUNCTION_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"^\s+\.type\s*(.*),@function$").unwrap()); + + // Example: .p2align 4, 0x90 + // Note: this will also match entries found by DATA_REGEX and FUNCTION_REGEX + // Never include in results + static DIRECTIVE_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"^\s+\..*[^:]$").unwrap()); + + // Never include in results + static BLANK_REGEX: LazyLock = LazyLock::new(|| Regex::new(r"^\s*$").unwrap()); + + let mut current_label = ""; + let mut line_info = Vec::new(); + let mut labels = HashSet::new(); + let mut opcode_operands = HashSet::new(); + let mut label_graph: DiGraphMap<_, _> = Default::default(); + + // Note the type of data held on each line of the block + for line in block.lines() { + if OPCODE_REGEX.is_match(line) { + line_info.push(Opcode); + // Skip the opcode, just add operands + for label_ref_cap in + LABEL_REF_REGEX.captures_iter(line).skip(1).filter_map(|cap| cap.get(1)) + { + opcode_operands.insert(label_ref_cap.as_str()); + } + } else if let Some(label_decl_cap) = + LABEL_DECL_REGEX.captures(line).and_then(|cap| cap.get(1)) + { + line_info.push(LabelDecl(label_decl_cap.as_str())); + labels.insert(label_decl_cap.as_str()); + current_label = label_decl_cap.as_str(); + } else if DATA_REGEX.is_match(line) && !current_label.is_empty() { + line_info.push(Data(current_label)); + // These will be checked for references to other labels later on + // Skip the data type, just capture its reference + for label_ref_cap in + LABEL_REF_REGEX.captures_iter(line).skip(1).filter_map(|cap| cap.get(1)) + { + // Create a graph of how data labels reference each other + label_graph.add_edge(current_label, label_ref_cap.as_str(), 1); + } + } else if let Some(function_cap) = FUNCTION_REGEX.captures(line).and_then(|cap| cap.get(1)) + { + line_info.push(FunctionDecl); + opcode_operands.insert(function_cap.as_str()); + // DIRECTIVE_REGEX must be checked after FUNCTION_REGEX and DATA_REGEX, matches them too + } else if DIRECTIVE_REGEX.is_match(line) { + line_info.push(Directive); + } else if BLANK_REGEX.is_match(line) { + line_info.push(Blank); + // If no matches are found then include line in output + } else { + line_info.push(Misc); + } + } + + let mut data_labels = Vec::new(); + let mut used_labels: HashSet<_> = labels.intersection(&opcode_operands).collect(); + + // We only include labels ref'd by data dirs if directly or indirectly used by an opcode + for label in &used_labels { + if label_graph.contains_node(label) { + let mut label_search = Dfs::new(&label_graph, label); + while let Some(next_label) = label_search.next(&label_graph) { + data_labels.push(next_label); + } + } + } + + used_labels.extend(&data_labels); + + let mut filtered_asm = String::new(); + for (line, line_type) in block.lines().zip(&line_info) { + match *line_type { + Opcode | Misc => { + filtered_asm.push_str(line); + filtered_asm.push('\n'); + } + Data(data) if used_labels.contains(&data) => { + filtered_asm.push_str(line); + filtered_asm.push('\n'); + } + LabelDecl(label) if used_labels.contains(&label) => { + filtered_asm.push('\n'); + filtered_asm.push_str(line); + filtered_asm.push('\n'); + } + _ => (), + } + } + + filtered_asm +} + +#[cfg(test)] +mod test { + #[test] + fn demangles() { + assert_eq!( + super::demangle_asm("_ZN4core3fmt9Arguments6new_v117h3c6f806acbe1ddabE"), + "core::fmt::Arguments::new_v1" + ); + } + + #[test] + fn many_demangles() { + assert_eq!( + super::demangle_asm(".section.text._ZN4core3fmt9Arguments6new_v117h3c6f806acbe1ddabE,\"ax\",@progbits\n .p2align4, 0x90\n .type_ZN4core3fmt9Arguments6new_v117h3c6f806acbe1ddabE,@function"), + ".section.text.core::fmt::Arguments::new_v1,\"ax\",@progbits\n .p2align4, 0x90\n .typecore::fmt::Arguments::new_v1,@function"); + } + + #[test] + fn demangle_pass_through() { + assert_eq!(super::demangle_asm("push rbp\n mov rbp, rsp"), "push rbp\n mov rbp, rsp"); + } + + #[test] + fn one_directive_removed() { + assert_eq!( + super::filter_asm(" .filesystem1 \"\"\n movq%rsp, %rbp\n"), + " movq%rsp, %rbp\n" + ); + } + + #[test] + fn many_directives_removed() { + assert_eq!( + super::filter_asm(" .cfi_def_cfa_register %rbp\n subq$80, %rsp\n .text\n"), + " subq$80, %rsp\n" + ); + } + + #[test] + fn used_label_kept() { + assert_eq!( + super::filter_asm(".Lcfi0:\n callq .Lcfi0\n"), + "\n.Lcfi0:\n callq .Lcfi0\n" + ); + } + + #[test] + fn unused_label_removed() { + assert_eq!( + super::filter_asm( + "addq $16, %rsp\n popq %rbp\n retq\n.Lfunc_end31:\nstr.0:\n" + ), + "addq $16, %rsp\n popq %rbp\n retq\n" + ); + } + + #[test] + fn used_data_kept() { + assert_eq!( + super::filter_asm("ref.2:\n .quad 1\n jmp ref.2\n"), + "\nref.2:\n .quad 1\n jmp ref.2\n" + ) + } + + #[test] + fn unused_data_removed() { + assert_eq!( + super::filter_asm("str.0:\n .ascii \"Hello, world\"\n pop rbp\n"), + " pop rbp\n" + ); + } + + #[test] + fn blank_lines_removed() { + assert_eq!( + super::filter_asm(" mov rbp, rsp\nmain:\n jmp core::fmt::Arguments\n \n"), + " mov rbp, rsp\n jmp core::fmt::Arguments\n" + ) + } + + #[test] + fn functions_kept() { + assert_eq!( + super::filter_asm(" .type main,@function\nmain:\n pushq %rax\n"), + "\nmain:\n pushq %rax\n" + ); + } + #[test] + fn used_data_ref_label_kept() { + assert_eq!( + super::filter_asm(".Lcfi0:\n .quad .Lcfi1\n mov .Lcfi0\n.Lcfi1:\n addq $16, %rsp\n"), + "\n.Lcfi0:\n .quad .Lcfi1\n mov .Lcfi0\n\n.Lcfi1:\n addq $16, %rsp\n" + ); + } + #[test] + fn unused_data_ref_label_removed() { + assert_eq!( + super::filter_asm(".Lcfi0:\n .quad 1\n mov .Lcfi0\n.Lcfi1:\n addq $16, %rsp\n"), + "\n.Lcfi0:\n .quad 1\n mov .Lcfi0\n addq $16, %rsp\n" + ); + } + #[test] + fn used_data_ref_label_graph_walk() { + assert_eq!( + super::filter_asm( + "main:\n .quad ref.1\n mov main\nref.1:\n .quad ref.2\nref.2:\n .quad 1" + ), + "\nmain:\n .quad ref.1\n mov main\n\nref.1:\n .quad ref.2\n\nref.2:\n .quad 1\n" + ); + } + #[test] + fn label_with_comment_recognized() { + assert_eq!( + super::filter_asm( + ".LBB6_10: # =>Comment\n movq %r15, %rsi\n movq %rbx, %rdx\n ja .LBB6_10\n" + ), + "\n.LBB6_10: # =>Comment\n movq %r15, %rsi\n movq %rbx, %rdx\n ja .LBB6_10\n" + ); + } + #[test] + fn comment_retained() { + assert_eq!(super::filter_asm("# %bb.0:\n subq $24, %rsp\n"), "# %bb.0:\n subq $24, %rsp\n") + } +} diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/attach_notice.sh b/anneal/v1/playground/rust-anneal-playground/compiler/base/attach_notice.sh new file mode 100755 index 0000000000..035696a1ff --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/attach_notice.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +set -eu + +NOTICE_FILE=$1 # full path to the notice file +TARGET_FILE=$2 # full patch to the target file + +POSITION=${3:-"top"} # possible values: top or bottom; default value: top + +function attach_notice() { + echo "Attaching ${NOTICE_FILE} to ${TARGET_FILE} (position: ${POSITION})" + + if [[ "${POSITION}" == "bottom" ]]; then + cat "${NOTICE_FILE}" >> "${TARGET_FILE}" + else + combined=$(mktemp) + cat "${NOTICE_FILE}" "${TARGET_FILE}" >> "${combined}" + chmod --reference "${TARGET_FILE}" "${combined}" + mv "${combined}" "${TARGET_FILE}" + fi + + echo "Done." +} + +if [[ -f "${NOTICE_FILE}" ]] && [[ -f "${TARGET_FILE}" ]]; then + attach_notice +fi diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/cargo-anneal-alpha24-cache-manifest.patch b/anneal/v1/playground/rust-anneal-playground/compiler/base/cargo-anneal-alpha24-cache-manifest.patch new file mode 100644 index 0000000000..66622f2ffc --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/cargo-anneal-alpha24-cache-manifest.patch @@ -0,0 +1,623 @@ +diff --git a/src/aeneas.rs b/src/aeneas.rs +index 6fab4b2..92620f9 100644 +--- a/src/aeneas.rs ++++ b/src/aeneas.rs +@@ -28,6 +28,11 @@ use walkdir::WalkDir; + use crate::{generate, resolve::LockedRoots, scanner::AnnealArtifact, setup::Tool}; + + const ANNEAL_PRELUDE: &str = include_str!("Anneal.lean"); ++const VENDORED_AENEAS_LEAN_DIR: &str = "vendor/aeneas/backends/lean"; ++const VENDORED_AENEAS_PACKAGES_DIR: &str = "vendor/aeneas/packages"; ++const PLAYGROUND_ANNEAL_LAKE_LEAN_DIAGNOSTICS: &str = "PLAYGROUND_ANNEAL_LAKE_LEAN_DIAGNOSTICS"; ++const PLAYGROUND_ANNEAL_BUILD_SPECS_SKIP_SUCCESS_DIAGNOSTICS: &str = ++ "PLAYGROUND_ANNEAL_BUILD_SPECS_SKIP_SUCCESS_DIAGNOSTICS"; + + /// Orchestrates the Aeneas translation and Lean verification process. + /// +@@ -94,6 +99,8 @@ pub fn run_aeneas( + .context("Failed to write Lean toolchain")?; + + let mut lake_roots = vec!["Generated".to_string()]; ++ let build_specs_skip_success_diagnostics = ++ std::env::var_os(PLAYGROUND_ANNEAL_BUILD_SPECS_SKIP_SUCCESS_DIAGNOSTICS).is_some(); + let toolchain = crate::setup::Toolchain::resolve()?; + + for artifact in artifacts { +@@ -153,7 +160,7 @@ pub fn run_aeneas( + log::trace!("Aeneas for '{}' took {:.2?}", artifact.name.target_name, start.elapsed()); + + // Aeneas might not generate Funs.lean or Types.lean if there are no +- // functions/types. However, `Specs.lean` and `Generated.lean` expect ++ // functions/types. However, `Spec.lean` and `Generated.lean` expect + // them to exist (as imports). + // + // If Anneal found items that *should* result in these files being +@@ -218,7 +225,7 @@ pub fn run_aeneas( + } + + // Note: we let types and funs lack Prefix imports here because `aeneas_only` +- // doesn't write `Generated.lean` or `Specs.lean`, which expect them as imports. ++ // doesn't write `Generated.lean` or `Spec.lean`, which expect them as imports. + + // Check for `FunsExternal_Template.lean`. + // +@@ -267,17 +274,22 @@ pub fn run_aeneas( + // the generated Lakefile, which is the standard syntax for Name literals in Lean. + lake_roots.push(format!("{}.Funs", slug)); + lake_roots.push(format!("{}.Types", slug)); ++ if build_specs_skip_success_diagnostics { ++ let specs_file = artifact.lean_spec_file_name(); ++ let specs_module = specs_file.trim_end_matches(".lean"); ++ lake_roots.push(format!("{}.{}", slug, specs_module)); ++ } + } + + // 4. Write Lakefile + // + // Aeneas and its Lean dependencies are unpacked from the managed archive. +- let path = materialize_aeneas_dependency(&tmp_lean_root, &lean_root, &toolchain)?; ++ materialize_aeneas_dependency(&tmp_lean_root, &toolchain)?; + let aeneas_dep = format!( + r#"-- Aeneas rev: {} + require aeneas from "{}""#, + env!("ANNEAL_AENEAS_REV"), +- path.display() ++ VENDORED_AENEAS_LEAN_DIR + ); + + let roots_str = lake_roots.iter().map(|r| format!("`{}", r)).collect::>().join(", "); +@@ -307,53 +319,220 @@ lean_lib «User» where + ); + write_if_changed(&tmp_lean_root.join("lakefile.lean"), &lakefile) + .context("Failed to write Lakefile")?; ++ write_lake_manifest(&tmp_lean_root).context("Failed to write Lake manifest")?; + +- // ATOMIC SWAP: If we successfully generated everything, we now swap the +- // temporary directory with the real one. + let lean_root = roots.lean_root(); +- if lean_root.exists() { +- // Preserve the `.lake` directory and manifest to prevent re-downloading +- // dependencies (like Mathlib) on subsequent runs. +- let old_lake = lean_root.join(".lake"); +- let old_manifest = lean_root.join("lake-manifest.json"); +- if old_lake.exists() { +- fs::rename(&old_lake, tmp_lean_root.join(".lake"))?; +- } +- if old_manifest.exists() { +- fs::rename(&old_manifest, tmp_lean_root.join("lake-manifest.json"))?; +- } +- +- // Remove the existing directory before renaming the temporary directory. +- // Note: `fs::rename` on Unix typically requires the target directory to be +- // empty if it exists. While not strictly atomic (there is a brief window +- // where the directory is missing), this prevents a half-written state. +- log::debug!("Removing existing lean directory: {}", lean_root.display()); +- fs::remove_dir_all(&lean_root).context("Failed to remove existing lean directory")?; +- } +- +- log::debug!("Renaming {} to {}", tmp_lean_root.display(), lean_root.display()); +- fs::rename(&tmp_lean_root, &lean_root) +- .context("Failed to rename temporary lean directory to target")?; ++ sync_lean_root(&tmp_lean_root, &lean_root).context("Failed to sync Lean directory")?; + + Ok(()) + } + + fn materialize_aeneas_dependency( + tmp_lean_root: &Path, +- lean_root: &Path, + toolchain: &crate::setup::Toolchain, +-) -> Result { ++) -> Result<()> { + let vendor_root = tmp_lean_root.join("vendor").join("aeneas"); + let lean_dst = vendor_root.join("backends").join("lean"); + let packages_dst = vendor_root.join("packages"); + + println!("Materializing packages by copying from toolchain..."); ++ let start = std::time::Instant::now(); + copy_toolchain_tree_writable(&toolchain.aeneas_lean_dir(), &lean_dst) + .context("Failed to copy Aeneas Lean package from toolchain")?; + copy_toolchain_tree_writable(&toolchain.aeneas_root().join("packages"), &packages_dst) + .context("Failed to copy Aeneas Lean dependencies from toolchain")?; ++ log::trace!("Materializing Aeneas packages took {:.2?}", start.elapsed()); ++ ++ Ok(()) ++} ++ ++fn write_lake_manifest(lean_root: &Path) -> Result<()> { ++ let aeneas_manifest_path = lean_root.join(VENDORED_AENEAS_LEAN_DIR).join("lake-manifest.json"); ++ let content = fs::read_to_string(&aeneas_manifest_path).with_context(|| { ++ format!("Failed to read vendored manifest {}", aeneas_manifest_path.display()) ++ })?; ++ let mut manifest: serde_json::Value = ++ serde_json::from_str(&content).context("Failed to parse vendored Lake manifest")?; ++ ++ let Some(packages) = manifest.get_mut("packages").and_then(|packages| packages.as_array_mut()) ++ else { ++ bail!("Vendored Lake manifest packages field is not an array"); ++ }; ++ for package in packages.iter_mut() { ++ rewrite_vendored_manifest_package(lean_root, package)?; ++ } ++ packages.insert( ++ 0, ++ serde_json::json!({ ++ "type": "path", ++ "scope": "", ++ "name": "aeneas", ++ "manifestFile": "lake-manifest.json", ++ "inherited": false, ++ "dir": VENDORED_AENEAS_LEAN_DIR, ++ "configFile": "lakefile.lean" ++ }), ++ ); ++ ++ manifest["name"] = serde_json::Value::String("anneal_verification".to_owned()); ++ manifest["lakeDir"] = serde_json::Value::String(".lake".to_owned()); ++ manifest["packagesDir"] = serde_json::Value::String(".lake/packages".to_owned()); ++ ++ let mut content = ++ serde_json::to_string_pretty(&manifest).context("Failed to serialize Lake manifest")?; ++ content.push('\n'); ++ write_if_changed(&lean_root.join("lake-manifest.json"), &content)?; ++ Ok(()) ++} ++ ++fn rewrite_vendored_manifest_package( ++ lean_root: &Path, ++ package: &mut serde_json::Value, ++) -> Result<()> { ++ let name = package ++ .get("name") ++ .and_then(|name| name.as_str()) ++ .context("Vendored Lake manifest package is missing a name")? ++ .to_owned(); ++ let dir = std::path::PathBuf::from(VENDORED_AENEAS_PACKAGES_DIR).join(&name); ++ let absolute_dir = lean_root.join(&dir); ++ if !absolute_dir.exists() { ++ bail!("Vendored Lake package directory does not exist: {}", absolute_dir.display()); ++ } ++ ++ let Some(package) = package.as_object_mut() else { ++ bail!("Vendored Lake manifest package is not an object"); ++ }; ++ package.insert("type".to_owned(), serde_json::Value::String("path".to_owned())); ++ package.insert("dir".to_owned(), serde_json::Value::String(path_to_lake_string(&dir))); ++ package.insert("inherited".to_owned(), serde_json::Value::Bool(true)); ++ package.remove("url"); ++ package.remove("rev"); ++ package.remove("inputRev"); ++ package.remove("subDir"); ++ ++ Ok(()) ++} ++ ++fn path_to_lake_string(path: &Path) -> String { ++ path.to_string_lossy().replace('\\', "/") ++} ++ ++fn sync_lean_root(tmp_lean_root: &Path, lean_root: &Path) -> Result<()> { ++ let start = std::time::Instant::now(); ++ if !lean_root.exists() { ++ log::debug!("Renaming {} to {}", tmp_lean_root.display(), lean_root.display()); ++ fs::rename(tmp_lean_root, lean_root) ++ .context("Failed to rename temporary lean directory to target")?; ++ log::trace!("Syncing Lean directory took {:.2?}", start.elapsed()); ++ return Ok(()); ++ } ++ ++ if !lean_root.is_dir() { ++ bail!("Lean root exists but is not a directory: {}", lean_root.display()); ++ } ++ ++ log::debug!( ++ "Syncing {} into {} while preserving unchanged files", ++ tmp_lean_root.display(), ++ lean_root.display() ++ ); ++ sync_directory_preserving_unchanged(tmp_lean_root, lean_root, true) ++ .context("Failed to merge temporary Lean directory into existing Lean directory")?; ++ fs::remove_dir_all(tmp_lean_root).context("Failed to remove temporary Lean directory")?; ++ log::trace!("Syncing Lean directory took {:.2?}", start.elapsed()); ++ Ok(()) ++} ++ ++fn sync_directory_preserving_unchanged(src: &Path, dst: &Path, preserve_top_level_lake: bool) -> Result<()> { ++ fs::create_dir_all(dst) ++ .with_context(|| format!("Failed to create destination directory {}", dst.display()))?; ++ ++ let mut expected = std::collections::BTreeSet::new(); ++ for entry in fs::read_dir(src).with_context(|| format!("Failed to read {}", src.display()))? { ++ let entry = entry.context("Failed to read source directory entry")?; ++ let file_name = entry.file_name(); ++ expected.insert(file_name.clone()); ++ ++ let src_path = entry.path(); ++ let dst_path = dst.join(&file_name); ++ let src_metadata = fs::symlink_metadata(&src_path) ++ .with_context(|| format!("Failed to stat {}", src_path.display()))?; ++ ++ if src_metadata.is_dir() { ++ if path_exists(&dst_path) && !dst_path.is_dir() { ++ remove_path(&dst_path) ++ .with_context(|| format!("Failed to replace {}", dst_path.display()))?; ++ } ++ sync_directory_preserving_unchanged(&src_path, &dst_path, false)?; ++ } else { ++ sync_file_preserving_unchanged(&src_path, &dst_path)?; ++ } ++ } ++ ++ for entry in fs::read_dir(dst).with_context(|| format!("Failed to read {}", dst.display()))? { ++ let entry = entry.context("Failed to read destination directory entry")?; ++ let file_name = entry.file_name(); ++ if preserve_top_level_lake && file_name == std::ffi::OsStr::new(".lake") { ++ continue; ++ } ++ if !expected.contains(&file_name) { ++ let path = entry.path(); ++ remove_path(&path).with_context(|| format!("Failed to remove stale path {}", path.display()))?; ++ } ++ } ++ ++ Ok(()) ++} ++ ++fn sync_file_preserving_unchanged(src: &Path, dst: &Path) -> Result<()> { ++ if files_equal(src, dst)? { ++ return Ok(()); ++ } ++ ++ if path_exists(dst) { ++ remove_path(dst).with_context(|| format!("Failed to replace {}", dst.display()))?; ++ } ++ fs::rename(src, dst) ++ .with_context(|| format!("Failed to move {} to {}", src.display(), dst.display()))?; ++ Ok(()) ++} ++ ++fn files_equal(src: &Path, dst: &Path) -> Result { ++ if !dst.is_file() { ++ return Ok(false); ++ } ++ ++ let src_metadata = ++ fs::metadata(src).with_context(|| format!("Failed to stat {}", src.display()))?; ++ let dst_metadata = ++ fs::metadata(dst).with_context(|| format!("Failed to stat {}", dst.display()))?; ++ if src_metadata.len() != dst_metadata.len() { ++ return Ok(false); ++ } ++ if src_metadata.len() == 0 { ++ return Ok(true); ++ } ++ ++ let src_content = fs::read(src).with_context(|| format!("Failed to read {}", src.display()))?; ++ let dst_content = fs::read(dst).with_context(|| format!("Failed to read {}", dst.display()))?; ++ Ok(src_content == dst_content) ++} ++ ++fn path_exists(path: &Path) -> bool { ++ fs::symlink_metadata(path).is_ok() ++} + +- Ok(lean_root.join("vendor").join("aeneas").join("backends").join("lean")) ++fn remove_path(path: &Path) -> Result<()> { ++ let metadata = ++ fs::symlink_metadata(path).with_context(|| format!("Failed to stat {}", path.display()))?; ++ if metadata.is_dir() { ++ fs::remove_dir_all(path) ++ .with_context(|| format!("Failed to remove directory {}", path.display()))?; ++ } else { ++ fs::remove_file(path).with_context(|| format!("Failed to remove file {}", path.display()))?; ++ } ++ Ok(()) + } + + fn copy_toolchain_tree_writable(src: &Path, dst: &Path) -> Result<()> { +@@ -503,7 +682,7 @@ fn is_lake_input_file(path: &Path) -> bool { + ) + } + +-/// Generates Anneal `Specs.lean` and writes `Generated.lean`, but does not run the `lake build`. ++/// Generates Anneal `Spec.lean` and writes `Generated.lean`, but does not run the `lake build`. + pub fn generate_lean_workspace(roots: &LockedRoots, artifacts: &[AnnealArtifact]) -> Result<()> { + let lean_generated_root = roots.lean_generated_root(); + let mut generated_imports = String::new(); +@@ -548,7 +727,7 @@ pub fn generate_lean_workspace(roots: &LockedRoots, artifacts: &[AnnealArtifact] + Ok(()) + } + +-/// Completes Lean verification by generating Anneal `Specs.lean`, writing `Generated.lean`, ++/// Completes Lean verification by generating Anneal `Spec.lean`, writing `Generated.lean`, + /// and running `lake build` + diagnostics. + pub fn verify_lean_workspace(roots: &LockedRoots, artifacts: &[AnnealArtifact]) -> Result<()> { + generate_lean_workspace(roots, artifacts)?; +@@ -562,94 +741,58 @@ pub fn verify_lean_workspace(roots: &LockedRoots, artifacts: &[AnnealArtifact]) + fn run_lake(roots: &LockedRoots, artifacts: &[AnnealArtifact]) -> Result<()> { + let generated = roots.lean_generated_root(); + let lean_root = generated.parent().unwrap(); +- log::info!("Running 'lake build' in {}", lean_root.display()); +- +- // 2. Build the project (dependencies only) + let toolchain = crate::setup::Toolchain::resolve()?; +- let mut cmd = std::process::Command::new(toolchain.lean_bin().join("lake")); +- cmd.args(["--keep-toolchain", "--old", "build", "Generated", "Anneal"]); +- cmd.current_dir(lean_root); +- configure_lake_command(&mut cmd, &toolchain)?; +- cmd.stdout(Stdio::piped()); +- cmd.stderr(Stdio::piped()); +- +- let start = std::time::Instant::now(); +- let mut child = cmd.spawn().context("Failed to spawn lake")?; + +- // Capture stderr in background +- let stderr_buffer = Arc::new(Mutex::new(Vec::new())); +- let stderr_clone = stderr_buffer.clone(); +- let stderr_handle = child.stderr.take().map(|stderr| { +- std::thread::spawn(move || { +- let reader = BufReader::new(stderr); +- for line in reader.lines().map_while(Result::ok) { +- stderr_clone.lock().unwrap().push(line); ++ let use_lake_lean_diagnostics = ++ std::env::var_os(PLAYGROUND_ANNEAL_LAKE_LEAN_DIAGNOSTICS).is_some(); ++ let build_specs_skip_success_diagnostics = ++ std::env::var_os(PLAYGROUND_ANNEAL_BUILD_SPECS_SKIP_SUCCESS_DIAGNOSTICS).is_some(); ++ let mut lake_build_error = None; ++ if use_lake_lean_diagnostics { ++ log::info!( ++ "[anneal-lake-lean] skipping standalone 'lake build'; diagnostics will use 'lake --old lean -- --json'" ++ ); ++ } else { ++ log::info!("Running 'lake build' in {}", lean_root.display()); ++ match run_lake_build(lean_root, &toolchain) { ++ Ok(()) if build_specs_skip_success_diagnostics => { ++ log::info!( ++ "[anneal-fast-diagnostics] successful Lake build included Spec; skipping post-build JSON diagnostics" ++ ); ++ return Ok(()); + } +- }) +- }); +- +- // UI Spinner +- let pb = ProgressBar::new_spinner(); +- pb.set_style(ProgressStyle::default_spinner().template("{spinner:.green} {msg}").unwrap()); +- pb.enable_steady_tick(std::time::Duration::from_millis(100)); +- pb.set_message("Building Lean dependencies..."); +- +- // Capture stdout in background (while ticking progress bar) +- let stdout_buffer = Arc::new(Mutex::new(Vec::new())); +- let stdout_clone = stdout_buffer.clone(); +- let pb_clone = pb.clone(); +- +- let stdout_handle = child.stdout.take().map(|stdout| { +- std::thread::spawn(move || { +- let reader = BufReader::new(stdout); +- for line in reader.lines().map_while(Result::ok) { +- stdout_clone.lock().unwrap().push(line); +- pb_clone.tick(); ++ Ok(()) => {} ++ Err(error) if build_specs_skip_success_diagnostics => { ++ log::warn!( ++ "[anneal-fast-diagnostics] Lake build failed after including Spec; running JSON diagnostics" ++ ); ++ log::debug!("Lake build failure before diagnostics: {error:?}"); ++ lake_build_error = Some(format!("{error:#}")); + } +- }) +- }); +- +- let status = child.wait().context("Failed to wait for lake")?; +- pb.finish_and_clear(); +- log::trace!("'lake build' took {:.2?}", start.elapsed()); +- +- // Join the threads to ensure we have all logs +- if let Some(handle) = stderr_handle +- && let Err(e) = handle.join() +- { +- log::error!("Stderr reading thread panicked: {:?}", e); +- } +- if let Some(handle) = stdout_handle +- && let Err(e) = handle.join() +- { +- log::error!("Stdout reading thread panicked: {:?}", e); +- } +- +- if !status.success() { +- let stderr = stderr_buffer.lock().unwrap().join("\n"); +- let stdout = stdout_buffer.lock().unwrap().join("\n"); +- bail!("Lean build failed\nSTDOUT:\n{}\nSTDERR:\n{}", stdout, stderr); ++ Err(error) => return Err(error), ++ } + } + + // 3. Run Diagnostics + log::info!("Running Lean diagnostics..."); ++ let diagnostics_start = std::time::Instant::now(); + let mut has_errors = false; + let mut mapper = crate::diagnostics::DiagnosticMapper::new(roots.workspace().clone()); + + for artifact in artifacts { ++ let diagnostic_start = std::time::Instant::now(); + let slug = artifact.artifact_slug(); +- // The path in generated file is `generated/Slug/Specs.lean` ++ // The path in generated file is `generated/Slug/Spec.lean` + // We construct the relative path from the Lake root (which is `target/anneal//lean`) + let specs_rel_path = format!("generated/{}/{}", slug, artifact.lean_spec_file_name()); + +- let mut cmd = std::process::Command::new(toolchain.lean_bin().join("lake")); +- cmd.args(["--keep-toolchain", "env", "lean", "--json", &specs_rel_path]); +- cmd.current_dir(lean_root); +- configure_lake_command(&mut cmd, &toolchain)?; +- cmd.stdout(Stdio::piped()); +- cmd.stderr(Stdio::piped()); +- +- let output = cmd.output().context("Failed to run lean compiler")?; ++ let output = run_lean_diagnostics_command( ++ &toolchain, ++ lean_root, ++ &specs_rel_path, ++ &slug, ++ use_lake_lean_diagnostics, ++ )?; + + let output_str = String::from_utf8_lossy(&output.stdout); + let specs_abs_path = lean_root.join(&specs_rel_path); +@@ -737,7 +880,9 @@ fn run_lake(roots: &LockedRoots, artifacts: &[AnnealArtifact]) -> Result<()> { + let (file, start, end) = resolve_mapping(&diag, &mappings); + mapper.render_raw(&file, diag.message, level, start, end, |s| eprintln!("{s}")); + } ++ log::trace!("Lean diagnostics for '{}' took {:.2?}", slug, diagnostic_start.elapsed()); + } ++ log::trace!("Lean diagnostics took {:.2?}", diagnostics_start.elapsed()); + + if has_errors { + let cmd = if std::env::var("__ZEROCOPY_LOCAL_DEV").is_ok() { +@@ -750,9 +895,112 @@ fn run_lake(roots: &LockedRoots, artifacts: &[AnnealArtifact]) -> Result<()> { + ); + } + ++ if let Some(error) = lake_build_error { ++ bail!("Lean build failed before diagnostics:\n{error}"); ++ } ++ ++ Ok(()) ++} ++ ++fn run_lake_build(lean_root: &Path, toolchain: &crate::setup::Toolchain) -> Result<()> { ++ let mut cmd = std::process::Command::new(toolchain.lean_bin().join("lake")); ++ cmd.args(["--keep-toolchain", "--old", "build", "Generated", "Anneal"]); ++ cmd.current_dir(lean_root); ++ configure_lake_command(&mut cmd, toolchain)?; ++ cmd.stdout(Stdio::piped()); ++ cmd.stderr(Stdio::piped()); ++ ++ let start = std::time::Instant::now(); ++ let mut child = cmd.spawn().context("Failed to spawn lake")?; ++ ++ // Capture stderr in background ++ let stderr_buffer = Arc::new(Mutex::new(Vec::new())); ++ let stderr_clone = stderr_buffer.clone(); ++ let stderr_handle = child.stderr.take().map(|stderr| { ++ std::thread::spawn(move || { ++ let reader = BufReader::new(stderr); ++ for line in reader.lines().map_while(Result::ok) { ++ stderr_clone.lock().unwrap().push(line); ++ } ++ }) ++ }); ++ ++ // UI Spinner ++ let pb = ProgressBar::new_spinner(); ++ pb.set_style(ProgressStyle::default_spinner().template("{spinner:.green} {msg}").unwrap()); ++ pb.enable_steady_tick(std::time::Duration::from_millis(100)); ++ pb.set_message("Building Lean dependencies..."); ++ ++ // Capture stdout in background (while ticking progress bar) ++ let stdout_buffer = Arc::new(Mutex::new(Vec::new())); ++ let stdout_clone = stdout_buffer.clone(); ++ let pb_clone = pb.clone(); ++ ++ let stdout_handle = child.stdout.take().map(|stdout| { ++ std::thread::spawn(move || { ++ let reader = BufReader::new(stdout); ++ for line in reader.lines().map_while(Result::ok) { ++ stdout_clone.lock().unwrap().push(line); ++ pb_clone.tick(); ++ } ++ }) ++ }); ++ ++ let status = child.wait().context("Failed to wait for lake")?; ++ pb.finish_and_clear(); ++ log::trace!("'lake build' took {:.2?}", start.elapsed()); ++ ++ // Join the threads to ensure we have all logs ++ if let Some(handle) = stderr_handle ++ && let Err(e) = handle.join() ++ { ++ log::error!("Stderr reading thread panicked: {:?}", e); ++ } ++ if let Some(handle) = stdout_handle ++ && let Err(e) = handle.join() ++ { ++ log::error!("Stdout reading thread panicked: {:?}", e); ++ } ++ ++ if !status.success() { ++ let stderr = stderr_buffer.lock().unwrap().join("\n"); ++ let stdout = stdout_buffer.lock().unwrap().join("\n"); ++ bail!("Lean build failed\nSTDOUT:\n{}\nSTDERR:\n{}", stdout, stderr); ++ } ++ + Ok(()) + } + ++fn run_lean_diagnostics_command( ++ toolchain: &crate::setup::Toolchain, ++ lean_root: &Path, ++ specs_rel_path: &str, ++ slug: &str, ++ use_lake_lean_diagnostics: bool, ++) -> Result { ++ let mut cmd = std::process::Command::new(toolchain.lean_bin().join("lake")); ++ let start = std::time::Instant::now(); ++ if use_lake_lean_diagnostics { ++ cmd.args(["--keep-toolchain", "--old", "lean", specs_rel_path, "--", "--json"]); ++ } else { ++ cmd.args(["--keep-toolchain", "env", "lean", "--json", specs_rel_path]); ++ } ++ cmd.current_dir(lean_root); ++ configure_lake_command(&mut cmd, toolchain)?; ++ cmd.stdout(Stdio::piped()); ++ cmd.stderr(Stdio::piped()); ++ ++ let output = cmd.output().context("Failed to run lean compiler")?; ++ if use_lake_lean_diagnostics { ++ log::trace!( ++ "'lake --old lean -- --json' for '{}' took {:.2?}", ++ slug, ++ start.elapsed() ++ ); ++ } ++ Ok(output) ++} ++ + fn configure_lake_command( + cmd: &mut std::process::Command, + toolchain: &crate::setup::Toolchain, +diff --git a/src/scanner.rs b/src/scanner.rs +index 44b6641..2cd29b7 100644 +--- a/src/scanner.rs ++++ b/src/scanner.rs +@@ -115,7 +115,7 @@ impl AnnealArtifact { + + /// Returns the name of the `.lean` spec file to use for this artifact. + pub fn lean_spec_file_name(&self) -> String { +- format!("{}.lean", self.artifact_slug()) ++ "Spec.lean".to_owned() + } + + /// Returns the absolute path to the .llbc file. +@@ -480,7 +480,7 @@ mod tests { + } + + #[test] +- fn test_lean_spec_file_name_uses_slug() { ++ fn test_lean_spec_file_name_is_stable() { + let name = AnnealTargetName { + package_name: PackageName::new("pkg-foo".to_string()), + target_name: "name-bar".to_string(), +@@ -495,10 +495,7 @@ mod tests { + items: vec![], + }; + +- // Slug should be PascalCase: PkgFoo_NameBar_ +- // Spec file should be slug + .lean + let spec_name = artifact.lean_spec_file_name(); +- assert!(spec_name.starts_with("PkgFooNameBar")); +- assert!(spec_name.ends_with(".lean")); ++ assert_eq!(spec_name, "Spec.lean"); + } + } diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/cargo-miri-playground b/anneal/v1/playground/rust-anneal-playground/compiler/base/cargo-miri-playground new file mode 100755 index 0000000000..74f393ec1f --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/cargo-miri-playground @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -eu + +export MIRI_SYSROOT=~/.cache/miri +export MIRIFLAGS="${MIRIFLAGS:-} -Zmiri-disable-isolation" +exec cargo miri run diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/cargo-wasm b/anneal/v1/playground/rust-anneal-playground/compiler/base/cargo-wasm new file mode 100755 index 0000000000..1220673e7c --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/cargo-wasm @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +set -eu + +# Rewrite our arguments to be `cargo build` instead of `cargo wasm`; +# this assumes that the command will always be `cargo wasm ...`. We +# capture the output directory in order to place the result file. +shift # Ignore "wasm" +args=() +while (( "$#" )); do + if [[ "$1" == "--" ]] ; then + : # Ignore + elif [[ "$1" == "-o" ]] ; then + shift + output="$1" + else + args+=("$1") + fi + + shift +done + +# Perform our build +# https://stackoverflow.com/a/7577209/155423 +cargo "build" "--target=wasm32-unknown-unknown" ${args[@]+"${args[@]}"} + +for wasm in $(find target/ -name '*wasm' -not -path '*/deps/*'); do + # Convert to textual format, demangling as we go + wasm-tools demangle "${wasm}" -t -o "${output}.wat" + + # The streaming playground expects the file to be without the + # extension while the original playground expects it to be with + # the extension. Support both for now. + cp "${output}.wat" "${output}" +done diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/crate-information.json b/anneal/v1/playground/rust-anneal-playground/compiler/base/crate-information.json new file mode 100644 index 0000000000..fc97ac0ac4 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/crate-information.json @@ -0,0 +1,2382 @@ +[ + { + "name": "addr2line", + "version": "0.25.1", + "id": "addr2line" + }, + { + "name": "adler2", + "version": "2.0.1", + "id": "adler2" + }, + { + "name": "ahash", + "version": "0.8.12", + "id": "ahash" + }, + { + "name": "aho-corasick", + "version": "1.1.4", + "id": "aho_corasick" + }, + { + "name": "aligned", + "version": "0.4.3", + "id": "aligned" + }, + { + "name": "aligned-vec", + "version": "0.6.4", + "id": "aligned_vec" + }, + { + "name": "alloc-no-stdlib", + "version": "2.0.4", + "id": "alloc_no_stdlib" + }, + { + "name": "alloc-stdlib", + "version": "0.2.2", + "id": "alloc_stdlib" + }, + { + "name": "allocator-api2", + "version": "0.2.21", + "id": "allocator_api2" + }, + { + "name": "ansi_term", + "version": "0.12.1", + "id": "ansi_term" + }, + { + "name": "anstream", + "version": "1.0.0", + "id": "anstream" + }, + { + "name": "anstyle", + "version": "1.0.14", + "id": "anstyle" + }, + { + "name": "anstyle-parse", + "version": "1.0.0", + "id": "anstyle_parse" + }, + { + "name": "anstyle-query", + "version": "1.1.5", + "id": "anstyle_query" + }, + { + "name": "anyhow", + "version": "1.0.102", + "id": "anyhow" + }, + { + "name": "approx", + "version": "0.5.1", + "id": "approx" + }, + { + "name": "arbitrary", + "version": "1.4.2", + "id": "arbitrary" + }, + { + "name": "arc-swap", + "version": "1.9.1", + "id": "arc_swap" + }, + { + "name": "arg_enum_proc_macro", + "version": "0.3.4", + "id": "arg_enum_proc_macro" + }, + { + "name": "arrayvec", + "version": "0.7.6", + "id": "arrayvec" + }, + { + "name": "as-slice", + "version": "0.2.1", + "id": "as_slice" + }, + { + "name": "async-compression", + "version": "0.4.42", + "id": "async_compression" + }, + { + "name": "async-trait", + "version": "0.1.89", + "id": "async_trait" + }, + { + "name": "atomic", + "version": "0.6.1", + "id": "atomic" + }, + { + "name": "atomic-waker", + "version": "1.1.2", + "id": "atomic_waker" + }, + { + "name": "autocfg", + "version": "1.5.1", + "id": "autocfg" + }, + { + "name": "av1-grain", + "version": "0.2.5", + "id": "av1_grain" + }, + { + "name": "av-scenechange", + "version": "0.14.1", + "id": "av_scenechange" + }, + { + "name": "avif-serialize", + "version": "0.8.9", + "id": "avif_serialize" + }, + { + "name": "aws-lc-rs", + "version": "1.17.0", + "id": "aws_lc_rs" + }, + { + "name": "aws-lc-sys", + "version": "0.41.0", + "id": "aws_lc_sys" + }, + { + "name": "backtrace", + "version": "0.3.76", + "id": "backtrace" + }, + { + "name": "base64", + "version": "0.22.1", + "id": "base64" + }, + { + "name": "bit_field", + "version": "0.10.3", + "id": "bit_field" + }, + { + "name": "bit-set", + "version": "0.5.3", + "id": "bit_set" + }, + { + "name": "bit-vec", + "version": "0.6.3", + "id": "bit_vec" + }, + { + "name": "bitflags", + "version": "2.12.1", + "id": "bitflags" + }, + { + "name": "bitstream-io", + "version": "4.10.0", + "id": "bitstream_io" + }, + { + "name": "bitvec", + "version": "1.0.1", + "id": "bitvec" + }, + { + "name": "block-buffer", + "version": "0.12.0", + "id": "block_buffer" + }, + { + "name": "block-buffer", + "version": "0.10.4", + "id": "block_buffer_0_10_4" + }, + { + "name": "borsh", + "version": "1.6.1", + "id": "borsh" + }, + { + "name": "brotli", + "version": "8.0.3", + "id": "brotli" + }, + { + "name": "brotli-decompressor", + "version": "5.0.1", + "id": "brotli_decompressor" + }, + { + "name": "built", + "version": "0.8.1", + "id": "built" + }, + { + "name": "bumpalo", + "version": "3.20.3", + "id": "bumpalo" + }, + { + "name": "bytecheck", + "version": "0.8.2", + "id": "bytecheck" + }, + { + "name": "bytecheck_derive", + "version": "0.8.2", + "id": "bytecheck_derive" + }, + { + "name": "bytemuck", + "version": "1.25.0", + "id": "bytemuck" + }, + { + "name": "bytemuck_derive", + "version": "1.10.2", + "id": "bytemuck_derive" + }, + { + "name": "byteorder", + "version": "1.5.0", + "id": "byteorder" + }, + { + "name": "byteorder-lite", + "version": "0.1.0", + "id": "byteorder_lite" + }, + { + "name": "bytes", + "version": "1.11.1", + "id": "bytes" + }, + { + "name": "bytes", + "version": "0.4.12", + "id": "bytes_0_4_12" + }, + { + "name": "cc", + "version": "1.2.63", + "id": "cc" + }, + { + "name": "cfg_aliases", + "version": "0.2.1", + "id": "cfg_aliases" + }, + { + "name": "cfg-if", + "version": "1.0.4", + "id": "cfg_if" + }, + { + "name": "chacha20", + "version": "0.10.0", + "id": "chacha20" + }, + { + "name": "chrono", + "version": "0.4.44", + "id": "chrono" + }, + { + "name": "clap", + "version": "4.6.1", + "id": "clap" + }, + { + "name": "clap_builder", + "version": "4.6.0", + "id": "clap_builder" + }, + { + "name": "clap_derive", + "version": "4.6.1", + "id": "clap_derive" + }, + { + "name": "clap_lex", + "version": "1.1.0", + "id": "clap_lex" + }, + { + "name": "cmake", + "version": "0.1.58", + "id": "cmake" + }, + { + "name": "cmov", + "version": "0.5.4", + "id": "cmov" + }, + { + "name": "color_quant", + "version": "1.1.0", + "id": "color_quant" + }, + { + "name": "colorchoice", + "version": "1.0.5", + "id": "colorchoice" + }, + { + "name": "compression-codecs", + "version": "0.4.38", + "id": "compression_codecs" + }, + { + "name": "compression-core", + "version": "0.4.32", + "id": "compression_core" + }, + { + "name": "const-default", + "version": "1.0.0", + "id": "const_default" + }, + { + "name": "const-oid", + "version": "0.10.2", + "id": "const_oid" + }, + { + "name": "convert_case", + "version": "0.10.0", + "id": "convert_case" + }, + { + "name": "cookie", + "version": "0.18.1", + "id": "cookie" + }, + { + "name": "cookie_store", + "version": "0.22.1", + "id": "cookie_store" + }, + { + "name": "cpufeatures", + "version": "0.3.0", + "id": "cpufeatures" + }, + { + "name": "crc32fast", + "version": "1.5.0", + "id": "crc32fast" + }, + { + "name": "crossbeam", + "version": "0.8.4", + "id": "crossbeam" + }, + { + "name": "crossbeam-channel", + "version": "0.5.15", + "id": "crossbeam_channel" + }, + { + "name": "crossbeam-deque", + "version": "0.8.6", + "id": "crossbeam_deque" + }, + { + "name": "crossbeam-epoch", + "version": "0.9.18", + "id": "crossbeam_epoch" + }, + { + "name": "crossbeam-queue", + "version": "0.3.12", + "id": "crossbeam_queue" + }, + { + "name": "crossbeam-utils", + "version": "0.8.21", + "id": "crossbeam_utils" + }, + { + "name": "crypto-common", + "version": "0.2.2", + "id": "crypto_common" + }, + { + "name": "crypto-common", + "version": "0.1.7", + "id": "crypto_common_0_1_7" + }, + { + "name": "cssparser", + "version": "0.31.2", + "id": "cssparser" + }, + { + "name": "cssparser-macros", + "version": "0.6.1", + "id": "cssparser_macros" + }, + { + "name": "csv", + "version": "1.4.0", + "id": "csv" + }, + { + "name": "csv-core", + "version": "0.1.13", + "id": "csv_core" + }, + { + "name": "ctutils", + "version": "0.4.2", + "id": "ctutils" + }, + { + "name": "data-encoding", + "version": "2.11.0", + "id": "data_encoding" + }, + { + "name": "new_debug_unreachable", + "version": "1.0.6", + "id": "debug_unreachable" + }, + { + "name": "deranged", + "version": "0.5.8", + "id": "deranged" + }, + { + "name": "derive_more", + "version": "2.1.1", + "id": "derive_more" + }, + { + "name": "derive_more", + "version": "0.99.20", + "id": "derive_more_0_99_20" + }, + { + "name": "derive_more-impl", + "version": "2.1.1", + "id": "derive_more_impl" + }, + { + "name": "destructure_traitobject", + "version": "0.2.0", + "id": "destructure_traitobject" + }, + { + "name": "digest", + "version": "0.11.3", + "id": "digest" + }, + { + "name": "digest", + "version": "0.10.7", + "id": "digest_0_10_7" + }, + { + "name": "displaydoc", + "version": "0.2.6", + "id": "displaydoc" + }, + { + "name": "document-features", + "version": "0.2.12", + "id": "document_features" + }, + { + "name": "dtoa", + "version": "1.0.11", + "id": "dtoa" + }, + { + "name": "dtoa-short", + "version": "0.3.5", + "id": "dtoa_short" + }, + { + "name": "dunce", + "version": "1.0.5", + "id": "dunce" + }, + { + "name": "ego-tree", + "version": "0.6.3", + "id": "ego_tree" + }, + { + "name": "either", + "version": "1.16.0", + "id": "either" + }, + { + "name": "encoding_rs", + "version": "0.8.35", + "id": "encoding_rs" + }, + { + "name": "env_filter", + "version": "1.0.1", + "id": "env_filter" + }, + { + "name": "env_logger", + "version": "0.11.10", + "id": "env_logger" + }, + { + "name": "equator", + "version": "0.4.2", + "id": "equator" + }, + { + "name": "equator-macro", + "version": "0.4.2", + "id": "equator_macro" + }, + { + "name": "equivalent", + "version": "1.0.2", + "id": "equivalent" + }, + { + "name": "errno", + "version": "0.3.14", + "id": "errno" + }, + { + "name": "exr", + "version": "1.74.0", + "id": "exr" + }, + { + "name": "fallible-iterator", + "version": "0.3.0", + "id": "fallible_iterator" + }, + { + "name": "fallible-iterator", + "version": "0.2.0", + "id": "fallible_iterator_0_2_0" + }, + { + "name": "fallible-streaming-iterator", + "version": "0.1.9", + "id": "fallible_streaming_iterator" + }, + { + "name": "faster-hex", + "version": "0.10.0", + "id": "faster_hex" + }, + { + "name": "fastrand", + "version": "2.4.1", + "id": "fastrand" + }, + { + "name": "fax", + "version": "0.2.7", + "id": "fax" + }, + { + "name": "fdeflate", + "version": "0.3.7", + "id": "fdeflate" + }, + { + "name": "filetime", + "version": "0.2.29", + "id": "filetime" + }, + { + "name": "find-msvc-tools", + "version": "0.1.9", + "id": "find_msvc_tools" + }, + { + "name": "fixedbitset", + "version": "0.5.7", + "id": "fixedbitset" + }, + { + "name": "fixedbitset", + "version": "0.4.2", + "id": "fixedbitset_0_4_2" + }, + { + "name": "flate2", + "version": "1.1.9", + "id": "flate2" + }, + { + "name": "fnv", + "version": "1.0.7", + "id": "fnv" + }, + { + "name": "foldhash", + "version": "0.2.0", + "id": "foldhash" + }, + { + "name": "foldhash", + "version": "0.1.5", + "id": "foldhash_0_1_5" + }, + { + "name": "form_urlencoded", + "version": "1.2.2", + "id": "form_urlencoded" + }, + { + "name": "fs_extra", + "version": "1.3.0", + "id": "fs_extra" + }, + { + "name": "funty", + "version": "2.0.0", + "id": "funty" + }, + { + "name": "futf", + "version": "0.1.5", + "id": "futf" + }, + { + "name": "futures", + "version": "0.3.32", + "id": "futures" + }, + { + "name": "futures", + "version": "0.1.31", + "id": "futures_0_1_31" + }, + { + "name": "futures-channel", + "version": "0.3.32", + "id": "futures_channel" + }, + { + "name": "futures-core", + "version": "0.3.32", + "id": "futures_core" + }, + { + "name": "futures-executor", + "version": "0.3.32", + "id": "futures_executor" + }, + { + "name": "futures-io", + "version": "0.3.32", + "id": "futures_io" + }, + { + "name": "futures-macro", + "version": "0.3.32", + "id": "futures_macro" + }, + { + "name": "futures-sink", + "version": "0.3.32", + "id": "futures_sink" + }, + { + "name": "futures-task", + "version": "0.3.32", + "id": "futures_task" + }, + { + "name": "futures-util", + "version": "0.3.32", + "id": "futures_util" + }, + { + "name": "fxhash", + "version": "0.2.1", + "id": "fxhash" + }, + { + "name": "generic-array", + "version": "1.4.3", + "id": "generic_array" + }, + { + "name": "generic-array", + "version": "0.14.7", + "id": "generic_array_0_14_7" + }, + { + "name": "getopts", + "version": "0.2.24", + "id": "getopts" + }, + { + "name": "getrandom", + "version": "0.4.2", + "id": "getrandom" + }, + { + "name": "getrandom", + "version": "0.2.17", + "id": "getrandom_0_2_17" + }, + { + "name": "getrandom", + "version": "0.3.4", + "id": "getrandom_0_3_4" + }, + { + "name": "gif", + "version": "0.14.2", + "id": "gif" + }, + { + "name": "gimli", + "version": "0.32.3", + "id": "gimli" + }, + { + "name": "glob", + "version": "0.3.3", + "id": "glob" + }, + { + "name": "h2", + "version": "0.4.14", + "id": "h2" + }, + { + "name": "half", + "version": "2.7.1", + "id": "half" + }, + { + "name": "hash32", + "version": "0.3.1", + "id": "hash32" + }, + { + "name": "hashbrown", + "version": "0.17.1", + "id": "hashbrown" + }, + { + "name": "hashbrown", + "version": "0.15.5", + "id": "hashbrown_0_15_5" + }, + { + "name": "hashbrown", + "version": "0.16.1", + "id": "hashbrown_0_16_1" + }, + { + "name": "hashlink", + "version": "0.11.0", + "id": "hashlink" + }, + { + "name": "hdrhistogram", + "version": "7.5.4", + "id": "hdrhistogram" + }, + { + "name": "heapless", + "version": "0.8.0", + "id": "heapless" + }, + { + "name": "heck", + "version": "0.5.0", + "id": "heck" + }, + { + "name": "hmac", + "version": "0.13.0", + "id": "hmac" + }, + { + "name": "html5ever", + "version": "0.27.0", + "id": "html5ever" + }, + { + "name": "html5ever", + "version": "0.26.0", + "id": "html5ever_0_26_0" + }, + { + "name": "http", + "version": "1.4.1", + "id": "http" + }, + { + "name": "http-body", + "version": "1.0.1", + "id": "http_body" + }, + { + "name": "http-body-util", + "version": "0.1.3", + "id": "http_body_util" + }, + { + "name": "http-range-header", + "version": "0.4.2", + "id": "http_range_header" + }, + { + "name": "httparse", + "version": "1.10.1", + "id": "httparse" + }, + { + "name": "httpdate", + "version": "1.0.3", + "id": "httpdate" + }, + { + "name": "humantime", + "version": "2.3.0", + "id": "humantime" + }, + { + "name": "hybrid-array", + "version": "0.4.12", + "id": "hybrid_array" + }, + { + "name": "hyper", + "version": "1.10.1", + "id": "hyper" + }, + { + "name": "hyper-rustls", + "version": "0.27.9", + "id": "hyper_rustls" + }, + { + "name": "hyper-util", + "version": "0.1.20", + "id": "hyper_util" + }, + { + "name": "iana-time-zone", + "version": "0.1.65", + "id": "iana_time_zone" + }, + { + "name": "icu_collections", + "version": "2.2.0", + "id": "icu_collections" + }, + { + "name": "icu_locale_core", + "version": "2.2.0", + "id": "icu_locale_core" + }, + { + "name": "icu_normalizer", + "version": "2.2.0", + "id": "icu_normalizer" + }, + { + "name": "icu_normalizer_data", + "version": "2.2.0", + "id": "icu_normalizer_data" + }, + { + "name": "icu_properties", + "version": "2.2.0", + "id": "icu_properties" + }, + { + "name": "icu_properties_data", + "version": "2.2.0", + "id": "icu_properties_data" + }, + { + "name": "icu_provider", + "version": "2.2.0", + "id": "icu_provider" + }, + { + "name": "idna", + "version": "1.1.0", + "id": "idna" + }, + { + "name": "idna_adapter", + "version": "1.2.2", + "id": "idna_adapter" + }, + { + "name": "image", + "version": "0.25.10", + "id": "image" + }, + { + "name": "image-webp", + "version": "0.2.4", + "id": "image_webp" + }, + { + "name": "imgref", + "version": "1.12.1", + "id": "imgref" + }, + { + "name": "indexmap", + "version": "2.14.0", + "id": "indexmap" + }, + { + "name": "iovec", + "version": "0.1.4", + "id": "iovec" + }, + { + "name": "ipnet", + "version": "2.12.0", + "id": "ipnet" + }, + { + "name": "is_terminal_polyfill", + "version": "1.70.2", + "id": "is_terminal_polyfill" + }, + { + "name": "itertools", + "version": "0.14.0", + "id": "itertools" + }, + { + "name": "itoa", + "version": "1.0.18", + "id": "itoa" + }, + { + "name": "jiff", + "version": "0.2.28", + "id": "jiff" + }, + { + "name": "jiff-static", + "version": "0.2.28", + "id": "jiff_static" + }, + { + "name": "jiff-tzdb", + "version": "0.1.6", + "id": "jiff_tzdb" + }, + { + "name": "jobserver", + "version": "0.1.34", + "id": "jobserver" + }, + { + "name": "lazy_static", + "version": "1.5.0", + "id": "lazy_static" + }, + { + "name": "lebe", + "version": "0.5.3", + "id": "lebe" + }, + { + "name": "libc", + "version": "0.2.186", + "id": "libc" + }, + { + "name": "libm", + "version": "0.2.16", + "id": "libm" + }, + { + "name": "libsqlite3-sys", + "version": "0.38.0", + "id": "libsqlite3_sys" + }, + { + "name": "linux-raw-sys", + "version": "0.12.1", + "id": "linux_raw_sys" + }, + { + "name": "litemap", + "version": "0.8.2", + "id": "litemap" + }, + { + "name": "litrs", + "version": "1.0.0", + "id": "litrs" + }, + { + "name": "lock_api", + "version": "0.4.14", + "id": "lock_api" + }, + { + "name": "log", + "version": "0.4.31", + "id": "log" + }, + { + "name": "log4rs", + "version": "1.4.0", + "id": "log4rs" + }, + { + "name": "log-mdc", + "version": "0.1.0", + "id": "log_mdc" + }, + { + "name": "loop9", + "version": "0.1.5", + "id": "loop9" + }, + { + "name": "mac", + "version": "0.1.1", + "id": "mac" + }, + { + "name": "markup5ever", + "version": "0.12.1", + "id": "markup5ever" + }, + { + "name": "markup5ever", + "version": "0.11.0", + "id": "markup5ever_0_11_0" + }, + { + "name": "markup5ever_rcdom", + "version": "0.2.0", + "id": "markup5ever_rcdom" + }, + { + "name": "matrixmultiply", + "version": "0.3.10", + "id": "matrixmultiply" + }, + { + "name": "maybe-rayon", + "version": "0.1.1", + "id": "maybe_rayon" + }, + { + "name": "md-5", + "version": "0.11.0", + "id": "md5" + }, + { + "name": "md-5", + "version": "0.10.6", + "id": "md5_0_10_6" + }, + { + "name": "memchr", + "version": "2.8.1", + "id": "memchr" + }, + { + "name": "memmap", + "version": "0.7.0", + "id": "memmap" + }, + { + "name": "mime", + "version": "0.3.17", + "id": "mime" + }, + { + "name": "mime_guess", + "version": "2.0.5", + "id": "mime_guess" + }, + { + "name": "miniz_oxide", + "version": "0.9.1", + "id": "miniz_oxide" + }, + { + "name": "miniz_oxide", + "version": "0.8.9", + "id": "miniz_oxide_0_8_9" + }, + { + "name": "mio", + "version": "1.2.1", + "id": "mio" + }, + { + "name": "mock_instant", + "version": "0.6.0", + "id": "mock_instant" + }, + { + "name": "moxcms", + "version": "0.8.1", + "id": "moxcms" + }, + { + "name": "munge", + "version": "0.4.7", + "id": "munge" + }, + { + "name": "munge_macro", + "version": "0.4.7", + "id": "munge_macro" + }, + { + "name": "nalgebra", + "version": "0.35.0", + "id": "nalgebra" + }, + { + "name": "nalgebra-macros", + "version": "0.3.0", + "id": "nalgebra_macros" + }, + { + "name": "ndarray", + "version": "0.17.2", + "id": "ndarray" + }, + { + "name": "no_std_io2", + "version": "0.9.4", + "id": "no_std_io2" + }, + { + "name": "nom", + "version": "8.0.0", + "id": "nom" + }, + { + "name": "noop_proc_macro", + "version": "0.3.0", + "id": "noop_proc_macro" + }, + { + "name": "nu-ansi-term", + "version": "0.50.3", + "id": "nu_ansi_term" + }, + { + "name": "num", + "version": "0.4.3", + "id": "num" + }, + { + "name": "num-bigint", + "version": "0.4.6", + "id": "num_bigint" + }, + { + "name": "num-complex", + "version": "0.4.6", + "id": "num_complex" + }, + { + "name": "num-conv", + "version": "0.2.2", + "id": "num_conv" + }, + { + "name": "num_cpus", + "version": "1.17.0", + "id": "num_cpus" + }, + { + "name": "num-derive", + "version": "0.4.2", + "id": "num_derive" + }, + { + "name": "num-integer", + "version": "0.1.46", + "id": "num_integer" + }, + { + "name": "num-iter", + "version": "0.1.45", + "id": "num_iter" + }, + { + "name": "num-rational", + "version": "0.4.2", + "id": "num_rational" + }, + { + "name": "num-traits", + "version": "0.2.19", + "id": "num_traits" + }, + { + "name": "object", + "version": "0.37.3", + "id": "object" + }, + { + "name": "once_cell", + "version": "1.21.4", + "id": "once_cell" + }, + { + "name": "openssl-probe", + "version": "0.2.1", + "id": "openssl_probe" + }, + { + "name": "ordered-float", + "version": "2.10.1", + "id": "ordered_float" + }, + { + "name": "parking_lot", + "version": "0.12.5", + "id": "parking_lot" + }, + { + "name": "parking_lot_core", + "version": "0.9.12", + "id": "parking_lot_core" + }, + { + "name": "paste", + "version": "1.0.15", + "id": "paste" + }, + { + "name": "pastey", + "version": "0.1.1", + "id": "pastey" + }, + { + "name": "percent-encoding", + "version": "2.3.2", + "id": "percent_encoding" + }, + { + "name": "petgraph", + "version": "0.8.3", + "id": "petgraph" + }, + { + "name": "petgraph", + "version": "0.6.5", + "id": "petgraph_0_6_5" + }, + { + "name": "phf", + "version": "0.13.1", + "id": "phf" + }, + { + "name": "phf", + "version": "0.10.1", + "id": "phf_0_10_1" + }, + { + "name": "phf", + "version": "0.11.3", + "id": "phf_0_11_3" + }, + { + "name": "phf_codegen", + "version": "0.11.3", + "id": "phf_codegen" + }, + { + "name": "phf_codegen", + "version": "0.10.0", + "id": "phf_codegen_0_10_0" + }, + { + "name": "phf_generator", + "version": "0.13.1", + "id": "phf_generator" + }, + { + "name": "phf_generator", + "version": "0.10.0", + "id": "phf_generator_0_10_0" + }, + { + "name": "phf_generator", + "version": "0.11.3", + "id": "phf_generator_0_11_3" + }, + { + "name": "phf_macros", + "version": "0.13.1", + "id": "phf_macros" + }, + { + "name": "phf_macros", + "version": "0.11.3", + "id": "phf_macros_0_11_3" + }, + { + "name": "phf_shared", + "version": "0.13.1", + "id": "phf_shared" + }, + { + "name": "phf_shared", + "version": "0.10.0", + "id": "phf_shared_0_10_0" + }, + { + "name": "phf_shared", + "version": "0.11.3", + "id": "phf_shared_0_11_3" + }, + { + "name": "pin-project-lite", + "version": "0.2.17", + "id": "pin_project_lite" + }, + { + "name": "pkg-config", + "version": "0.3.33", + "id": "pkg_config" + }, + { + "name": "png", + "version": "0.18.1", + "id": "png" + }, + { + "name": "postgres", + "version": "0.19.13", + "id": "postgres" + }, + { + "name": "postgres-protocol", + "version": "0.6.11", + "id": "postgres_protocol" + }, + { + "name": "postgres-types", + "version": "0.2.13", + "id": "postgres_types" + }, + { + "name": "potential_utf", + "version": "0.1.5", + "id": "potential_utf" + }, + { + "name": "powerfmt", + "version": "0.2.0", + "id": "powerfmt" + }, + { + "name": "ppv-lite86", + "version": "0.2.21", + "id": "ppv_lite86" + }, + { + "name": "precomputed-hash", + "version": "0.1.1", + "id": "precomputed_hash" + }, + { + "name": "proc-macro2", + "version": "1.0.106", + "id": "proc_macro2" + }, + { + "name": "profiling", + "version": "1.0.18", + "id": "profiling" + }, + { + "name": "profiling-procmacros", + "version": "1.0.18", + "id": "profiling_procmacros" + }, + { + "name": "psl-types", + "version": "2.0.11", + "id": "psl_types" + }, + { + "name": "ptr_meta", + "version": "0.3.1", + "id": "ptr_meta" + }, + { + "name": "ptr_meta_derive", + "version": "0.3.1", + "id": "ptr_meta_derive" + }, + { + "name": "publicsuffix", + "version": "2.3.0", + "id": "publicsuffix" + }, + { + "name": "pxfm", + "version": "0.1.29", + "id": "pxfm" + }, + { + "name": "qoi", + "version": "0.4.1", + "id": "qoi" + }, + { + "name": "quick-error", + "version": "2.0.1", + "id": "quick_error" + }, + { + "name": "quote", + "version": "1.0.45", + "id": "quote" + }, + { + "name": "radium", + "version": "0.7.0", + "id": "radium" + }, + { + "name": "rancor", + "version": "0.1.1", + "id": "rancor" + }, + { + "name": "rand", + "version": "0.10.1", + "id": "rand" + }, + { + "name": "rand", + "version": "0.8.6", + "id": "rand_0_8_6" + }, + { + "name": "rand", + "version": "0.9.4", + "id": "rand_0_9_4" + }, + { + "name": "rand_chacha", + "version": "0.10.0", + "id": "rand_chacha" + }, + { + "name": "rand_chacha", + "version": "0.3.1", + "id": "rand_chacha_0_3_1" + }, + { + "name": "rand_chacha", + "version": "0.9.0", + "id": "rand_chacha_0_9_0" + }, + { + "name": "rand_core", + "version": "0.10.1", + "id": "rand_core" + }, + { + "name": "rand_core", + "version": "0.6.4", + "id": "rand_core_0_6_4" + }, + { + "name": "rand_core", + "version": "0.9.5", + "id": "rand_core_0_9_5" + }, + { + "name": "rand_distr", + "version": "0.6.0", + "id": "rand_distr" + }, + { + "name": "rav1e", + "version": "0.8.1", + "id": "rav1e" + }, + { + "name": "ravif", + "version": "0.13.0", + "id": "ravif" + }, + { + "name": "rawpointer", + "version": "0.2.1", + "id": "rawpointer" + }, + { + "name": "rayon", + "version": "1.12.0", + "id": "rayon" + }, + { + "name": "rayon-core", + "version": "1.13.0", + "id": "rayon_core" + }, + { + "name": "regex", + "version": "1.12.3", + "id": "regex" + }, + { + "name": "regex-automata", + "version": "0.4.14", + "id": "regex_automata" + }, + { + "name": "regex-syntax", + "version": "0.8.10", + "id": "regex_syntax" + }, + { + "name": "rend", + "version": "0.5.3", + "id": "rend" + }, + { + "name": "reqwest", + "version": "0.13.4", + "id": "reqwest" + }, + { + "name": "reqwest", + "version": "0.12.28", + "id": "reqwest_0_12_28" + }, + { + "name": "rgb", + "version": "0.8.53", + "id": "rgb" + }, + { + "name": "ring", + "version": "0.17.14", + "id": "ring" + }, + { + "name": "rkyv", + "version": "0.8.16", + "id": "rkyv" + }, + { + "name": "rkyv_derive", + "version": "0.8.16", + "id": "rkyv_derive" + }, + { + "name": "rusqlite", + "version": "0.40.0", + "id": "rusqlite" + }, + { + "name": "rustc-demangle", + "version": "0.1.27", + "id": "rustc_demangle" + }, + { + "name": "rustc_version", + "version": "0.4.1", + "id": "rustc_version" + }, + { + "name": "rustix", + "version": "1.1.4", + "id": "rustix" + }, + { + "name": "rustls", + "version": "0.23.40", + "id": "rustls" + }, + { + "name": "rustls-native-certs", + "version": "0.8.4", + "id": "rustls_native_certs" + }, + { + "name": "rustls-pki-types", + "version": "1.14.1", + "id": "rustls_pki_types" + }, + { + "name": "rustls-platform-verifier", + "version": "0.7.0", + "id": "rustls_platform_verifier" + }, + { + "name": "rustversion", + "version": "1.0.22", + "id": "rustversion" + }, + { + "name": "ryu", + "version": "1.0.23", + "id": "ryu" + }, + { + "name": "safe_arch", + "version": "1.0.0", + "id": "safe_arch" + }, + { + "name": "same-file", + "version": "1.0.6", + "id": "same_file" + }, + { + "name": "scopeguard", + "version": "1.2.0", + "id": "scopeguard" + }, + { + "name": "scraper", + "version": "0.20.0", + "id": "scraper" + }, + { + "name": "select", + "version": "0.6.1", + "id": "select" + }, + { + "name": "selectors", + "version": "0.25.0", + "id": "selectors" + }, + { + "name": "semver", + "version": "1.0.28", + "id": "semver" + }, + { + "name": "serde", + "version": "1.0.228", + "id": "serde" + }, + { + "name": "serde_core", + "version": "1.0.228", + "id": "serde_core" + }, + { + "name": "serde_derive", + "version": "1.0.228", + "id": "serde_derive" + }, + { + "name": "serde_json", + "version": "1.0.150", + "id": "serde_json" + }, + { + "name": "serde_spanned", + "version": "1.1.1", + "id": "serde_spanned" + }, + { + "name": "serde_urlencoded", + "version": "0.7.1", + "id": "serde_urlencoded" + }, + { + "name": "serde-value", + "version": "0.7.0", + "id": "serde_value" + }, + { + "name": "serde_yaml", + "version": "0.9.34+deprecated", + "id": "serde_yaml" + }, + { + "name": "servo_arc", + "version": "0.3.0", + "id": "servo_arc" + }, + { + "name": "sha1_smol", + "version": "1.0.1", + "id": "sha1_smol" + }, + { + "name": "sha2", + "version": "0.11.0", + "id": "sha2" + }, + { + "name": "sharded-slab", + "version": "0.1.7", + "id": "sharded_slab" + }, + { + "name": "shlex", + "version": "2.0.1", + "id": "shlex" + }, + { + "name": "signal-hook-registry", + "version": "1.4.8", + "id": "signal_hook_registry" + }, + { + "name": "simba", + "version": "0.10.0", + "id": "simba" + }, + { + "name": "simd-adler32", + "version": "0.3.9", + "id": "simd_adler32" + }, + { + "name": "simd_helpers", + "version": "0.1.0", + "id": "simd_helpers" + }, + { + "name": "siphasher", + "version": "1.0.3", + "id": "siphasher" + }, + { + "name": "siphasher", + "version": "0.3.11", + "id": "siphasher_0_3_11" + }, + { + "name": "slab", + "version": "0.4.12", + "id": "slab" + }, + { + "name": "smallvec", + "version": "1.15.1", + "id": "smallvec" + }, + { + "name": "socket2", + "version": "0.6.4", + "id": "socket2" + }, + { + "name": "sptr", + "version": "0.3.2", + "id": "sptr" + }, + { + "name": "stable_deref_trait", + "version": "1.2.1", + "id": "stable_deref_trait" + }, + { + "name": "string_cache", + "version": "0.8.9", + "id": "string_cache" + }, + { + "name": "string_cache_codegen", + "version": "0.5.4", + "id": "string_cache_codegen" + }, + { + "name": "stringprep", + "version": "0.1.5", + "id": "stringprep" + }, + { + "name": "strsim", + "version": "0.11.1", + "id": "strsim" + }, + { + "name": "subtle", + "version": "2.6.1", + "id": "subtle" + }, + { + "name": "syn", + "version": "2.0.117", + "id": "syn" + }, + { + "name": "syn", + "version": "1.0.109", + "id": "syn_1_0_109" + }, + { + "name": "sync_wrapper", + "version": "1.0.2", + "id": "sync_wrapper" + }, + { + "name": "synstructure", + "version": "0.13.2", + "id": "synstructure" + }, + { + "name": "tap", + "version": "1.0.1", + "id": "tap" + }, + { + "name": "tar", + "version": "0.4.46", + "id": "tar" + }, + { + "name": "tempfile", + "version": "3.27.0", + "id": "tempfile" + }, + { + "name": "tendril", + "version": "0.4.3", + "id": "tendril" + }, + { + "name": "terminal_size", + "version": "0.4.4", + "id": "terminal_size" + }, + { + "name": "thiserror", + "version": "2.0.18", + "id": "thiserror" + }, + { + "name": "thiserror-impl", + "version": "2.0.18", + "id": "thiserror_impl" + }, + { + "name": "thread-id", + "version": "5.1.0", + "id": "thread_id" + }, + { + "name": "thread_local", + "version": "1.1.9", + "id": "thread_local" + }, + { + "name": "threadpool", + "version": "1.8.1", + "id": "threadpool" + }, + { + "name": "tiff", + "version": "0.11.3", + "id": "tiff" + }, + { + "name": "time", + "version": "0.3.47", + "id": "time" + }, + { + "name": "time-core", + "version": "0.1.8", + "id": "time_core" + }, + { + "name": "time-macros", + "version": "0.2.27", + "id": "time_macros" + }, + { + "name": "tinystr", + "version": "0.8.3", + "id": "tinystr" + }, + { + "name": "tinyvec", + "version": "1.11.0", + "id": "tinyvec" + }, + { + "name": "tinyvec_macros", + "version": "0.1.1", + "id": "tinyvec_macros" + }, + { + "name": "tokio", + "version": "1.52.3", + "id": "tokio" + }, + { + "name": "tokio-io", + "version": "0.1.13", + "id": "tokio_io" + }, + { + "name": "tokio-macros", + "version": "2.7.0", + "id": "tokio_macros" + }, + { + "name": "tokio-postgres", + "version": "0.7.17", + "id": "tokio_postgres" + }, + { + "name": "tokio-rustls", + "version": "0.26.4", + "id": "tokio_rustls" + }, + { + "name": "tokio-stream", + "version": "0.1.18", + "id": "tokio_stream" + }, + { + "name": "tokio-util", + "version": "0.7.18", + "id": "tokio_util" + }, + { + "name": "toml", + "version": "1.1.2+spec-1.1.0", + "id": "toml" + }, + { + "name": "toml_datetime", + "version": "1.1.1+spec-1.1.0", + "id": "toml_datetime" + }, + { + "name": "toml_parser", + "version": "1.1.2+spec-1.1.0", + "id": "toml_parser" + }, + { + "name": "toml_writer", + "version": "1.1.1+spec-1.1.0", + "id": "toml_writer" + }, + { + "name": "tower", + "version": "0.5.3", + "id": "tower" + }, + { + "name": "tower-http", + "version": "0.6.11", + "id": "tower_http" + }, + { + "name": "tower-layer", + "version": "0.3.3", + "id": "tower_layer" + }, + { + "name": "tower-service", + "version": "0.3.3", + "id": "tower_service" + }, + { + "name": "tracing", + "version": "0.1.44", + "id": "tracing" + }, + { + "name": "tracing-attributes", + "version": "0.1.31", + "id": "tracing_attributes" + }, + { + "name": "tracing-core", + "version": "0.1.36", + "id": "tracing_core" + }, + { + "name": "tracing-log", + "version": "0.2.0", + "id": "tracing_log" + }, + { + "name": "tracing-subscriber", + "version": "0.3.23", + "id": "tracing_subscriber" + }, + { + "name": "trpl", + "version": "0.3.0", + "id": "trpl" + }, + { + "name": "try-lock", + "version": "0.2.5", + "id": "try_lock" + }, + { + "name": "typemap-ors", + "version": "1.0.0", + "id": "typemap_ors" + }, + { + "name": "typenum", + "version": "1.20.1", + "id": "typenum" + }, + { + "name": "unicase", + "version": "2.9.0", + "id": "unicase" + }, + { + "name": "unicode-bidi", + "version": "0.3.18", + "id": "unicode_bidi" + }, + { + "name": "unicode-ident", + "version": "1.0.24", + "id": "unicode_ident" + }, + { + "name": "unicode-normalization", + "version": "0.1.25", + "id": "unicode_normalization" + }, + { + "name": "unicode-properties", + "version": "0.1.4", + "id": "unicode_properties" + }, + { + "name": "unicode-segmentation", + "version": "1.13.3", + "id": "unicode_segmentation" + }, + { + "name": "unicode-width", + "version": "0.2.2", + "id": "unicode_width" + }, + { + "name": "unicode-xid", + "version": "0.2.6", + "id": "unicode_xid" + }, + { + "name": "unsafe-any-ors", + "version": "1.0.0", + "id": "unsafe_any_ors" + }, + { + "name": "unsafe-libyaml", + "version": "0.2.11", + "id": "unsafe_libyaml" + }, + { + "name": "untrusted", + "version": "0.9.0", + "id": "untrusted" + }, + { + "name": "url", + "version": "2.5.8", + "id": "url" + }, + { + "name": "utf-8", + "version": "0.7.6", + "id": "utf8" + }, + { + "name": "utf8_iter", + "version": "1.0.4", + "id": "utf8_iter" + }, + { + "name": "utf8parse", + "version": "0.2.2", + "id": "utf8parse" + }, + { + "name": "uuid", + "version": "1.23.2", + "id": "uuid" + }, + { + "name": "v_frame", + "version": "0.3.9", + "id": "v_frame" + }, + { + "name": "vcpkg", + "version": "0.2.15", + "id": "vcpkg" + }, + { + "name": "version_check", + "version": "0.9.5", + "id": "version_check" + }, + { + "name": "walkdir", + "version": "2.5.0", + "id": "walkdir" + }, + { + "name": "want", + "version": "0.3.1", + "id": "want" + }, + { + "name": "wasm-bindgen", + "version": "0.2.122", + "id": "wasm_bindgen" + }, + { + "name": "wasm-bindgen-macro", + "version": "0.2.122", + "id": "wasm_bindgen_macro" + }, + { + "name": "wasm-bindgen-macro-support", + "version": "0.2.122", + "id": "wasm_bindgen_macro_support" + }, + { + "name": "wasm-bindgen-shared", + "version": "0.2.122", + "id": "wasm_bindgen_shared" + }, + { + "name": "rustls-webpki", + "version": "0.103.13", + "id": "webpki" + }, + { + "name": "webpki-roots", + "version": "1.0.7", + "id": "webpki_roots" + }, + { + "name": "weezl", + "version": "0.1.12", + "id": "weezl" + }, + { + "name": "whoami", + "version": "2.1.2", + "id": "whoami" + }, + { + "name": "wide", + "version": "1.4.0", + "id": "wide" + }, + { + "name": "windows_aarch64_gnullvm", + "version": "0.53.1", + "id": "windows_aarch64_gnullvm" + }, + { + "name": "windows_aarch64_msvc", + "version": "0.53.1", + "id": "windows_aarch64_msvc" + }, + { + "name": "windows_i686_gnu", + "version": "0.53.1", + "id": "windows_i686_gnu" + }, + { + "name": "windows_i686_msvc", + "version": "0.53.1", + "id": "windows_i686_msvc" + }, + { + "name": "windows-link", + "version": "0.2.1", + "id": "windows_link" + }, + { + "name": "windows-sys", + "version": "0.61.2", + "id": "windows_sys" + }, + { + "name": "windows-targets", + "version": "0.53.5", + "id": "windows_targets" + }, + { + "name": "windows-targets", + "version": "0.52.6", + "id": "windows_targets_0_52_6" + }, + { + "name": "windows_x86_64_gnu", + "version": "0.53.1", + "id": "windows_x86_64_gnu" + }, + { + "name": "windows_x86_64_gnu", + "version": "0.52.6", + "id": "windows_x86_64_gnu_0_52_6" + }, + { + "name": "windows_x86_64_gnullvm", + "version": "0.53.1", + "id": "windows_x86_64_gnullvm" + }, + { + "name": "windows_x86_64_msvc", + "version": "0.53.1", + "id": "windows_x86_64_msvc" + }, + { + "name": "winnow", + "version": "1.0.3", + "id": "winnow" + }, + { + "name": "writeable", + "version": "0.6.3", + "id": "writeable" + }, + { + "name": "wyz", + "version": "0.5.1", + "id": "wyz" + }, + { + "name": "xattr", + "version": "1.6.1", + "id": "xattr" + }, + { + "name": "xml5ever", + "version": "0.17.0", + "id": "xml5ever" + }, + { + "name": "y4m", + "version": "0.8.0", + "id": "y4m" + }, + { + "name": "yoke", + "version": "0.8.2", + "id": "yoke" + }, + { + "name": "yoke-derive", + "version": "0.8.2", + "id": "yoke_derive" + }, + { + "name": "zerocopy", + "version": "0.8.50", + "id": "zerocopy" + }, + { + "name": "zerocopy-derive", + "version": "0.8.50", + "id": "zerocopy_derive" + }, + { + "name": "zerofrom", + "version": "0.1.8", + "id": "zerofrom" + }, + { + "name": "zerofrom-derive", + "version": "0.1.7", + "id": "zerofrom_derive" + }, + { + "name": "zeroize", + "version": "1.8.2", + "id": "zeroize" + }, + { + "name": "zerotrie", + "version": "0.2.4", + "id": "zerotrie" + }, + { + "name": "zerovec", + "version": "0.11.6", + "id": "zerovec" + }, + { + "name": "zerovec-derive", + "version": "0.11.3", + "id": "zerovec_derive" + }, + { + "name": "zmij", + "version": "1.0.21", + "id": "zmij" + }, + { + "name": "zstd", + "version": "0.13.3", + "id": "zstd" + }, + { + "name": "zstd-safe", + "version": "7.2.4", + "id": "zstd_safe" + }, + { + "name": "zstd-sys", + "version": "2.0.16+zstd.1.5.7", + "id": "zstd_sys" + }, + { + "name": "zune-core", + "version": "0.5.1", + "id": "zune_core" + }, + { + "name": "zune-inflate", + "version": "0.2.54", + "id": "zune_inflate" + }, + { + "name": "zune-jpeg", + "version": "0.5.15", + "id": "zune_jpeg" + } +] \ No newline at end of file diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/entrypoint.sh b/anneal/v1/playground/rust-anneal-playground/compiler/base/entrypoint.sh new file mode 100755 index 0000000000..5e16270421 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/entrypoint.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +set -eu + +# This entrypoint is a no-op but I'm leaving it to be easier to +# re-create at some future point. +exec "$@" diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/modify-cargo-toml/.gitignore b/anneal/v1/playground/rust-anneal-playground/compiler/base/modify-cargo-toml/.gitignore new file mode 100644 index 0000000000..06aba01b65 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/modify-cargo-toml/.gitignore @@ -0,0 +1,2 @@ +Cargo.lock +/target diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/modify-cargo-toml/Cargo.toml b/anneal/v1/playground/rust-anneal-playground/compiler/base/modify-cargo-toml/Cargo.toml new file mode 100644 index 0000000000..5fea2a28da --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/modify-cargo-toml/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "modify-cargo-toml" +version = "0.1.0" +authors = ["Jake Goulding "] + +[workspace] + +[dependencies] +serde = "1.0.78" +toml = { version = "1.0.3", default-features = false, features = ["display", "parse", "serde"] } +serde_derive = "1.0.78" diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/modify-cargo-toml/src/lib.rs b/anneal/v1/playground/rust-anneal-playground/compiler/base/modify-cargo-toml/src/lib.rs new file mode 100644 index 0000000000..8b886a0a59 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/modify-cargo-toml/src/lib.rs @@ -0,0 +1,131 @@ +extern crate serde; +#[macro_use] +extern crate serde_derive; +extern crate toml; + +use std::collections::BTreeMap; +use toml::Value; + +type Other = BTreeMap; + +fn modify(cargo_toml: Value, f: F) -> Value +where + F: FnOnce(T) -> T, + T: serde::Serialize + for<'de> serde::Deserialize<'de>, +{ + let cargo_toml = cargo_toml.try_into().unwrap(); + + let cargo_toml = f(cargo_toml); + + Value::try_from(cargo_toml).unwrap() +} + +fn ensure_string_in_vec(values: &mut Vec, val: &str) { + if !values.iter().any(|f| f == val) { + values.push(val.into()); + } +} + +pub fn set_edition(cargo_toml: Value, edition: &str) -> Value { + #[derive(Debug, Serialize, Deserialize)] + #[serde(rename_all = "kebab-case")] + struct CargoToml { + package: Package, + #[serde(flatten)] + other: Other, + } + + #[derive(Debug, Serialize, Deserialize)] + #[serde(rename_all = "kebab-case")] + struct Package { + #[serde(default)] + edition: String, + #[serde(flatten)] + other: Other, + } + + modify(cargo_toml, |mut cargo_toml: CargoToml| { + cargo_toml.package.edition = edition.into(); + cargo_toml + }) +} + +pub fn remove_dependencies(cargo_toml: Value) -> Value { + #[derive(Debug, Serialize, Deserialize)] + #[serde(rename_all = "kebab-case")] + struct CargoToml { + dependencies: BTreeMap, + #[serde(flatten)] + other: Other, + } + + modify(cargo_toml, |mut cargo_toml: CargoToml| { + cargo_toml.dependencies.clear(); + cargo_toml + }) +} + +pub fn set_crate_type(cargo_toml: Value, crate_type: &str) -> Value { + #[derive(Debug, Serialize, Deserialize)] + #[serde(rename_all = "kebab-case")] + struct CargoToml { + #[serde(default)] + lib: Lib, + #[serde(flatten)] + other: Other, + } + + #[derive(Debug, Default, Serialize, Deserialize)] + #[serde(rename_all = "kebab-case")] + struct Lib { + #[serde(default, skip_serializing_if = "Vec::is_empty")] + crate_type: Vec, + #[serde(default)] + proc_macro: bool, + #[serde(flatten)] + other: Other, + } + + modify(cargo_toml, |mut cargo_toml: CargoToml| { + if crate_type == "proc-macro" { + cargo_toml.lib.proc_macro = true; + } else { + ensure_string_in_vec(&mut cargo_toml.lib.crate_type, crate_type); + } + cargo_toml + }) +} + +pub fn set_release_lto(cargo_toml: Value, lto: bool) -> Value { + #[derive(Debug, Serialize, Deserialize)] + #[serde(rename_all = "kebab-case")] + struct CargoToml { + #[serde(default)] + profile: Profiles, + #[serde(flatten)] + other: Other, + } + + #[derive(Debug, Default, Serialize, Deserialize)] + #[serde(rename_all = "kebab-case")] + struct Profiles { + #[serde(default)] + release: Profile, + #[serde(flatten)] + other: Other, + } + + #[derive(Debug, Default, Serialize, Deserialize)] + #[serde(rename_all = "kebab-case")] + struct Profile { + #[serde(default)] + lto: bool, + #[serde(flatten)] + other: Other, + } + + modify(cargo_toml, |mut cargo_toml: CargoToml| { + cargo_toml.profile.release.lto = lto; + cargo_toml + }) +} diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/.gitignore b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/.gitignore new file mode 100644 index 0000000000..eb5a316cbd --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/.gitignore @@ -0,0 +1 @@ +target diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/Cargo.lock b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/Cargo.lock new file mode 100644 index 0000000000..b3993fd340 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/Cargo.lock @@ -0,0 +1,1021 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "asm-cleanup" +version = "0.1.0" +dependencies = [ + "petgraph", + "regex", + "rustc-demangle", +] + +[[package]] +name = "assertables" +version = "10.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3c16d80246a076246d8b525d9f404543e90fe0818636cd89c249c2a4bee3bb1" +dependencies = [ + "regex", + "walkdir", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "log" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "113b30b4cd05f7c06868fdb2854f66a7b9fece9a48425351cd532e810d74024f" + +[[package]] +name = "mach2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b" + +[[package]] +name = "memchr" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" + +[[package]] +name = "mio" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "modify-cargo-toml" +version = "0.1.0" +dependencies = [ + "serde", + "serde_derive", + "toml", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "orchestrator" +version = "0.1.0" +dependencies = [ + "asm-cleanup", + "assertables", + "bincode", + "futures", + "libc", + "mach2", + "modify-cargo-toml", + "procfs", + "serde", + "serde_json", + "snafu", + "strum_macros", + "tempfile", + "tokio", + "tokio-stream", + "tokio-util", + "toml", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap", + "serde", +] + +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "procfs" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25485360a54d6861439d60facef26de713b1e126bf015ec8f98239467a2b82f7" +dependencies = [ + "bitflags", + "procfs-core", + "rustix", +] + +[[package]] +name = "procfs-core" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6401bf7b6af22f78b563665d15a22e9aef27775b79b149a66ca022468a4e405" +dependencies = [ + "bitflags", + "hex", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rustc-demangle" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[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 = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[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.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[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 = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "snafu" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1a012328be2e3f5d5f6f3218147ca02588cea4cb865e876849ab6debcf36522" +dependencies = [ + "futures-core", + "pin-project", + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f103c50866b8743da9429b8a581d81a27c2d3a9c4ac7df8f8571c1dd7896eda" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "strum_macros" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys", +] + +[[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 = "tokio" +version = "1.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "signal-hook-registry", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "futures-util", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +dependencies = [ + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +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-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[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 = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[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 = "winnow" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/Cargo.toml b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/Cargo.toml new file mode 100644 index 0000000000..7b19e8210b --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "orchestrator" +version = "0.1.0" +edition = "2021" + +[workspace] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(force_docker)'] } + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[dependencies] +asm-cleanup = { path = "../asm-cleanup" } +bincode = { version = "1.3", default-features = false } +futures = { version = "0.3.28", default-features = false, features = ["executor"] } +modify-cargo-toml = { path = "../modify-cargo-toml", default-features = false } +serde = { version = "1.0", default-features = false, features = ["derive"] } +serde_json = { version = "1.0.108", default-features = false, features = ["std"] } +snafu = { version = "0.9.0", default-features = false, features = ["futures", "std"] } +strum_macros = { version = "0.28.0", default-features = false } +tokio = { version = "1.28", default-features = false, features = ["fs", "io-std", "io-util", "macros", "process", "rt", "time", "sync"] } +tokio-stream = { version = "0.1.14", default-features = false } +tokio-util = { version = "0.7.8", default-features = false, features = ["io", "io-util", "rt"] } +toml = { version = "1.0.3", default-features = false, features = ["parse", "display"] } +tracing = { version = "0.1.37", default-features = false, features = ["attributes"] } + +[target.'cfg(target_os = "linux")'.dependencies] +procfs = { version = "0.18.0", default-features = false } + +[target.'cfg(target_os = "macos")'.dependencies] +libc = { version = "0.2.150", default-features = false } +mach2 = { version = "0.6.0", default-features = false } + +[dev-dependencies] +assertables = "10.1.0" +tempfile = "3.10.1" +tracing-subscriber = "0.3.17" diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/bin/worker.rs b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/bin/worker.rs new file mode 100644 index 0000000000..e434de6ace --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/bin/worker.rs @@ -0,0 +1,11 @@ +use orchestrator::worker::{listen, Error}; +use std::env; + +#[tokio::main(flavor = "current_thread")] +#[snafu::report] +pub async fn main() -> Result<(), Error> { + let project_dir = + env::args_os().nth(1).expect("Please specify project directory as the first argument"); + + listen(project_dir).await +} diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/coordinator.rs b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/coordinator.rs new file mode 100644 index 0000000000..b1aa1b0d3f --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/coordinator.rs @@ -0,0 +1,4282 @@ +use futures::{ + future::BoxFuture, + stream::{BoxStream, FuturesUnordered}, + Future, FutureExt, Stream, StreamExt, TryStreamExt, +}; +use serde::Deserialize; +use snafu::prelude::*; +use std::{ + collections::{BTreeSet, HashMap}, + fmt, mem, ops, + pin::{self, pin}, + process::Stdio, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, LazyLock, Mutex, + }, + task, + time::Duration, +}; +use tokio::{ + process::{Child, ChildStdin, ChildStdout, Command}, + select, + sync::{mpsc, oneshot, OnceCell}, + task::{JoinHandle, JoinSet}, + time::{self, MissedTickBehavior}, + try_join, +}; +use tokio_stream::wrappers::ReceiverStream; +use tokio_util::{io::SyncIoBridge, sync::CancellationToken, task::AbortOnDropHandle}; +use tracing::{error, info, info_span, instrument, trace, trace_span, warn, Instrument}; + +use crate::{ + bincode_input_closed, + message::{ + CommandStatistics, CoordinatorMessage, DeleteFileRequest, ExecuteCommandRequest, + ExecuteCommandResponse, JobId, Multiplexed, OneToOneResponse, ReadFileRequest, + ReadFileResponse, SerializedError2, WorkerMessage, WriteFileRequest, + }, + DropErrorDetailsExt, TaskAbortExt as _, +}; + +macro_rules! kvs { + ($($k:expr => $v:expr),+$(,)?) => { + [ + $((Into::into($k), Into::into($v)),)+ + ].into_iter() + }; +} + +pub mod limits; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Versions { + pub stable: ChannelVersions, + pub beta: ChannelVersions, + pub nightly: ChannelVersions, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ChannelVersions { + pub rustc: Version, + pub rustfmt: Version, + pub clippy: Version, + pub miri: Option, +} + +/// Parsing this struct is very lenient — we'd rather return some +/// partial data instead of absolutely nothing. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Version { + pub release: String, + pub commit_hash: String, + pub commit_date: String, +} + +impl Version { + fn parse_rustc_version_verbose(rustc_version: &str) -> Self { + let mut release = ""; + let mut commit_hash = ""; + let mut commit_date = ""; + + let fields = rustc_version.lines().skip(1).filter_map(|line| { + let mut pieces = line.splitn(2, ':'); + let key = pieces.next()?.trim(); + let value = pieces.next()?.trim(); + Some((key, value)) + }); + + for (k, v) in fields { + match k { + "release" => release = v, + "commit-hash" => commit_hash = v, + "commit-date" => commit_date = v, + _ => {} + } + } + + Self { + release: release.into(), + commit_hash: commit_hash.into(), + commit_date: commit_date.into(), + } + } + + // Parses versions of the shape `toolname 0.0.0 (0000000 0000-00-00)` + fn parse_tool_version(tool_version: &str) -> Self { + let mut parts = tool_version.split_whitespace().fuse().skip(1); + + let release = parts.next().unwrap_or("").into(); + let commit_hash = parts.next().unwrap_or("").trim_start_matches('(').into(); + let commit_date = parts.next().unwrap_or("").trim_end_matches(')').into(); + + Self { release, commit_hash, commit_date } + } +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum VersionsError { + #[snafu(display("Unable to determine versions for the stable channel"))] + Stable { source: VersionsChannelError }, + + #[snafu(display("Unable to determine versions for the beta channel"))] + Beta { source: VersionsChannelError }, + + #[snafu(display("Unable to determine versions for the nightly channel"))] + Nightly { source: VersionsChannelError }, +} + +#[derive(Debug, Snafu)] +pub enum VersionsChannelError { + #[snafu(transparent)] + Channel { source: Error }, + + #[snafu(transparent)] + Versions { source: ContainerVersionsError }, +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum ContainerVersionsError { + #[snafu(display("Failed to get `rustc` version"))] + Rustc { source: VersionError }, + + #[snafu(display("`rustc` not executable"))] + RustcMissing, + + #[snafu(display("Failed to get `rustfmt` version"))] + Rustfmt { source: VersionError }, + + #[snafu(display("`cargo fmt` not executable"))] + RustfmtMissing, + + #[snafu(display("Failed to get clippy version"))] + Clippy { source: VersionError }, + + #[snafu(display("`cargo clippy` not executable"))] + ClippyMissing, + + #[snafu(display("Failed to get miri version"))] + Miri { source: VersionError }, +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum VersionError { + #[snafu(display("Could not start the process"))] + #[snafu(context(false))] + SpawnProcess { source: SpawnCargoError }, + + #[snafu(display("The task panicked"))] + #[snafu(context(false))] + TaskPanic { source: tokio::task::JoinError }, +} + +#[derive(Debug, Clone)] +pub struct Crate { + pub name: String, + pub version: String, + pub id: String, +} + +#[derive(Deserialize)] +struct InternalCrate { + name: String, + version: String, + id: String, +} + +impl From for Crate { + fn from(other: InternalCrate) -> Self { + let InternalCrate { name, version, id } = other; + Self { name, version, id } + } +} + +#[derive(Debug, Snafu)] +pub enum CratesError { + #[snafu(display("Could not start the container"))] + #[snafu(context(false))] + Start { source: Error }, + + #[snafu(transparent)] + Container { source: ContainerCratesError }, +} + +#[derive(Debug, Snafu)] +pub enum ContainerCratesError { + #[snafu(display("Could not read the crate information file"))] + #[snafu(context(false))] + Read { source: CommanderError }, + + #[snafu(display("Could not parse the crate information file"))] + #[snafu(context(false))] + Deserialization { source: serde_json::Error }, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum AssemblyFlavor { + Att, + Intel, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum DemangleAssembly { + Demangle, + Mangle, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ProcessAssembly { + Filter, + Raw, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum CompileTarget { + Assembly(AssemblyFlavor, DemangleAssembly, ProcessAssembly), + Hir, + LlvmIr, + Mir, + Wasm, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Channel { + Stable, + Beta, + Nightly, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum AliasingModel { + Stacked, + Tree, +} + +impl Channel { + #[cfg(test)] + pub(crate) const ALL: [Self; 3] = [Self::Stable, Self::Beta, Self::Nightly]; + + #[cfg(test)] + pub(crate) fn to_str(self) -> &'static str { + match self { + Channel::Stable => "stable", + Channel::Beta => "beta", + Channel::Nightly => "nightly", + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Mode { + Debug, + Release, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Edition { + Rust2015, + Rust2018, + Rust2021, + Rust2024, +} + +impl Edition { + #[cfg(test)] + pub(crate) const ALL: [Self; 4] = + [Self::Rust2015, Self::Rust2018, Self::Rust2021, Self::Rust2024]; + + pub(crate) fn to_str(self) -> &'static str { + match self { + Edition::Rust2015 => "2015", + Edition::Rust2018 => "2018", + Edition::Rust2021 => "2021", + Edition::Rust2024 => "2024", + } + } + + pub(crate) fn to_cargo_toml_key(self) -> &'static str { + self.to_str() + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum CrateType { + Binary, + Library(LibraryType), +} + +impl CrateType { + const MAIN_RS: &'static str = "src/main.rs"; + const LIB_RS: &'static str = "src/lib.rs"; + + pub(crate) fn is_binary(self) -> bool { + self == CrateType::Binary + } + + pub(crate) fn primary_path(self) -> &'static str { + match self { + CrateType::Binary => Self::MAIN_RS, + CrateType::Library(_) => Self::LIB_RS, + } + } + + pub(crate) fn other_path(self) -> &'static str { + match self { + CrateType::Binary => Self::LIB_RS, + CrateType::Library(_) => Self::MAIN_RS, + } + } + + pub(crate) fn to_cargo_toml_key(self) -> &'static str { + use {CrateType::*, LibraryType::*}; + + match self { + Binary => "bin", + Library(Lib) => "lib", + Library(Dylib) => "dylib", + Library(Rlib) => "rlib", + Library(Staticlib) => "staticlib", + Library(Cdylib) => "cdylib", + Library(ProcMacro) => "proc-macro", + } + } + + pub(crate) fn to_library_cargo_toml_key(self) -> Option<&'static str> { + if self == Self::Binary { + None + } else { + Some(self.to_cargo_toml_key()) + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum LibraryType { + Lib, + Dylib, + Rlib, + Staticlib, + Cdylib, + ProcMacro, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ExecutionTool { + Cargo, + AnnealVerify, +} + +#[derive(Debug, Clone)] +pub struct ExecuteRequest { + pub channel: Channel, + pub mode: Mode, + pub edition: Edition, + pub crate_type: CrateType, + pub tests: bool, + pub backtrace: bool, + pub code: String, + pub execution_tool: ExecutionTool, +} + +const ANNEAL_WORKSPACE_DIR: &str = "anneal-workspace"; +const ANNEAL_MAIN_RS: &str = "anneal-workspace/src/main.rs"; +const ANNEAL_CARGO_TOML: &str = "anneal-workspace/Cargo.toml"; +const ANNEAL_CARGO_TARGET_DIR: &str = "/playground/anneal-workspace/target"; +const ANNEAL_TMP_DIR: &str = "/playground/anneal-workspace/tmp"; +const ANNEAL_TMP_KEEP: &str = "anneal-workspace/tmp/.keep"; + +fn anneal_cargo_toml_content(edition: Edition) -> String { + format!( + r#"[package] +name = "anneal-submission" +version = "0.0.0" +edition = "{}" + +[workspace] +"#, + edition.to_cargo_toml_key(), + ) +} + +impl LowerRequest for ExecuteRequest { + // Changed to support Anneal Verify, which will keep the Cargo.toml and src/main.rs around and + // just overwrite them instead of deleting and rewriting the entire playground every time. + fn delete_files(&self) -> impl Iterator { + let files = match self.execution_tool { + ExecutionTool::AnnealVerify => vec![], + ExecutionTool::Cargo => vec![delete_previous_primary_file_request(self.crate_type)], + }; + + files.into_iter() + } + + // Instead of writing all the playground files from scratch, + // just overwrite the existing ones in the Anneal Verify case. + fn write_files(&self) -> impl Iterator { + let files = match self.execution_tool { + ExecutionTool::AnnealVerify => vec![ + WriteFileRequest { + path: ANNEAL_CARGO_TOML.to_owned(), + content: anneal_cargo_toml_content(self.edition).into_bytes(), + }, + WriteFileRequest { + path: ANNEAL_MAIN_RS.to_owned(), + content: self.code.clone().into_bytes(), + }, + WriteFileRequest { path: ANNEAL_TMP_KEEP.to_owned(), content: Vec::new() }, + ], + ExecutionTool::Cargo => vec![write_primary_file_request(self.crate_type, &self.code)], + }; + + files.into_iter() + } + + fn execute_cargo_request(&self) -> ExecuteCommandRequest { + let (cmd, args, cwd) = match self.execution_tool { + ExecutionTool::Cargo => { + let cmd = match (self.tests, self.crate_type.is_binary()) { + (true, _) => "test", + (_, true) => "run", + (_, _) => "build", + }; + + let mut args = vec![cmd]; + + if let Mode::Release = self.mode { + args.push("--release"); + } + + ("cargo", args, None) + } + + ExecutionTool::AnnealVerify => ( + "sh", + vec![ + "-lc", + "anneal_start_ms=$(date +%s%3N); \ + echo \"[anneal] starting cargo anneal verify at $(date -u +%Y-%m-%dT%H:%M:%SZ)\"; \ + cargo anneal verify --unsound-allow-is-valid; \ + anneal_status=$?; \ + anneal_end_ms=$(date +%s%3N); \ + anneal_elapsed_ms=$((anneal_end_ms - anneal_start_ms)); \ + if [ \"$anneal_status\" -eq 0 ]; then \ + echo \"[anneal] verification succeeded in ${anneal_elapsed_ms} ms\"; \ + else \ + echo \"[anneal] verification failed after ${anneal_elapsed_ms} ms\"; \ + fi; \ + exit \"$anneal_status\"", + ], + Some(ANNEAL_WORKSPACE_DIR.to_owned()), + ), + }; + + let mut envs = HashMap::new(); + if self.backtrace { + envs.extend(kvs!("RUST_BACKTRACE" => "1")); + } + if self.execution_tool == ExecutionTool::AnnealVerify { + envs.extend(kvs!( + "CARGO_TARGET_DIR" => ANNEAL_CARGO_TARGET_DIR, + "TMPDIR" => ANNEAL_TMP_DIR, + "TEMP" => ANNEAL_TMP_DIR, + "TMP" => ANNEAL_TMP_DIR, + )); + + if let Ok(rust_log) = std::env::var("RUST_LOG") { + envs.insert("RUST_LOG".to_owned(), rust_log); + } + if std::env::var_os("PLAYGROUND_ANNEAL_LAKE_LEAN_DIAGNOSTICS").is_some() { + envs.insert("PLAYGROUND_ANNEAL_LAKE_LEAN_DIAGNOSTICS".to_owned(), "1".to_owned()); + } + if std::env::var_os("PLAYGROUND_ANNEAL_BUILD_SPECS_SKIP_SUCCESS_DIAGNOSTICS").is_some() + { + envs.insert( + "PLAYGROUND_ANNEAL_BUILD_SPECS_SKIP_SUCCESS_DIAGNOSTICS".to_owned(), + "1".to_owned(), + ); + } + } + + ExecuteCommandRequest { + cmd: cmd.to_owned(), + args: args.into_iter().map(|s| s.to_owned()).collect(), + envs, + cwd, + } + } + + fn instrumentation_kind(&self) -> Option<&'static str> { + match self.execution_tool { + ExecutionTool::AnnealVerify => Some("anneal_verify"), + ExecutionTool::Cargo => None, + } + } +} + +impl CargoTomlModifier for ExecuteRequest { + fn should_modify_cargo_toml(&self) -> bool { + self.execution_tool == ExecutionTool::Cargo + } + + fn modify_cargo_toml(&self, mut cargo_toml: toml::Value) -> toml::Value { + cargo_toml = modify_cargo_toml::set_edition(cargo_toml, self.edition.to_cargo_toml_key()); + + if let Some(crate_type) = self.crate_type.to_library_cargo_toml_key() { + cargo_toml = modify_cargo_toml::set_crate_type(cargo_toml, crate_type); + } + cargo_toml + } +} + +#[derive(Debug, Clone)] +pub struct ExecuteStatus { + pub resident_set_size_bytes: u64, + pub total_time_secs: f64, +} + +impl From for ExecuteStatus { + fn from(value: CommandStatistics) -> Self { + let CommandStatistics { total_time_secs, resident_set_size_bytes } = value; + Self { resident_set_size_bytes, total_time_secs } + } +} + +#[derive(Debug, Clone)] +pub struct ExecuteResponse { + pub success: bool, + pub exit_detail: String, +} + +#[derive(Debug, Clone)] +pub struct CompileRequest { + pub target: CompileTarget, + pub channel: Channel, + pub crate_type: CrateType, + pub mode: Mode, + pub edition: Edition, + // TODO: Remove `tests` and `backtrace` -- don't make sense for compiling. + pub tests: bool, + pub backtrace: bool, + pub code: String, +} + +impl CompileRequest { + const OUTPUT_PATH: &str = "compilation"; + + fn read_output_request(&self) -> ReadFileRequest { + ReadFileRequest { path: Self::OUTPUT_PATH.to_owned() } + } + + pub(crate) fn postprocess_result(&self, mut code: String) -> String { + if let CompileTarget::Assembly(_, demangle, process) = self.target { + if demangle == DemangleAssembly::Demangle { + code = asm_cleanup::demangle_asm(&code); + } + + if process == ProcessAssembly::Filter { + code = asm_cleanup::filter_asm(&code); + } + } + + code + } +} + +impl LowerRequest for CompileRequest { + fn delete_files(&self) -> impl Iterator { + [delete_previous_primary_file_request(self.crate_type)].into_iter() + } + + fn write_files(&self) -> impl Iterator { + [write_primary_file_request(self.crate_type, &self.code)].into_iter() + } + + fn execute_cargo_request(&self) -> ExecuteCommandRequest { + use CompileTarget::*; + + let mut args = if let Wasm = self.target { vec!["wasm"] } else { vec!["rustc"] }; + if let Mode::Release = self.mode { + args.push("--release"); + } + + match self.target { + Assembly(flavor, _, _) => { + args.extend(&["--", "--emit", "asm=compilation"]); + + // Enable extra assembly comments for nightly builds + if let Channel::Nightly = self.channel { + args.push("-Z"); + args.push("verbose-asm"); + } + + args.push("-C"); + match flavor { + AssemblyFlavor::Att => args.push("llvm-args=-x86-asm-syntax=att"), + AssemblyFlavor::Intel => args.push("llvm-args=-x86-asm-syntax=intel"), + } + } + LlvmIr => args.extend(&["--", "--emit", "llvm-ir=compilation"]), + Mir => args.extend(&["--", "--emit", "mir=compilation"]), + Hir => args.extend(&["--", "-Zunpretty=hir", "-o", Self::OUTPUT_PATH]), + Wasm => args.extend(&["-o", Self::OUTPUT_PATH]), + } + let mut envs = HashMap::new(); + if self.backtrace { + envs.extend(kvs!("RUST_BACKTRACE" => "1")); + } + + ExecuteCommandRequest { + cmd: "cargo".to_owned(), + args: args.into_iter().map(|s| s.to_owned()).collect(), + envs, + cwd: None, + } + } +} + +impl CargoTomlModifier for CompileRequest { + fn modify_cargo_toml(&self, mut cargo_toml: toml::Value) -> toml::Value { + cargo_toml = modify_cargo_toml::set_edition(cargo_toml, self.edition.to_cargo_toml_key()); + + if let Some(crate_type) = self.crate_type.to_library_cargo_toml_key() { + cargo_toml = modify_cargo_toml::set_crate_type(cargo_toml, crate_type); + } + + if CompileTarget::Wasm == self.target { + cargo_toml = modify_cargo_toml::remove_dependencies(cargo_toml); + cargo_toml = modify_cargo_toml::set_release_lto(cargo_toml, true); + } + + cargo_toml + } +} + +#[derive(Debug, Clone)] +pub struct CompileResponse { + pub success: bool, + pub exit_detail: String, + pub code: String, +} + +#[derive(Debug, Clone)] +pub struct FormatRequest { + pub channel: Channel, + pub crate_type: CrateType, + pub edition: Edition, + pub code: String, +} + +impl FormatRequest { + fn read_output_request(&self) -> ReadFileRequest { + ReadFileRequest { path: self.crate_type.primary_path().to_owned() } + } +} + +impl LowerRequest for FormatRequest { + fn delete_files(&self) -> impl Iterator { + [delete_previous_primary_file_request(self.crate_type)].into_iter() + } + + fn write_files(&self) -> impl Iterator { + [write_primary_file_request(self.crate_type, &self.code)].into_iter() + } + + fn execute_cargo_request(&self) -> ExecuteCommandRequest { + ExecuteCommandRequest { + cmd: "cargo".to_owned(), + args: vec!["fmt".to_owned()], + envs: Default::default(), + cwd: None, + } + } +} + +impl CargoTomlModifier for FormatRequest { + fn modify_cargo_toml(&self, mut cargo_toml: toml::Value) -> toml::Value { + cargo_toml = modify_cargo_toml::set_edition(cargo_toml, self.edition.to_cargo_toml_key()); + + if let Some(crate_type) = self.crate_type.to_library_cargo_toml_key() { + cargo_toml = modify_cargo_toml::set_crate_type(cargo_toml, crate_type); + } + cargo_toml + } +} + +#[derive(Debug, Clone)] +pub struct FormatResponse { + pub success: bool, + pub exit_detail: String, + pub code: String, +} + +#[derive(Debug, Clone)] +pub struct ClippyRequest { + pub channel: Channel, + pub crate_type: CrateType, + pub edition: Edition, + pub code: String, +} + +impl LowerRequest for ClippyRequest { + fn delete_files(&self) -> impl Iterator { + [delete_previous_primary_file_request(self.crate_type)].into_iter() + } + + fn write_files(&self) -> impl Iterator { + [write_primary_file_request(self.crate_type, &self.code)].into_iter() + } + + fn execute_cargo_request(&self) -> ExecuteCommandRequest { + ExecuteCommandRequest { + cmd: "cargo".to_owned(), + args: vec!["clippy".to_owned()], + envs: Default::default(), + cwd: None, + } + } +} + +impl CargoTomlModifier for ClippyRequest { + fn modify_cargo_toml(&self, mut cargo_toml: toml::Value) -> toml::Value { + cargo_toml = modify_cargo_toml::set_edition(cargo_toml, self.edition.to_cargo_toml_key()); + + if let Some(crate_type) = self.crate_type.to_library_cargo_toml_key() { + cargo_toml = modify_cargo_toml::set_crate_type(cargo_toml, crate_type); + } + cargo_toml + } +} + +#[derive(Debug, Clone)] +pub struct ClippyResponse { + pub success: bool, + pub exit_detail: String, +} + +#[derive(Debug, Clone)] +pub struct MiriRequest { + pub channel: Channel, + pub crate_type: CrateType, + pub edition: Edition, + pub tests: bool, + pub aliasing_model: AliasingModel, + pub code: String, +} + +impl LowerRequest for MiriRequest { + fn delete_files(&self) -> impl Iterator { + [delete_previous_primary_file_request(self.crate_type)].into_iter() + } + + fn write_files(&self) -> impl Iterator { + [write_primary_file_request(self.crate_type, &self.code)].into_iter() + } + + fn execute_cargo_request(&self) -> ExecuteCommandRequest { + let mut miriflags = Vec::new(); + + if matches!(self.aliasing_model, AliasingModel::Tree) { + miriflags.push("-Zmiri-tree-borrows"); + } + + miriflags.push("-Zmiri-disable-isolation"); + + let miriflags = miriflags.join(" "); + + let subcommand = if self.tests { "test" } else { "run" }; + + ExecuteCommandRequest { + cmd: "cargo".to_owned(), + args: ["miri", subcommand].map(Into::into).into(), + envs: kvs! { + "MIRIFLAGS" => miriflags, + // Be sure that `cargo miri` will not build a new + // sysroot. Creating a sysroot takes a while and Miri + // will build one by default if it's missing. If + // `MIRI_SYSROOT` is set and the sysroot is missing, + // it will error instead. + "MIRI_SYSROOT" => "/playground/.cache/miri", + } + .collect(), + cwd: None, + } + } +} + +impl CargoTomlModifier for MiriRequest { + fn modify_cargo_toml(&self, mut cargo_toml: toml::Value) -> toml::Value { + cargo_toml = modify_cargo_toml::set_edition(cargo_toml, self.edition.to_cargo_toml_key()); + + if let Some(crate_type) = self.crate_type.to_library_cargo_toml_key() { + cargo_toml = modify_cargo_toml::set_crate_type(cargo_toml, crate_type); + } + cargo_toml + } +} + +#[derive(Debug, Clone)] +pub struct MiriResponse { + pub success: bool, + pub exit_detail: String, +} + +#[derive(Debug, Clone)] +pub struct MacroExpansionRequest { + pub channel: Channel, + pub crate_type: CrateType, + pub edition: Edition, + pub code: String, +} + +impl LowerRequest for MacroExpansionRequest { + fn delete_files(&self) -> impl Iterator { + [delete_previous_primary_file_request(self.crate_type)].into_iter() + } + + fn write_files(&self) -> impl Iterator { + [write_primary_file_request(self.crate_type, &self.code)].into_iter() + } + + fn execute_cargo_request(&self) -> ExecuteCommandRequest { + ExecuteCommandRequest { + cmd: "cargo".to_owned(), + args: ["rustc", "--", "-Zunpretty=expanded"].map(str::to_owned).to_vec(), + envs: Default::default(), + cwd: None, + } + } +} + +impl CargoTomlModifier for MacroExpansionRequest { + fn modify_cargo_toml(&self, mut cargo_toml: toml::Value) -> toml::Value { + cargo_toml = modify_cargo_toml::set_edition(cargo_toml, self.edition.to_cargo_toml_key()); + + if let Some(crate_type) = self.crate_type.to_library_cargo_toml_key() { + cargo_toml = modify_cargo_toml::set_crate_type(cargo_toml, crate_type); + } + cargo_toml + } +} + +#[derive(Debug, Clone)] +pub struct MacroExpansionResponse { + pub success: bool, + pub exit_detail: String, +} + +#[derive(Debug, Clone)] +pub struct WithOutput { + pub response: T, + pub stdout: String, + pub stderr: String, +} + +impl WithOutput { + async fn try_absorb( + task: F, + stdout_rx: mpsc::Receiver, + stderr_rx: mpsc::Receiver, + ) -> Result, E> + where + F: Future>, + { + Self::try_absorb_stream( + task, + ReceiverStream::new(stdout_rx), + ReceiverStream::new(stderr_rx), + ) + .await + } + + async fn try_absorb_stream( + task: F, + stdout_rx: impl Stream, + stderr_rx: impl Stream, + ) -> Result, E> + where + F: Future>, + { + let stdout = stdout_rx.collect().map(Ok); + let stderr = stderr_rx.collect().map(Ok); + + let (response, stdout, stderr) = try_join!(task, stdout, stderr)?; + + Ok(WithOutput { response, stdout, stderr }) + } +} + +impl ops::Deref for WithOutput { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.response + } +} + +fn write_primary_file_request(crate_type: CrateType, code: &str) -> WriteFileRequest { + WriteFileRequest { path: crate_type.primary_path().to_owned(), content: code.into() } +} + +fn delete_previous_primary_file_request(crate_type: CrateType) -> DeleteFileRequest { + DeleteFileRequest { path: crate_type.other_path().to_owned() } +} + +#[derive(Debug)] +enum DemultiplexCommand { + Listen(JobId, mpsc::Sender), + ListenOnce(JobId, oneshot::Sender), +} + +type ResourceError = Box; +type ResourceResult = std::result::Result; + +/// Mediate resource limits and names for created objects. +/// +/// The [`Coordinator`][] requires mostly-global resources, such as +/// Docker containers or running processes. This trait covers two cases: +/// +/// 1. To avoid conflicts, each container must have a unique name. +/// 2. Containers and processes compete for CPU / memory. +/// +/// Only a global view guarantees the unique names and resource +/// allocation, so whoever creates [`Coordinator`][]s via the +/// [`CoordinatorFactory`][] is responsible. +pub trait ResourceLimits: Send + Sync + fmt::Debug + 'static { + /// Block until resources for a container are available. + fn next_container(&self) -> BoxFuture<'static, ResourceResult>>; + + /// Block until someone reqeusts that you return an in-use container. + fn container_requested(&self) -> BoxFuture<'static, ()>; +} + +/// Represents one allowed Docker container (or equivalent). +pub trait ContainerPermit: Send + Sync + fmt::Debug + fmt::Display + 'static { + /// Block until resources for a process are available. + fn next_process(&self) -> BoxFuture<'static, ResourceResult>>; +} + +/// Represents one allowed process. +pub trait ProcessPermit: Send + Sync + fmt::Debug + 'static {} + +/// Enforces a limited number of concurrent `Coordinator`s. +#[derive(Debug)] +pub struct CoordinatorFactory { + limits: Arc, +} + +impl CoordinatorFactory { + pub fn new(limits: Arc) -> Self { + Self { limits } + } + + pub fn build(&self) -> Coordinator + where + B: Backend + Default, + { + let limits = self.limits.clone(); + + let backend = B::default(); + + Coordinator::new(limits, backend) + } + + pub async fn container_requested(&self) { + self.limits.container_requested().await + } +} + +#[derive(Debug)] +pub struct Coordinator { + limits: Arc, + backend: B, + stable: OnceCell, + beta: OnceCell, + nightly: OnceCell, + token: CancelOnDrop, +} + +/// Runs things. +/// +/// # Liveness concerns +/// +/// If you use one of the streaming versions (e.g. `begin_execute`), +/// you need to make sure that the stdout / stderr / status channels +/// are continuously read from or dropped completely. If not, one +/// channel can fill up, preventing the other channels from receiving +/// data as well. +impl Coordinator +where + B: Backend, +{ + fn new(limits: Arc, backend: B) -> Self { + Self { + limits, + backend, + stable: OnceCell::new(), + beta: OnceCell::new(), + nightly: OnceCell::new(), + token: CancelOnDrop::default(), + } + } + + pub async fn versions(&self) -> Result { + use versions_error::*; + + let [stable, beta, nightly] = + [Channel::Stable, Channel::Beta, Channel::Nightly].map(async |c| { + let c = self.select_channel(c).await?; + c.versions().await.map_err(VersionsChannelError::from) + }); + + let stable = async { stable.await.context(StableSnafu) }; + let beta = async { beta.await.context(BetaSnafu) }; + let nightly = async { nightly.await.context(NightlySnafu) }; + + let (stable, beta, nightly) = try_join!(stable, beta, nightly)?; + + Ok(Versions { stable, beta, nightly }) + } + + pub async fn crates(&self) -> Result, CratesError> { + self.select_channel(Channel::Stable).await?.crates().await.map_err(Into::into) + } + + pub async fn execute( + &self, + request: ExecuteRequest, + ) -> Result, ExecuteError> { + use execute_error::*; + + self.select_channel(request.channel) + .await + .context(CouldNotStartContainerSnafu)? + .execute(request) + .await + } + + pub async fn begin_execute( + &self, + token: CancellationToken, + request: ExecuteRequest, + ) -> Result { + use execute_error::*; + + self.select_channel(request.channel) + .await + .context(CouldNotStartContainerSnafu)? + .begin_execute(token, request) + .await + } + + pub async fn compile( + &self, + request: CompileRequest, + ) -> Result, CompileError> { + use compile_error::*; + + self.select_channel(request.channel) + .await + .context(CouldNotStartContainerSnafu)? + .compile(request) + .await + } + + pub async fn begin_compile( + &self, + token: CancellationToken, + request: CompileRequest, + ) -> Result { + use compile_error::*; + + self.select_channel(request.channel) + .await + .context(CouldNotStartContainerSnafu)? + .begin_compile(token, request) + .await + } + + pub async fn format( + &self, + request: FormatRequest, + ) -> Result, FormatError> { + use format_error::*; + + self.select_channel(request.channel) + .await + .context(CouldNotStartContainerSnafu)? + .format(request) + .await + } + + pub async fn begin_format( + &self, + token: CancellationToken, + request: FormatRequest, + ) -> Result { + use format_error::*; + + self.select_channel(request.channel) + .await + .context(CouldNotStartContainerSnafu)? + .begin_format(token, request) + .await + } + + pub async fn clippy( + &self, + request: ClippyRequest, + ) -> Result, ClippyError> { + use clippy_error::*; + + self.select_channel(request.channel) + .await + .context(CouldNotStartContainerSnafu)? + .clippy(request) + .await + } + + pub async fn begin_clippy( + &self, + token: CancellationToken, + request: ClippyRequest, + ) -> Result { + use clippy_error::*; + + self.select_channel(request.channel) + .await + .context(CouldNotStartContainerSnafu)? + .begin_clippy(token, request) + .await + } + + pub async fn miri(&self, request: MiriRequest) -> Result, MiriError> { + use miri_error::*; + + self.select_channel(request.channel) + .await + .context(CouldNotStartContainerSnafu)? + .miri(request) + .await + } + + pub async fn begin_miri( + &self, + token: CancellationToken, + request: MiriRequest, + ) -> Result { + use miri_error::*; + + self.select_channel(request.channel) + .await + .context(CouldNotStartContainerSnafu)? + .begin_miri(token, request) + .await + } + + pub async fn macro_expansion( + &self, + request: MacroExpansionRequest, + ) -> Result, MacroExpansionError> { + use macro_expansion_error::*; + + self.select_channel(request.channel) + .await + .context(CouldNotStartContainerSnafu)? + .macro_expansion(request) + .await + } + + pub async fn begin_macro_expansion( + &self, + token: CancellationToken, + request: MacroExpansionRequest, + ) -> Result { + use macro_expansion_error::*; + + self.select_channel(request.channel) + .await + .context(CouldNotStartContainerSnafu)? + .begin_macro_expansion(token, request) + .await + } + + pub async fn idle(&mut self) -> Result<()> { + let Self { stable, beta, nightly, token, .. } = self; + + let token = mem::take(token); + token.cancel(); + + let channels = [stable, beta, nightly].map(async |c| match c.take() { + Some(c) => c.shutdown().await, + _ => Ok(()), + }); + + let [stable, beta, nightly] = channels; + + let (stable, beta, nightly) = try_join!(stable, beta, nightly)?; + let _: [(); 3] = [stable, beta, nightly]; + + Ok(()) + } + + pub async fn shutdown(mut self) -> Result { + self.idle().await?; + Ok(self.backend) + } + + async fn select_channel(&self, channel: Channel) -> Result<&Container, Error> { + let container = match channel { + Channel::Stable => &self.stable, + Channel::Beta => &self.beta, + Channel::Nightly => &self.nightly, + }; + + container + .get_or_try_init(|| { + let limits = self.limits.clone(); + let token = self.token.0.clone(); + Container::new(channel, limits, token, &self.backend) + }) + .await + } +} + +#[derive(Debug, Default)] +struct CancelOnDrop(CancellationToken); + +impl CancelOnDrop { + fn cancel(&self) { + self.0.cancel(); + } +} + +impl Drop for CancelOnDrop { + fn drop(&mut self) { + self.0.cancel(); + } +} + +#[derive(Debug)] +struct Container { + permit: Box, + task: AbortOnDropHandle>, + kill_child: TerminateContainer, + modify_cargo_toml: ModifyCargoToml, + commander: Commander, +} + +impl Container { + async fn new( + channel: Channel, + limits: Arc, + token: CancellationToken, + backend: &impl Backend, + ) -> Result { + let permit = limits.next_container().await.context(AcquirePermitSnafu)?; + let container_start = time::Instant::now(); + let container_image = channel.to_container_name(); + info!( + ?channel, + container = %container_image, + "starting compiler container" + ); + + let (mut child, kill_child, stdin, stdout) = + backend.run_worker_in_background(channel, &permit)?; + info!( + ?channel, + container = %container_image, + spawn_ms = container_start.elapsed().as_millis(), + "compiler container process spawned" + ); + let IoQueue { mut tasks, to_worker_tx, from_worker_rx } = + spawn_io_queue(stdin, stdout, token); + + let (command_tx, command_rx) = mpsc::channel(8); + let demultiplex = Commander::demultiplex(command_rx, from_worker_rx); + let demultiplex_task = tokio::spawn(demultiplex.in_current_span()).abort_on_drop(); + + let task = tokio::spawn( + async move { + let child = async { + let _: std::process::ExitStatus = + child.wait().await.context(JoinWorkerSnafu)?; + Ok(()) + }; + + let demultiplex_task = async { + demultiplex_task + .await + .context(DemultiplexerTaskPanickedSnafu)? + .context(DemultiplexerTaskFailedSnafu) + }; + + let task = async { + if let Some(t) = tasks.join_next().await { + t.context(IoQueuePanickedSnafu)??; + } + Ok(()) + }; + + let (c, d, t) = try_join!(child, demultiplex_task, task)?; + let _: [(); 3] = [c, d, t]; + + Ok(()) + } + .in_current_span(), + ) + .abort_on_drop(); + + let commander = + Commander { to_worker_tx, to_demultiplexer_tx: command_tx, id: Default::default() }; + + let manifest_start = time::Instant::now(); + let modify_cargo_toml = + ModifyCargoToml::new(commander.clone()).await.context(CouldNotLoadCargoTomlSnafu)?; + info!( + ?channel, + container = %container_image, + manifest_ms = manifest_start.elapsed().as_millis(), + ready_ms = container_start.elapsed().as_millis(), + "compiler container ready" + ); + + Ok(Container { permit, task, kill_child, modify_cargo_toml, commander }) + } + + async fn versions(&self) -> Result { + use container_versions_error::*; + + let token = CancellationToken::new(); + + let rustc = { + let token = token.clone(); + async { + self.rustc_version(token).await.context(RustcSnafu)?.context(RustcMissingSnafu) + } + }; + let rustfmt = { + let token = token.clone(); + async { + self.tool_version(token, "fmt") + .await + .context(RustfmtSnafu)? + .context(RustfmtMissingSnafu) + } + }; + let clippy = { + let token = token.clone(); + async { + self.tool_version(token, "clippy") + .await + .context(ClippySnafu)? + .context(ClippyMissingSnafu) + } + }; + let miri = { + let token = token.clone(); + async { self.tool_version(token, "miri").await.context(MiriSnafu) } + }; + + let _token = token.drop_guard(); + + let (rustc, rustfmt, clippy, miri) = try_join!(rustc, rustfmt, clippy, miri)?; + + Ok(ChannelVersions { rustc, rustfmt, clippy, miri }) + } + + async fn rustc_version( + &self, + token: CancellationToken, + ) -> Result, VersionError> { + let rustc_cmd = ExecuteCommandRequest::simple("rustc", ["--version", "--verbose"]); + let output = self.version_output(token, rustc_cmd).await?; + + Ok(output.map(|o| Version::parse_rustc_version_verbose(&o))) + } + + async fn tool_version( + &self, + token: CancellationToken, + subcommand_name: &str, + ) -> Result, VersionError> { + let tool_cmd = ExecuteCommandRequest::simple("cargo", [subcommand_name, "--version"]); + let output = self.version_output(token, tool_cmd).await?; + + Ok(output.map(|o| Version::parse_tool_version(&o))) + } + + async fn version_output( + &self, + token: CancellationToken, + cmd: ExecuteCommandRequest, + ) -> Result, VersionError> { + let SpawnCargo { permit: _permit, task, stdin_tx, stdout_rx, stderr_rx, status_rx } = + self.spawn_cargo_task(token, cmd, None).await?; + + drop(stdin_tx); + drop(status_rx); + + let task = async { task.await?.map_err(VersionError::from) }; + let o = WithOutput::try_absorb(task, stdout_rx, stderr_rx).await?; + Ok(if o.success { Some(o.stdout) } else { None }) + } + + async fn crates(&self) -> Result, ContainerCratesError> { + let read = ReadFileRequest { path: "crate-information.json".into() }; + let read = self.commander.one(read).await?; + let crates = serde_json::from_slice::>(&read.0)?; + Ok(crates.into_iter().map(Into::into).collect()) + } + + async fn execute( + &self, + request: ExecuteRequest, + ) -> Result, ExecuteError> { + let token = Default::default(); + + let ActiveExecution { permit: _permit, task, stdin_tx, stdout_rx, stderr_rx, status_rx } = + self.begin_execute(token, request).await?; + + drop(stdin_tx); + drop(status_rx); + + WithOutput::try_absorb(task, stdout_rx, stderr_rx).await + } + + #[instrument(skip_all)] + async fn begin_execute( + &self, + token: CancellationToken, + request: ExecuteRequest, + ) -> Result { + use execute_error::*; + + let SpawnCargo { permit, task, stdin_tx, stdout_rx, stderr_rx, status_rx } = + self.do_request(request, token).await?; + + let task = async move { + let ExecuteCommandResponse { success, exit_detail } = + task.await.context(CargoTaskPanickedSnafu)?.context(CargoFailedSnafu)?; + Ok(ExecuteResponse { success, exit_detail }) + } + .boxed(); + + let status_rx = tokio_stream::wrappers::ReceiverStream::new(status_rx) + .map(|s| { + let CommandStatistics { total_time_secs, resident_set_size_bytes } = s; + ExecuteStatus { resident_set_size_bytes, total_time_secs } + }) + .boxed(); + + Ok(ActiveExecution { permit, task, stdin_tx, stdout_rx, stderr_rx, status_rx }) + } + + async fn compile( + &self, + request: CompileRequest, + ) -> Result, CompileError> { + let token = Default::default(); + + let ActiveCompilation { permit: _permit, task, stdout_rx, stderr_rx } = + self.begin_compile(token, request).await?; + + WithOutput::try_absorb(task, stdout_rx, stderr_rx).await + } + + #[instrument(skip_all)] + async fn begin_compile( + &self, + token: CancellationToken, + request: CompileRequest, + ) -> Result { + use compile_error::*; + + let SpawnCargo { permit, task, stdin_tx, stdout_rx, stderr_rx, status_rx } = + self.do_request(&request, token).await?; + + drop(stdin_tx); + drop(status_rx); + + let commander = self.commander.clone(); + let task = async move { + let ExecuteCommandResponse { success, exit_detail } = + task.await.context(CargoTaskPanickedSnafu)?.context(CargoFailedSnafu)?; + + let code = if success { + let read_output = request.read_output_request(); + + let file: ReadFileResponse = + commander.one(read_output).await.context(CouldNotReadCodeSnafu)?; + String::from_utf8(file.0).context(CodeNotUtf8Snafu)? + } else { + String::new() + }; + + // TODO: This is synchronous... + let code = request.postprocess_result(code); + + Ok(CompileResponse { success, exit_detail, code }) + } + .boxed(); + + Ok(ActiveCompilation { permit, task, stdout_rx, stderr_rx }) + } + + async fn format( + &self, + request: FormatRequest, + ) -> Result, FormatError> { + let token = Default::default(); + + let ActiveFormatting { permit: _permit, task, stdout_rx, stderr_rx } = + self.begin_format(token, request).await?; + + WithOutput::try_absorb(task, stdout_rx, stderr_rx).await + } + + async fn begin_format( + &self, + token: CancellationToken, + request: FormatRequest, + ) -> Result { + use format_error::*; + + let SpawnCargo { permit, task, stdin_tx, stdout_rx, stderr_rx, status_rx } = + self.do_request(&request, token).await?; + + drop(stdin_tx); + drop(status_rx); + + let commander = self.commander.clone(); + let task = async move { + let ExecuteCommandResponse { success, exit_detail } = + task.await.context(CargoTaskPanickedSnafu)?.context(CargoFailedSnafu)?; + + let read_output = request.read_output_request(); + let file = commander.one(read_output).await.context(CouldNotReadCodeSnafu)?; + let code = String::from_utf8(file.0).context(CodeNotUtf8Snafu)?; + + Ok(FormatResponse { success, exit_detail, code }) + } + .boxed(); + + Ok(ActiveFormatting { permit, task, stdout_rx, stderr_rx }) + } + + async fn clippy( + &self, + request: ClippyRequest, + ) -> Result, ClippyError> { + let token = Default::default(); + + let ActiveClippy { permit: _permit, task, stdout_rx, stderr_rx } = + self.begin_clippy(token, request).await?; + + WithOutput::try_absorb(task, stdout_rx, stderr_rx).await + } + + async fn begin_clippy( + &self, + token: CancellationToken, + request: ClippyRequest, + ) -> Result { + use clippy_error::*; + + let SpawnCargo { permit, task, stdin_tx, stdout_rx, stderr_rx, status_rx } = + self.do_request(request, token).await?; + + drop(stdin_tx); + drop(status_rx); + + let task = async move { + let ExecuteCommandResponse { success, exit_detail } = + task.await.context(CargoTaskPanickedSnafu)?.context(CargoFailedSnafu)?; + + Ok(ClippyResponse { success, exit_detail }) + } + .boxed(); + + Ok(ActiveClippy { permit, task, stdout_rx, stderr_rx }) + } + + async fn miri(&self, request: MiriRequest) -> Result, MiriError> { + let token = Default::default(); + + let ActiveMiri { permit: _permit, task, stdout_rx, stderr_rx } = + self.begin_miri(token, request).await?; + + WithOutput::try_absorb(task, stdout_rx, stderr_rx).await + } + + async fn begin_miri( + &self, + token: CancellationToken, + request: MiriRequest, + ) -> Result { + use miri_error::*; + + let SpawnCargo { permit, task, stdin_tx, stdout_rx, stderr_rx, status_rx } = + self.do_request(request, token).await?; + + drop(stdin_tx); + drop(status_rx); + + let task = async move { + let ExecuteCommandResponse { success, exit_detail } = + task.await.context(CargoTaskPanickedSnafu)?.context(CargoFailedSnafu)?; + + Ok(MiriResponse { success, exit_detail }) + } + .boxed(); + + Ok(ActiveMiri { permit, task, stdout_rx, stderr_rx }) + } + + async fn macro_expansion( + &self, + request: MacroExpansionRequest, + ) -> Result, MacroExpansionError> { + let token = Default::default(); + + let ActiveMacroExpansion { permit: _permit, task, stdout_rx, stderr_rx } = + self.begin_macro_expansion(token, request).await?; + + WithOutput::try_absorb(task, stdout_rx, stderr_rx).await + } + + async fn begin_macro_expansion( + &self, + token: CancellationToken, + request: MacroExpansionRequest, + ) -> Result { + use macro_expansion_error::*; + + let SpawnCargo { permit, task, stdin_tx, stdout_rx, stderr_rx, status_rx } = + self.do_request(request, token).await?; + + drop(stdin_tx); + drop(status_rx); + + let task = async move { + let ExecuteCommandResponse { success, exit_detail } = + task.await.context(CargoTaskPanickedSnafu)?.context(CargoFailedSnafu)?; + + Ok(MacroExpansionResponse { success, exit_detail }) + } + .boxed(); + + Ok(ActiveMacroExpansion { permit, task, stdout_rx, stderr_rx }) + } + + async fn do_request( + &self, + request: impl LowerRequest + CargoTomlModifier, + token: CancellationToken, + ) -> Result { + use do_request_error::*; + + let instrumentation_kind = request.instrumentation_kind(); + let request_start = time::Instant::now(); + if let Some(kind) = instrumentation_kind { + info!(kind, "request received"); + } + + let delete_files = request + .delete_files() + .map(|req| async { + self.commander + .one(req) + .await + .context(CouldNotDeletePreviousCodeSnafu) + .map(drop::) + }) + .collect::>() + .try_collect::<()>(); + + let write_files = request + .write_files() + .map(|req| async { + self.commander + .one(req) + .await + .context(CouldNotWriteCodeSnafu) + .map(drop::) + }) + .collect::>() + .try_collect::<()>(); + + let modify_cargo_toml = async { + if request.should_modify_cargo_toml() { + self.modify_cargo_toml + .modify_for(&request) + .await + .context(CouldNotModifyCargoTomlSnafu) + } else { + Ok(()) + } + }; + + let prepare_start = time::Instant::now(); + let (d, w, m) = try_join!(delete_files, write_files, modify_cargo_toml)?; + let _: [(); 3] = [d, w, m]; + if let Some(kind) = instrumentation_kind { + info!( + kind, + prepare_ms = prepare_start.elapsed().as_millis(), + total_ms = request_start.elapsed().as_millis(), + "request files prepared" + ); + } + + let execute_cargo = request.execute_cargo_request(); + if let Some(kind) = instrumentation_kind { + info!( + kind, + cmd = %execute_cargo.cmd, + args = ?execute_cargo.args, + cwd = ?execute_cargo.cwd, + envs = ?execute_cargo.envs, + total_ms = request_start.elapsed().as_millis(), + "spawning command" + ); + } + + let spawn_start = time::Instant::now(); + let cargo = self + .spawn_cargo_task(token, execute_cargo, instrumentation_kind) + .await + .context(CouldNotStartCargoSnafu)?; + if let Some(kind) = instrumentation_kind { + info!( + kind, + spawn_ms = spawn_start.elapsed().as_millis(), + total_ms = request_start.elapsed().as_millis(), + "command dispatched" + ); + } + + Ok(cargo) + } + + async fn spawn_cargo_task( + &self, + token: CancellationToken, + execute_cargo: ExecuteCommandRequest, + instrumentation_kind: Option<&'static str>, + ) -> Result { + use spawn_cargo_error::*; + + let permit = self.permit.next_process().await.context(AcquirePermitSnafu)?; + + trace!(?execute_cargo, "starting cargo task"); + + let (stdin_tx, mut stdin_rx) = mpsc::channel(8); + let (stdout_tx, stdout_rx) = mpsc::channel(8); + let (stderr_tx, stderr_rx) = mpsc::channel(8); + let (status_tx, status_rx) = mpsc::channel(8); + + let (to_worker_tx, mut from_worker_rx) = + self.commander.many(execute_cargo).await.context(CouldNotStartCargoSnafu)?; + + let token = token.child_token(); + let drop_token = token.clone(); + + let command_start = time::Instant::now(); + let task = tokio::spawn({ + async move { + let mut cancelled = pin!(token.cancelled().fuse()); + let mut heartbeat = time::interval_at( + command_start + Duration::from_secs(5), + Duration::from_secs(5), + ); + heartbeat.set_missed_tick_behavior(MissedTickBehavior::Delay); + let mut stdin_open = true; + + loop { + enum Event { + Cancelled, + Heartbeat, + Stdin(Option), + FromWorker(WorkerMessage), + } + use Event::*; + + let event = select! { + () = &mut cancelled => Cancelled, + + stdin = stdin_rx.recv(), if stdin_open => Stdin(stdin), + + _ = heartbeat.tick(), if instrumentation_kind.is_some() => Heartbeat, + + Some(container_msg) = from_worker_rx.recv() => FromWorker(container_msg), + + else => return UnexpectedEndOfMessagesSnafu.fail(), + }; + + match event { + Cancelled => { + let msg = CoordinatorMessage::Kill; + trace!(msg_name = msg.as_ref(), "processing"); + to_worker_tx.send(msg).await.context(KillSnafu)?; + } + + Heartbeat => { + if let Some(kind) = instrumentation_kind { + info!( + kind, + elapsed_ms = command_start.elapsed().as_millis(), + "command still running" + ); + } + } + + Stdin(stdin) => { + let msg = match stdin { + Some(stdin) => CoordinatorMessage::StdinPacket(stdin), + + None => { + stdin_open = false; + CoordinatorMessage::StdinClose + } + }; + + trace!(msg_name = msg.as_ref(), "processing"); + to_worker_tx.send(msg).await.context(StdinSnafu)?; + } + + FromWorker(container_msg) => { + trace!(msg_name = container_msg.as_ref(), "processing"); + + match container_msg { + WorkerMessage::ExecuteCommand(resp) => { + if let Some(kind) = instrumentation_kind { + info!( + kind, + command_ms = command_start.elapsed().as_millis(), + success = resp.success, + exit_detail = %resp.exit_detail, + "command finished" + ); + } + return Ok(resp); + } + + WorkerMessage::StdoutPacket(packet) => { + if let Some(kind) = instrumentation_kind { + log_instrumented_command_output( + kind, + "stdout", + &command_start, + &packet, + ); + } + stdout_tx.send(packet).await.ok(/* Receiver gone, that's OK */); + } + + WorkerMessage::StderrPacket(packet) => { + if let Some(kind) = instrumentation_kind { + log_instrumented_command_output( + kind, + "stderr", + &command_start, + &packet, + ); + } + stderr_tx.send(packet).await.ok(/* Receiver gone, that's OK */); + } + + WorkerMessage::CommandStatistics(stats) => { + status_tx.send(stats).await.ok(/* Receiver gone, that's OK */); + } + + WorkerMessage::Error(e) => { + return Err(SerializedError2::adapt(e)).context(WorkerSnafu); + } + + WorkerMessage::Error2(e) => return Err(e).context(WorkerSnafu), + + _ => { + let message = container_msg.as_ref(); + return UnexpectedMessageSnafu { message }.fail(); + } + } + } + } + } + } + .instrument(trace_span!("cargo task").or_current()) + }) + .cancel_on_drop(drop_token); + + Ok(SpawnCargo { permit, task, stdin_tx, stdout_rx, stderr_rx, status_rx }) + } + + async fn shutdown(self) -> Result<()> { + let Self { permit, task, mut kill_child, modify_cargo_toml, commander } = self; + drop(commander); + drop(modify_cargo_toml); + + kill_child.terminate_now().await?; + + let r = task.await; + drop(permit); + + r.context(ContainerTaskPanickedSnafu)? + } +} + +fn log_instrumented_command_output( + kind: &'static str, + stream: &'static str, + command_start: &time::Instant, + packet: &str, +) { + for line in packet.lines() { + let line = line.trim_end(); + if line.is_empty() { + continue; + } + + let output = truncate_log_output(line); + info!( + kind, + stream, + elapsed_ms = command_start.elapsed().as_millis(), + output = %output, + "command output" + ); + } +} + +fn truncate_log_output(line: &str) -> String { + const MAX_CHARS: usize = 2_000; + + let mut chars = line.chars(); + let output = chars.by_ref().take(MAX_CHARS).collect::(); + if chars.next().is_some() { + format!("{output}...") + } else { + output + } +} + +pub struct ActiveExecution { + pub permit: Box, + pub task: BoxFuture<'static, Result>, + pub stdin_tx: mpsc::Sender, + pub stdout_rx: mpsc::Receiver, + pub stderr_rx: mpsc::Receiver, + pub status_rx: BoxStream<'static, ExecuteStatus>, +} + +impl fmt::Debug for ActiveExecution { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ActiveExecution") + .field("task", &"") + .field("stdin_tx", &self.stdin_tx) + .field("stdout_rx", &self.stdout_rx) + .field("stderr_rx", &self.stderr_rx) + .finish() + } +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum ExecuteError { + #[snafu(display("Could not start the container"))] + CouldNotStartContainer { source: Error }, + + #[snafu(transparent)] + DoRequest { source: DoRequestError }, + + #[snafu(display("The Cargo task panicked"))] + CargoTaskPanicked { source: tokio::task::JoinError }, + + #[snafu(display("Cargo task failed"))] + CargoFailed { source: SpawnCargoError }, +} + +pub struct ActiveCompilation { + pub permit: Box, + pub task: BoxFuture<'static, Result>, + pub stdout_rx: mpsc::Receiver, + pub stderr_rx: mpsc::Receiver, +} + +impl fmt::Debug for ActiveCompilation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ActiveCompilation") + .field("task", &"") + .field("stdout_rx", &self.stdout_rx) + .field("stderr_rx", &self.stderr_rx) + .finish() + } +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum CompileError { + #[snafu(display("Could not start the container"))] + CouldNotStartContainer { source: Error }, + + #[snafu(transparent)] + DoRequest { source: DoRequestError }, + + #[snafu(display("The Cargo task panicked"))] + CargoTaskPanicked { source: tokio::task::JoinError }, + + #[snafu(display("Cargo task failed"))] + CargoFailed { source: SpawnCargoError }, + + #[snafu(display("Could not read the compilation output"))] + CouldNotReadCode { source: CommanderError }, + + #[snafu(display("The compilation output was not UTF-8"))] + CodeNotUtf8 { source: std::string::FromUtf8Error }, +} + +pub struct ActiveFormatting { + pub permit: Box, + pub task: BoxFuture<'static, Result>, + pub stdout_rx: mpsc::Receiver, + pub stderr_rx: mpsc::Receiver, +} + +impl fmt::Debug for ActiveFormatting { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ActiveFormatting") + .field("task", &"") + .field("stdout_rx", &self.stdout_rx) + .field("stderr_rx", &self.stderr_rx) + .finish() + } +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum FormatError { + #[snafu(display("Could not start the container"))] + CouldNotStartContainer { source: Error }, + + #[snafu(transparent)] + DoRequest { source: DoRequestError }, + + #[snafu(display("The Cargo task panicked"))] + CargoTaskPanicked { source: tokio::task::JoinError }, + + #[snafu(display("Cargo task failed"))] + CargoFailed { source: SpawnCargoError }, + + #[snafu(display("Could not read the compilation output"))] + CouldNotReadCode { source: CommanderError }, + + #[snafu(display("The compilation output was not UTF-8"))] + CodeNotUtf8 { source: std::string::FromUtf8Error }, +} + +pub struct ActiveClippy { + pub permit: Box, + pub task: BoxFuture<'static, Result>, + pub stdout_rx: mpsc::Receiver, + pub stderr_rx: mpsc::Receiver, +} + +impl fmt::Debug for ActiveClippy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ActiveClippy") + .field("task", &"") + .field("stdout_rx", &self.stdout_rx) + .field("stderr_rx", &self.stderr_rx) + .finish() + } +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum ClippyError { + #[snafu(display("Could not start the container"))] + CouldNotStartContainer { source: Error }, + + #[snafu(transparent)] + DoRequest { source: DoRequestError }, + + #[snafu(display("The Cargo task panicked"))] + CargoTaskPanicked { source: tokio::task::JoinError }, + + #[snafu(display("Cargo task failed"))] + CargoFailed { source: SpawnCargoError }, +} + +pub struct ActiveMiri { + pub permit: Box, + pub task: BoxFuture<'static, Result>, + pub stdout_rx: mpsc::Receiver, + pub stderr_rx: mpsc::Receiver, +} + +impl fmt::Debug for ActiveMiri { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ActiveMiri") + .field("task", &"") + .field("stdout_rx", &self.stdout_rx) + .field("stderr_rx", &self.stderr_rx) + .finish() + } +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum MiriError { + #[snafu(display("Could not start the container"))] + CouldNotStartContainer { source: Error }, + + #[snafu(transparent)] + DoRequest { source: DoRequestError }, + + #[snafu(display("The Cargo task panicked"))] + CargoTaskPanicked { source: tokio::task::JoinError }, + + #[snafu(display("Cargo task failed"))] + CargoFailed { source: SpawnCargoError }, +} + +pub struct ActiveMacroExpansion { + pub permit: Box, + pub task: BoxFuture<'static, Result>, + pub stdout_rx: mpsc::Receiver, + pub stderr_rx: mpsc::Receiver, +} + +impl fmt::Debug for ActiveMacroExpansion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ActiveMacroExpansion") + .field("task", &"") + .field("stdout_rx", &self.stdout_rx) + .field("stderr_rx", &self.stderr_rx) + .finish() + } +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum MacroExpansionError { + #[snafu(display("Could not start the container"))] + CouldNotStartContainer { source: Error }, + + #[snafu(transparent)] + DoRequest { source: DoRequestError }, + + #[snafu(display("The Cargo task panicked"))] + CargoTaskPanicked { source: tokio::task::JoinError }, + + #[snafu(display("Cargo task failed"))] + CargoFailed { source: SpawnCargoError }, +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum DoRequestError { + #[snafu(display("Could not modify Cargo.toml"))] + CouldNotModifyCargoToml { source: ModifyCargoTomlError }, + + #[snafu(display("Could not delete previous source code"))] + CouldNotDeletePreviousCode { source: CommanderError }, + + #[snafu(display("Could not write source code"))] + CouldNotWriteCode { source: CommanderError }, + + #[snafu(display("Could not start Cargo task"))] + CouldNotStartCargo { source: SpawnCargoError }, +} + +/// Triggers `CancellationToken::cancel` when dropped, wrapping +/// another future (which should make use of the token) to keep this +/// guard paired with it. +#[derive(Debug, Default)] +struct CancelOnDropFuture { + token: CancellationToken, + fut: F, +} + +impl Drop for CancelOnDropFuture { + fn drop(&mut self) { + self.token.cancel(); + } +} + +impl Future for CancelOnDropFuture +where + F: Future + Unpin, +{ + type Output = F::Output; + + fn poll(mut self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll { + pin::Pin::new(&mut self.fut).poll(cx) + } +} + +trait CancelOnDropFutureExt { + fn cancel_on_drop(self, token: CancellationToken) -> CancelOnDropFuture + where + Self: Sized; +} + +impl CancelOnDropFutureExt for T { + fn cancel_on_drop(self, token: CancellationToken) -> CancelOnDropFuture + where + Self: Sized, + { + CancelOnDropFuture { token, fut: self } + } +} + +struct SpawnCargo { + permit: Box, + task: CancelOnDropFuture>>, + stdin_tx: mpsc::Sender, + stdout_rx: mpsc::Receiver, + stderr_rx: mpsc::Receiver, + status_rx: mpsc::Receiver, +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum SpawnCargoError { + #[snafu(display("Could not start Cargo"))] + CouldNotStartCargo { source: CommanderError }, + + #[snafu(display("The worker operation failed"))] + Worker { source: SerializedError2 }, + + #[snafu(display("Received the unexpected message `{message}`"))] + UnexpectedMessage { message: String }, + + #[snafu(display("There are no more messages"))] + UnexpectedEndOfMessages, + + #[snafu(display("Unable to send stdin message"))] + Stdin { source: MultiplexedSenderError }, + + #[snafu(display("Unable to send kill message"))] + Kill { source: MultiplexedSenderError }, + + #[snafu(display("Could not acquire a process permit"))] + AcquirePermit { source: ResourceError }, +} + +#[derive(Debug, Clone)] +struct Commander { + to_worker_tx: mpsc::Sender>, + to_demultiplexer_tx: mpsc::Sender<(oneshot::Sender<()>, DemultiplexCommand)>, + id: Arc, +} + +/// The set of files returned by `delete_files` should have no overlap +/// with the set of files returned by `write_files`. +trait LowerRequest { + fn delete_files(&self) -> impl Iterator; + + fn write_files(&self) -> impl Iterator; + + fn execute_cargo_request(&self) -> ExecuteCommandRequest; + + fn instrumentation_kind(&self) -> Option<&'static str> { + None + } +} + +impl LowerRequest for &S +where + S: LowerRequest, +{ + fn delete_files(&self) -> impl Iterator { + S::delete_files(self) + } + + fn write_files(&self) -> impl Iterator { + S::write_files(self) + } + + fn execute_cargo_request(&self) -> ExecuteCommandRequest { + S::execute_cargo_request(self) + } + + fn instrumentation_kind(&self) -> Option<&'static str> { + S::instrumentation_kind(self) + } +} + +trait CargoTomlModifier { + fn should_modify_cargo_toml(&self) -> bool { + true + } + + fn modify_cargo_toml(&self, cargo_toml: toml::Value) -> toml::Value; +} + +impl CargoTomlModifier for &C +where + C: CargoTomlModifier, +{ + fn should_modify_cargo_toml(&self) -> bool { + C::should_modify_cargo_toml(self) + } + + fn modify_cargo_toml(&self, cargo_toml: toml::Value) -> toml::Value { + C::modify_cargo_toml(self, cargo_toml) + } +} + +#[derive(Debug)] +struct ModifyCargoToml { + commander: Commander, + cargo_toml: toml::Value, +} + +impl ModifyCargoToml { + const PATH: &'static str = "Cargo.toml"; + + async fn new(commander: Commander) -> Result { + let cargo_toml = Self::read(&commander).await?; + Ok(Self { commander, cargo_toml }) + } + + async fn modify_for( + &self, + request: &impl CargoTomlModifier, + ) -> Result<(), ModifyCargoTomlError> { + let cargo_toml = self.cargo_toml.clone(); + let cargo_toml = request.modify_cargo_toml(cargo_toml); + Self::write(&self.commander, cargo_toml).await + } + + async fn read(commander: &Commander) -> Result { + use modify_cargo_toml_error::*; + + let path = Self::PATH.to_owned(); + let cargo_toml = + commander.one(ReadFileRequest { path }).await.context(CouldNotReadSnafu)?; + + let cargo_toml = String::from_utf8(cargo_toml.0)?; + let cargo_toml = toml::from_str(&cargo_toml)?; + + Ok(cargo_toml) + } + + async fn write( + commander: &Commander, + cargo_toml: toml::Value, + ) -> Result<(), ModifyCargoTomlError> { + use modify_cargo_toml_error::*; + + let cargo_toml = toml::to_string(&cargo_toml)?; + let content = cargo_toml.into_bytes(); + + let path = Self::PATH.to_owned(); + commander.one(WriteFileRequest { path, content }).await.context(CouldNotWriteSnafu)?; + + Ok(()) + } +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum ModifyCargoTomlError { + #[snafu(display("Could not read the file"))] + CouldNotRead { source: CommanderError }, + + #[snafu(display("Could not parse the file as UTF-8"))] + #[snafu(context(false))] + InvalidUtf8 { source: std::string::FromUtf8Error }, + + #[snafu(display("Could not deserialize the file as TOML"))] + #[snafu(context(false))] + CouldNotDeserialize { source: toml::de::Error }, + + #[snafu(display("Could not serialize the file as TOML"))] + #[snafu(context(false))] + CouldNotSerialize { source: toml::ser::Error }, + + #[snafu(display("Could not write the file"))] + CouldNotWrite { source: CommanderError }, +} + +struct MultiplexedSender { + job_id: JobId, + to_worker_tx: mpsc::Sender>, +} + +impl MultiplexedSender { + async fn send( + &self, + message: impl Into, + ) -> Result<(), MultiplexedSenderError> { + use multiplexed_sender_error::*; + + let message = message.into(); + let message = Multiplexed(self.job_id, message); + + self.to_worker_tx.send(message).await.drop_error_details().context(MultiplexedSenderSnafu) + } +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +#[snafu(display("Could not send a message to the worker"))] +pub struct MultiplexedSenderError { + source: mpsc::error::SendError<()>, +} + +impl Commander { + const GC_PERIOD: Duration = Duration::from_secs(30); + + #[instrument(skip_all)] + async fn demultiplex( + mut command_rx: mpsc::Receiver<(oneshot::Sender<()>, DemultiplexCommand)>, + mut from_worker_rx: mpsc::Receiver>, + ) -> Result<(), CommanderError> { + use commander_error::*; + + let mut waiting = HashMap::new(); + let mut waiting_once = HashMap::new(); + + let mut gc_interval = time::interval(Self::GC_PERIOD); + gc_interval.set_missed_tick_behavior(MissedTickBehavior::Delay); + + loop { + enum Event { + Command(Option<(oneshot::Sender<()>, DemultiplexCommand)>), + + FromWorker(Option>), + + // Find any channels where the receivers have been + // dropped and clear out the sending halves. + Gc, + } + use Event::*; + + let event = select! { + command = command_rx.recv() => Command(command), + + msg = from_worker_rx.recv() => FromWorker(msg), + + _ = gc_interval.tick() => Gc, + }; + + match event { + Command(None) => break, + Command(Some((ack_tx, command))) => { + match command { + DemultiplexCommand::Listen(job_id, waiter) => { + trace!(job_id, "adding listener (many)"); + let old = waiting.insert(job_id, waiter); + ensure!(old.is_none(), DuplicateDemultiplexerClientSnafu { job_id }); + } + + DemultiplexCommand::ListenOnce(job_id, waiter) => { + trace!(job_id, "adding listener (once)"); + let old = waiting_once.insert(job_id, waiter); + ensure!(old.is_none(), DuplicateDemultiplexerClientSnafu { job_id }); + } + } + + ack_tx.send(()).ok(/* Don't care about it */); + } + + FromWorker(None) => break, + FromWorker(Some(Multiplexed(job_id, msg))) => { + if let Some(waiter) = waiting_once.remove(&job_id) { + trace!(job_id, "notifying listener (once)"); + waiter.send(msg).ok(/* Don't care about it */); + continue; + } + + if let Some(waiter) = waiting.get(&job_id) { + trace!(job_id, "notifying listener (many)"); + waiter.send(msg).await.ok(/* Don't care about it */); + continue; + } + + warn!(job_id, msg_name = msg.as_ref(), "no listener to notify"); + } + + Gc => { + waiting.retain(|_job_id, tx| !tx.is_closed()); + waiting_once.retain(|_job_id, tx| !tx.is_closed()); + } + } + } + + Ok(()) + } + + fn next_id(&self) -> JobId { + self.id.fetch_add(1, Ordering::SeqCst) + } + + async fn send_to_demultiplexer( + &self, + command: DemultiplexCommand, + ) -> Result<(), CommanderError> { + use commander_error::*; + + let (ack_tx, ack_rx) = oneshot::channel(); + + self.to_demultiplexer_tx + .send((ack_tx, command)) + .await + .drop_error_details() + .context(UnableToSendToDemultiplexerSnafu)?; + + ack_rx.await.context(DemultiplexerDidNotRespondSnafu) + } + + fn build_multiplexed_sender(&self, job_id: JobId) -> MultiplexedSender { + let to_worker_tx = self.to_worker_tx.clone(); + MultiplexedSender { job_id, to_worker_tx } + } + + async fn one(&self, message: M) -> Result + where + M: Into, + M: OneToOneResponse, + Result: TryFrom, + { + use commander_error::*; + + let id = self.next_id(); + let to_worker_tx = self.build_multiplexed_sender(id); + let (from_demultiplexer_tx, from_demultiplexer_rx) = oneshot::channel(); + + self.send_to_demultiplexer(DemultiplexCommand::ListenOnce(id, from_demultiplexer_tx)) + .await?; + to_worker_tx.send(message).await.context(UnableToStartOneSnafu)?; + let msg = from_demultiplexer_rx.await.context(UnableToReceiveFromDemultiplexerSnafu)?; + + match >::try_from(msg) { + Ok(v) => v.context(WorkerOperationFailedSnafu), + Err(_) => UnexpectedResponseTypeSnafu.fail(), + } + } + + async fn many( + &self, + message: M, + ) -> Result<(MultiplexedSender, mpsc::Receiver), CommanderError> + where + M: Into, + { + use commander_error::*; + + let id = self.next_id(); + let to_worker_tx = self.build_multiplexed_sender(id); + let (from_worker_tx, from_worker_rx) = mpsc::channel(8); + + self.send_to_demultiplexer(DemultiplexCommand::Listen(id, from_worker_tx)).await?; + to_worker_tx.send(message).await.context(UnableToStartManySnafu)?; + + Ok((to_worker_tx, from_worker_rx)) + } +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum CommanderError { + #[snafu(display("Two listeners subscribed to job {job_id}"))] + DuplicateDemultiplexerClient { job_id: JobId }, + + #[snafu(display("Could not send a message to the demultiplexer"))] + UnableToSendToDemultiplexer { source: mpsc::error::SendError<()> }, + + #[snafu(display("Could not send a message to the demultiplexer"))] + DemultiplexerDidNotRespond { source: oneshot::error::RecvError }, + + #[snafu(display("Did not receive a response from the demultiplexer"))] + UnableToReceiveFromDemultiplexer { source: oneshot::error::RecvError }, + + #[snafu(display("Could not start single request/response interaction"))] + UnableToStartOne { source: MultiplexedSenderError }, + + #[snafu(display("Could not start continuous interaction"))] + UnableToStartMany { source: MultiplexedSenderError }, + + #[snafu(display("Did not receive the expected response type from the worker"))] + UnexpectedResponseType, + + #[snafu(display("The worker operation failed"))] + WorkerOperationFailed { source: SerializedError2 }, +} + +pub static TRACKED_CONTAINERS: LazyLock>>> = + LazyLock::new(Default::default); + +#[derive(Debug)] +pub struct TerminateContainer(Option<(String, Command)>); + +impl TerminateContainer { + pub fn new(name: String, command: Command) -> Self { + Self::start_tracking(&name); + + Self(Some((name, command))) + } + + pub fn none() -> Self { + Self(None) + } + + async fn terminate_now(&mut self) -> Result<(), TerminateContainerError> { + use terminate_container_error::*; + + if let Some((name, mut kill_child)) = self.0.take() { + Self::stop_tracking(&name, false); + let o = kill_child.output().await.context(TerminateContainerSnafu { name: &name })?; + Self::report_failure(name, o); + } else { + warn!("Would have stopped tracking in `terminate_now`, but found `None`"); + } + + Ok(()) + } + + #[instrument] + fn start_tracking(name: &str) { + let was_inserted = + TRACKED_CONTAINERS.lock().unwrap_or_else(|e| e.into_inner()).insert(name.into()); + + if was_inserted { + info!("Started tracking container"); + } else { + error!("Started tracking container, but it was already tracked"); + } + } + + #[instrument] + fn stop_tracking(name: &str, from_drop: bool) { + let was_tracked = TRACKED_CONTAINERS.lock().unwrap_or_else(|e| e.into_inner()).remove(name); + + if was_tracked { + info!(from_drop, "Stopped tracking container"); + } else { + error!("Stopped tracking container, but it was not in the tracking set"); + } + } + + fn report_failure(name: String, s: std::process::Output) { + // We generally don't care if the command itself succeeds or + // not; the container may already be dead! However, let's log + // it in an attempt to debug cases where there are more + // containers running than we expect. + + if !s.status.success() { + let code = s.status.code(); + // FUTURE: use `_owned` + let stdout = String::from_utf8_lossy(&s.stdout); + let stderr = String::from_utf8_lossy(&s.stderr); + + let stdout = stdout.trim(); + let stderr = stderr.trim(); + + error!(?code, %stdout, %stderr, %name, "Killing the container failed"); + } + } +} + +impl Drop for TerminateContainer { + fn drop(&mut self) { + if let Some((name, mut kill_child)) = self.0.take() { + Self::stop_tracking(&name, true); + match kill_child.as_std_mut().output() { + Ok(o) => Self::report_failure(name, o), + Err(e) => error!("Unable to kill container {name} while dropping: {e}"), + } + } + } +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +#[snafu(display("Unable to kill the Docker container {name}"))] +pub struct TerminateContainerError { + name: String, + source: std::io::Error, +} + +pub trait Backend { + fn run_worker_in_background( + &self, + channel: Channel, + id: impl fmt::Display, + ) -> Result<(Child, TerminateContainer, ChildStdin, ChildStdout)> { + let (mut start, kill) = self.prepare_worker_command(channel, id); + + let mut child = start + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .context(SpawnWorkerSnafu)?; + let stdin = child.stdin.take().context(WorkerStdinCaptureSnafu)?; + let stdout = child.stdout.take().context(WorkerStdoutCaptureSnafu)?; + Ok((child, kill, stdin, stdout)) + } + + fn prepare_worker_command( + &self, + channel: Channel, + id: impl fmt::Display, + ) -> (Command, TerminateContainer); +} + +impl Backend for &B +where + B: Backend, +{ + fn prepare_worker_command( + &self, + channel: Channel, + id: impl fmt::Display, + ) -> (Command, TerminateContainer) { + B::prepare_worker_command(self, channel, id) + } +} + +macro_rules! docker_command { + ($($arg:expr),* $(,)?) => ({ + let mut cmd = Command::new("docker"); + $( cmd.arg($arg); )* + cmd + }); +} + +macro_rules! docker_target_arch { + (x86_64: $x:expr, aarch64: $a:expr $(,)?) => {{ + #[cfg(target_arch = "x86_64")] + { + $x + } + + #[cfg(target_arch = "aarch64")] + { + $a + } + }}; +} + +const DOCKER_ARCH: &str = docker_target_arch! { + x86_64: "linux/amd64", + aarch64: "linux/arm64", +}; + +const DEFAULT_DOCKER_MEMORY: &str = "512m"; +const DEFAULT_DOCKER_MEMORY_SWAP: &str = "640m"; +const PLAYGROUND_ANNEAL_PERSISTENT_TARGET: &str = "PLAYGROUND_ANNEAL_PERSISTENT_TARGET"; +const PLAYGROUND_ANNEAL_PERSISTENT_TARGET_VOLUME_PREFIX: &str = + "PLAYGROUND_ANNEAL_PERSISTENT_TARGET_VOLUME_PREFIX"; +const DEFAULT_ANNEAL_PERSISTENT_TARGET_VOLUME_PREFIX: &str = "playground-anneal-target"; +const ANNEAL_DOCKER_TARGET_DIR: &str = "/playground/anneal-workspace/target/anneal"; + +fn basic_secure_docker_command() -> Command { + let memory = std::env::var("PLAYGROUND_DOCKER_MEMORY") + .unwrap_or_else(|_| DEFAULT_DOCKER_MEMORY.to_owned()); + let memory_swap = std::env::var("PLAYGROUND_DOCKER_MEMORY_SWAP") + .unwrap_or_else(|_| DEFAULT_DOCKER_MEMORY_SWAP.to_owned()); + + let mut command = + docker_command!("run", "--platform", DOCKER_ARCH, "--cap-drop=ALL", "--net", "none",); + command.arg("--memory").arg(memory).arg("--memory-swap").arg(memory_swap).args([ + "--pids-limit", + "512", + "--oom-score-adj", + "1000", + ]); + command +} + +#[derive(Default)] +pub struct DockerBackend(()); + +impl Backend for DockerBackend { + fn prepare_worker_command( + &self, + channel: Channel, + id: impl fmt::Display, + ) -> (Command, TerminateContainer) { + let name = format!("playground-{id}"); + + let mut command = basic_secure_docker_command(); + command + .args(["--name", &name]) + .arg("-i") + .args(["-a", "stdin", "-a", "stdout", "-a", "stderr"]) + .arg("--rm"); + if let Some(volume) = anneal_persistent_target_volume(channel) { + let mount = format!("type=volume,source={volume},target={ANNEAL_DOCKER_TARGET_DIR}"); + info!( + ?channel, + volume = %volume, + target = ANNEAL_DOCKER_TARGET_DIR, + "[anneal-cache] mounting persistent Anneal target volume" + ); + command.args(["--mount", &mount]); + } + command.arg(channel.to_container_name()).arg("worker").arg("/playground"); + + let mut kill = Command::new("docker"); + kill.arg("kill").args(["--signal", "KILL"]).arg(&name); + let kill = TerminateContainer::new(name, kill); + + (command, kill) + } +} + +fn anneal_persistent_target_volume(channel: Channel) -> Option { + if std::env::var_os(PLAYGROUND_ANNEAL_PERSISTENT_TARGET).is_none() { + return None; + } + + let prefix = std::env::var(PLAYGROUND_ANNEAL_PERSISTENT_TARGET_VOLUME_PREFIX) + .unwrap_or_else(|_| DEFAULT_ANNEAL_PERSISTENT_TARGET_VOLUME_PREFIX.to_owned()); + let channel = match channel { + Channel::Stable => "stable", + Channel::Beta => "beta", + Channel::Nightly => "nightly", + }; + Some(format!("{prefix}-{channel}")) +} + +impl Channel { + fn to_container_name(self) -> &'static str { + match self { + Channel::Stable => "rust-stable", + Channel::Beta => "rust-beta", + Channel::Nightly => "rust-nightly", + } + } +} + +pub type Result = ::std::result::Result; + +#[derive(Debug, Snafu)] +pub enum Error { + #[snafu(display("Reached system process limit"))] + SpawnWorker { source: std::io::Error }, + + #[snafu(display("Unable to join child process"))] + JoinWorker { source: std::io::Error }, + + #[snafu(display("The demultiplexer task panicked"))] + DemultiplexerTaskPanicked { source: tokio::task::JoinError }, + + #[snafu(display("The demultiplexer task failed"))] + DemultiplexerTaskFailed { source: CommanderError }, + + #[snafu(display("The IO queue task panicked"))] + IoQueuePanicked { source: tokio::task::JoinError }, + + #[snafu(transparent)] + KillWorker { source: TerminateContainerError }, + + #[snafu(display("The container task panicked"))] + ContainerTaskPanicked { source: tokio::task::JoinError }, + + #[snafu(display("Worker process's stdin not captured"))] + WorkerStdinCapture, + + #[snafu(display("Worker process's stdout not captured"))] + WorkerStdoutCapture, + + #[snafu(display("Failed to flush child stdin"))] + WorkerStdinFlush { source: std::io::Error }, + + #[snafu(display("Failed to deserialize worker message"))] + WorkerMessageDeserialization { source: bincode::Error }, + + #[snafu(display("Failed to serialize coordinator message"))] + CoordinatorMessageSerialization { source: bincode::Error }, + + #[snafu(display("Failed to send worker message through channel"))] + UnableToSendWorkerMessage { source: mpsc::error::SendError<()> }, + + #[snafu(display("Unable to load original Cargo.toml"))] + CouldNotLoadCargoToml { source: ModifyCargoTomlError }, + + #[snafu(display("Could not acquire a container permit"))] + AcquirePermit { source: ResourceError }, +} + +struct IoQueue { + tasks: JoinSet>, + to_worker_tx: mpsc::Sender>, + from_worker_rx: mpsc::Receiver>, +} + +// Child stdin/out <--> messages. +fn spawn_io_queue(stdin: ChildStdin, stdout: ChildStdout, token: CancellationToken) -> IoQueue { + use std::io::{prelude::*, BufReader, BufWriter}; + + let mut tasks = JoinSet::new(); + + let (tx, from_worker_rx) = mpsc::channel(8); + tasks.spawn_blocking(move || { + let span = info_span!("child_io_queue::input"); + let _span = span.enter(); + + let stdout = SyncIoBridge::new(stdout); + let mut stdout = BufReader::new(stdout); + + loop { + let worker_msg = bincode::deserialize_from(&mut stdout); + + if bincode_input_closed(&worker_msg) { + break; + }; + + let worker_msg = worker_msg.context(WorkerMessageDeserializationSnafu)?; + + tx.blocking_send(worker_msg) + .drop_error_details() + .context(UnableToSendWorkerMessageSnafu)?; + } + + Ok(()) + }); + + let (to_worker_tx, mut rx) = mpsc::channel(8); + tasks.spawn_blocking(move || { + let span = info_span!("child_io_queue::output"); + let _span = span.enter(); + + let stdin = SyncIoBridge::new(stdin); + let mut stdin = BufWriter::new(stdin); + + let handle = tokio::runtime::Handle::current(); + + loop { + let coordinator_msg = handle.block_on(token.run_until_cancelled(rx.recv())); + + let Some(Some(coordinator_msg)) = coordinator_msg else { + break; + }; + + bincode::serialize_into(&mut stdin, &coordinator_msg) + .context(CoordinatorMessageSerializationSnafu)?; + + stdin.flush().context(WorkerStdinFlushSnafu)?; + } + + Ok(()) + }); + + IoQueue { tasks, to_worker_tx, from_worker_rx } +} + +#[cfg(test)] +mod tests { + use assertables::*; + use futures::future::{join, try_join_all}; + use std::{ + env, + sync::{LazyLock, Once}, + }; + use tempfile::TempDir; + + use super::*; + + #[allow(dead_code)] + fn setup_tracing() { + use tracing::Level; + use tracing_subscriber::fmt::TestWriter; + + tracing_subscriber::fmt() + .with_ansi(false) + .with_max_level(Level::TRACE) + .with_writer(TestWriter::new()) + .try_init() + .ok(); + } + + #[derive(Debug)] + struct TestBackend { + project_dir: TempDir, + } + + impl Default for TestBackend { + fn default() -> Self { + static COMPILE_WORKER_ONCE: Once = Once::new(); + + COMPILE_WORKER_ONCE.call_once(|| { + let output = std::process::Command::new("cargo") + .arg("build") + .output() + .expect("Build failed"); + assert!(output.status.success(), "Build failed"); + }); + + let project_dir = TempDir::with_prefix("playground") + .expect("Failed to create temporary project directory"); + + for channel in Channel::ALL { + let channel = channel.to_str(); + let channel_dir = project_dir.path().join(channel); + + let output = std::process::Command::new("cargo") + .arg(format!("+{channel}")) + .arg("new") + .args(["--name", "playground"]) + .arg(&channel_dir) + .output() + .expect("Cargo new failed"); + assert!(output.status.success(), "Cargo new failed"); + + let main = channel_dir.join("src").join("main.rs"); + std::fs::remove_file(main).expect("Could not delete main.rs"); + } + + Self { project_dir } + } + } + + impl Backend for TestBackend { + fn prepare_worker_command( + &self, + channel: Channel, + _id: impl fmt::Display, + ) -> (Command, TerminateContainer) { + let channel_dir = self.project_dir.path().join(channel.to_str()); + + let mut command = Command::new("./target/debug/worker"); + command.env("RUSTUP_TOOLCHAIN", channel.to_str()); + command.arg(channel_dir); + + (command, TerminateContainer::none()) + } + } + + static MAX_CONCURRENT_TESTS: LazyLock = LazyLock::new(|| { + env::var("TESTS_MAX_CONCURRENCY").ok().and_then(|v| v.parse().ok()).unwrap_or(5) + }); + + static TEST_COORDINATOR_ID_PROVIDER: LazyLock> = + LazyLock::new(|| Arc::new(limits::Global::new(100, *MAX_CONCURRENT_TESTS))); + + static TEST_COORDINATOR_FACTORY: LazyLock = + LazyLock::new(|| CoordinatorFactory::new(TEST_COORDINATOR_ID_PROVIDER.clone())); + + fn new_coordinator_test() -> Coordinator { + TEST_COORDINATOR_FACTORY.build() + } + + fn new_coordinator_docker() -> Coordinator { + TEST_COORDINATOR_FACTORY.build() + } + + fn new_coordinator() -> Coordinator { + #[cfg(not(force_docker))] + { + new_coordinator_test() + } + + #[cfg(force_docker)] + { + new_coordinator_docker() + } + } + + #[tokio::test] + #[snafu::report] + async fn versions() -> Result<()> { + let coordinator = new_coordinator(); + + let versions = coordinator.versions().with_timeout().await.unwrap(); + + assert_starts_with!(versions.stable.rustc.release, "1."); + + coordinator.shutdown().await?; + + Ok(()) + } + + const ARBITRARY_EXECUTE_REQUEST: ExecuteRequest = ExecuteRequest { + channel: Channel::Stable, + mode: Mode::Debug, + edition: Edition::Rust2021, + crate_type: CrateType::Binary, + tests: false, + backtrace: false, + code: String::new(), + execution_tool: ExecutionTool::Cargo, + }; + + fn new_execute_request() -> ExecuteRequest { + ExecuteRequest { + code: r#"fn main() { println!("Hello, coordinator!"); }"#.into(), + ..ARBITRARY_EXECUTE_REQUEST + } + } + + #[test] + fn anneal_cargo_toml_uses_requested_edition() { + for edition in Edition::ALL { + let cargo_toml = anneal_cargo_toml_content(edition); + let expected = format!(r#"edition = "{}""#, edition.to_cargo_toml_key()); + + assert_contains!(cargo_toml, &expected); + } + } + + #[tokio::test] + #[snafu::report] + async fn execute_response() -> Result<()> { + let coordinator = new_coordinator(); + + let response = coordinator.execute(new_execute_request()).with_timeout().await.unwrap(); + + assert!(response.success, "stderr: {}", response.stderr); + assert_contains!(response.stderr, "Compiling"); + assert_contains!(response.stderr, "Finished"); + assert_contains!(response.stderr, "Running"); + assert_contains!(response.stdout, "Hello, coordinator!"); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn execute_mode() -> Result<()> { + let params = [(Mode::Debug, "[unoptimized + debuginfo]"), (Mode::Release, "[optimized]")]; + + let tests = params.into_iter().map(async |(mode, expected)| { + let coordinator = new_coordinator(); + + let request = ExecuteRequest { mode, ..new_execute_request() }; + let response = coordinator.execute(request).await.unwrap(); + + assert!(response.success, "({mode:?}) stderr: {}", response.stderr); + assert_contains!(response.stderr, expected); + + coordinator.shutdown().await?; + + Ok::<_, Error>(()) + }); + + try_join_all(tests).with_timeout().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn execute_edition() -> Result<()> { + let params = [ + (r#"fn x() { let dyn = true; }"#, [true, false, false, false]), + (r#"fn x() { u16::try_from(1u8); }"#, [false, false, true, true]), + (r#"fn x() { let gen = true; }"#, [true, true, true, false]), + ]; + + let tests = params.into_iter().flat_map(|(code, works_in)| { + Edition::ALL.into_iter().zip(works_in).map(async |(edition, expected_to_work)| { + let coordinator = new_coordinator(); + + let request = ExecuteRequest { + code: code.into(), + edition, + crate_type: CrateType::Library(LibraryType::Lib), + ..ARBITRARY_EXECUTE_REQUEST + }; + let response = coordinator.execute(request).await.unwrap(); + + assert_eq!( + response.success, expected_to_work, + "({edition:?}), stderr: {}", + response.stderr, + ); + + coordinator.shutdown().await?; + + Ok::<_, Error>(()) + }) + }); + + try_join_all(tests).with_timeout().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn execute_crate_type() -> Result<()> { + let params = [ + (CrateType::Binary, "Running `target"), + (CrateType::Library(LibraryType::Cdylib), "function `main` is never used"), + ]; + + let tests = params.into_iter().map(async |(crate_type, expected)| { + let coordinator = new_coordinator(); + + let request = ExecuteRequest { crate_type, ..new_execute_request() }; + let response = coordinator.execute(request).await.unwrap(); + + assert!(response.success, "({crate_type:?}), stderr: {}", response.stderr,); + assert_contains!(response.stderr, expected); + + coordinator.shutdown().await?; + + Ok::<_, Error>(()) + }); + + try_join_all(tests).with_timeout().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn execute_tests() -> Result<()> { + let code = r#"fn main() {} #[test] fn test() {}"#; + + let params = [(false, "Running `"), (true, "Running unittests")]; + + let tests = params.into_iter().map(async |(tests, expected)| { + let coordinator = new_coordinator(); + + let request = ExecuteRequest { code: code.into(), tests, ..new_execute_request() }; + let response = coordinator.execute(request).await.unwrap(); + + assert!(response.success, "({tests:?}), stderr: {}", response.stderr); + assert_contains!(response.stderr, expected); + + coordinator.shutdown().await?; + + Ok::<_, Error>(()) + }); + + try_join_all(tests).with_timeout().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn execute_backtrace() -> Result<()> { + let code = r#"fn main() { panic!("Disco"); }"#; + + let params = [(false, "note: run with `RUST_BACKTRACE=1`"), (true, "stack backtrace:")]; + + let tests = params.into_iter().map(async |(backtrace, expected)| { + let coordinator = new_coordinator(); + + let request = ExecuteRequest { code: code.into(), backtrace, ..new_execute_request() }; + let response = coordinator.execute(request).await.unwrap(); + + assert!(!response.success, "({backtrace:?}), stderr: {}", response.stderr,); + assert_contains!(response.stderr, expected); + + coordinator.shutdown().await?; + + Ok::<_, Error>(()) + }); + + try_join_all(tests).with_timeout().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn execute_stdin() -> Result<()> { + let coordinator = new_coordinator(); + + let request = ExecuteRequest { + code: r#" + fn main() { + let mut input = String::new(); + if std::io::stdin().read_line(&mut input).is_ok() { + println!("You entered >>>{input:?}<<<"); + } + } + "# + .into(), + ..ARBITRARY_EXECUTE_REQUEST + }; + + let token = Default::default(); + let ActiveExecution { + permit: _permit, + task, + stdin_tx, + stdout_rx, + stderr_rx, + status_rx: _status_rx, + } = coordinator.begin_execute(token, request).await.unwrap(); + + stdin_tx.send("this is stdin\n".into()).await.unwrap(); + // Purposefully not dropping stdin_tx / status_rx early -- + // real users might forget. + + let WithOutput { response, stdout, stderr } = + WithOutput::try_absorb(task, stdout_rx, stderr_rx).with_timeout().await.unwrap(); + + assert!(response.success, "{stderr}"); + assert_contains!(stdout, r#">>>"this is stdin\n"<<<"#); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn execute_stdin_close() -> Result<()> { + let coordinator = new_coordinator(); + + let request = ExecuteRequest { + code: r#" + fn main() { + let mut input = String::new(); + while let Ok(n) = std::io::stdin().read_line(&mut input) { + if n == 0 { + break; + } + println!("You entered >>>{input:?}<<<"); + input.clear(); + } + } + "# + .into(), + ..ARBITRARY_EXECUTE_REQUEST + }; + + let token = Default::default(); + let ActiveExecution { permit: _permit, task, stdin_tx, stdout_rx, stderr_rx, status_rx: _ } = + coordinator.begin_execute(token, request).await.unwrap(); + + for i in 0..3 { + stdin_tx.send(format!("line {i}\n")).await.unwrap(); + } + + stdin_tx.send("no newline".into()).await.unwrap(); + drop(stdin_tx); // Close the stdin handle + + let WithOutput { response, stdout, stderr } = + WithOutput::try_absorb(task, stdout_rx, stderr_rx).with_timeout().await.unwrap(); + + assert!(response.success, "{stderr}"); + assert_contains!(stdout, r#">>>"line 0\n"<<<"#); + assert_contains!(stdout, r#">>>"line 1\n"<<<"#); + assert_contains!(stdout, r#">>>"line 2\n"<<<"#); + assert_contains!(stdout, r#">>>"no newline"<<<"#); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn execute_kill() -> Result<()> { + let coordinator = new_coordinator(); + + let request = ExecuteRequest { + code: r#" + fn main() { + println!("Before"); + loop { + std::thread::sleep(std::time::Duration::from_secs(1)); + } + println!("After"); + } + "# + .into(), + ..ARBITRARY_EXECUTE_REQUEST + }; + + let token = CancellationToken::new(); + let ActiveExecution { + permit: _permit, + task, + stdin_tx: _, + stdout_rx, + stderr_rx, + status_rx: _, + } = coordinator.begin_execute(token.clone(), request).await.unwrap(); + + let stdout_rx = ReceiverStream::new(stdout_rx); + let stderr_rx = ReceiverStream::new(stderr_rx); + + // We (a) want to wait for some output before we try to + // kill the process and (b) need to keep pumping stdout / + // stderr / status to avoid locking up the output. + let stdout_rx = stdout_rx.inspect(|_| token.cancel()); + + let WithOutput { response, stdout, stderr } = + WithOutput::try_absorb_stream(task, stdout_rx, stderr_rx).with_timeout().await.unwrap(); + + assert!(!response.success, "{stderr}"); + assert_contains!(response.exit_detail, "kill"); + + assert_contains!(stdout, "Before"); + assert_not_contains!(stdout, "After"); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn execute_status() -> Result<()> { + let coordinator = new_coordinator(); + + let request = ExecuteRequest { + code: r#" + use std::{time::{Instant, Duration}, thread}; + + const MORE_THAN_STATUS_INTERVAL: Duration = Duration::from_millis(1100); + + fn main() { + let start = Instant::now(); + while start.elapsed() < MORE_THAN_STATUS_INTERVAL { + // Busy loop + } + thread::sleep(MORE_THAN_STATUS_INTERVAL); + } + "# + .into(), + ..ARBITRARY_EXECUTE_REQUEST + }; + + let token = CancellationToken::new(); + let ActiveExecution { permit: _permit, task, stdin_tx: _, stdout_rx, stderr_rx, status_rx } = + coordinator.begin_execute(token.clone(), request).await.unwrap(); + + let statuses = status_rx.collect::>(); + + let output = WithOutput::try_absorb(task, stdout_rx, stderr_rx); + + let (statuses, output) = join(statuses, output).with_timeout().await; + + let WithOutput { response, stderr, .. } = output.unwrap(); + + assert!(response.success, "{stderr}"); + + let [first, last] = [statuses.first(), statuses.last()].map(|s| s.unwrap().total_time_secs); + + let cpu_time_used = last - first; + assert!(cpu_time_used > 1.0, "CPU usage did not increase enough ({first} -> {last})"); + + coordinator.shutdown().await?; + + Ok(()) + } + + const HELLO_WORLD_CODE: &str = r#"fn main() { println!("Hello World!"); }"#; + + const ARBITRARY_COMPILE_REQUEST: CompileRequest = CompileRequest { + target: CompileTarget::Mir, + channel: Channel::Stable, + crate_type: CrateType::Binary, + mode: Mode::Release, + edition: Edition::Rust2021, + tests: false, + backtrace: false, + code: String::new(), + }; + + #[tokio::test] + #[snafu::report] + async fn compile_response() -> Result<()> { + let coordinator = new_coordinator(); + + let req = CompileRequest { code: HELLO_WORLD_CODE.into(), ..ARBITRARY_COMPILE_REQUEST }; + + let response = coordinator.compile(req).with_timeout().await.unwrap(); + + assert!(response.success, "stderr: {}", response.stderr); + assert_contains!(response.stderr, "Compiling"); + assert_contains!(response.stderr, "Finished"); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn compile_streaming() -> Result<()> { + let coordinator = new_coordinator(); + + let req = CompileRequest { code: HELLO_WORLD_CODE.into(), ..ARBITRARY_COMPILE_REQUEST }; + + let token = Default::default(); + let ActiveCompilation { permit: _permit, task, stdout_rx, stderr_rx } = + coordinator.begin_compile(token, req).await.unwrap(); + + let WithOutput { response, stdout: _, stderr } = + WithOutput::try_absorb(task, stdout_rx, stderr_rx).await.unwrap(); + + assert!(response.success, "stderr: {stderr}"); + assert_contains!(stderr, "Compiling"); + assert_contains!(stderr, "Finished"); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn compile_edition() -> Result<()> { + for edition in Edition::ALL { + let coordinator = new_coordinator(); + + let req = + CompileRequest { edition, code: SUBTRACT_CODE.into(), ..ARBITRARY_HIR_REQUEST }; + + let response = coordinator.compile(req).with_timeout().await.unwrap(); + + let prelude = format!("std::prelude::rust_{}", edition.to_str()); + + assert!(response.success, "stderr: {}", response.stderr); + assert_contains!(response.code, &prelude); + + coordinator.shutdown().await?; + } + + Ok(()) + } + + const ADD_CODE: &str = r#"#[inline(never)] pub fn add(a: u8, b: u8) -> u8 { a + b }"#; + + const ARBITRARY_ASSEMBLY_REQUEST: CompileRequest = CompileRequest { + target: CompileTarget::Assembly( + DEFAULT_ASSEMBLY_FLAVOR, + DEFAULT_ASSEMBLY_DEMANGLE, + DEFAULT_ASSEMBLY_PROCESS, + ), + channel: Channel::Beta, + crate_type: CrateType::Library(LibraryType::Lib), + mode: Mode::Release, + edition: Edition::Rust2018, + tests: false, + backtrace: false, + code: String::new(), + }; + + const DEFAULT_ASSEMBLY_FLAVOR: AssemblyFlavor = AssemblyFlavor::Intel; + const DEFAULT_ASSEMBLY_DEMANGLE: DemangleAssembly = DemangleAssembly::Demangle; + const DEFAULT_ASSEMBLY_PROCESS: ProcessAssembly = ProcessAssembly::Filter; + + #[tokio::test] + #[snafu::report] + async fn compile_assembly() -> Result<()> { + let coordinator = new_coordinator(); + + let req = CompileRequest { code: ADD_CODE.into(), ..ARBITRARY_ASSEMBLY_REQUEST }; + + let response = coordinator.compile(req).with_timeout().await.unwrap(); + + let asm = docker_target_arch! { + x86_64: "eax, [rsi + rdi]", + aarch64: "w0, w1, w0", + }; + + assert!(response.success, "stderr: {}", response.stderr); + assert_contains!(response.code, asm); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + // Assembly flavor only makes sense when targeting x86(_64): this + // test will always fail on aarch64. + async fn compile_assembly_flavor() -> Result<()> { + let cases = [ + (AssemblyFlavor::Att, "(%rsi,%rdi), %eax"), + (AssemblyFlavor::Intel, "eax, [rsi + rdi]"), + ]; + + for (flavor, expected) in cases { + let coordinator = new_coordinator(); + + let req = CompileRequest { + target: CompileTarget::Assembly( + flavor, + DEFAULT_ASSEMBLY_DEMANGLE, + DEFAULT_ASSEMBLY_PROCESS, + ), + code: ADD_CODE.into(), + ..ARBITRARY_ASSEMBLY_REQUEST + }; + + let response = coordinator.compile(req).with_timeout().await.unwrap(); + + assert!(response.success, "stderr: {}", response.stderr); + assert_contains!(response.code, expected); + + coordinator.shutdown().await?; + } + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + // The demangling expects Linux-style symbols, not macOS: this + // test will always fail on macOS. + async fn compile_assembly_demangle() -> Result<()> { + let cases = [ + (DemangleAssembly::Mangle, "10playground3add"), + (DemangleAssembly::Demangle, "playground::add"), + ]; + + for (mangle, expected) in cases { + let coordinator = new_coordinator(); + + let req = CompileRequest { + target: CompileTarget::Assembly( + DEFAULT_ASSEMBLY_FLAVOR, + mangle, + DEFAULT_ASSEMBLY_PROCESS, + ), + code: ADD_CODE.into(), + ..ARBITRARY_ASSEMBLY_REQUEST + }; + + let response = coordinator.compile(req).with_timeout().await.unwrap(); + + assert!(response.success, "stderr: {}", response.stderr); + assert_contains!(response.code, expected); + + coordinator.shutdown().await?; + } + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn compile_assembly_process() -> Result<()> { + let cases = [(ProcessAssembly::Raw, true), (ProcessAssembly::Filter, false)]; + + for (process, expected) in cases { + let coordinator = new_coordinator(); + + let req = CompileRequest { + target: CompileTarget::Assembly( + DEFAULT_ASSEMBLY_FLAVOR, + DEFAULT_ASSEMBLY_DEMANGLE, + process, + ), + code: ADD_CODE.into(), + ..ARBITRARY_ASSEMBLY_REQUEST + }; + + let response = coordinator.compile(req).with_timeout().await.unwrap(); + + assert!(response.success, "stderr: {}", response.stderr); + if expected { + assert_contains!(response.code, ".cfi_startproc"); + } else { + assert_not_contains!(response.code, ".cfi_startproc"); + } + + coordinator.shutdown().await?; + } + + Ok(()) + } + + const SUBTRACT_CODE: &str = r#"pub fn sub(a: u8, b: u8) -> u8 { a - b }"#; + + const ARBITRARY_HIR_REQUEST: CompileRequest = CompileRequest { + target: CompileTarget::Hir, + channel: Channel::Nightly, + crate_type: CrateType::Library(LibraryType::Lib), + mode: Mode::Release, + edition: Edition::Rust2021, + tests: false, + backtrace: false, + code: String::new(), + }; + + #[tokio::test] + #[snafu::report] + async fn compile_hir() -> Result<()> { + let coordinator = new_coordinator(); + + let req = CompileRequest { code: SUBTRACT_CODE.into(), ..ARBITRARY_HIR_REQUEST }; + + let response = coordinator.compile(req).with_timeout().await.unwrap(); + + assert!(response.success, "stderr: {}", response.stderr); + assert_contains!(response.code, "extern crate std"); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn compile_llvm_ir() -> Result<()> { + let coordinator = new_coordinator(); + + let req = CompileRequest { + target: CompileTarget::LlvmIr, + channel: Channel::Stable, + crate_type: CrateType::Library(LibraryType::Lib), + mode: Mode::Debug, + edition: Edition::Rust2015, + tests: false, + backtrace: false, + code: r#"pub fn mul(a: u8, b: u8) -> u8 { a * b }"#.into(), + }; + + let response = coordinator.compile(req).with_timeout().await.unwrap(); + + assert!(response.success, "stderr: {}", response.stderr); + assert_contains!(response.code, "@llvm.umul.with.overflow.i8(i8, i8)"); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn compile_wasm() -> Result<()> { + // cargo-wasm only exists inside the container + let coordinator = new_coordinator_docker(); + + let req = CompileRequest { + target: CompileTarget::Wasm, + channel: Channel::Nightly, + crate_type: CrateType::Library(LibraryType::Cdylib), + mode: Mode::Release, + edition: Edition::Rust2021, + tests: false, + backtrace: false, + code: r#"#[export_name = "inc"] pub fn inc(a: u8) -> u8 { a + 1 }"#.into(), + }; + + let response = coordinator.compile(req).with_timeout().await.unwrap(); + + assert!(response.success, "stderr: {}", response.stderr); + assert_contains!(response.code, r#"(func $inc (;0;) (type 0) (param i32) (result i32)"#); + + coordinator.shutdown().await?; + + Ok(()) + } + + const ARBITRARY_FORMAT_REQUEST: FormatRequest = FormatRequest { + channel: Channel::Stable, + crate_type: CrateType::Binary, + edition: Edition::Rust2015, + code: String::new(), + }; + + const ARBITRARY_FORMAT_INPUT: &str = "fn main(){1+1;}"; + #[rustfmt::skip] + const ARBITRARY_FORMAT_OUTPUT: &[&str] = &[ + "fn main() {", + " 1 + 1;", + "}" + ]; + + #[tokio::test] + #[snafu::report] + async fn format() -> Result<()> { + let coordinator = new_coordinator(); + + let req = FormatRequest { code: ARBITRARY_FORMAT_INPUT.into(), ..ARBITRARY_FORMAT_REQUEST }; + + let response = coordinator.format(req).with_timeout().await.unwrap(); + + assert!(response.success, "stderr: {}", response.stderr); + let lines = response.code.lines().collect::>(); + assert_eq!(ARBITRARY_FORMAT_OUTPUT, lines); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn format_channel() -> Result<()> { + for channel in Channel::ALL { + let coordinator = new_coordinator(); + + let req = FormatRequest { + channel, + code: ARBITRARY_FORMAT_INPUT.into(), + ..ARBITRARY_FORMAT_REQUEST + }; + + let response = coordinator.format(req).with_timeout().await.unwrap(); + + assert!(response.success, "stderr: {}", response.stderr); + let lines = response.code.lines().collect::>(); + assert_eq!(ARBITRARY_FORMAT_OUTPUT, lines); + + coordinator.shutdown().await?; + } + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn format_edition() -> Result<()> { + let cases = [ + ("fn main() { async { 1 } }", [false, true, true, true]), + ("fn main() { gen { 1 } }", [false, false, false, true]), + ]; + + for (code, works_in) in cases { + let coordinator = new_coordinator(); + + for (edition, works) in Edition::ALL.into_iter().zip(works_in) { + let req = FormatRequest { edition, code: code.into(), ..ARBITRARY_FORMAT_REQUEST }; + + let response = coordinator.format(req).with_timeout().await.unwrap(); + + assert_eq!(response.success, works, "{code} in {edition:?}"); + } + } + + Ok(()) + } + + const ARBITRARY_CLIPPY_REQUEST: ClippyRequest = ClippyRequest { + channel: Channel::Stable, + crate_type: CrateType::Library(LibraryType::Rlib), + edition: Edition::Rust2021, + code: String::new(), + }; + + #[tokio::test] + #[snafu::report] + async fn clippy() -> Result<()> { + let coordinator = new_coordinator(); + + let req = ClippyRequest { + code: r#" + fn main() { + let a = 0.0 / 0.0; + println!("NaN is {}", a); + } + "# + .into(), + ..ARBITRARY_CLIPPY_REQUEST + }; + + let response = coordinator.clippy(req).with_timeout().await.unwrap(); + + assert!(!response.success, "stderr: {}", response.stderr); + assert_contains!(response.stderr, "deny(clippy::eq_op)"); + assert_contains!(response.stderr, "warn(clippy::zero_divided_by_zero)"); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn clippy_edition() -> Result<()> { + let cases = [( + "#![deny(clippy::single_element_loop)] + fn a() { for i in [1] { dbg!(i); } }", + [true, true, false, false], + )]; + + let tests = cases.into_iter().flat_map(|(code, expected_to_be_clean)| { + Edition::ALL.into_iter().zip(expected_to_be_clean).map( + move |(edition, expected_to_be_clean)| async move { + let coordinator = new_coordinator(); + + let req = + ClippyRequest { edition, code: code.into(), ..ARBITRARY_CLIPPY_REQUEST }; + + let response = coordinator.clippy(req).with_timeout().await.unwrap(); + + assert_eq!( + response.success, expected_to_be_clean, + "{code:?} in {edition:?}, {}", + response.stderr + ); + + coordinator.shutdown().await?; + + Ok::<_, Error>(()) + }, + ) + }); + + try_join_all(tests).with_timeout().await?; + + Ok(()) + } + + const ARBITRARY_MIRI_REQUEST: MiriRequest = MiriRequest { + channel: Channel::Nightly, + crate_type: CrateType::Binary, + edition: Edition::Rust2021, + tests: false, + aliasing_model: AliasingModel::Stacked, + code: String::new(), + }; + + #[tokio::test] + #[snafu::report] + async fn miri() -> Result<()> { + // We set the `MIRI_SYSROOT` variable to something that's only + // valid on Linux. + let coordinator = new_coordinator_docker(); + + let req = MiriRequest { + code: r#" + fn main() { + unsafe { core::mem::MaybeUninit::::uninit().assume_init() }; + } + "# + .into(), + ..ARBITRARY_MIRI_REQUEST + }; + + let response = coordinator.miri(req).with_timeout().await.unwrap(); + + assert!(!response.success, "stderr: {}", response.stderr); + + assert_contains!(response.stderr, "Undefined Behavior"); + assert_contains!(response.stderr, "memory is uninitialized"); + assert_contains!(response.stderr, "operation requires initialized memory"); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn miri_tests() -> Result<()> { + let coordinator = new_coordinator_docker(); + + let req = MiriRequest { + tests: true, + code: r#" + #[test] + fn oops() { + unsafe { core::mem::MaybeUninit::::uninit().assume_init() }; + } + "# + .into(), + ..ARBITRARY_MIRI_REQUEST + }; + + let response = coordinator.miri(req).with_timeout().await.unwrap(); + + assert!(!response.success, "stderr: {}", response.stderr); + + assert_contains!(response.stderr, "Undefined Behavior"); + assert_contains!(response.stderr, "memory is uninitialized"); + assert_contains!(response.stderr, "operation requires initialized memory"); + + coordinator.shutdown().await?; + + Ok(()) + } + + const ARBITRARY_MACRO_EXPANSION_REQUEST: MacroExpansionRequest = MacroExpansionRequest { + channel: Channel::Nightly, + crate_type: CrateType::Library(LibraryType::Cdylib), + edition: Edition::Rust2018, + code: String::new(), + }; + + #[tokio::test] + #[snafu::report] + async fn macro_expansion() -> Result<()> { + let coordinator = new_coordinator(); + + let req = MacroExpansionRequest { + code: r#" + #[derive(Debug)] + struct Dummy; + + fn main() { println!("Hello!"); } + "# + .into(), + ..ARBITRARY_MACRO_EXPANSION_REQUEST + }; + + let response = coordinator.macro_expansion(req).with_timeout().await.unwrap(); + + assert!(response.success, "stderr: {}", response.stderr); + assert_contains!(response.stdout, "impl ::core::fmt::Debug for Dummy"); + assert_contains!(response.stdout, "Formatter::write_str"); + + coordinator.shutdown().await?; + + Ok(()) + } + + // The next set of tests are broader than the functionality of a + // single operation. + + #[tokio::test] + #[snafu::report] + async fn compile_clears_old_main_rs() -> Result<()> { + let coordinator = new_coordinator(); + + // Create a main.rs file + let req = ExecuteRequest { + channel: Channel::Stable, + crate_type: CrateType::Binary, + mode: Mode::Debug, + edition: Edition::Rust2021, + tests: false, + backtrace: false, + code: "pub fn alpha() {}".into(), + execution_tool: ExecutionTool::Cargo, + }; + + let response = coordinator.execute(req.clone()).with_timeout().await.unwrap(); + assert!(!response.success, "stderr: {}", response.stderr); + assert_contains!(response.stderr, "`main` function not found"); + + // Create a lib.rs file + let req = CompileRequest { + target: CompileTarget::LlvmIr, + channel: req.channel, + mode: req.mode, + edition: req.edition, + crate_type: CrateType::Library(LibraryType::Rlib), + tests: req.tests, + backtrace: req.backtrace, + code: "pub fn beta() {}".into(), + }; + + let response = coordinator.compile(req.clone()).with_timeout().await.unwrap(); + assert!(response.success, "stderr: {}", response.stderr); + + assert_not_contains!(response.code, "alpha"); + assert_contains!(response.code, "beta"); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn still_usable_after_idle() -> Result<()> { + let mut coordinator = new_coordinator(); + + let req = ExecuteRequest { + channel: Channel::Stable, + mode: Mode::Debug, + edition: Edition::Rust2021, + crate_type: CrateType::Binary, + tests: false, + backtrace: false, + code: r#"fn main() { println!("hello") }"#.into(), + execution_tool: ExecutionTool::Cargo, + }; + + let res = coordinator.execute(req.clone()).await.unwrap(); + assert_eq!(res.stdout, "hello\n"); + + coordinator.idle().await.unwrap(); + + let res = coordinator.execute(req).await.unwrap(); + assert_eq!(res.stdout, "hello\n"); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn exit_due_to_signal_is_reported() -> Result<()> { + let coordinator = new_coordinator(); + let req = ExecuteRequest { + channel: Channel::Stable, + mode: Mode::Release, + edition: Edition::Rust2021, + crate_type: CrateType::Binary, + tests: false, + backtrace: false, + code: r#"fn main() { std::process::abort(); }"#.into(), + execution_tool: ExecutionTool::Cargo, + }; + + let res = coordinator.execute(req.clone()).await.unwrap(); + + assert!(!res.success); + assert_contains!(res.exit_detail, "abort"); + + coordinator.shutdown().await?; + + Ok(()) + } + + fn new_execution_limited_request() -> ExecuteRequest { + ExecuteRequest { + channel: Channel::Stable, + mode: Mode::Debug, + edition: Edition::Rust2021, + crate_type: CrateType::Binary, + tests: false, + backtrace: false, + code: Default::default(), + execution_tool: ExecutionTool::Cargo, + } + } + + #[tokio::test] + #[snafu::report] + async fn network_connections_are_disabled() -> Result<()> { + // The limits are only applied to the container + let coordinator = new_coordinator_docker(); + + let req = ExecuteRequest { + code: r#" + fn main() { + match ::std::net::TcpStream::connect("google.com:80") { + Ok(_) => println!("Able to connect to the outside world"), + Err(e) => println!("Failed to connect {}, {:?}", e, e), + } + } + "# + .into(), + ..new_execution_limited_request() + }; + + let res = coordinator.execute(req).with_timeout().await.unwrap(); + + assert_contains!(res.stdout, "Failed to connect"); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn memory_usage_is_limited() -> Result<()> { + // The limits are only applied to the container + let coordinator = new_coordinator_docker(); + + let req = ExecuteRequest { + code: r#" + fn main() { + let gigabyte = 1024 * 1024 * 1024; + let mut big = vec![0u8; 1 * gigabyte]; + for i in &mut big { *i += 1; } + } + "# + .into(), + ..new_execution_limited_request() + }; + + let res = coordinator.execute(req).with_timeout().await.unwrap(); + + assert!(!res.success); + // TODO: We need to actually inform the user about this somehow. The UI is blank. + // assert_contains!(res.stdout, "Killed"); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn number_of_pids_is_limited() -> Result<()> { + // The limits are only applied to the container + let coordinator = new_coordinator_docker(); + + let req = ExecuteRequest { + code: r##" + fn main() { + ::std::process::Command::new("sh").arg("-c").arg(r#" + z() { + z& + z + } + z + "#).status().unwrap(); + } + "## + .into(), + ..new_execution_limited_request() + }; + + let res = coordinator.execute(req).with_timeout().await.unwrap(); + + assert_contains!(res.stderr, "Cannot fork"); + + coordinator.shutdown().await?; + + Ok(()) + } + + #[tokio::test] + #[snafu::report] + async fn amount_of_output_is_limited() -> Result<()> { + // The limits are only applied to the container + let coordinator = new_coordinator_docker(); + + let req = ExecuteRequest { + code: r##" + use std::io::Write; + + fn main() { + let a = "a".repeat(1024); + let out = std::io::stdout(); + let mut out = out.lock(); + loop {//for _ in 0..1_000_000 { + let _ = out.write_all(a.as_bytes()); + let _ = out.write_all(b"\n"); + } + } + "## + .into(), + ..new_execution_limited_request() + }; + + let err = coordinator.execute(req).with_timeout().await.unwrap_err(); + let err = snafu::ChainCompat::new(&err).last().unwrap(); + assert_contains!(err.to_string(), "bytes of output, exiting"); + + coordinator.shutdown().await?; + + Ok(()) + } + + static TIMEOUT: LazyLock = LazyLock::new(|| { + let millis = env::var("TESTS_TIMEOUT_MS").ok().and_then(|v| v.parse().ok()).unwrap_or(5000); + Duration::from_millis(millis) + }); + + trait TimeoutExt: Future + Sized { + async fn with_timeout(self) -> Self::Output { + tokio::time::timeout(*TIMEOUT, self).await.expect("The operation timed out") + } + } + + impl TimeoutExt for F {} +} diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/coordinator/limits.rs b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/coordinator/limits.rs new file mode 100644 index 0000000000..ef57380c4e --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/coordinator/limits.rs @@ -0,0 +1,327 @@ +use futures::{future::BoxFuture, prelude::*}; +use std::{ + fmt, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, + }, +}; +use tokio::sync::{OwnedSemaphorePermit, Semaphore, TryAcquireError}; + +use super::{ContainerPermit, ProcessPermit, ResourceError, ResourceLimits, ResourceResult}; + +/// Describe how the resource was (or was not) acquired. +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum Acquisition { + /// The success path + Acquired, + /// The caller did not wait to acquire anything + Aborted, + /// Could not acquire + Error, +} + +impl Acquisition { + fn from_result(value: &Result) -> Self { + match value { + Ok(_) => Acquisition::Acquired, + Err(_) => Acquisition::Error, + } + } +} + +/// Hooks for monitoring how resources are requested and used. +pub trait Lifecycle: Send + Sync + fmt::Debug + Clone + 'static { + fn container_start(&self) {} + fn container_acquired(&self, #[allow(unused)] how: Acquisition) {} + fn container_release(&self) {} + + fn process_start(&self) {} + fn process_acquired(&self, #[allow(unused)] how: Acquisition) {} + fn process_release(&self) {} +} + +/// Does nothing for each event. +#[derive(Debug, Clone)] +pub struct NoOpLifecycle; + +impl Lifecycle for NoOpLifecycle {} + +/// Prints to stderr for each event. +#[derive(Debug, Clone)] +pub struct StderrLifecycle; + +impl Lifecycle for StderrLifecycle { + fn container_start(&self) { + eprintln!("container_start"); + } + + fn container_acquired(&self, how: Acquisition) { + eprintln!("container_acquired {how:?}"); + } + + fn container_release(&self) { + eprintln!("container_release"); + } + + fn process_start(&self) { + eprintln!("process_start"); + } + + fn process_acquired(&self, how: Acquisition) { + eprintln!("process_acquired {how:?}"); + } + + fn process_release(&self) { + eprintln!("process_release"); + } +} + +/// A reasonable choice when there's a single [`ResourceLimits`][] in +/// the entire process. +/// +/// This represents uniqueness via a combination of +/// +/// 1. **process start time** — this helps avoid conflicts from other +/// processes, assuming they were started at least one second +/// apart. +/// +/// 2. **instance counter** — this avoids conflicts from other +/// [`Coordinator`][super::Coordinator]s started inside this +/// process. +#[derive(Debug)] +pub struct Global { + lifecycle: L, + container_semaphore: Arc, + process_semaphore: Arc, + container_request_semaphore: Arc, + start: u64, + id: AtomicU64, +} + +/// Manages containers +#[derive(Debug)] +struct TrackContainer +where + L: Lifecycle, +{ + lifecycle: L, + #[allow(unused)] + container_permit: OwnedSemaphorePermit, + process_semaphore: Arc, + start: u64, + id: u64, +} + +/// Manages processess +#[derive(Debug)] +struct TrackProcess +where + L: Lifecycle, +{ + lifecycle: L, + #[allow(unused)] + process_permit: OwnedSemaphorePermit, +} + +impl Global { + pub fn new(container_limit: usize, process_limit: usize) -> Self { + Self::with_lifecycle(container_limit, process_limit, NoOpLifecycle) + } +} + +impl Global +where + L: Lifecycle, +{ + pub fn with_lifecycle(container_limit: usize, process_limit: usize, lifecycle: L) -> Self { + let container_semaphore = Arc::new(Semaphore::new(container_limit)); + let process_semaphore = Arc::new(Semaphore::new(process_limit)); + let container_request_semaphore = Arc::new(Semaphore::new(0)); + + let now = std::time::SystemTime::now(); + let start = now.duration_since(std::time::UNIX_EPOCH).unwrap_or_default().as_secs(); + + let id = AtomicU64::new(0); + + Self { + lifecycle, + container_semaphore, + process_semaphore, + container_request_semaphore, + start, + id, + } + } +} + +impl ResourceLimits for Global +where + L: Lifecycle, +{ + fn next_container(&self) -> BoxFuture<'static, ResourceResult>> { + let lifecycle = self.lifecycle.clone(); + let container_semaphore = self.container_semaphore.clone(); + let process_semaphore = self.process_semaphore.clone(); + let container_request_semaphore = self.container_request_semaphore.clone(); + let start = self.start; + let id = self.id.fetch_add(1, Ordering::SeqCst); + + async move { + let guard = ContainerAcquireGuard::start(&lifecycle); + + // Attempt to acquire the container semaphore. If we don't + // immediately get it, notify the container request + // semaphore. Any idle-but-not-yet-exited connections + // should watch that semaphore to see if they should give + // up thier container to allow someone else in. + // + // There *is* a race here: a container might naturally + // exit after we attempt to acquire the first time. In + // that case, we'd spuriously notify the request semaphore + // and a container might exit earlier than it needed + // to. However, this should be a transient issue and only + // occur when we are already at the upper bounds of our + // limits. In those cases, freeing an extra container or + // two shouldn't be the worst thing. + + let container_permit = match container_semaphore.clone().try_acquire_owned() { + Ok(permit) => Ok(permit), + Err(TryAcquireError::NoPermits) => { + container_request_semaphore.add_permits(1); + container_semaphore.acquire_owned().await.map_err(ResourceError::from) + } + Err(e) => Err(e.into()), + }; + + let container_permit = guard.complete(container_permit)?; + + let token = + TrackContainer { lifecycle, container_permit, process_semaphore, start, id }; + Ok(Box::new(token) as _) + } + .boxed() + } + + fn container_requested(&self) -> BoxFuture<'static, ()> { + let container_request_semaphore = self.container_request_semaphore.clone(); + + async move { + let permit = + container_request_semaphore.acquire().await.expect("The semaphore is never closed"); + + // We're now dealing with the request to return a + // container so we discard the permit to prevent anyone + // else from trying to handle it. + permit.forget(); + } + .boxed() + } +} + +impl fmt::Display for TrackContainer +where + L: Lifecycle, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { start, id, .. } = self; + write!(f, "{start}-{id}") + } +} + +impl ContainerPermit for TrackContainer +where + L: Lifecycle, +{ + fn next_process(&self) -> BoxFuture<'static, ResourceResult>> { + let lifecycle = self.lifecycle.clone(); + let process_semaphore = self.process_semaphore.clone(); + + async move { + let guard = ProcessAcquireGuard::start(&lifecycle); + + let process_permit = process_semaphore.acquire_owned().await; + let process_permit = guard.complete(process_permit)?; + + let token = TrackProcess { lifecycle, process_permit }; + Ok(Box::new(token) as _) + } + .boxed() + } +} + +impl Drop for TrackContainer +where + L: Lifecycle, +{ + fn drop(&mut self) { + self.lifecycle.container_release() + } +} + +impl ProcessPermit for TrackProcess where L: Lifecycle {} + +impl Drop for TrackProcess +where + L: Lifecycle, +{ + fn drop(&mut self) { + self.lifecycle.process_release() + } +} + +/// Lifecycle drop guard for containers +struct ContainerAcquireGuard<'a, L: Lifecycle>(&'a L, Acquisition); + +impl<'a, L> ContainerAcquireGuard<'a, L> +where + L: Lifecycle, +{ + fn start(lifecycle: &'a L) -> Self { + lifecycle.container_start(); + Self(lifecycle, Acquisition::Aborted) + } + + fn complete(mut self, r: Result) -> Result { + self.1 = Acquisition::from_result(&r); + r + } +} + +impl<'a, L> Drop for ContainerAcquireGuard<'a, L> +where + L: Lifecycle, +{ + fn drop(&mut self) { + self.0.container_acquired(self.1); + } +} + +/// Lifecycle drop guard for processes +struct ProcessAcquireGuard<'a, L>(&'a L, Acquisition) +where + L: Lifecycle; + +impl<'a, L> ProcessAcquireGuard<'a, L> +where + L: Lifecycle, +{ + fn start(lifecycle: &'a L) -> Self { + lifecycle.process_start(); + Self(lifecycle, Acquisition::Aborted) + } + + fn complete(mut self, r: Result) -> Result { + self.1 = Acquisition::from_result(&r); + r + } +} + +impl<'a, L> Drop for ProcessAcquireGuard<'a, L> +where + L: Lifecycle, +{ + fn drop(&mut self) { + self.0.process_acquired(self.1); + } +} diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/lib.rs b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/lib.rs new file mode 100644 index 0000000000..62a3746af8 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/lib.rs @@ -0,0 +1,35 @@ +#![deny(rust_2018_idioms)] + +pub mod coordinator; +mod message; +pub mod worker; + +pub trait TaskAbortExt: Sized { + fn abort_on_drop(self) -> tokio_util::task::AbortOnDropHandle; +} + +impl TaskAbortExt for tokio::task::JoinHandle { + fn abort_on_drop(self) -> tokio_util::task::AbortOnDropHandle { + tokio_util::task::AbortOnDropHandle::new(self) + } +} + +pub trait DropErrorDetailsExt { + fn drop_error_details(self) -> Result>; +} + +impl DropErrorDetailsExt for Result> { + fn drop_error_details(self) -> Result> { + self.map_err(|_| tokio::sync::mpsc::error::SendError(())) + } +} + +fn bincode_input_closed(coordinator_msg: &bincode::Result) -> bool { + if let Err(e) = coordinator_msg { + if let bincode::ErrorKind::Io(e) = &**e { + return e.kind() == std::io::ErrorKind::UnexpectedEof; + } + } + + false +} diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/message.rs b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/message.rs new file mode 100644 index 0000000000..7d7110b26d --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/message.rs @@ -0,0 +1,219 @@ +use serde::{Deserialize, Serialize}; +use std::{ + collections::{HashMap, VecDeque}, + fmt, +}; + +pub type JobId = u64; +pub type Path = String; + +macro_rules! impl_narrow_to_broad { + ($enum_type:ident, $($variant_name:ident => $variant_type:ident),* $(,)?) => { + $( + impl From<$variant_type> for $enum_type { + fn from(other: $variant_type) -> Self { + $enum_type::$variant_name(other) + } + } + )* + }; +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Multiplexed(pub JobId, pub T); + +#[derive(Debug, Serialize, Deserialize, strum_macros::AsRefStr)] +pub enum CoordinatorMessage { + WriteFile(WriteFileRequest), + DeleteFile(DeleteFileRequest), + ReadFile(ReadFileRequest), + ExecuteCommand(ExecuteCommandRequest), + StdinPacket(String), + StdinClose, + Kill, +} + +impl_narrow_to_broad!( + CoordinatorMessage, + WriteFile => WriteFileRequest, + DeleteFile => DeleteFileRequest, + ReadFile => ReadFileRequest, + ExecuteCommand => ExecuteCommandRequest, +); + +#[derive(Debug, Serialize, Deserialize, strum_macros::AsRefStr)] +pub enum WorkerMessage { + WriteFile(WriteFileResponse), + DeleteFile(DeleteFileResponse), + ReadFile(ReadFileResponse), + ExecuteCommand(ExecuteCommandResponse), + StdoutPacket(String), + StderrPacket(String), + CommandStatistics(CommandStatistics), + /// Vestigial; remove after a while + Error(SerializedError), + Error2(SerializedError2), +} + +macro_rules! impl_broad_to_narrow_with_error { + ($enum_type:ident, $($variant_name:ident => $variant_type:ty),* $(,)?) => { + $( + impl TryFrom<$enum_type> for Result<$variant_type, SerializedError2> { + type Error = $enum_type; + + fn try_from(other: $enum_type) -> Result { + match other { + $enum_type::$variant_name(x) => Ok(Ok(x)), + $enum_type::Error(e) => Ok(Err(SerializedError2::adapt(e))), + $enum_type::Error2(e) => Ok(Err(e)), + o => Err(o) + } + } + } + )* + }; +} + +impl_narrow_to_broad!( + WorkerMessage, + WriteFile => WriteFileResponse, + DeleteFile => DeleteFileResponse, + ReadFile => ReadFileResponse, + ExecuteCommand => ExecuteCommandResponse, + CommandStatistics => CommandStatistics, +); + +impl_broad_to_narrow_with_error!( + WorkerMessage, + WriteFile => WriteFileResponse, + DeleteFile => DeleteFileResponse, + ReadFile => ReadFileResponse, + ExecuteCommand => ExecuteCommandResponse, +); + +#[derive(Debug, Serialize, Deserialize)] +pub struct WriteFileRequest { + pub path: Path, + pub content: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct WriteFileResponse(pub ()); + +#[derive(Debug, Serialize, Deserialize)] +pub struct DeleteFileRequest { + pub path: Path, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct DeleteFileResponse(pub ()); + +#[derive(Debug, Serialize, Deserialize)] +pub struct ReadFileRequest { + pub path: Path, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ReadFileResponse(pub Vec); + +#[derive(Debug, Serialize, Deserialize)] +pub struct ExecuteCommandRequest { + pub cmd: String, + pub args: Vec, + pub envs: HashMap, + pub cwd: Option, // None means in project direcotry. +} + +impl ExecuteCommandRequest { + pub fn simple( + cmd: impl Into, + args: impl IntoIterator>, + ) -> Self { + Self { + cmd: cmd.into(), + args: args.into_iter().map(Into::into).collect(), + envs: Default::default(), + cwd: None, + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ExecuteCommandResponse { + pub success: bool, + pub exit_detail: String, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct CommandStatistics { + pub total_time_secs: f64, + pub resident_set_size_bytes: u64, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct SerializedError(pub String); + +impl SerializedError { + pub fn new(e: impl snafu::Error) -> Self { + Self(snafu::Report::from_error(e).to_string()) + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct SerializedError2 { + pub message: String, + pub source: Option>, +} + +impl SerializedError2 { + pub fn new(e: impl snafu::Error) -> Self { + let mut messages = snafu::CleanedErrorText::new(&e) + .map(|(_, t, _)| t) + .filter(|t| !t.is_empty()) + .collect::>(); + + let message = messages.pop_front().unwrap_or_else(|| "No error message".into()); + let source = messages + .into_iter() + .rev() + .fold(None, |source, message| Some(Box::new(Self { source, message }))); + + Self { message, source } + } + + pub fn adapt(other: SerializedError) -> Self { + Self { message: other.0, source: None } + } +} + +impl snafu::Error for SerializedError2 { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + self.source.as_ref().map(|x| &**x as &dyn snafu::Error) + } +} + +impl fmt::Display for SerializedError2 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.message.fmt(f) + } +} + +pub trait OneToOneResponse { + type Response; +} + +impl OneToOneResponse for WriteFileRequest { + type Response = WriteFileResponse; +} + +impl OneToOneResponse for DeleteFileRequest { + type Response = DeleteFileResponse; +} + +impl OneToOneResponse for ReadFileRequest { + type Response = ReadFileResponse; +} + +impl OneToOneResponse for ExecuteCommandRequest { + type Response = ExecuteCommandResponse; +} diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/worker.rs b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/worker.rs new file mode 100644 index 0000000000..c70df1a693 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/orchestrator/src/worker.rs @@ -0,0 +1,1264 @@ +//! # Task information +//! +//! ## Hierarchy +//! +//! ```text +//! listen +//! ├── stdin +//! ├── stdout +//! ├── handle_coordinator_message +//! │ └── background (N) +//! └── manage_processes +//! └── process (N) +//! ├── process stdin +//! ├── process stdout +//! └── process stderr +//! ``` +//! +//! ## Notable resources +//! +//! - stdin +//! - [`std::io::Stdin`][] +//! - stdout +//! - [`std::io::Stdout`][] +//! - process +//! - [`tokio::process::Child`][] +//! - process stdin +//! - [`tokio::process::ChildStdin`][] +//! - process stdout +//! - [`tokio::process::ChildStdout`][] +//! - process stderr +//! - [`tokio::process::ChildStderr`][] +//! + +use futures::FutureExt as _; +use snafu::prelude::*; +use std::{ + collections::HashMap, + io, + path::{Path, PathBuf}, + pin::pin, + process::{ExitStatus, Stdio}, +}; +use tokio::{ + fs, + io::{AsyncRead, AsyncReadExt, AsyncWriteExt}, + process::{Child, ChildStderr, ChildStdin, ChildStdout, Command}, + select, + sync::mpsc, + task::JoinSet, +}; +use tokio_util::sync::{CancellationToken, DropGuard}; + +use crate::{ + bincode_input_closed, + message::{ + CoordinatorMessage, DeleteFileRequest, DeleteFileResponse, ExecuteCommandRequest, + ExecuteCommandResponse, JobId, Multiplexed, ReadFileRequest, ReadFileResponse, + SerializedError2, WorkerMessage, WriteFileRequest, WriteFileResponse, + }, + DropErrorDetailsExt as _, TaskAbortExt as _, +}; + +pub async fn listen(project_dir: impl Into) -> Result<(), Error> { + let project_dir = project_dir.into(); + + let (coordinator_msg_tx, coordinator_msg_rx) = mpsc::channel(8); + let (worker_msg_tx, worker_msg_rx) = mpsc::channel(8); + let mut io_tasks = spawn_io_queue(coordinator_msg_tx, worker_msg_rx); + + let (process_tx, process_rx) = mpsc::channel(8); + let process_task = + tokio::spawn(manage_processes(process_rx, project_dir.clone())).abort_on_drop(); + + let handler_task = tokio::spawn(handle_coordinator_message( + coordinator_msg_rx, + worker_msg_tx, + project_dir, + process_tx, + )) + .abort_on_drop(); + + select! { + Some(io_task) = io_tasks.join_next() => { + io_task.context(IoTaskPanickedSnafu)?.context(IoTaskFailedSnafu)?; + } + + process_task = process_task => { + process_task.context(ProcessTaskPanickedSnafu)?.context(ProcessTaskFailedSnafu)?; + } + + handler_task = handler_task => { + handler_task.context(HandlerTaskPanickedSnafu)?.context(HandlerTaskFailedSnafu)?; + } + } + + Ok(()) +} + +#[derive(Debug, Snafu)] +pub enum Error { + #[snafu(display("The IO queue task panicked"))] + IoTaskPanicked { source: tokio::task::JoinError }, + + #[snafu(display("The IO queue task failed"))] + IoTaskFailed { source: IoQueueError }, + + #[snafu(display("The process task panicked"))] + ProcessTaskPanicked { source: tokio::task::JoinError }, + + #[snafu(display("The process task failed"))] + ProcessTaskFailed { source: ProcessError }, + + #[snafu(display("The coordinator message handler task panicked"))] + HandlerTaskPanicked { source: tokio::task::JoinError }, + + #[snafu(display("The coordinator message handler task failed"))] + HandlerTaskFailed { source: HandleCoordinatorMessageError }, +} + +async fn handle_coordinator_message( + mut coordinator_msg_rx: mpsc::Receiver>, + worker_msg_tx: mpsc::Sender>, + project_dir: PathBuf, + process_tx: mpsc::Sender>, +) -> Result<(), HandleCoordinatorMessageError> { + use handle_coordinator_message_error::*; + + let mut tasks = JoinSet::new(); + + loop { + select! { + coordinator_msg = coordinator_msg_rx.recv() => { + let Some(Multiplexed(job_id, coordinator_msg)) = coordinator_msg else { break }; + + let worker_msg_tx = || MultiplexingSender { + job_id, + tx: worker_msg_tx.clone(), + }; + + match coordinator_msg { + CoordinatorMessage::WriteFile(req) => { + let project_dir = project_dir.clone(); + let worker_msg_tx = worker_msg_tx(); + + tasks.spawn(async move { + worker_msg_tx + .send(handle_write_file(req, project_dir).await) + .await + .context(UnableToSendWriteFileResponseSnafu) + }); + } + + CoordinatorMessage::DeleteFile(req) => { + let project_dir = project_dir.clone(); + let worker_msg_tx = worker_msg_tx(); + + tasks.spawn(async move { + worker_msg_tx + .send(handle_delete_file(req, project_dir).await) + .await + .context(UnableToSendDeleteFileResponseSnafu) + }); + } + + CoordinatorMessage::ReadFile(req) => { + let project_dir = project_dir.clone(); + let worker_msg_tx = worker_msg_tx(); + + tasks.spawn(async move { + worker_msg_tx + .send(handle_read_file(req, project_dir).await) + .await + .context(UnableToSendReadFileResponseSnafu) + }); + } + + CoordinatorMessage::ExecuteCommand(req) => { + process_tx + .send(Multiplexed(job_id, ProcessCommand::Start(req, worker_msg_tx()))) + .await + .drop_error_details() + .context(UnableToSendCommandExecutionRequestSnafu)?; + } + + CoordinatorMessage::StdinPacket(data) => { + process_tx + .send(Multiplexed(job_id, ProcessCommand::Stdin(data))) + .await + .drop_error_details() + .context(UnableToSendStdinPacketSnafu)?; + } + + CoordinatorMessage::StdinClose => { + process_tx + .send(Multiplexed(job_id, ProcessCommand::StdinClose)) + .await + .drop_error_details() + .context(UnableToSendStdinCloseSnafu)?; + } + + CoordinatorMessage::Kill => { + process_tx + .send(Multiplexed(job_id, ProcessCommand::Kill)) + .await + .drop_error_details() + .context(UnableToSendKillSnafu)?; + } + } + } + + Some(task) = tasks.join_next() => { + task.context(TaskPanickedSnafu)??; + } + } + } + + Ok(()) +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum HandleCoordinatorMessageError { + #[snafu(display("Could not send the write command response to the coordinator"))] + UnableToSendWriteFileResponse { source: MultiplexingSenderError }, + + #[snafu(display("Could not send the delete command response to the coordinator"))] + UnableToSendDeleteFileResponse { source: MultiplexingSenderError }, + + #[snafu(display("Could not send the read command response to the coordinator"))] + UnableToSendReadFileResponse { source: MultiplexingSenderError }, + + #[snafu(display("Failed to send command execution request to the command task"))] + UnableToSendCommandExecutionRequest { source: mpsc::error::SendError<()> }, + + #[snafu(display("Failed to send stdin packet to the command task"))] + UnableToSendStdinPacket { source: mpsc::error::SendError<()> }, + + #[snafu(display("Failed to send stdin close request to the command task"))] + UnableToSendStdinClose { source: mpsc::error::SendError<()> }, + + #[snafu(display("Failed to send kill request to the command task"))] + UnableToSendKill { source: mpsc::error::SendError<()> }, + + #[snafu(display("A coordinator command handler background task panicked"))] + TaskPanicked { source: tokio::task::JoinError }, +} + +#[derive(Debug, Clone)] +struct MultiplexingSender { + job_id: JobId, + tx: mpsc::Sender>, +} + +impl MultiplexingSender { + async fn send( + &self, + message: Result, impl std::error::Error>, + ) -> Result<(), MultiplexingSenderError> { + match message { + Ok(v) => self.send_ok(v).await, + Err(e) => self.send_err(e).await, + } + } + + async fn send_ok( + &self, + message: impl Into, + ) -> Result<(), MultiplexingSenderError> { + self.send_raw(message.into()).await + } + + async fn send_err(&self, e: impl std::error::Error) -> Result<(), MultiplexingSenderError> { + self.send_raw(WorkerMessage::Error2(SerializedError2::new(e))).await + } + + async fn send_raw(&self, message: WorkerMessage) -> Result<(), MultiplexingSenderError> { + use multiplexing_sender_error::*; + + self.tx + .send(Multiplexed(self.job_id, message)) + .await + .drop_error_details() + .context(UnableToSendWorkerMessageSnafu) + } +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum MultiplexingSenderError { + #[snafu(display("Failed to send worker message to the serialization task"))] + UnableToSendWorkerMessage { source: mpsc::error::SendError<()> }, +} + +async fn handle_write_file( + req: WriteFileRequest, + project_dir: PathBuf, +) -> Result { + use write_file_error::*; + + let path = parse_working_dir(Some(req.path), project_dir); + + // Create intermediate directories. + if let Some(parent_dir) = path.parent() { + fs::create_dir_all(parent_dir).await.context(UnableToCreateDirSnafu { parent_dir })?; + } + + fs::write(&path, req.content).await.context(UnableToWriteFileSnafu { path })?; + + Ok(WriteFileResponse(())) +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum WriteFileError { + #[snafu(display("Failed to create parent directory {}", parent_dir.display()))] + UnableToCreateDir { source: std::io::Error, parent_dir: PathBuf }, + + #[snafu(display("Failed to write file {}", path.display()))] + UnableToWriteFile { source: std::io::Error, path: PathBuf }, +} + +async fn handle_delete_file( + req: DeleteFileRequest, + project_dir: PathBuf, +) -> Result { + use delete_file_error::*; + + let path = parse_working_dir(Some(req.path), project_dir); + + let r = match fs::remove_file(&path).await { + Ok(()) => Ok(()), + Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(()), + Err(e) => Err(e), + }; + + r.context(UnableToDeleteFileSnafu { path })?; + Ok(DeleteFileResponse(())) +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum DeleteFileError { + #[snafu(display("Failed to delete file {}", path.display()))] + UnableToDeleteFile { source: std::io::Error, path: PathBuf }, +} + +async fn handle_read_file( + req: ReadFileRequest, + project_dir: PathBuf, +) -> Result { + use read_file_error::*; + + let path = parse_working_dir(Some(req.path), project_dir); + + let content = fs::read(&path).await.context(UnableToReadFileSnafu { path })?; + + Ok(ReadFileResponse(content)) +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum ReadFileError { + #[snafu(display("Failed to read file {}", path.display()))] + UnableToReadFile { source: std::io::Error, path: PathBuf }, +} + +// Current working directory defaults to project dir unless specified otherwise. +fn parse_working_dir(cwd: Option, project_path: impl Into) -> PathBuf { + let mut final_path = project_path.into(); + if let Some(path) = cwd { + // Absolute path will replace final_path. + final_path.push(path) + } + final_path +} + +enum ProcessCommand { + Start(ExecuteCommandRequest, MultiplexingSender), + Stdin(String), + StdinClose, + Kill, +} + +struct ProcessState { + project_path: PathBuf, + processes: JoinSet>, + stdin_senders: HashMap>, + stdin_shutdown_tx: mpsc::Sender, + kill_tokens: HashMap, +} + +impl ProcessState { + fn new(project_path: PathBuf, stdin_shutdown_tx: mpsc::Sender) -> Self { + Self { + project_path, + processes: Default::default(), + stdin_senders: Default::default(), + stdin_shutdown_tx, + kill_tokens: Default::default(), + } + } + + async fn start( + &mut self, + job_id: JobId, + req: ExecuteCommandRequest, + worker_msg_tx: MultiplexingSender, + ) -> Result<(), ProcessError> { + use process_error::*; + + let token = CancellationToken::new(); + + let RunningChild { child, stdin_rx, stdin, stdout, stderr } = + match process_begin(req, &self.project_path, &mut self.stdin_senders, job_id) { + Ok(v) => v, + Err(e) => { + // Should we add a message for process started + // in addition to the current message which + // indicates that the process has ended? + worker_msg_tx + .send_err(e) + .await + .context(UnableToSendExecuteCommandStartedResponseSnafu)?; + return Ok(()); + } + }; + + let statistics_task = tokio::task::spawn_blocking({ + let child_id = child.id(); + let worker_msg_tx = worker_msg_tx.clone(); + let handle = tokio::runtime::Handle::current(); + move || stream_command_statistics(child_id, worker_msg_tx, handle) + }); + + let task_set = stream_stdio(worker_msg_tx.clone(), stdin_rx, stdin, stdout, stderr); + + self.kill_tokens.insert(job_id, token.clone().drop_guard()); + + self.processes.spawn({ + let stdin_shutdown_tx = self.stdin_shutdown_tx.clone(); + async move { + let message = + process_end(token, child, task_set, statistics_task, stdin_shutdown_tx, job_id) + .await; + + worker_msg_tx.send(message).await.context(UnableToSendExecuteCommandResponseSnafu) + } + }); + + Ok(()) + } + + async fn stdin(&mut self, job_id: JobId, packet: String) -> Result<(), ProcessError> { + use process_error::*; + + if let Some(stdin_tx) = self.stdin_senders.get(&job_id) { + stdin_tx.send(packet).await.drop_error_details().context(UnableToSendStdinDataSnafu)?; + } + + Ok(()) + } + + fn stdin_close(&mut self, job_id: JobId) { + self.stdin_senders.remove(&job_id); + // Should we care if we remove a sender that's already removed? + } + + async fn join_process(&mut self) -> Option> { + use process_error::*; + + let process = self.processes.join_next().await?; + Some(process.context(ProcessTaskPanickedSnafu).and_then(|e| e)) + } + + fn kill(&mut self, job_id: JobId) { + if let Some(token) = self.kill_tokens.remove(&job_id) { + drop(token); + } + } +} + +async fn manage_processes( + mut rx: mpsc::Receiver>, + project_path: PathBuf, +) -> Result<(), ProcessError> { + use process_error::*; + + let (stdin_shutdown_tx, mut stdin_shutdown_rx) = mpsc::channel(8); + let mut state = ProcessState::new(project_path, stdin_shutdown_tx); + + loop { + select! { + cmd = rx.recv() => { + let Some(Multiplexed(job_id, cmd)) = cmd else { break }; + + match cmd { + ProcessCommand::Start(req, worker_msg_tx) => state.start(job_id, req, worker_msg_tx).await?, + + ProcessCommand::Stdin(packet) => state.stdin(job_id, packet).await?, + + ProcessCommand::StdinClose => state.stdin_close(job_id), + + ProcessCommand::Kill => state.kill(job_id), + } + } + + job_id = stdin_shutdown_rx.recv() => { + let job_id = job_id.context(StdinShutdownReceiverEndedSnafu)?; + state.stdin_close(job_id); + } + + Some(process) = state.join_process() => { + process?; + } + } + } + + Ok(()) +} + +struct RunningChild { + child: Child, + stdin_rx: mpsc::Receiver, + stdin: ChildStdin, + stdout: ChildStdout, + stderr: ChildStderr, +} + +fn process_begin( + req: ExecuteCommandRequest, + project_path: &Path, + stdin_senders: &mut HashMap>, + job_id: JobId, +) -> Result { + use process_error::*; + + let ExecuteCommandRequest { cmd, args, envs, cwd } = req; + let mut child = Command::new(&cmd) + .args(args) + .envs(envs) + .current_dir(parse_working_dir(cwd, project_path)) + .kill_on_drop(true) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .context(UnableToSpawnProcessSnafu { cmd })?; + + let stdin = child.stdin.take().context(UnableToCaptureStdinSnafu)?; + let stdout = child.stdout.take().context(UnableToCaptureStdoutSnafu)?; + let stderr = child.stderr.take().context(UnableToCaptureStderrSnafu)?; + + // Preparing for receiving stdin packet. + let (stdin_tx, stdin_rx) = mpsc::channel(8); + stdin_senders.insert(job_id, stdin_tx); + + Ok(RunningChild { child, stdin_rx, stdin, stdout, stderr }) +} + +async fn process_end( + token: CancellationToken, + mut child: Child, + mut task_set: JoinSet>, + statistics_task: tokio::task::JoinHandle>, + stdin_shutdown_tx: mpsc::Sender, + job_id: JobId, +) -> Result { + use process_error::*; + + let mut cancelled = pin!(token.cancelled().fuse()); + + let status = loop { + select! { + // The user requested that the process be killed + () = &mut cancelled => { + child.kill().await.context(KillChildSnafu)?; + }, + + // The process exited normally + status = child.wait() => break status, + + // One of our tasks exited unexpectedly + // TODO: dedupe errors or fully split them + Some(task) = task_set.join_next() => { + task.context(StdioTaskPanickedSnafu)? + .context(StdioTaskFailedSnafu)?; + }, + }; + }; + + let status = status.context(WaitChildSnafu)?; + + stdin_shutdown_tx + .send(job_id) + .await + .drop_error_details() + .context(UnableToSendStdinShutdownSnafu)?; + + // Check any remaining tasks to see if they had an error + while let Some(task) = task_set.join_next().await { + task.context(StdioTaskPanickedSnafu)?.context(StdioTaskFailedSnafu)?; + } + + // TODO: check this for death earlier? + statistics_task + .await + .context(StatisticsTaskPanickedSnafu)? + .context(StatisticsTaskFailedSnafu)?; + + let success = status.success(); + let exit_detail = extract_exit_detail(status); + + Ok(ExecuteCommandResponse { success, exit_detail }) +} + +mod signals { + mod descriptions { + #![allow(dead_code)] + + pub const SIGABRT: &str = "abort program"; + pub const SIGALRM: &str = "real-time timer expired"; + pub const SIGBUS: &str = "bus error"; + pub const SIGEMT: &str = "emulate instruction executed"; + pub const SIGFPE: &str = "floating-point exception"; + pub const SIGHUP: &str = "terminal line hangup"; + pub const SIGILL: &str = "illegal instruction"; + pub const SIGINT: &str = "interrupt program"; + pub const SIGKILL: &str = "kill program"; + pub const SIGPIPE: &str = "write on a pipe with no reader"; + pub const SIGQUIT: &str = "quit program"; + pub const SIGSEGV: &str = "segmentation violation"; + pub const SIGSYS: &str = "non-existent system call invoked"; + pub const SIGTERM: &str = "software termination signal"; + pub const SIGTRAP: &str = "trace trap"; + pub const SIGUSR1: &str = "user-defined signal 1"; + pub const SIGUSR2: &str = "user-defined signal 2"; + } + + type Pair = (&'static str, &'static str); + + macro_rules! sigtable { + [$($name:ident,)*] => { + [ + $((stringify!($name), descriptions::$name),)* + ] + }; + } + + #[cfg(target_os = "macos")] + const SIGNALS: [Pair; 15] = sigtable![ + SIGHUP, // 1 + SIGINT, // 2 + SIGQUIT, // 3 + SIGILL, // 4 + SIGTRAP, // 5 + SIGABRT, // 6 + SIGEMT, // 7 + SIGFPE, // 8 + SIGKILL, // 9 + SIGBUS, // 10 + SIGSEGV, // 11 + SIGSYS, // 12 + SIGPIPE, // 13 + SIGALRM, // 14 + SIGTERM, // 15 + ]; + + #[cfg(target_os = "linux")] + const SIGNALS: [Pair; 15] = sigtable![ + SIGHUP, // 1 + SIGINT, // 2 + SIGQUIT, // 3 + SIGILL, // 4 + SIGTRAP, // 5 + SIGABRT, // 6 + SIGBUS, // 7 + SIGFPE, // 8 + SIGKILL, // 9 + SIGUSR1, // 10 + SIGSEGV, // 11 + SIGUSR2, // 12 + SIGPIPE, // 13 + SIGALRM, // 14 + SIGTERM, // 15 + ]; + + const SIG_UNKNOWN: Pair = ("???", "Unknown signal"); + + pub fn get(signal: i32) -> Pair { + let details = (|| { + let signal = usize::try_from(signal).ok()?; + let signal = signal.checked_sub(1)?; + SIGNALS.get(signal).copied() + })(); + + details.unwrap_or(SIG_UNKNOWN) + } +} + +fn extract_exit_detail(status: ExitStatus) -> String { + use std::os::unix::process::ExitStatusExt; + + if let Some(code) = status.code() { + return format!("Exited with status {code}"); + } + + if let Some(signal) = status.signal() { + let (name, description) = signals::get(signal); + return format!("Exited with signal {signal} ({name}): {description}"); + } + + String::new() +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum ProcessError { + #[snafu(display("Failed to spawn child process {cmd}"))] + UnableToSpawnProcess { source: std::io::Error, cmd: String }, + + #[snafu(display("Failed to capture child process stdin"))] + UnableToCaptureStdin, + + #[snafu(display("Failed to capture child process stdout"))] + UnableToCaptureStdout, + + #[snafu(display("Failed to capture child process stderr"))] + UnableToCaptureStderr, + + #[snafu(display("Failed to send stdin data"))] + UnableToSendStdinData { source: mpsc::error::SendError<()> }, + + #[snafu(display("Failed to kill the child process"))] + KillChild { source: std::io::Error }, + + #[snafu(display("Failed to wait for child process exiting"))] + WaitChild { source: std::io::Error }, + + #[snafu(display("Failed to send the stdin shutdown request"))] + UnableToSendStdinShutdown { source: mpsc::error::SendError<()> }, + + #[snafu(display("The command's stdio task panicked"))] + StdioTaskPanicked { source: tokio::task::JoinError }, + + #[snafu(display("The command's stdio task failed"))] + StdioTaskFailed { source: StdioError }, + + #[snafu(display("The command's statistics task panicked"))] + StatisticsTaskPanicked { source: tokio::task::JoinError }, + + #[snafu(display("The command's statistics task failed"))] + StatisticsTaskFailed { source: CommandStatisticsError }, + + #[snafu(display("Failed to send the command started response to the coordinator"))] + UnableToSendExecuteCommandStartedResponse { source: MultiplexingSenderError }, + + #[snafu(display("Failed to send the command completed response to the coordinator"))] + UnableToSendExecuteCommandResponse { source: MultiplexingSenderError }, + + #[snafu(display("The stdin shutdown receiver ended prematurely"))] + StdinShutdownReceiverEnded, + + #[snafu(display("The process task panicked"))] + ProcessTaskPanicked { source: tokio::task::JoinError }, +} + +#[cfg(target_os = "macos")] +mod stats { + use mach2::mach_time::{mach_timebase_info, mach_timebase_info_data_t}; + use snafu::prelude::*; + use std::mem::MaybeUninit; + + use crate::message::CommandStatistics; + + pub struct Process { + pid: i32, + timebase: mach_timebase_info_data_t, + } + + impl Process { + pub fn new(pid: i32) -> Result { + let timebase = timebase()?; + Ok(Self { pid, timebase }) + } + + pub fn stats(&self) -> Option { + let usage = proc_pid_rusage(self.pid).ok()?; + + let total_time_secs = self.ticks_to_seconds(usage.ri_user_time + usage.ri_system_time); + let resident_set_size_bytes = usage.ri_resident_size; + + Some(CommandStatistics { total_time_secs, resident_set_size_bytes }) + } + + fn ticks_to_seconds(&self, v: u64) -> f64 { + let nanos = v as f64 / self.timebase.denom as f64 * self.timebase.numer as f64; + nanos / 1_000_000_000.0 + } + } + + fn timebase() -> Result { + let mut timebase = Default::default(); + + // SAFETY: We've initialized the data structure + let retval = unsafe { mach_timebase_info(&mut timebase) }; + + if retval != mach2::kern_return::KERN_SUCCESS { + Snafu.fail() + } else { + Ok(timebase) + } + } + + fn proc_pid_rusage(pid: i32) -> std::io::Result { + // SAFETY: We only access the usage information after checking + // the function call succeeded. + unsafe { + let mut ri = MaybeUninit::::uninit(); + + let retval = libc::proc_pid_rusage(pid, libc::RUSAGE_INFO_V4, ri.as_mut_ptr().cast()); + + if retval == 0 { + Ok(ri.assume_init()) + } else { + Err(std::io::Error::last_os_error()) + } + } + } + + #[derive(Debug, Snafu)] + #[snafu(display("Unable to get the timebase conversion"))] + pub struct Error; +} + +#[cfg(target_os = "linux")] +mod stats { + use procfs::process::Process as ProcfsProcess; + use snafu::prelude::*; + + use crate::message::CommandStatistics; + + pub struct Process { + process: ProcfsProcess, + ticks_per_second: u64, + page_size: u64, + } + + impl Process { + pub fn new(pid: i32) -> Result { + let process = ProcfsProcess::new(pid).context(Snafu)?; + + let ticks_per_second = procfs::ticks_per_second(); + let page_size = procfs::page_size(); + + Ok(Self { process, ticks_per_second, page_size }) + } + + pub fn stats(&self) -> Option { + let stat = self.process.stat().ok()?; + + let total_time_secs = self.ticks_to_seconds(stat.utime + stat.stime); + let resident_set_size_bytes = self.pages_to_bytes(stat.rss); + + Some(CommandStatistics { total_time_secs, resident_set_size_bytes }) + } + + fn ticks_to_seconds(&self, v: u64) -> f64 { + v as f64 / self.ticks_per_second as f64 + } + + fn pages_to_bytes(&self, v: u64) -> u64 { + v * self.page_size + } + } + + #[derive(Debug, Snafu)] + #[snafu(display("Could not get information for the process"))] + pub struct Error { + source: procfs::ProcError, + } +} + +fn stream_command_statistics( + child_id: Option, + worker_msg_tx: MultiplexingSender, + handle: tokio::runtime::Handle, +) -> Result<(), CommandStatisticsError> { + use command_statistics_error::*; + use stats::*; + use std::time::Duration; + + const STATISTIC_INTERVAL: Duration = Duration::from_secs(1); + + let process_id = child_id.context(ChildIdMissingSnafu)?; + + let process_id = process_id.try_into().context(ProcessIdOutOfRangeSnafu { process_id })?; + + let process = Process::new(process_id).context(InvalidProcessSnafu { process_id })?; + + while let Some(stats) = process.stats() { + let sent = handle.block_on(worker_msg_tx.send_ok(stats)); + if sent.is_err() { + // No one listening anymore + break; + } + + std::thread::sleep(STATISTIC_INTERVAL); + } + + Ok(()) +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum CommandStatisticsError { + #[snafu(display("The child did not have a process ID"))] + ChildIdMissing, + + #[snafu(display("The process ID {process_id} could not be converted"))] + ProcessIdOutOfRange { source: std::num::TryFromIntError, process_id: u32 }, + + #[snafu(display("The process ID {process_id} is not valid"))] + InvalidProcess { source: stats::Error, process_id: i32 }, +} + +fn stream_stdio( + coordinator_tx: MultiplexingSender, + mut stdin_rx: mpsc::Receiver, + mut stdin: ChildStdin, + stdout: ChildStdout, + stderr: ChildStderr, +) -> JoinSet> { + use stdio_error::*; + + let mut set = JoinSet::new(); + + set.spawn(async move { + while let Some(data) = stdin_rx.recv().await { + stdin.write_all(data.as_bytes()).await.context(UnableToWriteStdinSnafu)?; + stdin.flush().await.context(UnableToFlushStdinSnafu)?; + } + + Ok(()) + }); + + set.spawn({ + copy_child_output(stdout, coordinator_tx.clone(), WorkerMessage::StdoutPacket) + .context(CopyStdoutSnafu) + }); + + set.spawn({ + copy_child_output(stderr, coordinator_tx, WorkerMessage::StderrPacket) + .context(CopyStderrSnafu) + }); + + set +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum StdioError { + #[snafu(display("Failed to write stdin data"))] + UnableToWriteStdin { source: std::io::Error }, + + #[snafu(display("Failed to flush stdin data"))] + UnableToFlushStdin { source: std::io::Error }, + + #[snafu(display("Failed to copy child stdout"))] + CopyStdout { source: CopyChildOutputError }, + + #[snafu(display("Failed to copy child stderr"))] + CopyStderr { source: CopyChildOutputError }, +} + +struct Utf8BufReader { + reader: R, + buffer: Box<[u8]>, + n_incomplete: usize, +} + +impl Utf8BufReader +where + R: AsyncRead + Unpin, +{ + const DEFAULT_CAPACITY: usize = 32 * 1024; + + fn new(reader: R) -> Self { + Self { reader, buffer: vec![0; Self::DEFAULT_CAPACITY].into(), n_incomplete: 0 } + } + + async fn next(&mut self) -> Result, Utf8BufReaderError> { + use std::str; + use utf8_buf_reader_error::*; + + loop { + let after_incomplete_bytes = &mut self.buffer[self.n_incomplete..]; + let n_read = self.reader.read(after_incomplete_bytes).await.context(ReaderSnafu)?; + let n_valid = self.n_incomplete + n_read; + + if n_read == 0 && self.n_incomplete == 0 { + return Ok(None); + } + + let valid_utf_8_bytes = match str::from_utf8(&self.buffer[..n_valid]) { + Ok(s) => s.len(), + Err(e) => e.valid_up_to(), + }; + + // We can't parse any UTF-8 + if valid_utf_8_bytes == 0 { + // This should be enough bytes to get one UTF-8 character. + ensure!(n_valid < 4, InvalidUtf8Snafu); + + // We aren't going to get any more input + ensure!(n_read != 0, RanOutOfInputSnafu); + } + + // Safety: We just calculated the number of valid UTF-8 bytes + // and the buffer hasn't changed since then. + let s = unsafe { + let utf8_bytes = self.buffer.get_unchecked(..valid_utf_8_bytes); + str::from_utf8_unchecked(utf8_bytes) + }; + let s = s.to_owned(); + + // Move any trailing incomplete bytes + self.buffer.copy_within(valid_utf_8_bytes..n_valid, 0); + + self.n_incomplete = n_valid - valid_utf_8_bytes; + + if !s.is_empty() { + return Ok(Some(s)); + } + } + } +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum Utf8BufReaderError { + Reader { + source: std::io::Error, + }, + + #[snafu(display("Insufficient data to complete a UTF-8 character"))] + RanOutOfInput, + + #[snafu(display("Found non-UTF-8 data"))] + InvalidUtf8, +} + +#[cfg(test)] +mod test { + use std::{ + assert_matches, + collections::VecDeque, + pin::Pin, + task::{Context, Poll}, + }; + + use super::*; + + struct FixedAsyncRead(VecDeque>>); + + impl FixedAsyncRead { + fn is_empty(&self) -> bool { + self.0.is_empty() + } + + fn success_exact(i: impl IntoIterator>>) -> Self { + Self(i.into_iter().map(Into::into).chain(Some(vec![])).map(Ok).collect()) + } + } + + impl AsyncRead for FixedAsyncRead { + fn poll_read( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + buf: &mut tokio::io::ReadBuf<'_>, + ) -> Poll> { + let this = Pin::get_mut(self); + let next_result = this.0.pop_front().expect("FixedAsyncRead ran out of input"); + + if let Ok(v) = &next_result { + buf.put_slice(v); + } + + Poll::Ready(next_result.map(drop)) + } + } + + #[tokio::test] + async fn small_reads() { + let bytes: [u8; 4] = "🙂".as_bytes().try_into().unwrap(); + + let reader = FixedAsyncRead::success_exact(bytes.map(|b| [b])); + let mut buffer = Utf8BufReader::new(reader); + + assert_eq!(buffer.next().await.unwrap().as_deref(), Some("🙂")); + assert_eq!(buffer.next().await.unwrap().as_deref(), None); + assert!(buffer.reader.is_empty()); + } + + #[tokio::test] + async fn incomplete_utf8() { + let bytes: [u8; 4] = "🙂".as_bytes().try_into().unwrap(); + + let partial_string = &bytes[..3]; + let reader = FixedAsyncRead::success_exact([partial_string]); + let mut buffer = Utf8BufReader::new(reader); + + assert_matches!(buffer.next().await, Err(Utf8BufReaderError::RanOutOfInput)); + assert!(buffer.reader.is_empty()); + } + + #[tokio::test] + async fn invalid_utf8() { + let mut bytes: [u8; 4] = "🙂".as_bytes().try_into().unwrap(); + bytes[0] = 0xFF; + + let reader = FixedAsyncRead::success_exact([bytes]); + let mut buffer = Utf8BufReader::new(reader); + + assert_matches!(buffer.next().await, Err(Utf8BufReaderError::InvalidUtf8)); + assert!(!buffer.reader.is_empty()); + } + + #[tokio::test] + async fn valid_followed_by_invalid_utf8() { + let bytes = [b'A', 0xc3, 0x28, 0xc3, 0x28, 0xc3, 0x28]; + + let reader = FixedAsyncRead::success_exact([bytes]); + let mut buffer = Utf8BufReader::new(reader); + + assert_matches!(buffer.next().await, Ok(Some(s)) if s == "A"); + assert_matches!(buffer.next().await, Err(Utf8BufReaderError::InvalidUtf8)); + assert!(buffer.reader.is_empty()); + } + + #[tokio::test] + async fn split_across_responses() { + let bytes: [u8; 12] = "🙂🙂🙂".as_bytes().try_into().unwrap(); + + let (head, tail) = bytes.split_at(6); + let reader = FixedAsyncRead::success_exact([head, tail]); + let mut buffer = Utf8BufReader::new(reader); + + assert_eq!(buffer.next().await.unwrap().as_deref(), Some("🙂")); + assert_eq!(buffer.next().await.unwrap().as_deref(), Some("🙂🙂")); + assert_eq!(buffer.next().await.unwrap().as_deref(), None); + assert!(buffer.reader.is_empty()); + } +} + +const OUTPUT_BYTE_LIMIT: usize = 640 * 1024; + +async fn copy_child_output( + output: impl AsyncRead + Unpin, + coordinator_tx: MultiplexingSender, + mut xform: impl FnMut(String) -> WorkerMessage, +) -> Result<(), CopyChildOutputError> { + use copy_child_output_error::*; + + let mut buf = Utf8BufReader::new(output); + let mut n_total_bytes: usize = 0; + + while let Some(buffer) = buf.next().await.context(UnableToReadSnafu)? { + let n_bytes = buffer.len(); + + coordinator_tx.send_ok(xform(buffer)).await.context(UnableToSendSnafu)?; + + n_total_bytes = n_total_bytes.saturating_add(n_bytes); + ensure!(n_total_bytes <= OUTPUT_BYTE_LIMIT, TooManyBytesSnafu { n_total_bytes }); + } + + Ok(()) +} + +const BYTE_LIMIT_URL: &str = "https://github.com/rust-lang/rust-playground/discussions/1027"; + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum CopyChildOutputError { + #[snafu(display("Failed to read child output"))] + UnableToRead { source: Utf8BufReaderError }, + + #[snafu(display("Failed to send output packet"))] + UnableToSend { source: MultiplexingSenderError }, + + #[snafu(display( + "Generated {n_total_bytes} bytes of output, exiting (640K ought to be enough for anybody). If this was not an accident, tell us more at {BYTE_LIMIT_URL}" + ))] + TooManyBytes { n_total_bytes: usize }, +} + +// stdin/out <--> messages. +fn spawn_io_queue( + coordinator_msg_tx: mpsc::Sender>, + mut worker_msg_rx: mpsc::Receiver>, +) -> JoinSet> { + use io_queue_error::*; + use std::io::{prelude::*, BufReader, BufWriter}; + + let mut tasks = JoinSet::new(); + + tasks.spawn_blocking(move || { + let stdin = std::io::stdin(); + let mut stdin = BufReader::new(stdin); + + loop { + let coordinator_msg = bincode::deserialize_from(&mut stdin); + + if bincode_input_closed(&coordinator_msg) { + break; + }; + + let coordinator_msg = + coordinator_msg.context(UnableToDeserializeCoordinatorMessageSnafu)?; + + coordinator_msg_tx + .blocking_send(coordinator_msg) + .drop_error_details() + .context(UnableToSendCoordinatorMessageSnafu)?; + } + + Ok(()) + }); + + tasks.spawn_blocking(move || { + let stdout = std::io::stdout(); + let mut stdout = BufWriter::new(stdout); + + loop { + let worker_msg = + worker_msg_rx.blocking_recv().context(UnableToReceiveWorkerMessageSnafu)?; + + bincode::serialize_into(&mut stdout, &worker_msg) + .context(UnableToSerializeWorkerMessageSnafu)?; + + stdout.flush().context(UnableToFlushStdoutSnafu)?; + } + }); + + tasks +} + +#[derive(Debug, Snafu)] +#[snafu(module)] +pub enum IoQueueError { + #[snafu(display("Failed to deserialize coordinator message"))] + UnableToDeserializeCoordinatorMessage { source: bincode::Error }, + + #[snafu(display("Failed to serialize worker message"))] + UnableToSerializeWorkerMessage { source: bincode::Error }, + + #[snafu(display("Failed to send coordinator message from deserialization task"))] + UnableToSendCoordinatorMessage { source: mpsc::error::SendError<()> }, + + #[snafu(display("Failed to receive worker message"))] + UnableToReceiveWorkerMessage, + + #[snafu(display("Failed to flush stdout"))] + UnableToFlushStdout { source: std::io::Error }, +} diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/base/security_notice.txt b/anneal/v1/playground/rust-anneal-playground/compiler/base/security_notice.txt new file mode 100644 index 0000000000..cb3c0a9cf4 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/base/security_notice.txt @@ -0,0 +1,11 @@ +# Hello, and thanks for looking into the Rust Playground's security! +# +# This build is running on an unprivileged, sandboxed Docker container with no +# network access, so while you can technically run arbitrary code on the +# Playground you shouldn't be able to do any damage with it. +# +# Nothing is perfect though: if you find a way to escape the sandbox, please +# disclose it following our security policy! You can find the policy at: +# +# https://www.rust-lang.org/policies/security +# diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/build.sh b/anneal/v1/playground/rust-anneal-playground/compiler/build.sh new file mode 100755 index 0000000000..49683319b7 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/build.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +set -euv -o pipefail + +channels_to_build="${CHANNELS_TO_BUILD-stable beta nightly}" + +repository=shepmaster + +for channel in $channels_to_build; do + image_name="rust-${channel}" + full_name="${repository}/${image_name}" + + build_start_ms=$(date +%s%3N) + echo "[anneal-build-timing] image=${image_name} event=start epoch_ms=${build_start_ms}" + + docker build \ + -t "${image_name}" \ + -t "${full_name}" \ + --build-arg channel="${channel}" \ + base + + build_end_ms=$(date +%s%3N) + echo "[anneal-build-timing] image=${image_name} event=finish epoch_ms=${build_end_ms} elapsed_ms=$((build_end_ms - build_start_ms))" +done diff --git a/anneal/v1/playground/rust-anneal-playground/compiler/fetch.sh b/anneal/v1/playground/rust-anneal-playground/compiler/fetch.sh new file mode 100755 index 0000000000..3b74b2748e --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/compiler/fetch.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -euv -o pipefail + +repository=shepmaster + +for image in rust-stable rust-beta rust-nightly; do + docker pull "${repository}/${image}" + # The backend expects images without a repository prefix + docker tag "${repository}/${image}" "${image}" +done diff --git a/anneal/v1/playground/rust-anneal-playground/top-crates/.gitignore b/anneal/v1/playground/rust-anneal-playground/top-crates/.gitignore new file mode 100644 index 0000000000..eb5a316cbd --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/top-crates/.gitignore @@ -0,0 +1 @@ +target diff --git a/anneal/v1/playground/rust-anneal-playground/top-crates/Cargo.lock b/anneal/v1/playground/rust-anneal-playground/top-crates/Cargo.lock new file mode 100644 index 0000000000..739277a138 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/top-crates/Cargo.lock @@ -0,0 +1,5351 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "annotate-snippets" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f211a51805bc641f3ad5b7664c77d2547af685cc33b4cd8d31964027a46f13f1" +dependencies = [ + "anstyle", + "memchr", + "unicode-width", +] + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-hyperlink" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a14cad0fa1d1fb02de486a95ea7fd8dd28567b82f65b4ca34bffa7da81823e4" +dependencies = [ + "libc", + "percent-encoding", +] + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-progress" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee65f3323c89eac2de51015f125682e9a88c3bf7a10d0c39b3768ff6af654ff7" + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "arc-swap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" +dependencies = [ + "rustversion", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "aws-lc-rs" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bitflags" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" + +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + +[[package]] +name = "blake3" +version = "1.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures 0.3.0", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cargo" +version = "0.97.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17e884ee08e07c51a4ef6cb35894b29cdeb90616dedb16cde41e27874a8404e1" +dependencies = [ + "anstream", + "anstyle", + "anstyle-progress", + "anyhow", + "async-trait", + "base64", + "blake3", + "cargo-credential", + "cargo-credential-libsecret", + "cargo-credential-macos-keychain", + "cargo-credential-wincred", + "cargo-platform", + "cargo-util", + "cargo-util-schemas", + "cargo-util-terminal", + "clap", + "clap_complete", + "color-print", + "crates-io", + "curl", + "curl-sys", + "filetime", + "flate2", + "futures", + "futures-timer", + "git2", + "git2-curl", + "gix", + "glob", + "heck", + "hex", + "hmac 0.13.0", + "home", + "http", + "http-auth", + "ignore", + "im-rc", + "indexmap", + "itertools", + "jiff", + "jobserver", + "libc", + "libgit2-sys", + "memchr", + "opener", + "os_info", + "pasetors", + "pathdiff", + "rand 0.10.1", + "regex", + "rusqlite", + "rustc-hash", + "rustc-stable-hash", + "rustfix", + "same-file", + "semver", + "serde", + "serde-untagged", + "serde_ignored", + "serde_json", + "sha1 0.11.0", + "shell-escape", + "tar", + "tempfile", + "thiserror", + "time", + "toml", + "toml_edit", + "tracing", + "tracing-chrome", + "tracing-subscriber", + "unicase", + "unicode-ident", + "unicode-width", + "url", + "walkdir", + "windows-sys 0.61.2", + "winnow 1.0.3", +] + +[[package]] +name = "cargo-credential" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa57675b822ecda7f0be12eedbfabd890066271eedc7f2c45ed41e86e0f327a8" +dependencies = [ + "anyhow", + "libc", + "serde", + "serde_json", + "thiserror", + "time", + "windows-sys 0.61.2", +] + +[[package]] +name = "cargo-credential-libsecret" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8771c255a26ef3f81bb91fb0c508b6e85ba767d8b3bd5fee47068bc32dd7b62d" +dependencies = [ + "anyhow", + "cargo-credential", + "libloading", +] + +[[package]] +name = "cargo-credential-macos-keychain" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7b96457c9839aeaaf77ad7c3b09eb00587da221cfb539b82c654486092f9f" +dependencies = [ + "cargo-credential", + "security-framework", +] + +[[package]] +name = "cargo-credential-wincred" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c21c232e758ef669f021d020ed03b8cabb1a924fc0832d66716b582eee291670" +dependencies = [ + "cargo-credential", + "windows-sys 0.61.2", +] + +[[package]] +name = "cargo-platform" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0061da739915fae12ea00e16397555ed4371a6bb285431aab930f61b0aa4ba" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "cargo-util" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a34f8b80c3b233269d3defad193678c74b4dcfd16aa0dab0e1b7b8d3e3c34eb" +dependencies = [ + "anyhow", + "core-foundation 0.10.1", + "filetime", + "hex", + "ignore", + "jobserver", + "libc", + "miow", + "same-file", + "sha2 0.11.0", + "shell-escape", + "tempfile", + "tracing", + "walkdir", + "windows-sys 0.61.2", +] + +[[package]] +name = "cargo-util-schemas" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37156912bbbffb4d28a143546837050f267c218c0862258385d51a482e6646f2" +dependencies = [ + "jiff", + "semver", + "serde", + "serde-untagged", + "serde-value", + "thiserror", + "toml", + "unicode-ident", + "url", +] + +[[package]] +name = "cargo-util-terminal" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baff8199ae90b871b3383da1b2bfd1a9f003f0b043c9278550d220a66c99a5b" +dependencies = [ + "annotate-snippets", + "anstream", + "anstyle", + "anstyle-hyperlink", + "anstyle-progress", + "anyhow", + "libc", + "serde", + "serde_json", + "supports-hyperlinks", + "supports-unicode", + "windows-sys 0.61.2", +] + +[[package]] +name = "cc" +version = "1.2.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex 2.0.1", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + +[[package]] +name = "clap" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_complete" +version = "4.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7a9bfdb35811f9e59832f0f05975114d2251b415fb534108e6f34060fd772" +dependencies = [ + "clap", + "clap_lex", + "is_executable", + "shlex 1.3.0", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "clru" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197fd99cb113a8d5d9b6376f3aa817f32c1078f2343b714fff7d2ca44fdf67d5" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + +[[package]] +name = "color-print" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aa954171903797d5623e047d9ab69d91b493657917bdfb8c2c80ecaf9cdb6f4" +dependencies = [ + "color-print-proc-macro", +] + +[[package]] +name = "color-print-proc-macro" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692186b5ebe54007e45a59aea47ece9eb4108e141326c304cdc91699a7118a22" +dependencies = [ + "nom", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[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 = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crates-io" +version = "0.40.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8bff9b303e2c1ca7c8c6021c52bde41a38c00009ff6e4ca2b578d1bbe26f8f1" +dependencies = [ + "curl", + "percent-encoding", + "serde", + "serde_json", + "thiserror", + "url", +] + +[[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 = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ct-codecs" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49fb0c6640b4507ebd99ff67677009e381ba5eee1d14df78de4a3d16eb123c39" + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + +[[package]] +name = "curl" +version = "0.4.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79fc3b6dd0b87ba36e565715bf9a2ced221311db47bd18011676f24a6066edbc" +dependencies = [ + "curl-sys", + "libc", + "openssl-probe 0.1.6", + "openssl-sys", + "schannel", + "socket2", + "windows-sys 0.59.0", +] + +[[package]] +name = "curl-sys" +version = "0.4.88+curl-8.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644816de6547255eff4e491a1dda1c19b7237f00b62a61e6e64859ce4f2906d0" +dependencies = [ + "cc", + "libc", + "libnghttp2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "windows-sys 0.61.2", +] + +[[package]] +name = "dashmap" +version = "6.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid 0.9.6", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.6", + "subtle", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.0", + "const-oid 0.10.2", + "crypto-common 0.2.2", + "ctutils", +] + +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags", + "objc2", +] + +[[package]] +name = "displaydoc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +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 = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519-compact" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5c0284a5d4b1a2fae017a9fe55fd7d01699711f1b572493f16593e173ea2801" +dependencies = [ + "getrandom 0.4.2", +] + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[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 = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[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 = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "faster-hex" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7223ae2d2f179b803433d9c830478527e92b8117eab39460edae7f1614d9fb73" +dependencies = [ + "heapless", + "serde", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" + +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if", + "libc", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "miniz_oxide", + "zlib-rs", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-timer" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 6.0.0", + "rand_core 0.10.1", + "wasip2", + "wasip3", + "wasm-bindgen", +] + +[[package]] +name = "git2" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b88256088d75a56f8ecfa070513a775dd9107f6530ef14919dac831af9cfe2b" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "openssl-probe 0.1.6", + "openssl-sys", + "url", +] + +[[package]] +name = "git2-curl" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8dcabbc09ece4d30a9aa983d5804203b7e2f8054a171f792deff59b56d31fa" +dependencies = [ + "curl", + "git2", + "log", + "url", +] + +[[package]] +name = "gix" +version = "0.81.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0473c64d9ccbcfb9953a133b47c8b9a335b87ac6c52b983ee4b03d49000b0f3f" +dependencies = [ + "gix-actor", + "gix-archive", + "gix-attributes", + "gix-blame", + "gix-command", + "gix-commitgraph", + "gix-config", + "gix-credentials", + "gix-date", + "gix-diff", + "gix-dir", + "gix-discover", + "gix-error", + "gix-features", + "gix-filter", + "gix-fs", + "gix-glob", + "gix-hash", + "gix-hashtable", + "gix-ignore", + "gix-index", + "gix-lock", + "gix-merge", + "gix-negotiate", + "gix-object", + "gix-odb", + "gix-pack", + "gix-path", + "gix-pathspec", + "gix-prompt", + "gix-protocol", + "gix-ref", + "gix-refspec", + "gix-revision", + "gix-revwalk", + "gix-sec", + "gix-shallow", + "gix-status", + "gix-submodule", + "gix-tempfile", + "gix-trace", + "gix-transport", + "gix-traverse", + "gix-url", + "gix-utils", + "gix-validate", + "gix-worktree", + "gix-worktree-state", + "gix-worktree-stream", + "nonempty", + "prodash", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-actor" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e5e5b518339d5e6718af108fd064d4e9ba33caf728cf487352873d76411df35" +dependencies = [ + "bstr", + "gix-date", + "gix-error", + "winnow 0.7.15", +] + +[[package]] +name = "gix-archive" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "651c99be11aac9b303483193ae50b45eb6e094da4f5ed797019b03948f51aad6" +dependencies = [ + "bstr", + "gix-date", + "gix-error", + "gix-object", + "gix-worktree-stream", +] + +[[package]] +name = "gix-attributes" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c233d6eaa098c0ca5ce03236fd7a96e27f1abe72fad74b46003fbd11fe49563c" +dependencies = [ + "bstr", + "gix-glob", + "gix-path", + "gix-quote", + "gix-trace", + "kstring", + "smallvec", + "thiserror", + "unicode-bom", +] + +[[package]] +name = "gix-bitmap" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ebef0c26ad305747649e727bbcd56a7b7910754eb7cea88f6dff6f93c51283" +dependencies = [ + "gix-error", +] + +[[package]] +name = "gix-blame" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77aaf9f7348f4da3ebfbfbbc35fa0d07155d98377856198dde6f695fd648705" +dependencies = [ + "gix-commitgraph", + "gix-date", + "gix-diff", + "gix-error", + "gix-hash", + "gix-object", + "gix-revwalk", + "gix-trace", + "gix-traverse", + "gix-worktree", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-chunk" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9faee47943b638e58ddd5e275a4906ad3e4b6c8584f1d41bd18ab9032ec52afb" +dependencies = [ + "gix-error", +] + +[[package]] +name = "gix-command" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae4bb9fa74c44c93f7238b08255f7f9afc158bafea4b95af665fa535352cd73c" +dependencies = [ + "bstr", + "gix-path", + "gix-quote", + "gix-trace", + "shell-words", +] + +[[package]] +name = "gix-commitgraph" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3196655fd1443f3c58a48c114aa480be3e4e87b393d7292daaa0d543862eb445" +dependencies = [ + "bstr", + "gix-chunk", + "gix-error", + "gix-hash", + "memmap2", + "nonempty", +] + +[[package]] +name = "gix-config" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08939b4c4ed7a663d0e64be9e1e9bdf23a1fb4fcee1febdf449f12229542e50d" +dependencies = [ + "bstr", + "gix-config-value", + "gix-features", + "gix-glob", + "gix-path", + "gix-ref", + "gix-sec", + "memchr", + "smallvec", + "thiserror", + "unicode-bom", + "winnow 0.7.15", +] + +[[package]] +name = "gix-config-value" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4378c53ec3db049919edf91ff76f56f28886a8b4b4a5a9dc633108d84afc3675" +dependencies = [ + "bitflags", + "bstr", + "gix-path", + "libc", + "thiserror", +] + +[[package]] +name = "gix-credentials" +version = "0.37.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0493f25da3ce9e8f7d925e5b64dc6d0b6109c96add422a6bcada52416448147d" +dependencies = [ + "bstr", + "gix-command", + "gix-config-value", + "gix-date", + "gix-path", + "gix-prompt", + "gix-sec", + "gix-trace", + "gix-url", + "thiserror", +] + +[[package]] +name = "gix-date" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ecab64a98bbac9f8e02990a9ea5e3c974a7d49b95f2bd70ad94ad22fa6b48c" +dependencies = [ + "bstr", + "gix-error", + "itoa", + "jiff", +] + +[[package]] +name = "gix-diff" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88f3b3475e5d3877d7c30c40827cc2441936ce890efc226e5ba4afe3a7ae33f0" +dependencies = [ + "bstr", + "gix-attributes", + "gix-command", + "gix-filter", + "gix-fs", + "gix-hash", + "gix-index", + "gix-object", + "gix-path", + "gix-pathspec", + "gix-tempfile", + "gix-trace", + "gix-traverse", + "gix-worktree", + "imara-diff 0.1.8", + "imara-diff 0.2.0", + "thiserror", +] + +[[package]] +name = "gix-dir" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da4604a360988f0ba8efe6f90093ca5a844f4a7f8e1a3dcda501ec44e600ea9" +dependencies = [ + "bstr", + "gix-discover", + "gix-fs", + "gix-ignore", + "gix-index", + "gix-object", + "gix-path", + "gix-pathspec", + "gix-trace", + "gix-utils", + "gix-worktree", + "thiserror", +] + +[[package]] +name = "gix-discover" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c65bd3330fe0cb9d40d875bf862fd5e8ad6fa4164ddbc4842fbeb889c3f0b2c6" +dependencies = [ + "bstr", + "dunce", + "gix-fs", + "gix-path", + "gix-ref", + "gix-sec", + "thiserror", +] + +[[package]] +name = "gix-error" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57831e199be480af90dcd7e459abed8a174c09ec9a6e2cc8f7ca6c54598b06b" +dependencies = [ + "bstr", +] + +[[package]] +name = "gix-features" +version = "0.46.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "752493cd4b1d5eaaa0138a7493f65c96863fefa990fc021e0e519579e389ab20" +dependencies = [ + "bytes", + "crc32fast", + "crossbeam-channel", + "gix-path", + "gix-trace", + "gix-utils", + "libc", + "once_cell", + "parking_lot", + "prodash", + "thiserror", + "walkdir", + "zlib-rs", +] + +[[package]] +name = "gix-filter" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37598282a6566da6fb52667570c7fe0aedcb122ac886724a9e62a2180523e35" +dependencies = [ + "bstr", + "encoding_rs", + "gix-attributes", + "gix-command", + "gix-hash", + "gix-object", + "gix-packetline", + "gix-path", + "gix-quote", + "gix-trace", + "gix-utils", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-fs" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a964b4aec683eb0bacb87533defa80805bb4768056371a47ab38b00a2d377b72" +dependencies = [ + "bstr", + "fastrand", + "gix-features", + "gix-path", + "gix-utils", + "thiserror", +] + +[[package]] +name = "gix-glob" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03e6cd88cc0dc1eafa1fddac0fb719e4e74b6ea58dd016e71125fde4a326bee" +dependencies = [ + "bitflags", + "bstr", + "gix-features", + "gix-path", +] + +[[package]] +name = "gix-hash" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fb896a02d9ab96fa518475a5f30ad3952010f801a8de5840f633f4a6b985dfb" +dependencies = [ + "faster-hex", + "gix-features", + "sha1-checked", + "thiserror", +] + +[[package]] +name = "gix-hashtable" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2664216fc5e89b51e756a4a3ac676315602ce2dac07acf1da959a22038d69b33" +dependencies = [ + "gix-hash", + "hashbrown 0.16.1", + "parking_lot", +] + +[[package]] +name = "gix-ignore" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f915dcf6911e3027537166d34e13f0fe101ed12225178d2ae29cd1272cff26" +dependencies = [ + "bstr", + "gix-glob", + "gix-path", + "gix-trace", + "unicode-bom", +] + +[[package]] +name = "gix-index" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bae54ab14e4e74d5dda60b82ea7afad7c8eb3be68283d6d5f29bd2e6d47fff7" +dependencies = [ + "bitflags", + "bstr", + "filetime", + "fnv", + "gix-bitmap", + "gix-features", + "gix-fs", + "gix-hash", + "gix-lock", + "gix-object", + "gix-traverse", + "gix-utils", + "gix-validate", + "hashbrown 0.16.1", + "itoa", + "libc", + "memmap2", + "rustix", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-lock" +version = "21.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054fbd0989700c69dc5aa80bc66944f05df1e15aa7391a9e42aca7366337905f" +dependencies = [ + "gix-tempfile", + "gix-utils", + "thiserror", +] + +[[package]] +name = "gix-merge" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4606747466512d22c2dffc019142e1941238f543987ea51353c938cca80c500" +dependencies = [ + "bstr", + "gix-command", + "gix-diff", + "gix-filter", + "gix-fs", + "gix-hash", + "gix-index", + "gix-object", + "gix-path", + "gix-quote", + "gix-revision", + "gix-revwalk", + "gix-tempfile", + "gix-trace", + "gix-worktree", + "imara-diff 0.1.8", + "nonempty", + "thiserror", +] + +[[package]] +name = "gix-negotiate" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea064c7595eea08fdd01c70748af747d9acc40f727b61f4c8a2145a5c5fc28c" +dependencies = [ + "bitflags", + "gix-commitgraph", + "gix-date", + "gix-hash", + "gix-object", + "gix-revwalk", +] + +[[package]] +name = "gix-object" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cafb802bb688a7c1e69ef965612ff5ff859f046bfb616377e4a0ba4c01e43d47" +dependencies = [ + "bstr", + "gix-actor", + "gix-date", + "gix-features", + "gix-hash", + "gix-hashtable", + "gix-path", + "gix-utils", + "gix-validate", + "itoa", + "smallvec", + "thiserror", + "winnow 0.7.15", +] + +[[package]] +name = "gix-odb" +version = "0.78.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24833ae9323b4f7079575fb9f961cf9c414b0afbec428a536ab8e7dd93bc002b" +dependencies = [ + "arc-swap", + "gix-features", + "gix-fs", + "gix-hash", + "gix-hashtable", + "gix-object", + "gix-pack", + "gix-path", + "gix-quote", + "parking_lot", + "tempfile", + "thiserror", +] + +[[package]] +name = "gix-pack" +version = "0.68.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3484119cd19859d7d7639413c27e192478fa354d3f4ff5f7e3c041e8040f0f4" +dependencies = [ + "clru", + "gix-chunk", + "gix-error", + "gix-features", + "gix-hash", + "gix-hashtable", + "gix-object", + "gix-path", + "gix-tempfile", + "memmap2", + "parking_lot", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-packetline" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18337ba2830bb43367d1af43819c8c78f31337f079fc76d0f1f1750a173126" +dependencies = [ + "bstr", + "faster-hex", + "gix-trace", + "thiserror", +] + +[[package]] +name = "gix-path" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8fd1fe596dc393b538e1d5492c5585971a9311475b3255f7b889023df208476" +dependencies = [ + "bstr", + "gix-trace", + "gix-validate", + "thiserror", +] + +[[package]] +name = "gix-pathspec" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f89611f13544ca5ebeb68a502673814ef57200df60c24a61c2ce7b96f612f08b" +dependencies = [ + "bitflags", + "bstr", + "gix-attributes", + "gix-config-value", + "gix-glob", + "gix-path", + "thiserror", +] + +[[package]] +name = "gix-prompt" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de52c2570684db3eb8cebda77c1d0e3d03ddaad2d9bbb5055eba31fb9f8292a" +dependencies = [ + "gix-command", + "gix-config-value", + "parking_lot", + "rustix", + "thiserror", +] + +[[package]] +name = "gix-protocol" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f38666350736b5877c79f57ddae02bde07a4ce186d889adc391e831cddcbe76" +dependencies = [ + "bstr", + "gix-credentials", + "gix-date", + "gix-features", + "gix-hash", + "gix-lock", + "gix-negotiate", + "gix-object", + "gix-ref", + "gix-refspec", + "gix-revwalk", + "gix-shallow", + "gix-trace", + "gix-transport", + "gix-utils", + "maybe-async", + "nonempty", + "thiserror", + "winnow 0.7.15", +] + +[[package]] +name = "gix-quote" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6e541fc33cc2b783b7979040d445a0c86a2eca747c8faea4ca84230d06ae6ef" +dependencies = [ + "bstr", + "gix-error", + "gix-utils", +] + +[[package]] +name = "gix-ref" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2159978abb99b7027c8579d15211e262ef0ef2594d5cecb3334fbcbdfe2997c" +dependencies = [ + "gix-actor", + "gix-features", + "gix-fs", + "gix-hash", + "gix-lock", + "gix-object", + "gix-path", + "gix-tempfile", + "gix-utils", + "gix-validate", + "memmap2", + "thiserror", + "winnow 0.7.15", +] + +[[package]] +name = "gix-refspec" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc806ee13f437428f8a1ba4c72ecfaa3f20e14f5f0d4c2bc17d0b33e794aa6ac" +dependencies = [ + "bstr", + "gix-error", + "gix-glob", + "gix-hash", + "gix-revision", + "gix-validate", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-revision" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c08f1ec5d1e6a524f8ba291c41f0ccaef64e48ed0e8cf790b3461cae45f6d3d" +dependencies = [ + "bitflags", + "bstr", + "gix-commitgraph", + "gix-date", + "gix-error", + "gix-hash", + "gix-object", + "gix-revwalk", + "gix-trace", + "nonempty", +] + +[[package]] +name = "gix-revwalk" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4b2b87772b21ca449249e86d32febadba5cba32b0fcce804ab9cefc6f2111c" +dependencies = [ + "gix-commitgraph", + "gix-date", + "gix-error", + "gix-hash", + "gix-hashtable", + "gix-object", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-sec" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "283f4a746c9bde8550be63e6f961ff4651f412ca12666e8f5615f39464960ab9" +dependencies = [ + "bitflags", + "gix-path", + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "gix-shallow" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf60711c9083b2364b3fac8a352444af76b17201f3682fdebe74fa66d89a772" +dependencies = [ + "bstr", + "gix-hash", + "gix-lock", + "nonempty", + "thiserror", +] + +[[package]] +name = "gix-status" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d6c598e3fdbc352fba1c5ba7e709e69402fafbc44d9295edad2e3c4738996b" +dependencies = [ + "bstr", + "filetime", + "gix-diff", + "gix-dir", + "gix-features", + "gix-filter", + "gix-fs", + "gix-hash", + "gix-index", + "gix-object", + "gix-path", + "gix-pathspec", + "gix-worktree", + "portable-atomic", + "thiserror", +] + +[[package]] +name = "gix-submodule" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce5c3929c5e6821f651d35e8420f72fea3cfafe9fc1e928a61e718b462c72a5" +dependencies = [ + "bstr", + "gix-config", + "gix-path", + "gix-pathspec", + "gix-refspec", + "gix-url", + "thiserror", +] + +[[package]] +name = "gix-tempfile" +version = "21.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22227f6b203f511ff451c33c89899e87e4f571fc596b06f68e6e613a6508528" +dependencies = [ + "dashmap", + "gix-fs", + "libc", + "parking_lot", + "tempfile", +] + +[[package]] +name = "gix-trace" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44dc45eae785c0eb14173e0f152e6e224dcf4d45b6a6999a3aed22af541ad678" + +[[package]] +name = "gix-transport" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a521e39c6235ce63ed6c001e2dd79818c830b82c3b7b59247ee7b229c39ec9bb" +dependencies = [ + "base64", + "bstr", + "curl", + "gix-command", + "gix-credentials", + "gix-features", + "gix-packetline", + "gix-quote", + "gix-sec", + "gix-url", + "thiserror", +] + +[[package]] +name = "gix-traverse" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "963dc2afcdb611092aa587c3f9365e749ac0a0892ff27662dbc75f26c953fbec" +dependencies = [ + "bitflags", + "gix-commitgraph", + "gix-date", + "gix-hash", + "gix-hashtable", + "gix-object", + "gix-revwalk", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-url" +version = "0.35.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a61ead12e33fa52ae92b207ee27554f646a8e7a3dad8b78da1582ec91eda0a6" +dependencies = [ + "bstr", + "gix-path", + "percent-encoding", + "thiserror", +] + +[[package]] +name = "gix-utils" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66c50966184123caf580ffa64e28031a878597f1c7fceb8fe19566c38eb1b771" +dependencies = [ + "bstr", + "fastrand", + "unicode-normalization", +] + +[[package]] +name = "gix-validate" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bc6fc771c4063ba7cd2f47b91fb6076251c6a823b64b7fe7b8874b0fe4afae3" +dependencies = [ + "bstr", +] + +[[package]] +name = "gix-worktree" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6bd5830cbc43c9c00918b826467d2afad685b195cb82329cde2b2d116d2c578" +dependencies = [ + "bstr", + "gix-attributes", + "gix-fs", + "gix-glob", + "gix-hash", + "gix-ignore", + "gix-index", + "gix-object", + "gix-path", + "gix-validate", +] + +[[package]] +name = "gix-worktree-state" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644a1681f96e1be43c2a8384337d9d220e7624f50db54beda70997052aebf707" +dependencies = [ + "bstr", + "gix-features", + "gix-filter", + "gix-fs", + "gix-index", + "gix-object", + "gix-path", + "gix-worktree", + "io-close", + "thiserror", +] + +[[package]] +name = "gix-worktree-stream" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e3fb70a1f650a5cec7d5b8d10d6d6fe86daf3cf15bde08ba0c70988a2932c3" +dependencies = [ + "gix-attributes", + "gix-error", + "gix-features", + "gix-filter", + "gix-fs", + "gix-hash", + "gix-object", + "gix-path", + "gix-traverse", + "parking_lot", +] + +[[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.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "h2" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "hashlink" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0b22561a9c04a7cb1a302c013e0259cd3b4bb619f145b32f72b8b4bcbed230" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "http" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-auth" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "150fa4a9462ef926824cf4519c84ed652ca8f4fbae34cb8af045b5cbcaf98822" +dependencies = [ + "memchr", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[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", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hybrid-array" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +dependencies = [ + "typenum", +] + +[[package]] +name = "hyper" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "ignore" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + +[[package]] +name = "im-rc" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe" +dependencies = [ + "bitmaps", + "rand_core 0.6.4", + "rand_xoshiro", + "sized-chunks", + "typenum", + "version_check", +] + +[[package]] +name = "imara-diff" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17d34b7d42178945f775e84bc4c36dde7c1c6cdfea656d3354d009056f2bb3d2" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "imara-diff" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f01d462f766df78ab820dd06f5eb700233c51f0f4c2e846520eaf4ba6aa5c5c" +dependencies = [ + "hashbrown 0.15.5", + "memchr", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "io-close" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cadcf447f06744f8ce713d2d6239bb5bde2c357a452397a9ed90c625da390bc" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "is_executable" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baabb8b4867b26294d818bf3f651a454b6901431711abb96e296245888d6e8c4" +dependencies = [ + "windows-sys 0.60.2", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jiff" +version = "0.2.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102" +dependencies = [ + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", + "windows-link", +] + +[[package]] +name = "jiff-static" +version = "0.2.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c900ef84826f1338a557697dc8fc601df9ca9af4ac137c7fb61d4c6f2dfd3076" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys", + "log", + "simd_cesu8", + "thiserror", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "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.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" +dependencies = [ + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "kstring" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558bf9508a558512042d3095138b1f7b8fe90c5467d94f9f1da28b3731c5dbd1" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libgit2-sys" +version = "0.18.5+1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "005d6ae6eac1912906073e069f7db60b1fa98e052a68227824afe3e3a1c59ca2" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "libnghttp2-sys" +version = "0.1.13+1.68.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "492e00167f1418c15648144f42bbfc63099806ecee9bf8d09a6353d6b4856b3c" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libssh2-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bc9657773828b90eeb625adff10eeac83cc21bbfd8e23a03eaa8a33c9e28d9" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[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.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "113b30b4cd05f7c06868fdb2854f66a7b9fece9a48425351cd532e810d74024f" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "maybe-async" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "746873a384ad60adc5db74471dfaba74bd278afbdcfd81db93fafcdfc8b5ca0c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "memchr" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" + +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[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.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "miow" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "536bfad37a309d62069485248eeaba1e8d9853aaf951caaeaed0585a95346f08" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "nix" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nonempty" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9737e026353e5cd0736f98eddae28665118eb6f6600902a7f50db585621fecb6" + +[[package]] +name = "normpath" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9985ef7269fa99f3b12437bb698381da2428743ab90f20393f399fa14cab21a" +dependencies = [ + "windows-sys 0.61.2", +] + +[[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.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" +dependencies = [ + "bitflags", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags", + "dispatch2", + "objc2", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-core-image" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-location" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags", + "block2", + "libc", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +dependencies = [ + "bitflags", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-core-location", + "objc2-core-text", + "objc2-foundation", + "objc2-quartz-core", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "opener" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2fa337e0cf13357c13ef1dc108df1333eb192f75fc170bea03fcf1fd404c2ee" +dependencies = [ + "bstr", + "normpath", + "windows-sys 0.61.2", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.116" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28a22dc7140cda5f096e5e7724a6962ca81a7f8bfd2979f9b18c11af56318c4" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "orion" +version = "0.17.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6758747fd1ce1efaf2bd43219ac4aa9e28263b236b2b6a1e486bcd06820707" +dependencies = [ + "fiat-crypto", + "subtle", +] + +[[package]] +name = "os_info" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf20a545b305cf1da722b236b5155c9bb35f1d5ceb28c048bd96ca842f41b5b" +dependencies = [ + "android_system_properties", + "log", + "nix", + "objc2", + "objc2-foundation", + "objc2-ui-kit", + "windows-sys 0.61.2", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.9", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[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 = "pasetors" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e838401fb2873bad417e6a03179014c748746f67311cb7317ab14fc0881fa9f0" +dependencies = [ + "ct-codecs", + "ed25519-compact", + "getrandom 0.4.2", + "orion", + "p384", + "rand_core 0.6.4", + "regex", + "serde", + "serde_derive", + "serde_json", + "sha2 0.10.9", + "subtle", + "time", + "zeroize", +] + +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[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.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +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 = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prodash" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "962200e2d7d551451297d9fdce85138374019ada198e30ea9ede38034e27604c" +dependencies = [ + "parking_lot", +] + +[[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", + "thiserror", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "aws-lc-rs", + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.4", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror", + "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", + "tracing", + "windows-sys 0.60.2", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +dependencies = [ + "rand_chacha", + "rand_core 0.9.5", +] + +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "chacha20", + "getrandom 0.4.2", + "rand_core 0.10.1", +] + +[[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 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "reqwest" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "mime", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "serde", + "serde_json", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + +[[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.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rsqlite-vfs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51c9ae4df8a7fba42103df5c621fa3c37eccf3a3c650879e90fc48b11cc192c" +dependencies = [ + "hashbrown 0.16.1", + "thiserror", +] + +[[package]] +name = "rusqlite" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0d2b0146dd9661bf67bb107c0bb2a55064d556eeb3fc314151b957f313bcd4e" +dependencies = [ + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", + "sqlite-wasm-rs", +] + +[[package]] +name = "rust-playground-top-crates" +version = "0.1.7" +dependencies = [ + "cargo", + "cargo-util-schemas", + "itertools", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "tempfile", + "tokio", + "toml", +] + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc-stable-hash" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "781442f29170c5c93b7185ad559492601acdc71d5bb0706f5868094f45cfcd08" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustfix" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602c6a9fecd66c254d55f3fce9e63e738e71fc3ed2693e69eb2453bb6d7bdcc7" +dependencies = [ + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +dependencies = [ + "aws-lc-rs", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" +dependencies = [ + "openssl-probe 0.2.1", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" +dependencies = [ + "core-foundation 0.10.1", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "aws-lc-rs", + "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 = "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.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +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 = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +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-untagged" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" +dependencies = [ + "erased-serde", + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[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_ignored" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115dffd5f3853e06e746965a20dcbae6ee747ae30b543d91b0e089668bb07798" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", +] + +[[package]] +name = "sha1-checked" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89f599ac0c323ebb1c6082821a54962b839832b03984598375bff3975b804423" +dependencies = [ + "digest 0.10.7", + "sha1 0.10.6", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", +] + +[[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 = "shell-escape" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" + +[[package]] +name = "shell-words" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "simd_cesu8" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlite-wasm-rs" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc3efc0da82635d7e1ced0053bbbfa8c7ab9645d0bf36ceb4f7127bb85315d75" +dependencies = [ + "cc", + "js-sys", + "rsqlite-vfs", + "wasm-bindgen", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "supports-hyperlinks" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91" + +[[package]] +name = "supports-unicode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[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.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +dependencies = [ + "bitflags", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tar" +version = "0.4.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" +dependencies = [ + "filetime", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.2", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "terminal_size" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" +dependencies = [ + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +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.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +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.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow 1.0.3", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow 1.0.3", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow 1.0.3", +] + +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "url", +] + +[[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.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-chrome" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf0a738ed5d6450a9fb96e86a23ad808de2b727fd1394585da5cdd6788ffe724" +dependencies = [ + "serde_json", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +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-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[package]] +name = "unicode-bom" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[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 = "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 = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" +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-root-certs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" +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-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + +[[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.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.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.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.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.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.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.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.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.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.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "yoke" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zlib-rs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/anneal/v1/playground/rust-anneal-playground/top-crates/Cargo.toml b/anneal/v1/playground/rust-anneal-playground/top-crates/Cargo.toml new file mode 100644 index 0000000000..e348db6256 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/top-crates/Cargo.toml @@ -0,0 +1,24 @@ +[package] +authors = ["Jake Goulding "] +name = "rust-playground-top-crates" +version = "0.1.7" +edition = "2018" + +description = "Calculates what crates should be included in the playground" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/rust-playground" + +[workspace] + +[dependencies] +cargo = "0.97.0" +cargo-util-schemas = "0.14.0" +itertools = "0.14.0" +reqwest = { version = "0.13.0", features = ["json"] } +semver = { version = "1.0.11", features = ["serde"] } +serde = "1.0.1" +serde_derive = "1.0.1" +serde_json = "1.0.0" +tempfile = "3.20.0" +tokio = { version = "1.52.3", default-features = false, features = ["rt", "macros"] } +toml = "1.0.3" diff --git a/anneal/v1/playground/rust-anneal-playground/top-crates/crate-modifications.toml b/anneal/v1/playground/rust-anneal-playground/top-crates/crate-modifications.toml new file mode 100644 index 0000000000..565d00b268 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/top-crates/crate-modifications.toml @@ -0,0 +1,23 @@ +additions = [ + # Crates that the compiler recommends + # rg 'https://crates.io/crates/[a-z_-]+' \ + # --glob '**/tests/**/*.stderr' \ + # --glob 'compiler/rustc_error_codes/**/*.md' \ + # --only-matching \ + # --no-line-number \ + # --no-filename \ + # | sort \ + # | uniq \ + # | cut -d '/' -f 5 + "async-trait", + "sptr", + # Crate that The Rust Programming Language book uses + "trpl", +] + +[[exclusions]] +# crypto-common 0.1.7 depends on `generic-array =0.14.7`. Since +# there's now a version 1.x of generic-array; it's no big deal to +# exclude the newest version of the older series. +name = "generic-array" +versions = "0.14.9" diff --git a/anneal/v1/playground/rust-anneal-playground/top-crates/src/lib.rs b/anneal/v1/playground/rust-anneal-playground/top-crates/src/lib.rs new file mode 100644 index 0000000000..015b5f551d --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/top-crates/src/lib.rs @@ -0,0 +1,718 @@ +#![deny(rust_2018_idioms)] + +use cargo::{ + core::{ + compiler::{CompileKind, CompileTarget, TargetInfo}, + package::PackageSet, + resolver::{self}, + Dependency, Package, PackageId, SourceId, Summary, Target, + }, + sources::{ + source::{QueryKind, Source, SourceMap}, + SourceConfigMap, + }, + util::{cache_lock::CacheLockMode, interning::InternedString, VersionExt}, + GlobalContext, +}; +use itertools::Itertools; +use semver::Version; +use serde::{Deserialize, Serialize}; +use std::collections::{btree_map::Entry, BTreeMap, BTreeSet, HashSet}; + +const PLAYGROUND_TARGET_PLATFORM: &str = "x86_64-unknown-linux-gnu"; + +struct GlobalState<'cfg> { + config: &'cfg GlobalContext, + compile_kind: CompileKind, + target_info: TargetInfo, + crates_io: SourceId, + source: Box, + modifications: &'cfg Modifications, +} + +/// The list of crates from crates.io +#[derive(Debug, Deserialize)] +struct TopCrates { + crates: Vec, +} + +/// The shared description of a crate +#[derive(Debug, Deserialize)] +struct Crate { + #[serde(rename = "id")] + name: InternedString, +} + +/// A mapping of a crates name to its identifier used in source code +#[derive(Debug, Serialize)] +pub struct CrateInformation { + pub name: String, + pub version: Version, + pub id: String, +} + +/// Hand-curated changes to the crate list +#[derive(Debug, Default, Deserialize)] +pub struct Modifications { + #[serde(default)] + pub exclusions: Vec, + #[serde(default)] + pub additions: BTreeSet, +} + +#[derive(Debug, Deserialize)] +pub struct Exclusion { + name: InternedString, + versions: Option, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "kebab-case")] +pub struct DependencySpec { + #[serde(skip_serializing_if = "String::is_empty")] + pub package: String, + #[serde(serialize_with = "exact_version")] + pub version: Version, + #[serde(skip_serializing_if = "BTreeSet::is_empty")] + pub features: BTreeSet, + #[serde(skip_serializing_if = "is_true")] + pub default_features: bool, +} + +#[derive(Debug)] +struct ResolvedDep { + summary: Summary, + lib_target: Target, + features: FeaturesLite, +} + +#[derive(Debug)] +struct FeaturesLite { + features: BTreeSet, + uses_default_features: bool, +} + +impl Default for FeaturesLite { + fn default() -> Self { + Self { + features: Default::default(), + uses_default_features: true, + } + } +} + +impl FeaturesLite { + fn merge(&mut self, other: FeaturesLite) -> &mut Self { + self.features.extend(other.features); + self.uses_default_features = self.uses_default_features || other.uses_default_features; + self + } + + fn finalize(&self) -> Self { + let mut features = self.features.clone(); + let mut uses_default_features = self.uses_default_features; + + // This is probably not needed, but keeping it for + // belt-and-suspenders. + if features.remove("default") { + uses_default_features = true; + } + + Self { + features, + uses_default_features, + } + } + + fn feature_strings(&self) -> Vec { + self.features.iter().map(|s| s.to_string()).collect() + } +} + +fn exact_version(version: &Version, serializer: S) -> Result +where + S: serde::Serializer, +{ + semver::Comparator { + op: semver::Op::Exact, + major: version.major, + minor: Some(version.minor), + patch: Some(version.patch), + pre: version.pre.clone(), + } + .serialize(serializer) +} + +fn is_true(b: &bool) -> bool { + *b +} + +impl Modifications { + fn excluded(&self, name: &str, version: &Version) -> bool { + let Some(exclusion) = self.exclusions.iter().find(|n| n.name == name) else { + return false; + }; + + match &exclusion.versions { + Some(versions) => versions.matches(version), + + // An unspecified version selector means to exclude all versions + _ => true, + } + } +} + +async fn simple_get(url: &str) -> reqwest::Result { + reqwest::ClientBuilder::new() + .user_agent("Rust Playground - Top Crates Utility") + .build()? + .get(url) + .send() + .await +} + +impl TopCrates { + /// List top 100 crates by number of downloads on crates.io. + async fn download() -> TopCrates { + let resp = simple_get("https://crates.io/api/v1/crates?page=1&per_page=100&sort=downloads") + .await + .expect("Could not fetch top crates"); + assert!( + resp.status().is_success(), + "Could not download top crates; HTTP status was {}", + resp.status(), + ); + + resp.json().await.expect("Invalid JSON") + } + + async fn add_rust_cookbook_crates(&mut self) { + let resp = simple_get( + "https://raw.githubusercontent.com/rust-lang-nursery/rust-cookbook/master/Cargo.toml", + ) + .await + .expect("Could not fetch cookbook manifest"); + assert!( + resp.status().is_success(), + "Could not download cookbook; HTTP status was {}", + resp.status(), + ); + + let content = resp.text().await.expect("could not read cookbook manifest"); + + let manifest = content + .parse::() + .expect("could not parse cookbook manifest"); + + let dependencies = manifest["dependencies"] + .as_table() + .expect("no dependencies found for cookbook manifest"); + self.crates.extend({ + dependencies.iter().map(|(name, _)| Crate { + name: InternedString::new(name), + }) + }) + } + + /// Add crates that have been hand-picked + fn add_curated_crates(&mut self, modifications: &Modifications) { + self.crates.extend({ + modifications + .additions + .iter() + .copied() + .map(|name| Crate { name }) + }); + } +} + +/// Finds the features specified by the custom metadata of `pkg`. +/// +/// Our custom metadata format looks like: +/// +/// [package.metadata.playground] +/// default-features = true +/// features = ["std", "extra-traits"] +/// all-features = false +/// +/// All fields are optional. +fn playground_metadata_features(pkg: &Package) -> Option { + let custom_metadata = pkg.manifest().custom_metadata()?; + let playground_metadata = custom_metadata.get("playground")?; + + #[derive(Deserialize)] + #[serde(default, rename_all = "kebab-case")] + struct Metadata { + features: BTreeSet, + default_features: bool, + all_features: bool, + } + + impl Default for Metadata { + fn default() -> Self { + Metadata { + features: BTreeSet::new(), + default_features: true, + all_features: false, + } + } + } + + let metadata = match playground_metadata.clone().try_into::() { + Ok(metadata) => metadata, + Err(err) => { + eprintln!( + "Failed to parse custom metadata for {} {}: {}", + pkg.name(), + pkg.version(), + err + ); + return None; + } + }; + + // If `all-features` is set then we ignore `features`. + let summary = pkg.summary(); + let enabled_features: BTreeSet = if metadata.all_features { + summary.features().keys().copied().collect() + } else { + metadata.features + }; + + Some(FeaturesLite { + features: enabled_features, + uses_default_features: metadata.default_features, + }) +} + +fn make_global_state<'cfg>( + config: &'cfg GlobalContext, + modifications: &'cfg Modifications, +) -> GlobalState<'cfg> { + // Information about the playground's target platform. + let compile_target = CompileTarget::new(PLAYGROUND_TARGET_PLATFORM, false) + .expect("Unable to create a CompileTarget"); + let compile_kind = CompileKind::Target(compile_target); + let rustc = config + .load_global_rustc(None) + .expect("Unable to load the global rustc"); + let target_info = TargetInfo::new(config, &[compile_kind], &rustc, compile_kind) + .expect("Unable to create a TargetInfo"); + + // Source for obtaining packages from the crates.io registry. + let crates_io = SourceId::crates_io(config).expect("Unable to create crates.io source ID"); + + let source_config_map = SourceConfigMap::new(config).unwrap(); + let yanked_whitelist = HashSet::new(); + let source = source_config_map + .load(crates_io, &yanked_whitelist) + .expect("Unable to create registry source"); + + GlobalState { + config, + compile_kind, + target_info, + crates_io, + source, + modifications, + } +} + +fn bulk_download(global: &mut GlobalState<'_>, package_ids: &[PackageId]) -> Vec { + let mut sources = SourceMap::new(); + sources.insert(Box::new(&mut *global.source)); + + let package_set = PackageSet::new(package_ids, sources, global.config) + .expect("Unable to create a PackageSet"); + + package_set + .get_many(package_set.package_ids()) + .expect("Unable to download packages") + .into_iter() + .cloned() + .collect() +} + +async fn populate_initial_direct_dependencies( + global: &mut GlobalState<'_>, +) -> BTreeMap { + let mut top = TopCrates::download().await; + top.add_rust_cookbook_crates().await; + top.add_curated_crates(global.modifications); + + // Find the newest (non-prerelease, non-yanked) versions of all + // the interesting crates. + let mut package_ids = Vec::new(); + for Crate { name } in top.crates { + // Query the registry for a summary of this crate. + // Usefully, this doesn't seem to include yanked versions + let version = None; + let dep = Dependency::parse(name, version, global.crates_io) + .unwrap_or_else(|e| panic!("Unable to parse dependency for {}: {}", name, e)); + + let matches = global + .source + .query_vec(&dep, QueryKind::Exact) + .await + .unwrap_or_else(|e| panic!("Unable to query registry for {}: {}", name, e)); + + // Find the newest non-prelease version + let summary = matches + .into_iter() + .filter(|summary| !summary.as_summary().version().is_prerelease()) + .max_by_key(|summary| summary.as_summary().version().clone()) + .unwrap_or_else(|| panic!("Registry has no viable versions of {}", name)); + + let version = summary.as_summary().version().clone(); + + if global.modifications.excluded(&name, &version) { + continue; + } + + let package_id = PackageId::new(name, version, global.crates_io); + package_ids.push(package_id); + } + + let packages = bulk_download(global, &package_ids); + + let mut initial_direct_dependencies = BTreeMap::new(); + for download in packages { + let id = download.package_id(); + let lib_target = download + .library() + .unwrap_or_else(|| panic!("{} did not have a library", id)) + .clone(); + + let features = playground_metadata_features(&download).unwrap_or_default(); + + let dep = ResolvedDep { + summary: download.summary().clone(), + lib_target, + features, + }; + + initial_direct_dependencies.insert(id, dep); + } + + initial_direct_dependencies +} + +fn write_scratch_cargo_toml( + package_name: &str, + crates: &BTreeMap, +) -> (tempfile::TempDir, std::path::PathBuf) { + use cargo_util_schemas::manifest::{ + InheritableDependency, PackageName, TomlDependency, TomlDetailedDependency, TomlManifest, + }; + use std::fs; + + let scratch_dir = tempfile::tempdir().expect("Could not create scratch directory"); + let o = std::process::Command::new("cargo") + .arg("init") + .arg("--vcs=none") + .args(["--name", package_name]) + .arg(scratch_dir.path()) + .output() + .expect("Could not initialize scratch project"); + assert!(o.status.success(), "{}", String::from_utf8_lossy(&o.stderr)); + + let manifest_path = scratch_dir.path().join("Cargo.toml"); + + let manifest_content = fs::read(&manifest_path).expect("Could not read manifest"); + let mut manifest = ::toml::from_slice::(&manifest_content) + .expect("Could not deserialize manifest"); + + let deps = manifest.dependencies.get_or_insert_default(); + for (pkg_id, details) in crates { + let name = pkg_id.name(); + let version = pkg_id.version(); + + let name = PackageName::new(name.to_string()).expect("Package name invalid"); + + let dep = TomlDetailedDependency { + version: Some(version.to_string()), + features: Some(details.features.feature_strings()), + default_features: Some(details.features.uses_default_features), + + ..Default::default() + }; + + let version = InheritableDependency::Value(TomlDependency::Detailed(dep)); + deps.insert(name, version); + } + let manifest_content = ::toml::to_string(&manifest).expect("Could not serialize manifest"); + fs::write(&manifest_path, manifest_content).expect("Could not write manifest"); + + (scratch_dir, manifest_path) +} + +fn load_workspace<'ctx>( + global: &GlobalState<'ctx>, + manifest_path: &std::path::Path, +) -> cargo::core::Workspace<'ctx> { + let manifest = cargo::util::toml::read_manifest(manifest_path, global.crates_io, global.config) + .expect("Could not read the manifest"); + let cargo::core::EitherManifest::Real(manifest) = manifest else { + panic!("Only real manifests are supported") + }; + + let package = Package::new(manifest, manifest_path); + let target_dir = None; + let require_optional_deps = false; + cargo::core::Workspace::ephemeral(package, global.config, target_dir, require_optional_deps) + .expect("Could not construct a workspace") +} + +fn resolve_dependencies( + global: &GlobalState<'_>, + scratch_package_name: String, + ws: &cargo::core::Workspace<'_>, +) -> (resolver::Resolve, resolver::features::ResolvedFeatures) { + let dry_run = true; + let (pkg_set, resolve) = + cargo::ops::resolve_ws(ws, dry_run).expect("Could not resolve the workspace"); + + let requested_kinds = &[global.compile_kind]; + let mut target_data = cargo::core::compiler::RustcTargetData::new(ws, requested_kinds) + .expect("Could not construct target data"); + let cli_features = resolver::CliFeatures { + features: Default::default(), + all_features: false, + uses_default_features: true, + }; + let spec = cargo::core::PackageIdSpec::new(scratch_package_name); + let specs = &[spec]; + let requested_targets = &[]; + let opts = resolver::features::FeatureOpts::default(); + + let feature_resolve = resolver::features::FeatureResolver::resolve( + ws, + &mut target_data, + &resolve, + &pkg_set, + &cli_features, + specs, + requested_targets, + opts, + ) + .expect("Could not resolve features"); + + (resolve, feature_resolve) +} + +fn extend_direct_dependencies( + global: &mut GlobalState<'_>, + crates: &mut BTreeMap, +) { + let scratch_package_name = "top-crates-scratch-space".to_owned(); + + // Adds a direct dependency on each starting crate. + let (_scratch_dir, manifest_path) = write_scratch_cargo_toml(&scratch_package_name, crates); + + let ws = load_workspace(global, &manifest_path); + + // Resolve transitive dependencies. + let (resolve, feature_resolve) = resolve_dependencies(global, scratch_package_name, &ws); + + let root_package_names = ws + .members() + .flat_map(|member| member.dependencies().iter().map(|d| d.package_name())) + .collect::>(); + + let root_package_ids = resolve + .iter() + .filter(|pkg_id| root_package_names.contains(&pkg_id.name())) + .collect::>(); + + let mut visited = BTreeMap::new(); + let mut to_visit = root_package_ids; + + // Find all transitive dependencies that are compatible with the + // playground's platform and are activated (if optional). + while !to_visit.is_empty() { + let mut next_to_visit = BTreeSet::new(); + + for pkg_id in to_visit { + for (dep_pkg_id, deps) in resolve.deps(pkg_id) { + // Don't add excluded packages + if global + .modifications + .excluded(&dep_pkg_id.name(), dep_pkg_id.version()) + { + continue; + } + + // A package may depend on the same dependency + // multiple times. A key case for this is + // platform-specific dependencies. For example: + // + // ```toml + // [dependencies] + // jiff = { version = "0.2", optional = true, default-features = false, features = [ "std" ] } + // + // [target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies] + // jiff = { version = "0.2", optional = true, default-features = false, features = ["js"] } + // ``` + for dep in deps { + let dep_name = dep.name_in_toml(); + + let active = if dep.is_optional() { + feature_resolve.is_dep_activated( + pkg_id, + resolver::features::FeaturesFor::default(), + dep_name, + ) + } else { + true + }; + + if !active { + continue; + } + + let for_our_platform = dep.platform().is_none_or(|platform| { + platform.matches(PLAYGROUND_TARGET_PLATFORM, global.target_info.cfg()) + }); + + if !for_our_platform { + continue; + } + + let features = FeaturesLite { + features: dep.features().iter().cloned().collect(), + uses_default_features: dep.uses_default_features(), + }; + + match visited.entry(dep_pkg_id) { + Entry::Vacant(entry) => entry.insert(features), + Entry::Occupied(mut entry) => entry.get_mut().merge(features), + }; + + next_to_visit.insert(dep_pkg_id); + } + } + } + + to_visit = next_to_visit; + } + + let package_ids = visited.keys().cloned().collect::>(); + let packages = bulk_download(global, &package_ids); + + for download in packages { + let id = download.package_id(); + let lib_target = download + .library() + .unwrap_or_else(|| panic!("{} did not have a library", id)) + .clone(); + + let mut features = visited.remove(&id).unwrap_or_else(|| { + unreachable!("Downloaded a crate that we didn't visit"); + }); + + if let Some(metadata_features) = playground_metadata_features(&download) { + features.merge(metadata_features); + } + + let dep = ResolvedDep { + summary: download.summary().clone(), + lib_target, + features, + }; + + crates.insert(id, dep); + } +} + +pub async fn generate_info( + modifications: &Modifications, +) -> (BTreeMap, Vec) { + // Setup to interact with cargo. + let config = GlobalContext::default().expect("Unable to create default Cargo config"); + let _lock = config.acquire_package_cache_lock(CacheLockMode::DownloadExclusive); + let mut global = make_global_state(&config, modifications); + + let mut resolved_crates = populate_initial_direct_dependencies(&mut global).await; + + loop { + let num_crates_before = resolved_crates.len(); + extend_direct_dependencies(&mut global, &mut resolved_crates); + let num_crates_after = resolved_crates.len(); + if num_crates_before == num_crates_after { + break; + } + } + + let dependencies = generate_dependency_specs(&resolved_crates); + let infos = generate_crate_information(&dependencies); + (dependencies, infos) +} + +fn generate_dependency_specs( + crates: &BTreeMap, +) -> BTreeMap { + // Sort all packages by name then version (descending), so that + // when we group them we know we get all the same crates together + // and the newest version first. + let mut crates = crates.values().collect_vec(); + crates.sort_by(|a, b| { + let name_cmp = a.summary.name().as_str().cmp(b.summary.name().as_str()); + let version_cmp = a.summary.version().cmp(b.summary.version()); + name_cmp.then(version_cmp.reverse()) + }); + + let mut dependencies = BTreeMap::new(); + for (name, pkgs) in &crates.iter().chunk_by(|dep| dep.summary.name()) { + let mut first = true; + + for dep in pkgs { + let summary = &dep.summary; + let version = summary.version(); + + // We see the newest version first. Any subsequent + // versions will have their version appended so that they + // are uniquely named + let crate_name = dep.lib_target.crate_name(); + let exposed_name = if first { + crate_name + } else { + format!( + "{}_{}_{}_{}", + crate_name, version.major, version.minor, version.patch + ) + }; + + let features = dep.features.finalize(); + + dependencies.insert( + exposed_name, + DependencySpec { + package: name.to_string(), + version: version.clone(), + features: features.features, + default_features: features.uses_default_features, + }, + ); + + first = false; + } + } + + dependencies +} + +fn generate_crate_information( + dependencies: &BTreeMap, +) -> Vec { + let mut infos = Vec::new(); + + for (exposed_name, dependency_spec) in dependencies { + infos.push(CrateInformation { + name: dependency_spec.package.clone(), + version: dependency_spec.version.clone(), + id: exposed_name.clone(), + }); + } + + infos +} diff --git a/anneal/v1/playground/rust-anneal-playground/top-crates/src/main.rs b/anneal/v1/playground/rust-anneal-playground/top-crates/src/main.rs new file mode 100644 index 0000000000..d976221120 --- /dev/null +++ b/anneal/v1/playground/rust-anneal-playground/top-crates/src/main.rs @@ -0,0 +1,125 @@ +#![deny(rust_2018_idioms)] + +use rust_playground_top_crates::*; +use serde::Serialize; +use std::{ + collections::BTreeMap, + fs::{self, File}, + path::{Path, PathBuf}, +}; + +/// A Cargo.toml file. +#[derive(Serialize)] +#[serde(rename_all = "kebab-case")] +struct TomlManifest { + package: TomlPackage, + profile: Profiles, + dependencies: BTreeMap, + build_dependencies: BTreeMap, +} + +/// Header of Cargo.toml file. +#[derive(Serialize)] +struct TomlPackage { + name: String, + version: String, + authors: Vec, + resolver: String, +} + +/// Profile used for build dependencies (build scripts, proc macros, and their +/// dependencies). +#[derive(Serialize)] +#[serde(rename_all = "kebab-case")] +struct BuildOverride { + codegen_units: u32, + debug: bool, +} + +/// A profile section in a Cargo.toml file +#[derive(Serialize)] +#[serde(rename_all = "kebab-case")] +struct Profile { + codegen_units: u32, + incremental: bool, + build_override: BuildOverride, +} + +/// Available profile types +#[derive(Serialize)] +struct Profiles { + dev: Profile, + release: Profile, +} + +#[tokio::main(flavor = "current_thread")] +async fn main() { + let d = fs::read_to_string("crate-modifications.toml") + .expect("unable to read crate modifications file"); + + let modifications: Modifications = + toml::from_str(&d).expect("unable to parse crate modifications file"); + + let (dependencies, infos) = rust_playground_top_crates::generate_info(&modifications).await; + + // Construct playground's Cargo.toml. + let manifest = TomlManifest { + package: TomlPackage { + name: "playground".to_owned(), + version: "0.0.1".to_owned(), + authors: vec!["The Rust Playground".to_owned()], + resolver: "2".to_owned(), + }, + profile: Profiles { + dev: Profile { + codegen_units: 1, + incremental: false, + build_override: BuildOverride { + codegen_units: 1, + debug: true, + }, + }, + release: Profile { + codegen_units: 1, + incremental: false, + build_override: BuildOverride { + codegen_units: 1, + debug: false, + }, + }, + }, + dependencies: dependencies.clone(), + build_dependencies: dependencies, + }; + + // Write manifest file. + let base_directory: PathBuf = std::env::args_os() + .nth(1) + .unwrap_or_else(|| "../compiler/base".into()) + .into(); + + let cargo_toml = base_directory.join("Cargo.toml"); + write_manifest(manifest, &cargo_toml); + println!("wrote {}", cargo_toml.display()); + + let path = base_directory.join("crate-information.json"); + let mut f = File::create(&path) + .unwrap_or_else(|e| panic!("Unable to create {}: {}", path.display(), e)); + serde_json::to_writer_pretty(&mut f, &infos) + .unwrap_or_else(|e| panic!("Unable to write {}: {}", path.display(), e)); + println!("Wrote {}", path.display()); +} + +fn write_manifest(manifest: TomlManifest, path: impl AsRef) { + let content = toml::to_string(&manifest).expect("Couldn't serialize TOML"); + + let disclaimer = "# This file is automatically @generated by the top-crates script. +# Do not edit it manually. Any pull requests changing this file will likely be closed. +# See https://github.com/rust-lang/rust-playground/blob/main/CRATE_POLICY.md for details. +# +"; + + let content = disclaimer.to_string() + &content; + + fs::write(path, content).expect("Couldn't write Cargo.toml"); +}