From 067d822244adee0ffd107fa6de8cc63295effa12 Mon Sep 17 00:00:00 2001 From: Sienna Meridian Satterwhite Date: Tue, 10 Mar 2026 23:38:21 +0000 Subject: [PATCH] feat(training): add burn MLP and CART tree trainers with weight export Behind the `training` feature flag (burn 0.20 + ndarray + autodiff). Trains a single-hidden-layer MLP with Adam optimizer and weighted BCE loss, plus a CART decision tree using Gini impurity. Exports trained weights as Rust const arrays that compile directly into the binary. Signed-off-by: Sienna Meridian Satterwhite --- Cargo.lock | 4288 ++++++++++++++++++++++++++++++++- Cargo.toml | 15 + src/training/export.rs | 342 +++ src/training/mlp.rs | 113 + src/training/mod.rs | 5 + src/training/train_ddos.rs | 493 ++++ src/training/train_scanner.rs | 515 ++++ src/training/tree.rs | 409 ++++ 8 files changed, 6103 insertions(+), 77 deletions(-) create mode 100644 src/training/export.rs create mode 100644 src/training/mlp.rs create mode 100644 src/training/mod.rs create mode 100644 src/training/train_ddos.rs create mode 100644 src/training/train_scanner.rs create mode 100644 src/training/tree.rs diff --git a/Cargo.lock b/Cargo.lock index c39397f..8cccf71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,17 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures 0.2.17", +] + [[package]] name = "ahash" version = "0.8.12" @@ -51,6 +62,24 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" +[[package]] +name = "aligned" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685" +dependencies = [ + "as-slice", +] + +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -143,6 +172,12 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + [[package]] name = "arc-swap" version = "1.8.2" @@ -152,6 +187,17 @@ dependencies = [ "rustversion", ] +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -164,6 +210,24 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "as-slice" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "ash" +version = "0.38.0+1.3.281" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" +dependencies = [ + "libloading", +] + [[package]] name = "asn1-rs" version = "0.6.2" @@ -173,7 +237,7 @@ dependencies = [ "asn1-rs-derive", "asn1-rs-impl", "displaydoc", - "nom", + "nom 7.1.3", "num-traits", "rusticata-macros", "thiserror 1.0.69", @@ -215,6 +279,18 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + [[package]] name = "async-compat" version = "0.2.5" @@ -287,6 +363,12 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "atomic_float" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628d228f918ac3b82fe590352cc719d30664a0c13ca3a60266fe02c7132d480a" + [[package]] name = "attohttpc" version = "0.30.1" @@ -305,6 +387,49 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "av-scenechange" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394" +dependencies = [ + "aligned", + "anyhow", + "arg_enum_proc_macro", + "arrayvec", + "log", + "num-rational", + "num-traits", + "pastey", + "rayon", + "thiserror 2.0.18", + "v_frame", + "y4m", +] + +[[package]] +name = "av1-grain" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom 8.0.0", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d" +dependencies = [ + "arrayvec", +] + [[package]] name = "aws-lc-rs" version = "1.16.1" @@ -334,14 +459,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", - "axum-core", + "axum-core 0.4.5", "bytes", "futures-util", "http", "http-body", "http-body-util", "itoa", - "matchit", + "matchit 0.7.3", "memchr", "mime", "percent-encoding", @@ -354,6 +479,42 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" +dependencies = [ + "axum-core 0.5.6", + "base64", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit 0.8.4", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper", + "tokio", + "tokio-tungstenite", + "tower 0.5.3", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "axum-core" version = "0.4.5" @@ -374,6 +535,25 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "backon" version = "1.6.0" @@ -397,7 +577,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -427,6 +607,36 @@ dependencies = [ "serde", ] +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "serde", + "unty", +] + +[[package]] +name = "bindgen" +version = "0.71.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" +dependencies = [ + "bitflags 2.11.0", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 2.1.1", + "shlex", + "syn 2.0.117", +] + [[package]] name = "bit-set" version = "0.8.0" @@ -442,6 +652,12 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +[[package]] +name = "bit_field" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" + [[package]] name = "bitflags" version = "1.3.2" @@ -453,6 +669,18 @@ name = "bitflags" version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +dependencies = [ + "serde_core", +] + +[[package]] +name = "bitstream-io" +version = "4.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60d4bd9d1db2c6bdf285e223a7fa369d5ce98ec767dec949c6ca62863ce61757" +dependencies = [ + "core2", +] [[package]] name = "blake2" @@ -473,10 +701,16 @@ dependencies = [ "arrayvec", "cc", "cfg-if", - "constant_time_eq", - "cpufeatures", + "constant_time_eq 0.4.2", + "cpufeatures 0.2.17", ] +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + [[package]] name = "block-buffer" version = "0.10.4" @@ -536,33 +770,610 @@ dependencies = [ "serde", ] +[[package]] +name = "built" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64" + [[package]] name = "bumpalo" version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +[[package]] +name = "burn" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b78ff10ed98b73e1d477ea6e6e1ec1b9cf9f71a17afc3fea9f4dca482d43dcd4" +dependencies = [ + "burn-autodiff", + "burn-candle", + "burn-collective", + "burn-core", + "burn-cpu", + "burn-cuda", + "burn-ndarray", + "burn-nn", + "burn-optim", + "burn-remote", + "burn-rocm", + "burn-router", + "burn-store", + "burn-tch", + "burn-train", + "burn-wgpu", +] + +[[package]] +name = "burn-autodiff" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2f04955e9b4acd5e6a6229f80217dae79742975a97dc2253003f226333ad307" +dependencies = [ + "burn-backend", + "burn-std", + "derive-new", + "hashbrown 0.16.1", + "log", + "num-traits", + "parking_lot", + "portable-atomic", + "spin 0.10.0", + "tracing", +] + +[[package]] +name = "burn-backend" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a724a5d8d5865a1f6b304f629eb19f51489760689501c583b3e1f4209f067357" +dependencies = [ + "burn-std", + "bytemuck", + "cubecl", + "derive-new", + "hashbrown 0.16.1", + "num-traits", + "rand 0.9.2", + "rand_distr", + "serde", + "thiserror 2.0.18", +] + +[[package]] +name = "burn-candle" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21c752d5008923eb9299783da5edae3242b94afdb956e88d2b37b025244b5071" +dependencies = [ + "burn-backend", + "burn-std", + "candle-core", + "derive-new", +] + +[[package]] +name = "burn-collective" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd5b2199984291a0f3828d5ac04039fb864c56c3bdd9ee4172a63e457b668e4c" +dependencies = [ + "burn-communication", + "burn-std", + "burn-tensor", + "bytes", + "futures", + "log", + "rmp-serde", + "serde", + "tokio", + "tokio-util", +] + +[[package]] +name = "burn-communication" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585526cd672adc35918d8aea9bcb50669067904f36090caaffa9573d22fc7ade" +dependencies = [ + "axum 0.8.8", + "burn-std", + "burn-tensor", + "bytes", + "derive-new", + "futures", + "futures-util", + "log", + "rmp-serde", + "serde", + "serde_bytes", + "tokio", + "tokio-tungstenite", + "tokio-util", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "burn-core" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3634c3ba84397bcf2977ce746954d7e0a40e2d862e92362dd694c29e18df62" +dependencies = [ + "ahash", + "bincode 2.0.1", + "burn-dataset", + "burn-derive", + "burn-std", + "burn-tensor", + "data-encoding", + "derive-new", + "flate2", + "half", + "hashbrown 0.16.1", + "log", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rand 0.9.2", + "regex", + "rmp-serde", + "serde", + "serde_json", + "spin 0.10.0", + "uuid", +] + +[[package]] +name = "burn-cpu" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60aa53c4536719f1c91c250d4b4348daca473c44cf0c45b81096785f5510c192" +dependencies = [ + "burn-backend", + "burn-cubecl", + "burn-fusion", + "cubecl", +] + +[[package]] +name = "burn-cubecl" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d6d13aff03fec966da4300459688883f8a1d741dddbf19d1bfc2562656a9a9b" +dependencies = [ + "burn-backend", + "burn-cubecl-fusion", + "burn-fusion", + "burn-ir", + "burn-std", + "cubecl", + "cubek", + "derive-new", + "futures-lite", + "log", + "serde", + "text_placeholder", +] + +[[package]] +name = "burn-cubecl-fusion" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17d25b2e9fb805931401f79782aabd92462d65e60bc207035a3e554de8d7cd9f" +dependencies = [ + "burn-backend", + "burn-fusion", + "burn-ir", + "burn-std", + "cubecl", + "cubek", + "derive-new", + "serde", +] + +[[package]] +name = "burn-cuda" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d0c68cf653eb9c27dcbe046bb7b04cc18c6b33afda4c09317c102e6f4ae7cb6" +dependencies = [ + "burn-backend", + "burn-cubecl", + "burn-fusion", + "cubecl", +] + +[[package]] +name = "burn-dataset" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e87741e2ff9015845ed2b41b47f9e82795cf274bf2328a29619a2e6f662495c" +dependencies = [ + "csv", + "derive-new", + "dirs", + "gix-tempfile", + "image", + "r2d2", + "r2d2_sqlite", + "rand 0.9.2", + "rmp-serde", + "rusqlite", + "sanitize-filename", + "serde", + "serde_json", + "serde_rusqlite", + "strum 0.27.2", + "tempfile", + "thiserror 2.0.18", +] + +[[package]] +name = "burn-derive" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "102d7e2f705b0cda2f89dd0e55e9bbfc6184029929d53487beb606c3303b29a5" +dependencies = [ + "derive-new", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "burn-fusion" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea83d7f8574bcc07967291c5bb679ddc0a655c8db0642eca62755e2fffc8047" +dependencies = [ + "burn-backend", + "burn-ir", + "derive-new", + "hashbrown 0.16.1", + "log", + "serde", + "spin 0.10.0", + "tracing", +] + +[[package]] +name = "burn-ir" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd2b1b37a7289bd85438800deaaebde50507336429b80f96a71730794db5bc31" +dependencies = [ + "burn-backend", + "hashbrown 0.16.1", + "serde", +] + +[[package]] +name = "burn-ndarray" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96be578991cecef163e41a73bf985d8d7eb7fb8ef7bececf8d48523c481ecddf" +dependencies = [ + "atomic_float", + "burn-autodiff", + "burn-backend", + "burn-ir", + "burn-std", + "bytemuck", + "const-random", + "itertools 0.14.0", + "libm", + "macerator", + "matrixmultiply", + "ndarray 0.17.2", + "num-traits", + "paste", + "portable-atomic", + "portable-atomic-util", + "rand 0.9.2", + "rayon", + "seq-macro", +] + +[[package]] +name = "burn-nn" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b8c6c14b94e5b1dddd68f8e6d669f20bac8f99fcb2e4f1a480212d1b598133" +dependencies = [ + "burn-core", + "num-traits", +] + +[[package]] +name = "burn-optim" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a8c376d835d92ea363c05c6f48ac19bb687b683c7958c310a716ef8d5d77ba3" +dependencies = [ + "burn-core", + "derive-new", + "hashbrown 0.16.1", + "log", + "num-traits", + "serde", +] + +[[package]] +name = "burn-remote" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7238df1d59dcbb6880fe92ca0aa7b02b64d02394815e618da3d7933950bdaf39" +dependencies = [ + "async-channel", + "axum 0.8.8", + "burn-communication", + "burn-ir", + "burn-router", + "burn-std", + "burn-tensor", + "bytes", + "derive-new", + "futures-util", + "log", + "rmp-serde", + "serde", + "serde_bytes", + "tokio", + "tokio-tungstenite", + "tokio-util", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "burn-rocm" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73e2abda6ee63bdcb730f1a335349a9ff83f03048130d405b6ecdccd2df3ff23" +dependencies = [ + "burn-backend", + "burn-cubecl", + "burn-fusion", + "cubecl", +] + +[[package]] +name = "burn-router" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823ccb88484736a2861d53dc7f67db375ef050b0446bb02dd7cb8783ac6b69a2" +dependencies = [ + "burn-backend", + "burn-ir", + "burn-std", + "hashbrown 0.16.1", + "log", + "spin 0.10.0", +] + +[[package]] +name = "burn-std" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a9ed8e34a4a49d3754586f306075d6b55a5e08343ac75c06f47e7d9f825271" +dependencies = [ + "bytemuck", + "bytes", + "cubecl", + "cubecl-common", + "half", + "num-traits", + "serde", +] + +[[package]] +name = "burn-store" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be80a7b084a19901dc1d0a2e9b77e226c5c575879fe66de891c67062db41a6d" +dependencies = [ + "burn-core", + "burn-nn", + "burn-tensor", + "byteorder", + "bytes", + "half", + "hashbrown 0.16.1", + "memmap2", + "regex", + "safetensors 0.7.0", + "textdistance", +] + +[[package]] +name = "burn-tch" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061cd3df7b4126949561185454b9b67623f6885657361cad2a07a2340b3b3108" +dependencies = [ + "burn-backend", + "cc", + "libc", + "log", + "tch", + "torch-sys", +] + +[[package]] +name = "burn-tensor" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3720e52e00ed0155ced4f8681d0e8a362e699cee36494ec5b97ad44fcc5194c0" +dependencies = [ + "burn-backend", + "burn-std", + "colored", + "derive-new", + "num-traits", + "serde", +] + +[[package]] +name = "burn-train" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c3128c7571992c382a5ad057c72654c1048ea4dcf138d1f394313047e69803a" +dependencies = [ + "async-channel", + "burn-core", + "burn-ndarray", + "burn-optim", + "derive-new", + "log", + "nvml-wrapper", + "ratatui", + "rstest", + "serde", + "sysinfo 0.37.2", + "systemstat", + "thiserror 2.0.18", + "tracing-appender", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "burn-wgpu" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df78d62afc9b9fbb8ee4e49b72006485bb64f778a790e185a2d919479bcfc008" +dependencies = [ + "burn-backend", + "burn-cubecl", + "burn-fusion", + "cubecl", +] + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" dependencies = [ + "portable-atomic", "serde", ] +[[package]] +name = "bytesize" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e93abca9e28e0a1b9877922aacb20576e05d4679ffa78c3d6dc22a26a216659" + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "candle-core" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c15b675b80d994b2eadb20a4bbe434eabeb454eac3ee5e2b4cf6f147ee9be091" +dependencies = [ + "byteorder", + "float8 0.6.1", + "gemm", + "half", + "libm", + "memmap2", + "num-traits", + "num_cpus", + "rand 0.9.2", + "rand_distr", + "rayon", + "safetensors 0.7.0", + "thiserror 2.0.18", + "yoke", + "zip 7.2.0", +] + +[[package]] +name = "caseless" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6fd507454086c8edfd769ca6ada439193cdb209c7681712ef6275cccbfe5d8" +dependencies = [ + "unicode-normalization", +] + +[[package]] +name = "cassowary" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" + [[package]] name = "cast" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + [[package]] name = "cc" version = "1.2.56" @@ -581,6 +1392,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom 7.1.3", +] + [[package]] name = "cf-rustracing" version = "1.2.1" @@ -621,6 +1441,17 @@ 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.0", +] + [[package]] name = "chrono" version = "0.4.44" @@ -630,7 +1461,7 @@ dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -660,6 +1491,27 @@ dependencies = [ "half", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common 0.1.7", + "inout", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "4.5.60" @@ -718,12 +1570,38 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "codespan-reporting" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" +dependencies = [ + "serde", + "termcolor", + "unicode-width 0.2.0", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "colorchoice" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "colored" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "combine" version = "4.6.7" @@ -734,6 +1612,34 @@ dependencies = [ "memchr", ] +[[package]] +name = "compact_str" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "static_assertions", +] + +[[package]] +name = "comrak" +version = "0.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fefab951771fc3beeed0773ce66a4f7b706273fc6c4c95b08dd1615744abcf5" +dependencies = [ + "caseless", + "entities", + "memchr", + "slug", + "typed-arena", + "unicode_categories", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -749,12 +1655,53 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "constant_time_eq" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" +[[package]] +name = "constcat" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d3e02915a2cea4d74caa8681e2d44b1c3254bdbf17d11d41d587ff858832c" + +[[package]] +name = "convert_case" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "convert_case" version = "0.10.0" @@ -800,6 +1747,26 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.11.0", + "core-foundation 0.10.1", + "libc", +] + +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -809,6 +1776,15 @@ 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 = "crc32fast" version = "1.5.0" @@ -903,6 +1879,31 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crossterm" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" +dependencies = [ + "bitflags 2.11.0", + "crossterm_winapi", + "mio", + "parking_lot", + "rustix 0.38.44", + "signal-hook 0.3.18", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + [[package]] name = "crunchy" version = "0.2.4" @@ -928,6 +1929,451 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "csv" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde_core", +] + +[[package]] +name = "csv-core" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" +dependencies = [ + "memchr", +] + +[[package]] +name = "cubecl" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053856efd5436224775b9423d43d86f53d5b1d3af9a6b9983d9a313a0922638f" +dependencies = [ + "cubecl-core", + "cubecl-cpu", + "cubecl-cuda", + "cubecl-hip", + "cubecl-ir", + "cubecl-runtime", + "cubecl-std", + "cubecl-wgpu", + "half", +] + +[[package]] +name = "cubecl-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60bf8aaeb572c8cf2f2ffd07fa9bb1a2cf9336d1aa11ecd4d9a2f2e30c4be706" +dependencies = [ + "backtrace", + "bytemuck", + "bytes", + "cfg-if", + "cfg_aliases", + "derive-new", + "derive_more", + "dirs", + "embassy-futures", + "embassy-time", + "float4", + "float8 0.4.2", + "futures-lite", + "half", + "hashbrown 0.15.5", + "log", + "num-traits", + "parking_lot", + "portable-atomic", + "portable-atomic-util", + "rand 0.9.2", + "sanitize-filename", + "serde", + "serde_bytes", + "serde_json", + "spin 0.10.0", + "tracing", + "wasm-bindgen-futures", + "web-time", +] + +[[package]] +name = "cubecl-core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98374a31d2b68b55709891169832ccf205408c201c5e023964482441f213d0b9" +dependencies = [ + "bitflags 2.11.0", + "bytemuck", + "cubecl-common", + "cubecl-ir", + "cubecl-macros", + "cubecl-runtime", + "derive-new", + "derive_more", + "enumset", + "float-ord", + "half", + "hashbrown 0.15.5", + "log", + "num-traits", + "paste", + "serde", + "serde_json", + "tracing", + "variadics_please", +] + +[[package]] +name = "cubecl-cpp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb24d96c1ff84ab4def0a529e384311a15cb771310aaf2b640c312384c3bca23" +dependencies = [ + "bytemuck", + "cubecl-common", + "cubecl-core", + "cubecl-opt", + "cubecl-runtime", + "derive-new", + "half", + "itertools 0.14.0", + "log", +] + +[[package]] +name = "cubecl-cpu" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "152588a6e16b6bda5e8216af7a6fad3d7de4697294b6ce0f6acbe3a9029ff674" +dependencies = [ + "bytemuck", + "cubecl-common", + "cubecl-core", + "cubecl-opt", + "cubecl-runtime", + "cubecl-std", + "derive-new", + "half", + "log", + "paste", + "serde", + "sysinfo 0.36.1", + "tracel-llvm", + "tracel-llvm-bundler", +] + +[[package]] +name = "cubecl-cuda" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f74a5750c45090d1fc5ddf6a19fea9a099aa1f6800b78f1167a2d60182d1d96" +dependencies = [ + "bytemuck", + "cubecl-common", + "cubecl-core", + "cubecl-cpp", + "cubecl-runtime", + "cubecl-zspace", + "cudarc", + "derive-new", + "half", + "log", + "serde", + "tracing", +] + +[[package]] +name = "cubecl-hip" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbae9bc7ee6093d0d7a549c05873dff3478f9087b59eb09b223a97d642c849aa" +dependencies = [ + "bytemuck", + "cubecl-common", + "cubecl-core", + "cubecl-cpp", + "cubecl-hip-sys", + "cubecl-runtime", + "cubecl-zspace", + "derive-new", + "half", + "log", + "paste", + "serde", + "tracing", +] + +[[package]] +name = "cubecl-hip-sys" +version = "7.1.5280200" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcdd98f72d6f17836a0477bcd5ae5dd6b57a80fb62a3c0919f867a231f897f28" +dependencies = [ + "libc", + "regex", +] + +[[package]] +name = "cubecl-ir" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361b608ff9f05024c7a7e381852689acd95b6af5af956d68734692b27d5f75ef" +dependencies = [ + "cubecl-common", + "cubecl-macros-internal", + "derive-new", + "derive_more", + "enumset", + "float-ord", + "fnv", + "half", + "hashbrown 0.15.5", + "num-traits", + "portable-atomic", + "serde", + "variadics_please", +] + +[[package]] +name = "cubecl-macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c9a872d16207c6a27ed45942fd311a281394dd384b14a21f72131db1556a977" +dependencies = [ + "cubecl-common", + "darling 0.21.3", + "derive-new", + "ident_case", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "cubecl-macros-internal" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa3fa0626cdf28b9c49084c2bb51493bfde44378e22d90624aacaafb81da3588" +dependencies = [ + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "cubecl-opt" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdcff25fdcbd82ea4277c30a81e162722859f57c6ae105c0a3c53f8bb91154f6" +dependencies = [ + "cubecl-common", + "cubecl-core", + "cubecl-ir", + "float-ord", + "log", + "num", + "petgraph 0.6.5", + "smallvec", + "stable-vec", + "type-map", +] + +[[package]] +name = "cubecl-runtime" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b02e28997a8d75311afae4d2cea7b593eb125312f845874118a59d78c7a6b34c" +dependencies = [ + "async-channel", + "bytemuck", + "cfg-if", + "cfg_aliases", + "cubecl-common", + "cubecl-ir", + "derive-new", + "derive_more", + "dirs", + "enumset", + "foldhash 0.1.5", + "hashbrown 0.15.5", + "log", + "md5", + "serde", + "serde_json", + "spin 0.10.0", + "thiserror 2.0.18", + "toml 0.9.12+spec-1.1.0", + "tracing", + "variadics_please", + "wasm-bindgen-futures", + "web-time", +] + +[[package]] +name = "cubecl-std" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ff5741c98b7a7a5944b4afb0b67dd7f5e0be41ce7f303b587f8b0d6430b29b" +dependencies = [ + "cubecl-common", + "cubecl-core", + "cubecl-runtime", + "foldhash 0.1.5", + "half", + "num-traits", + "paste", + "serde", + "spin 0.10.0", + "variadics_please", +] + +[[package]] +name = "cubecl-wgpu" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29787364632fc7ec6a11cf3d95187f82f6fcce17d6bb4f0fb0dde580b837631d" +dependencies = [ + "async-channel", + "bytemuck", + "cfg-if", + "cfg_aliases", + "cubecl-common", + "cubecl-core", + "cubecl-ir", + "cubecl-runtime", + "derive-new", + "derive_more", + "half", + "hashbrown 0.15.5", + "log", + "sanitize-filename", + "tracing", + "wgpu", +] + +[[package]] +name = "cubecl-zspace" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a0f819071413b19a00b7105497e0f6d2cf3e7e9d65cbb8d4ecf1ddb29c61dc2" + +[[package]] +name = "cubek" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb1cce47db02017925301bedec92ae84628493df3f9761ea7ac42a60c6146f8" +dependencies = [ + "cubecl", + "cubek-attention", + "cubek-convolution", + "cubek-matmul", + "cubek-quant", + "cubek-random", + "cubek-reduce", +] + +[[package]] +name = "cubek-attention" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7278bd122b2428af479f9af05285160613733c33c93b63ab3c6d25cd0460c18b" +dependencies = [ + "bytemuck", + "cubecl", + "cubecl-common", + "cubek-matmul", + "cubek-random", + "half", + "serde", +] + +[[package]] +name = "cubek-convolution" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18eb04bca4ae104d62a56def04b04f3d079c42fe49aac62202c96876f90fa28b" +dependencies = [ + "bytemuck", + "cubecl", + "cubecl-common", + "cubek-matmul", + "derive-new", + "enumset", + "half", + "serde", +] + +[[package]] +name = "cubek-matmul" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28f3b04b113760e97c65a8a4dca9afc220744031eeecd5ad6cd0e3be91ba3a9" +dependencies = [ + "bytemuck", + "cubecl", + "cubecl-common", + "half", + "serde", +] + +[[package]] +name = "cubek-quant" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ec3ae04af324df2d615c2b394e270d58d6f08cb833d67633e2ba794de75916" +dependencies = [ + "cubecl", + "cubecl-common", + "half", + "serde", +] + +[[package]] +name = "cubek-random" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65a34844d8b7f739185c1d24896137dcb73f458830444103b45f678585ad983e" +dependencies = [ + "cubecl", + "cubecl-common", + "half", + "num-traits", + "rand 0.9.2", + "serde", +] + +[[package]] +name = "cubek-reduce" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42397d9ed85bb3084dfb56ed26de75690b5b07caf42a32f4006b57eb23d5b6d6" +dependencies = [ + "cubecl", + "half", + "num-traits", + "serde", + "thiserror 2.0.18", +] + +[[package]] +name = "cudarc" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aa12038120eb13347a6ae2ffab1d34efe78150125108627fd85044dd4d6ff1e" +dependencies = [ + "libloading", +] + [[package]] name = "curve25519-dalek" version = "5.0.0-pre.1" @@ -935,7 +2381,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f9200d1d13637f15a6acb71e758f64624048d85b31a5fdbfd8eca1e2687d0b7" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "curve25519-dalek-derive", "digest 0.11.0-rc.10", "fiat-crypto", @@ -972,7 +2418,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70def8d72740e44d9f676d8dab2c933a236663d86dd24319b57a2bed4d694774" dependencies = [ - "petgraph", + "petgraph 0.7.1", ] [[package]] @@ -981,8 +2427,28 @@ version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", ] [[package]] @@ -999,17 +2465,80 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", +] + [[package]] name = "darling_macro" version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ - "darling_core", + "darling_core 0.20.11", "quote", "syn 2.0.117", ] +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core 0.23.0", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "data-encoding" version = "2.10.0" @@ -1035,7 +2564,7 @@ checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" dependencies = [ "asn1-rs", "displaydoc", - "nom", + "nom 7.1.3", "num-bigint", "num-traits", "rusticata-macros", @@ -1061,6 +2590,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive-new" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "derive_builder" version = "0.20.2" @@ -1076,7 +2616,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ - "darling", + "darling 0.20.11", "proc-macro2", "quote", "syn 2.0.117", @@ -1107,7 +2647,7 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ - "convert_case", + "convert_case 0.10.0", "proc-macro2", "quote", "rustc_version", @@ -1115,6 +2655,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "deunicode" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04" + [[package]] name = "diatomic-waker" version = "0.2.3" @@ -1143,6 +2689,27 @@ dependencies = [ "crypto-common 0.2.1", ] +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + [[package]] name = "dispatch2" version = "0.3.1" @@ -1210,6 +2777,22 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "dyn-stack" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c4713e43e2886ba72b8271aa66c93d722116acf7a75555cce11dcde84388fe8" +dependencies = [ + "bytemuck", + "dyn-stack-macros", +] + +[[package]] +name = "dyn-stack-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d926b4d407d372f141f93bb444696142c29d32962ccbd3531117cf3aa0bfa9" + [[package]] name = "ed25519" version = "3.0.0-rc.4" @@ -1255,6 +2838,62 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "embassy-futures" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01" + +[[package]] +name = "embassy-time" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f820157f198ada183ad62e0a66f554c610cdcd1a9f27d4b316358103ced7a1f8" +dependencies = [ + "cfg-if", + "critical-section", + "document-features", + "embassy-time-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "futures-util", +] + +[[package]] +name = "embassy-time-driver" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6" +dependencies = [ + "document-features", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + [[package]] name = "embedded-io" version = "0.4.0" @@ -1267,6 +2906,12 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" +[[package]] +name = "entities" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" + [[package]] name = "enum-as-inner" version = "0.6.1" @@ -1310,6 +2955,48 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "enumset" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b07a8dfbbbfc0064c0a6bdf9edcf966de6b1c33ce344bdeca3b41615452634" +dependencies = [ + "enumset_derive", + "serde", +] + +[[package]] +name = "enumset_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43e744e4ea338060faee68ed933e46e722fb7f3617e722a5772d7e856d8b3ce" +dependencies = [ + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1347,6 +3034,33 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "exr" +version = "1.74.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[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 = "fastbloom" version = "0.14.1" @@ -1365,18 +3079,64 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fax" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" +dependencies = [ + "fax_derive", +] + +[[package]] +name = "fax_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + [[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.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" +dependencies = [ + "cfg-if", + "libc", + "libredox", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "fixedbitset" version = "0.5.7" @@ -1394,6 +3154,39 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float-ord" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d" + +[[package]] +name = "float4" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5939bac0ef2ad7c83a53e4fb889c1d81f007b07061d648cd271071984d86f257" + +[[package]] +name = "float8" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4203231de188ebbdfb85c11f3c20ca2b063945710de04e7b59268731e728b462" +dependencies = [ + "half", +] + +[[package]] +name = "float8" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719a903cc23e4a89e87962c2a80fdb45cdaad0983a89bd150bb57b4c8571a7d5" +dependencies = [ + "half", + "num-traits", + "rand 0.9.2", + "rand_distr", +] + [[package]] name = "fnntw" version = "0.4.1" @@ -1429,6 +3222,33 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -1488,7 +3308,7 @@ version = "7.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "175cd8cca9e1d45b87f18ffa75088f2099e3c4fe5e2f83e42de112560bea8ea6" dependencies = [ - "fixedbitset", + "fixedbitset 0.5.7", "futures-core", "futures-lite", "pin-project", @@ -1554,6 +3374,12 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + [[package]] name = "futures-util" version = "0.3.32" @@ -1571,6 +3397,125 @@ dependencies = [ "slab", ] +[[package]] +name = "gemm" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa0673db364b12263d103b68337a68fbecc541d6f6b61ba72fe438654709eacb" +dependencies = [ + "dyn-stack", + "gemm-c32", + "gemm-c64", + "gemm-common", + "gemm-f16", + "gemm-f32", + "gemm-f64", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "seq-macro", +] + +[[package]] +name = "gemm-c32" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "086936dbdcb99e37aad81d320f98f670e53c1e55a98bee70573e83f95beb128c" +dependencies = [ + "dyn-stack", + "gemm-common", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "seq-macro", +] + +[[package]] +name = "gemm-c64" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c8aeeeec425959bda4d9827664029ba1501a90a0d1e6228e48bef741db3a3f" +dependencies = [ + "dyn-stack", + "gemm-common", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "seq-macro", +] + +[[package]] +name = "gemm-common" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88027625910cc9b1085aaaa1c4bc46bb3a36aad323452b33c25b5e4e7c8e2a3e" +dependencies = [ + "bytemuck", + "dyn-stack", + "half", + "libm", + "num-complex", + "num-traits", + "once_cell", + "paste", + "pulp", + "raw-cpuid", + "rayon", + "seq-macro", + "sysctl", +] + +[[package]] +name = "gemm-f16" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3df7a55202e6cd6739d82ae3399c8e0c7e1402859b30e4cb780e61525d9486e" +dependencies = [ + "dyn-stack", + "gemm-common", + "gemm-f32", + "half", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "rayon", + "seq-macro", +] + +[[package]] +name = "gemm-f32" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e0b8c9da1fbec6e3e3ab2ce6bc259ef18eb5f6f0d3e4edf54b75f9fd41a81c" +dependencies = [ + "dyn-stack", + "gemm-common", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "seq-macro", +] + +[[package]] +name = "gemm-f64" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "056131e8f2a521bfab322f804ccd652520c79700d81209e9d9275bbdecaadc6a" +dependencies = [ + "dyn-stack", + "gemm-common", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "seq-macro", +] + [[package]] name = "generator" version = "0.8.8" @@ -1582,8 +3527,8 @@ dependencies = [ "libc", "log", "rustversion", - "windows-link", - "windows-result", + "windows-link 0.2.1", + "windows-result 0.4.1", ] [[package]] @@ -1633,6 +3578,7 @@ dependencies = [ "js-sys", "libc", "r-efi 6.0.0", + "rand_core 0.10.0", "wasip2", "wasip3", "wasm-bindgen", @@ -1650,12 +3596,111 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "gif" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5df2ba84018d80c213569363bdcd0c64e6933c67fe4c1d60ecf822971a3c35e" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "gimli" version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +[[package]] +name = "gix-features" +version = "0.45.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56aad357ae016449434705033df644ac6253dfcf1281aad3af3af9e907560d1" +dependencies = [ + "gix-trace", + "gix-utils", + "libc", +] + +[[package]] +name = "gix-fs" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "785b9c499e46bc78d7b81c148c21b3fca18655379ee729a856ed19ce50d359ec" +dependencies = [ + "bstr", + "fastrand", + "gix-features", + "gix-path", + "gix-utils", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-path" +version = "0.10.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cb06c3e4f8eed6e24fd915fa93145e28a511f4ea0e768bae16673e05ed3f366" +dependencies = [ + "bstr", + "gix-trace", + "gix-validate", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-tempfile" +version = "20.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad89218e74850f42d364ed3877c7291f0474c8533502df91bb877ecc5cb0dd40" +dependencies = [ + "dashmap", + "gix-fs", + "libc", + "parking_lot", + "signal-hook 0.4.3", + "signal-hook-registry", + "tempfile", +] + +[[package]] +name = "gix-trace" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f69a13643b8437d4ca6845e08143e847a36ca82903eed13303475d0ae8b162e0" + +[[package]] +name = "gix-utils" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "befcdbdfb1238d2854591f760a48711bed85e72d80a10e8f2f93f656746ef7c5" +dependencies = [ + "fastrand", + "unicode-normalization", +] + +[[package]] +name = "gix-validate" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b1e63a5b516e970a594f870ed4571a8fdcb8a344e7bd407a20db8bd61dbfde4" +dependencies = [ + "bstr", + "thiserror 2.0.18", +] + +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + [[package]] name = "glob" version = "0.3.3" @@ -1674,6 +3719,78 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "glow" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "gpu-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +dependencies = [ + "bitflags 2.11.0", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "gpu-allocator" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" +dependencies = [ + "log", + "presser", + "thiserror 1.0.69", + "windows 0.58.0", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" +dependencies = [ + "bitflags 2.11.0", + "gpu-descriptor-types", + "hashbrown 0.15.5", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.11.0", +] + [[package]] name = "h2" version = "0.4.13" @@ -1699,8 +3816,13 @@ version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ + "bytemuck", "cfg-if", "crunchy", + "num-traits", + "rand 0.9.2", + "rand_distr", + "serde", "zerocopy", ] @@ -1719,13 +3841,31 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[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 = [ + "allocator-api2", + "equivalent", "foldhash 0.1.5", + "serde", ] [[package]] @@ -1737,6 +3877,17 @@ dependencies = [ "allocator-api2", "equivalent", "foldhash 0.2.0", + "serde", + "serde_core", +] + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", ] [[package]] @@ -1777,6 +3928,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + [[package]] name = "hickory-proto" version = "0.25.2" @@ -1830,6 +3987,15 @@ dependencies = [ "tracing", ] +[[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 = "hostname" version = "0.4.2" @@ -1838,7 +4004,7 @@ checksum = "617aaa3557aef3810a6369d0a99fac8a080891b68bd9f9812a1eeda0c0730cbd" dependencies = [ "cfg-if", "libc", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -1934,7 +4100,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots", + "webpki-roots 1.0.6", ] [[package]] @@ -1985,7 +4151,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.62.2", ] [[package]] @@ -2138,6 +4304,46 @@ dependencies = [ "xmltree", ] +[[package]] +name = "image" +version = "0.25.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "moxcms", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core 0.5.1", + "zune-jpeg 0.5.12", +] + +[[package]] +name = "image-webp" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" +dependencies = [ + "byteorder-lite", + "quick-error 2.0.1", +] + +[[package]] +name = "imgref" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8" + [[package]] name = "indexmap" version = "1.9.3" @@ -2160,6 +4366,48 @@ dependencies = [ "serde_core", ] +[[package]] +name = "indoc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "instability" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357b7205c6cd18dd2c86ed312d1e70add149aea98e7ef72b9fdf0270e555c11d" +dependencies = [ + "darling 0.23.0", + "indoc", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "ipconfig" version = "0.3.2" @@ -2223,7 +4471,7 @@ dependencies = [ "portmapper", "rand 0.9.2", "reqwest 0.12.28", - "rustc-hash", + "rustc-hash 2.1.1", "rustls", "rustls-pki-types", "rustls-webpki", @@ -2238,7 +4486,7 @@ dependencies = [ "tracing", "url", "wasm-bindgen-futures", - "webpki-roots", + "webpki-roots 1.0.6", ] [[package]] @@ -2329,7 +4577,7 @@ dependencies = [ "iroh-quinn-proto", "iroh-quinn-udp", "pin-project-lite", - "rustc-hash", + "rustc-hash 2.1.1", "rustls", "socket2 0.6.3", "thiserror 2.0.18", @@ -2354,7 +4602,7 @@ dependencies = [ "lru-slab", "rand 0.9.2", "ring", - "rustc-hash", + "rustc-hash 2.1.1", "rustls", "rustls-pki-types", "slab", @@ -2399,7 +4647,7 @@ dependencies = [ "iroh-metrics", "iroh-quinn", "iroh-quinn-proto", - "lru", + "lru 0.16.3", "n0-error", "n0-future", "num_enum", @@ -2420,7 +4668,7 @@ dependencies = [ "tracing", "url", "vergen-gitcl", - "webpki-roots", + "webpki-roots 1.0.6", "ws_stream_wasm", "z32", ] @@ -2478,6 +4726,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -2606,6 +4863,23 @@ dependencies = [ "serde_json", ] +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading", + "pkg-config", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + [[package]] name = "kube" version = "3.0.1" @@ -2710,18 +4984,88 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" +[[package]] +name = "lebe" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" + [[package]] name = "libc" version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +[[package]] +name = "libfuzzer-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link 0.2.1", +] + +[[package]] +name = "liblzma" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6033b77c21d1f56deeae8014eb9fbe7bdf1765185a6c508b5ca82eeaed7f899" +dependencies = [ + "liblzma-sys", + "num_cpus", +] + +[[package]] +name = "liblzma-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f2db66f3268487b5033077f266da6777d057949b8f93c8ad82e441df25e6186" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "libm" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" +[[package]] +name = "libredox" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" +dependencies = [ + "bitflags 2.11.0", + "libc", + "plain", + "redox_syscall 0.7.3", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "libz-ng-sys" version = "1.1.24" @@ -2741,6 +5085,12 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -2798,6 +5148,24 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.5", +] + [[package]] name = "lru" version = "0.16.3" @@ -2819,6 +5187,43 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3d25b0e0b648a86960ac23b7ad4abb9717601dec6f66c165f5b037f3f03065f" +[[package]] +name = "macerator" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84b0b2dbe8b22f9e96ba12e29964889010117f92e6bd006010887320ae58e2f0" +dependencies = [ + "bytemuck", + "cfg_aliases", + "half", + "macerator-macros", + "moddef", + "num-traits", + "paste", + "rustc_version", +] + +[[package]] +name = "macerator-macros" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ee1819976b67f4d782390c55a75c13401c7a988517f7f8e60a33484dc2e00a" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + [[package]] name = "matchers" version = "0.2.0" @@ -2834,12 +5239,57 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "num_cpus", + "once_cell", + "rawpointer", + "thread-tree", +] + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + +[[package]] +name = "md5" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0" + [[package]] name = "memchr" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", + "stable_deref_trait", +] + [[package]] name = "memoffset" version = "0.6.5" @@ -2849,6 +5299,21 @@ dependencies = [ "autocfg", ] +[[package]] +name = "metal" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00c15a6f673ff72ddcc22394663290f870fb224c1bfce55734a75c414150e605" +dependencies = [ + "bitflags 2.11.0", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", + "paste", +] + [[package]] name = "mime" version = "0.3.17" @@ -2878,10 +5343,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", + "log", "wasi", "windows-sys 0.61.2", ] +[[package]] +name = "moddef" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0b3262dc837d2513fe2ef31ff8461352ef932dcca31ba0c0abe33547cf6b9b" + [[package]] name = "moka" version = "0.12.14" @@ -2899,6 +5371,16 @@ dependencies = [ "uuid", ] +[[package]] +name = "moxcms" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" +dependencies = [ + "num-traits", + "pxfm", +] + [[package]] name = "n0-error" version = "0.1.3" @@ -2953,6 +5435,87 @@ dependencies = [ "n0-future", ] +[[package]] +name = "naga" +version = "26.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916cbc7cb27db60be930a4e2da243cf4bc39569195f22fd8ee419cd31d5b662c" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags 2.11.0", + "cfg-if", + "cfg_aliases", + "codespan-reporting", + "half", + "hashbrown 0.15.5", + "hexf-parse", + "indexmap 2.13.0", + "libm", + "log", + "num-traits", + "once_cell", + "rustc-hash 1.1.0", + "spirv", + "thiserror 2.0.18", + "unicode-ident", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "ndarray" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", +] + +[[package]] +name = "ndarray" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520080814a7a6b4a6e9070823bb24b4531daac8c4627e08ba5de8c5ef2f2752d" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", + "rayon", +] + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + [[package]] name = "neli" version = "0.7.4" @@ -3095,11 +5658,17 @@ dependencies = [ "tokio-util", "tracing", "web-sys", - "windows", - "windows-result", + "windows 0.62.2", + "windows-result 0.4.1", "wmi", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + [[package]] name = "nix" version = "0.24.3" @@ -3128,6 +5697,30 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "ntapi" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae" +dependencies = [ + "winapi", +] + [[package]] name = "ntimestamp" version = "1.0.0" @@ -3152,6 +5745,20 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -3162,12 +5769,33 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "bytemuck", + "num-traits", +] + [[package]] name = "num-conv" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "num-format" version = "0.4.4" @@ -3187,6 +5815,28 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -3194,6 +5844,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", ] [[package]] @@ -3227,6 +5888,38 @@ dependencies = [ "libc", ] +[[package]] +name = "nvml-wrapper" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d5c6c0ef9702176a570f06ad94f3198bc29c524c8b498f1b9346e1b1bdcbb3a" +dependencies = [ + "bitflags 2.11.0", + "libloading", + "nvml-wrapper-sys", + "static_assertions", + "thiserror 1.0.69", + "wrapcenum-derive", +] + +[[package]] +name = "nvml-wrapper-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd23dbe2eb8d8335d2bce0299e0a07d6a63c089243d626ca75b770a962ff49e6" +dependencies = [ + "libloading", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + [[package]] name = "objc2" version = "0.6.4" @@ -3255,6 +5948,16 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" +[[package]] +name = "objc2-io-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" +dependencies = [ + "libc", + "objc2-core-foundation", +] + [[package]] name = "objc2-security" version = "0.3.2" @@ -3413,6 +6116,12 @@ dependencies = [ "tracing", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "ordered-float" version = "2.10.1" @@ -3512,9 +6221,20 @@ checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.18", "smallvec", - "windows-link", + "windows-link 0.2.1", +] + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", ] [[package]] @@ -3523,6 +6243,24 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pastey" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", + "hmac", + "password-hash", + "sha2 0.10.9", +] + [[package]] name = "pem" version = "3.0.6" @@ -3597,13 +6335,23 @@ dependencies = [ "sha2 0.10.9", ] +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset 0.4.2", + "indexmap 2.13.0", +] + [[package]] name = "petgraph" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ - "fixedbitset", + "fixedbitset 0.5.7", "indexmap 2.13.0", ] @@ -3682,7 +6430,7 @@ dependencies = [ "httpdate", "indexmap 1.9.3", "log", - "lru", + "lru 0.16.3", "once_cell", "parking_lot", "pingora-core", @@ -3751,7 +6499,7 @@ dependencies = [ "unicase", "windows-sys 0.59.0", "x509-parser", - "zstd", + "zstd 0.13.3", ] [[package]] @@ -3772,8 +6520,8 @@ dependencies = [ "pingora-error", "pingora-http", "thread_local", - "zstd", - "zstd-safe", + "zstd 0.13.3", + "zstd-safe 7.2.4", ] [[package]] @@ -3838,7 +6586,7 @@ checksum = "67f034be36772f318370d058913db43dbd22c3763ad974c995ba2e4afb2bb52a" dependencies = [ "crossbeam-queue", "log", - "lru", + "lru 0.16.3", "parking_lot", "pingora-timeout", "thread_local", @@ -3927,7 +6675,7 @@ dependencies = [ "futures-lite", "getrandom 0.4.2", "log", - "lru", + "lru 0.16.3", "ntimestamp", "reqwest 0.13.2", "self_cell", @@ -3957,6 +6705,12 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "plist" version = "1.8.0" @@ -3998,11 +6752,27 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.11.0", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "portable-atomic" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +dependencies = [ + "serde", +] [[package]] name = "portable-atomic-util" @@ -4092,6 +6862,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + [[package]] name = "prettyplease" version = "0.2.37" @@ -4179,6 +6955,25 @@ dependencies = [ "yansi", ] +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" +dependencies = [ + "quote", + "syn 2.0.117", +] + [[package]] name = "prometheus" version = "0.13.4" @@ -4242,12 +7037,56 @@ version = "2.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" +[[package]] +name = "pulp" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e205bb30d5b916c55e584c22201771bcf2bad9aabd5d4127f38387140c38632" +dependencies = [ + "bytemuck", + "cfg-if", + "libm", + "num-complex", + "paste", + "pulp-wasm-simd-flag", + "raw-cpuid", + "reborrow", + "version_check", +] + +[[package]] +name = "pulp-wasm-simd-flag" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40e24eee682d89fb193496edf918a7f407d30175b2e785fe057e4392dfd182e0" + +[[package]] +name = "pxfm" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quick-xml" version = "0.38.4" @@ -4268,7 +7107,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", + "rustc-hash 2.1.1", "rustls", "socket2 0.6.3", "thiserror 2.0.18", @@ -4289,7 +7128,7 @@ dependencies = [ "lru-slab", "rand 0.9.2", "ring", - "rustc-hash", + "rustc-hash 2.1.1", "rustls", "rustls-pki-types", "slab", @@ -4334,6 +7173,28 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "r2d2" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +dependencies = [ + "log", + "parking_lot", + "scheduled-thread-pool", +] + +[[package]] +name = "r2d2_sqlite" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63417e83dc891797eea3ad379f52a5986da4bca0d6ef28baf4d14034dd111b0c" +dependencies = [ + "r2d2", + "rusqlite", + "uuid", +] + [[package]] name = "rand" version = "0.8.5" @@ -4355,6 +7216,17 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +dependencies = [ + "chacha20", + "getrandom 0.4.2", + "rand_core 0.10.0", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -4393,6 +7265,22 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" + +[[package]] +name = "rand_distr" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" +dependencies = [ + "num-traits", + "rand 0.9.2", +] + [[package]] name = "rand_xorshift" version = "0.4.0" @@ -4402,6 +7290,105 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "range-alloc" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca45419789ae5a7899559e9512e58ca889e41f04f1f2445e9f4b290ceccd1d08" + +[[package]] +name = "ratatui" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" +dependencies = [ + "bitflags 2.11.0", + "cassowary", + "compact_str", + "crossterm", + "indoc", + "instability", + "itertools 0.13.0", + "lru 0.12.5", + "paste", + "strum 0.26.3", + "time", + "unicode-segmentation", + "unicode-truncate", + "unicode-width 0.2.0", +] + +[[package]] +name = "rav1e" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b" +dependencies = [ + "aligned-vec", + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av-scenechange", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.14.0", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "paste", + "profiling", + "rand 0.9.2", + "rand_chacha 0.9.0", + "simd_helpers", + "thiserror 2.0.18", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef69c1990ceef18a116855938e74793a5f7496ee907562bd0857b6ac734ab285" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error 2.0.1", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" version = "1.11.0" @@ -4422,6 +7409,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "reborrow" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" + [[package]] name = "redox_syscall" version = "0.5.18" @@ -4431,6 +7424,26 @@ dependencies = [ "bitflags 2.11.0", ] +[[package]] +name = "redox_syscall" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.18", +] + [[package]] name = "regex" version = "1.12.3" @@ -4460,6 +7473,18 @@ version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + +[[package]] +name = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + [[package]] name = "reqwest" version = "0.12.28" @@ -4471,6 +7496,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", + "h2", "http", "http-body", "http-body-util", @@ -4499,7 +7525,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots", + "webpki-roots 1.0.6", ] [[package]] @@ -4543,6 +7569,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" +[[package]] +name = "rgb" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" + [[package]] name = "ring" version = "0.17.14" @@ -4576,6 +7608,49 @@ dependencies = [ "serde", ] +[[package]] +name = "rstest" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5a3193c063baaa2a95a33f03035c8a72b83d97a54916055ba22d35ed3839d49" +dependencies = [ + "futures-timer", + "futures-util", + "rstest_macros", +] + +[[package]] +name = "rstest_macros" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c845311f0ff7951c5506121a9ad75aec44d083c31583b2ea5a30bcb0b0abba0" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version", + "syn 2.0.117", + "unicode-ident", +] + +[[package]] +name = "rusqlite" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f" +dependencies = [ + "bitflags 2.11.0", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + [[package]] name = "rust_decimal" version = "1.40.0" @@ -4592,6 +7667,12 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc-hash" version = "2.1.1" @@ -4613,7 +7694,20 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" dependencies = [ - "nom", + "nom 7.1.3", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.11.0", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", ] [[package]] @@ -4625,7 +7719,7 @@ dependencies = [ "bitflags 2.11.0", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.12.1", "windows-sys 0.61.2", ] @@ -4741,7 +7835,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" dependencies = [ "fnv", - "quick-error", + "quick-error 1.2.3", "tempfile", "wait-timeout", ] @@ -4752,6 +7846,27 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +[[package]] +name = "safetensors" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93279b86b3de76f820a8854dd06cbc33cfa57a417b19c47f6a25280112fb1df" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "safetensors" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "675656c1eabb620b921efea4f9199f97fc86e36dd6ffd1fbbe48d0f59a4987f5" +dependencies = [ + "hashbrown 0.16.1", + "serde", + "serde_json", +] + [[package]] name = "same-file" version = "1.0.6" @@ -4761,6 +7876,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "sanitize-filename" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc984f4f9ceb736a7bb755c3e3bd17dc56370af2600c9780dcc48c66453da34d" +dependencies = [ + "regex", +] + [[package]] name = "schannel" version = "0.1.28" @@ -4770,6 +7894,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "scheduled-thread-pool" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" +dependencies = [ + "parking_lot", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -4855,6 +7988,12 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" +[[package]] +name = "seq-macro" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" + [[package]] name = "serde" version = "1.0.228" @@ -4918,6 +8057,27 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_rusqlite" +version = "0.40.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8bd74f47e124e760475a7e863b5820dcef09cae50782d03d65961f5ca1e6d9" +dependencies = [ + "rusqlite", + "serde_core", +] + [[package]] name = "serde_spanned" version = "0.6.9" @@ -4927,6 +8087,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +dependencies = [ + "serde_core", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -4963,6 +8132,17 @@ dependencies = [ "rust_decimal", ] +[[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_smol" version = "1.0.1" @@ -4976,7 +8156,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -4987,7 +8167,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1e3878ab0f98e35b2df35fe53201d088299b41a6bb63e3e34dada2ac4abd924" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.11.0-rc.10", ] @@ -5006,6 +8186,37 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b57709da74f9ff9f4a27dce9526eec25ca8407c45a7887243b031a58935fb8e" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" +dependencies = [ + "libc", + "mio", + "signal-hook 0.3.18", +] + [[package]] name = "signal-hook-registry" version = "1.4.8" @@ -5028,6 +8239,15 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + [[package]] name = "simdutf8" version = "0.1.5" @@ -5055,6 +8275,25 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + +[[package]] +name = "slug" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724" +dependencies = [ + "deunicode", + "wasm-bindgen", +] + [[package]] name = "smallvec" version = "1.15.1" @@ -5112,6 +8351,19 @@ name = "spin" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "lock_api", + "portable-atomic", +] + +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.11.0", +] [[package]] name = "spki" @@ -5123,6 +8375,12 @@ dependencies = [ "der", ] +[[package]] +name = "stable-vec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dac7bc0f7d0d44329b200020effbc25a534d89fa142af95e3ddf76113412a5e" + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -5197,11 +8455,13 @@ dependencies = [ "anyhow", "arc-swap", "async-trait", - "bincode", + "bincode 1.3.3", "blake3", + "burn", "bytes", "clap", "criterion", + "csv", "dns-lookup", "fnntw", "futures", @@ -5224,15 +8484,16 @@ dependencies = [ "prometheus", "proptest", "rand 0.9.2", + "rayon", "regex", "reqwest 0.12.28", - "rustc-hash", + "rustc-hash 2.1.1", "rustls", "serde", "serde_json", "tempfile", "tokio", - "toml", + "toml 0.8.23", "tracing", "tracing-opentelemetry", "tracing-subscriber", @@ -5287,12 +8548,96 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "sysctl" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01198a2debb237c62b6826ec7081082d951f46dbb64b0e8c7649a452230d1dfc" +dependencies = [ + "bitflags 2.11.0", + "byteorder", + "enum-as-inner", + "libc", + "thiserror 1.0.69", + "walkdir", +] + +[[package]] +name = "sysinfo" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252800745060e7b9ffb7b2badbd8b31cfa4aa2e61af879d0a3bf2a317c20217d" +dependencies = [ + "libc", + "memchr", + "ntapi", + "objc2-core-foundation", + "objc2-io-kit", + "windows 0.61.3", +] + +[[package]] +name = "sysinfo" +version = "0.37.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16607d5caffd1c07ce073528f9ed972d88db15dd44023fa57142963be3feb11f" +dependencies = [ + "libc", + "memchr", + "ntapi", + "objc2-core-foundation", + "objc2-io-kit", + "windows 0.61.3", +] + +[[package]] +name = "systemstat" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6e89b75de097d0c52a1dc2114e19439d55f0e2e42d32168c6df44f139dfb66f" +dependencies = [ + "bytesize", + "lazy_static", + "libc", + "nom 7.1.3", + "time", + "winapi", +] + [[package]] name = "tagptr" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" +[[package]] +name = "tar" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tch" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e09b91610202dc4820c21eb474a42b386ef69f323b1c0902b5472ba7456ebb5" +dependencies = [ + "half", + "lazy_static", + "libc", + "ndarray 0.16.1", + "rand 0.8.5", + "safetensors 0.3.3", + "thiserror 1.0.69", + "torch-sys", + "zip 0.6.6", +] + [[package]] name = "tempfile" version = "3.26.0" @@ -5302,10 +8647,36 @@ dependencies = [ "fastrand", "getrandom 0.4.2", "once_cell", - "rustix", + "rustix 1.1.4", "windows-sys 0.61.2", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "text_placeholder" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5008f74a09742486ef0047596cf35df2b914e2a8dca5727fcb6ba6842a766b" +dependencies = [ + "hashbrown 0.13.2", + "serde", + "serde_json", +] + +[[package]] +name = "textdistance" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa672c55ab69f787dbc9126cc387dbe57fdd595f585e4524cf89018fa44ab819" + [[package]] name = "thiserror" version = "1.0.69" @@ -5346,6 +8717,15 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "thread-tree" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbd370cb847953a25954d9f63e14824a36113f8c72eecf6eccef5dc4b45d630" +dependencies = [ + "crossbeam-channel", +] + [[package]] name = "thread_local" version = "1.1.9" @@ -5365,6 +8745,20 @@ dependencies = [ "trackable", ] +[[package]] +name = "tiff" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error 2.0.1", + "weezl", + "zune-jpeg 0.4.21", +] + [[package]] name = "time" version = "0.3.47" @@ -5399,6 +8793,15 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinystr" version = "0.8.2" @@ -5448,6 +8851,7 @@ dependencies = [ "signal-hook-registry", "socket2 0.6.3", "tokio-macros", + "tracing", "windows-sys 0.61.2", ] @@ -5495,6 +8899,18 @@ dependencies = [ "tokio-stream", ] +[[package]] +name = "tokio-tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + [[package]] name = "tokio-util" version = "0.7.18" @@ -5539,11 +8955,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", - "serde_spanned", + "serde_spanned 0.6.9", "toml_datetime 0.6.11", "toml_edit 0.22.27", ] +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap 2.13.0", + "serde_core", + "serde_spanned 1.0.4", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow", +] + [[package]] name = "toml_datetime" version = "0.6.11" @@ -5553,6 +8984,15 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_datetime" version = "1.0.0+spec-1.1.0" @@ -5570,7 +9010,7 @@ checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap 2.13.0", "serde", - "serde_spanned", + "serde_spanned 0.6.9", "toml_datetime 0.6.11", "toml_write", "winnow", @@ -5603,6 +9043,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +[[package]] +name = "toml_writer" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" + [[package]] name = "tonic" version = "0.12.3" @@ -5611,7 +9057,7 @@ checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" dependencies = [ "async-stream", "async-trait", - "axum", + "axum 0.7.9", "base64", "bytes", "h2", @@ -5633,6 +9079,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "torch-sys" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef40c585e342df95b66a1fa7c923188623999c2b657227befb481dfb03a6a42" +dependencies = [ + "anyhow", + "cc", + "libc", + "serde", + "serde_json", + "ureq", + "zip 0.6.6", +] + [[package]] name = "tower" version = "0.4.13" @@ -5703,6 +9164,85 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" +[[package]] +name = "tracel-llvm" +version = "20.1.4-7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982535db9eb1a30ac0f2c50239a0eec3e5cf50993a88e92b04747bd2f4d365b2" +dependencies = [ + "tracel-mlir-rs", + "tracel-mlir-sys", +] + +[[package]] +name = "tracel-llvm-bundler" +version = "20.1.4-7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c75b8e477cb8d49d907afab029ca74d48459f5b88c27bdb4c6cd6acb5e61977" +dependencies = [ + "anyhow", + "bytes", + "constcat", + "dirs", + "liblzma", + "regex", + "reqwest 0.12.28", + "serde", + "serde_json", + "sha2 0.10.9", + "tar", + "walkdir", +] + +[[package]] +name = "tracel-mlir-rs" +version = "20.1.4-7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a478a35efd68d0ba73f747adfb7923b121c64e7f5be9cd8364ca1dcb772d5c" +dependencies = [ + "tracel-mlir-rs-macros", + "tracel-mlir-sys", +] + +[[package]] +name = "tracel-mlir-rs-macros" +version = "20.1.4-7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a94f36868c3b10b1825945223d99d106c73f4d249f063caa4651deeb9379344" +dependencies = [ + "comrak", + "convert_case 0.8.0", + "proc-macro2", + "quote", + "regex", + "syn 2.0.117", + "tracel-llvm-bundler", + "tracel-tblgen-rs", + "unindent", +] + +[[package]] +name = "tracel-mlir-sys" +version = "20.1.4-7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02f26d31af0c225a6d2e3d65d012fd6de848c9fc776897b152ee83b7d1bd15c4" +dependencies = [ + "tracel-llvm-bundler", +] + +[[package]] +name = "tracel-tblgen-rs" +version = "20.1.4-7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00d2581070380418ccc33b500f3739e4d4869421fdb477fcea51ff97c6253a52" +dependencies = [ + "bindgen", + "cc", + "paste", + "thiserror 2.0.18", + "tracel-llvm-bundler", +] + [[package]] name = "tracing" version = "0.1.44" @@ -5715,6 +9255,18 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786d480bce6247ab75f005b14ae1624ad978d3029d9113f0a22fa1ac773faeaf" +dependencies = [ + "crossbeam-channel", + "thiserror 2.0.18", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.31" @@ -5821,6 +9373,44 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.2", + "sha1", + "thiserror 2.0.18", + "utf-8", +] + +[[package]] +name = "type-map" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90" +dependencies = [ + "rustc-hash 2.1.1", +] + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "typed-path" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" + [[package]] name = "typenum" version = "1.19.0" @@ -5851,18 +9441,62 @@ 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-segmentation" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "unicode-truncate" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" +dependencies = [ + "itertools 0.13.0", + "unicode-segmentation", + "unicode-width 0.1.14", +] + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + [[package]] name = "unicode-xid" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "unindent" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" + [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -5875,6 +9509,30 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + +[[package]] +name = "ureq" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +dependencies = [ + "base64", + "flate2", + "log", + "once_cell", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "url", + "webpki-roots 0.26.11", +] + [[package]] name = "url" version = "2.5.8" @@ -5888,6 +9546,12 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -5908,6 +9572,18 @@ checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" dependencies = [ "getrandom 0.4.2", "js-sys", + "rand 0.10.0", + "wasm-bindgen", +] + +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +dependencies = [ + "aligned-vec", + "num-traits", "wasm-bindgen", ] @@ -5917,6 +9593,23 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +[[package]] +name = "variadics_please" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b6d82be61465f97d42bd1d15bf20f3b0a3a0905018f38f9d6f6962055b0b5c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "vergen" version = "9.1.0" @@ -5971,6 +9664,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + [[package]] name = "wait-timeout" version = "0.2.1" @@ -6158,6 +9857,15 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.6", +] + [[package]] name = "webpki-roots" version = "1.0.6" @@ -6167,6 +9875,161 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "wgpu" +version = "26.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70b6ff82bbf6e9206828e1a3178e851f8c20f1c9028e74dd3a8090741ccd5798" +dependencies = [ + "arrayvec", + "bitflags 2.11.0", + "cfg-if", + "cfg_aliases", + "document-features", + "hashbrown 0.15.5", + "js-sys", + "log", + "naga", + "parking_lot", + "portable-atomic", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "26.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f62f1053bd28c2268f42916f31588f81f64796e2ff91b81293515017ca8bd9" +dependencies = [ + "arrayvec", + "bit-set", + "bit-vec", + "bitflags 2.11.0", + "cfg_aliases", + "document-features", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "log", + "naga", + "once_cell", + "parking_lot", + "portable-atomic", + "profiling", + "raw-window-handle", + "rustc-hash 1.1.0", + "smallvec", + "thiserror 2.0.18", + "wgpu-core-deps-apple", + "wgpu-core-deps-emscripten", + "wgpu-core-deps-windows-linux-android", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core-deps-apple" +version = "26.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18ae5fbde6a4cbebae38358aa73fcd6e0f15c6144b67ef5dc91ded0db125dbdf" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-core-deps-emscripten" +version = "26.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7670e390f416006f746b4600fdd9136455e3627f5bd763abf9a65daa216dd2d" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-core-deps-windows-linux-android" +version = "26.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "720a5cb9d12b3d337c15ff0e24d3e97ed11490ff3f7506e7f3d98c68fa5d6f14" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-hal" +version = "26.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d0e67224cc7305b3b4eb2cc57ca4c4c3afc665c1d1bee162ea806e19c47bdd" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags 2.11.0", + "block", + "bytemuck", + "cfg-if", + "cfg_aliases", + "core-graphics-types", + "glow", + "glutin_wgl_sys", + "gpu-alloc", + "gpu-allocator", + "gpu-descriptor", + "hashbrown 0.15.5", + "js-sys", + "khronos-egl", + "libc", + "libloading", + "log", + "metal", + "naga", + "ndk-sys", + "objc", + "ordered-float 3.9.2", + "parking_lot", + "portable-atomic", + "portable-atomic-util", + "profiling", + "range-alloc", + "raw-window-handle", + "renderdoc-sys", + "smallvec", + "thiserror 2.0.18", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "windows 0.58.0", + "windows-core 0.58.0", +] + +[[package]] +name = "wgpu-types" +version = "26.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca7a8d8af57c18f57d393601a1fb159ace8b2328f1b6b5f80893f7d672c9ae2" +dependencies = [ + "bitflags 2.11.0", + "bytemuck", + "js-sys", + "log", + "thiserror 2.0.18", + "web-sys", +] + [[package]] name = "widestring" version = "1.2.1" @@ -6204,16 +10067,48 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections 0.2.0", + "windows-core 0.61.2", + "windows-future 0.2.1", + "windows-link 0.1.3", + "windows-numerics 0.2.0", +] + [[package]] name = "windows" version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ - "windows-collections", - "windows-core", - "windows-future", - "windows-numerics", + "windows-collections 0.3.2", + "windows-core 0.62.2", + "windows-future 0.3.2", + "windows-numerics 0.3.1", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", ] [[package]] @@ -6222,7 +10117,33 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-core", + "windows-core 0.62.2", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement 0.60.2", + "windows-interface 0.59.3", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", ] [[package]] @@ -6231,11 +10152,22 @@ version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", + "windows-implement 0.60.2", + "windows-interface 0.59.3", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading 0.1.0", ] [[package]] @@ -6244,9 +10176,20 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "windows-core", - "windows-link", - "windows-threading", + "windows-core 0.62.2", + "windows-link 0.2.1", + "windows-threading 0.2.1", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] @@ -6260,6 +10203,17 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "windows-interface" version = "0.59.3" @@ -6271,20 +10225,54 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + [[package]] name = "windows-numerics" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" dependencies = [ - "windows-core", - "windows-link", + "windows-core 0.62.2", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", ] [[package]] @@ -6293,7 +10281,26 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result 0.2.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", ] [[package]] @@ -6302,7 +10309,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -6356,7 +10363,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -6411,7 +10418,7 @@ version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link", + "windows-link 0.2.1", "windows_aarch64_gnullvm 0.53.1", "windows_aarch64_msvc 0.53.1", "windows_i686_gnu 0.53.1", @@ -6422,13 +10429,22 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + [[package]] name = "windows-threading" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -6729,8 +10745,20 @@ dependencies = [ "log", "serde", "thiserror 2.0.18", - "windows", - "windows-core", + "windows 0.62.2", + "windows-core 0.62.2", +] + +[[package]] +name = "wrapcenum-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76ff259533532054cfbaefb115c613203c73707017459206380f03b3b3f266e" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] @@ -6768,13 +10796,23 @@ dependencies = [ "data-encoding", "der-parser", "lazy_static", - "nom", + "nom 7.1.3", "oid-registry", "rusticata-macros", "thiserror 1.0.69", "time", ] +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix 1.1.4", +] + [[package]] name = "xml-rs" version = "0.8.28" @@ -6790,6 +10828,12 @@ dependencies = [ "xml-rs", ] +[[package]] +name = "y4m" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" + [[package]] name = "yansi" version = "1.0.1" @@ -6919,19 +10963,70 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq 0.1.5", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "zip" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42e33efc22a0650c311c2ef19115ce232583abbe80850bc8b66509ebef02de0" +dependencies = [ + "crc32fast", + "indexmap 2.13.0", + "memchr", + "typed-path", +] + [[package]] name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe 5.0.2+zstd.1.5.2", +] + [[package]] name = "zstd" version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" dependencies = [ - "zstd-safe", + "zstd-safe 7.2.4", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", ] [[package]] @@ -6952,3 +11047,42 @@ dependencies = [ "cc", "pkg-config", ] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" +dependencies = [ + "zune-core 0.4.12", +] + +[[package]] +name = "zune-jpeg" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "410e9ecef634c709e3831c2cfdb8d9c32164fae1c67496d5b68fff728eec37fe" +dependencies = [ + "zune-core 0.5.1", +] diff --git a/Cargo.toml b/Cargo.toml index caf0319..58b64e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,6 +77,17 @@ iroh-gossip = { version = "0.96", features = ["net"] } blake3 = "1" hex = "0.4" rand = "0.9" +rayon = "1" +tempfile = "3" + +# Dataset ingestion (CIC-IDS2017 CSV parsing) +csv = "1" + +# burn-rs ML framework (training only, behind `training` feature) +burn = { version = "0.20", features = ["ndarray", "autodiff"], optional = true } + +[features] +training = ["burn"] [dev-dependencies] criterion = { version = "0.5", features = ["html_reports"] } @@ -87,6 +98,10 @@ tempfile = "3" name = "scanner_bench" harness = false +[[bench]] +name = "ddos_bench" +harness = false + [profile.release] opt-level = 3 lto = true diff --git a/src/training/export.rs b/src/training/export.rs new file mode 100644 index 0000000..1b0af93 --- /dev/null +++ b/src/training/export.rs @@ -0,0 +1,342 @@ +//! Weight export: converts trained models into standalone Rust `const` arrays +//! and optionally Lean 4 definitions. +//! +//! The generated Rust source is meant to be placed in +//! `src/ensemble/gen/{scanner,ddos}_weights.rs` so the inference side can use +//! compile-time weight constants with zero runtime cost. + +use anyhow::Result; +use std::fmt::Write as FmtWrite; +use std::path::Path; + +/// All data needed to emit a standalone inference source file. +pub struct ExportedModel { + /// Module name used in generated code comments and Lean defs. + pub model_name: String, + /// Number of input features. + pub input_dim: usize, + /// Hidden layer width (always 32 in the current ensemble). + pub hidden_dim: usize, + /// Weight matrix for layer 1: `hidden_dim x input_dim`. + pub w1: Vec>, + /// Bias vector for layer 1: length `hidden_dim`. + pub b1: Vec, + /// Weight vector for layer 2: length `hidden_dim`. + pub w2: Vec, + /// Bias scalar for layer 2. + pub b2: f32, + /// Packed decision tree nodes. + pub tree_nodes: Vec<(u8, f32, u16, u16)>, + /// MLP classification threshold. + pub threshold: f32, + /// Per-feature normalization minimums. + pub norm_mins: Vec, + /// Per-feature normalization maximums. + pub norm_maxs: Vec, +} + +/// Generate a Rust source file with `const` arrays for all model weights. +pub fn generate_rust_source(model: &ExportedModel) -> String { + let mut s = String::with_capacity(8192); + + writeln!( + s, + "//! Auto-generated weights for the {} ensemble.", + model.model_name + ) + .unwrap(); + writeln!( + s, + "//! DO NOT EDIT — regenerate with `cargo run --features training -- train-{}-mlp`.", + model.model_name.to_ascii_lowercase() + ) + .unwrap(); + writeln!(s).unwrap(); + + // Threshold. + writeln!(s, "pub const THRESHOLD: f32 = {:.8};", model.threshold).unwrap(); + writeln!(s).unwrap(); + + // Normalization params. + write_f32_array(&mut s, "NORM_MINS", &model.norm_mins); + write_f32_array(&mut s, "NORM_MAXS", &model.norm_maxs); + + // W1: hidden_dim x input_dim. + writeln!( + s, + "pub const W1: [[f32; {}]; {}] = [", + model.input_dim, model.hidden_dim + ) + .unwrap(); + for row in &model.w1 { + write!(s, " [").unwrap(); + for (i, v) in row.iter().enumerate() { + if i > 0 { + write!(s, ", ").unwrap(); + } + write!(s, "{:.8}", v).unwrap(); + } + writeln!(s, "],").unwrap(); + } + writeln!(s, "];").unwrap(); + writeln!(s).unwrap(); + + // B1. + write_f32_array(&mut s, "B1", &model.b1); + + // W2. + write_f32_array(&mut s, "W2", &model.w2); + + // B2. + writeln!(s, "pub const B2: f32 = {:.8};", model.b2).unwrap(); + writeln!(s).unwrap(); + + // Tree nodes. + writeln!( + s, + "pub const TREE_NODES: [(u8, f32, u16, u16); {}] = [", + model.tree_nodes.len() + ) + .unwrap(); + for &(feat, thresh, left, right) in &model.tree_nodes { + writeln!( + s, + " ({}, {:.8}, {}, {}),", + feat, thresh, left, right + ) + .unwrap(); + } + writeln!(s, "];").unwrap(); + + s +} + +/// Generate Lean 4 definitions for formal verification. +pub fn generate_lean_source(model: &ExportedModel) -> String { + let mut s = String::with_capacity(8192); + + writeln!( + s, + "-- Auto-generated Lean 4 definitions for {} ensemble.", + model.model_name + ) + .unwrap(); + writeln!( + s, + "-- DO NOT EDIT — regenerate with the training pipeline." + ) + .unwrap(); + writeln!(s).unwrap(); + + writeln!( + s, + "namespace Sunbeam.Ensemble.{}", + capitalize(&model.model_name) + ) + .unwrap(); + writeln!(s).unwrap(); + + writeln!(s, "def inputDim : Nat := {}", model.input_dim).unwrap(); + writeln!(s, "def hiddenDim : Nat := {}", model.hidden_dim).unwrap(); + writeln!(s, "def threshold : Float := {:.8}", model.threshold).unwrap(); + writeln!(s, "def b2 : Float := {:.8}", model.b2).unwrap(); + writeln!(s).unwrap(); + + write_lean_float_list(&mut s, "normMins", &model.norm_mins); + write_lean_float_list(&mut s, "normMaxs", &model.norm_maxs); + write_lean_float_list(&mut s, "b1", &model.b1); + write_lean_float_list(&mut s, "w2", &model.w2); + + // W1 as list of lists. + writeln!(s, "def w1 : List (List Float) := [").unwrap(); + for (i, row) in model.w1.iter().enumerate() { + let comma = if i + 1 < model.w1.len() { "," } else { "" }; + write!(s, " [").unwrap(); + for (j, v) in row.iter().enumerate() { + if j > 0 { + write!(s, ", ").unwrap(); + } + write!(s, "{:.8}", v).unwrap(); + } + writeln!(s, "]{}", comma).unwrap(); + } + writeln!(s, "]").unwrap(); + writeln!(s).unwrap(); + + // Tree nodes as list of tuples. + writeln!( + s, + "def treeNodes : List (Nat × Float × Nat × Nat) := [" + ) + .unwrap(); + for (i, &(feat, thresh, left, right)) in model.tree_nodes.iter().enumerate() { + let comma = if i + 1 < model.tree_nodes.len() { + "," + } else { + "" + }; + writeln!( + s, + " ({}, {:.8}, {}, {}){}", + feat, thresh, left, right, comma + ) + .unwrap(); + } + writeln!(s, "]").unwrap(); + writeln!(s).unwrap(); + + writeln!( + s, + "end Sunbeam.Ensemble.{}", + capitalize(&model.model_name) + ) + .unwrap(); + + s +} + +/// Write the generated Rust source to a file. +pub fn export_to_file(model: &ExportedModel, path: &Path) -> Result<()> { + let source = generate_rust_source(model); + std::fs::write(path, source.as_bytes()) + .map_err(|e| anyhow::anyhow!("writing export to {}: {}", path.display(), e))?; + Ok(()) +} + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +fn write_f32_array(s: &mut String, name: &str, values: &[f32]) { + writeln!(s, "pub const {}: [f32; {}] = [", name, values.len()).unwrap(); + write!(s, " ").unwrap(); + for (i, v) in values.iter().enumerate() { + if i > 0 { + write!(s, ", ").unwrap(); + } + // Line-wrap every 8 values for readability. + if i > 0 && i % 8 == 0 { + write!(s, "\n ").unwrap(); + } + write!(s, "{:.8}", v).unwrap(); + } + writeln!(s, "\n];").unwrap(); + writeln!(s).unwrap(); +} + +fn write_lean_float_list(s: &mut String, name: &str, values: &[f32]) { + write!(s, "def {} : List Float := [", name).unwrap(); + for (i, v) in values.iter().enumerate() { + if i > 0 { + write!(s, ", ").unwrap(); + } + write!(s, "{:.8}", v).unwrap(); + } + writeln!(s, "]").unwrap(); + writeln!(s).unwrap(); +} + +fn capitalize(s: &str) -> String { + let mut c = s.chars(); + match c.next() { + None => String::new(), + Some(first) => first.to_uppercase().to_string() + c.as_str(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn make_test_model() -> ExportedModel { + ExportedModel { + model_name: "scanner".to_string(), + input_dim: 2, + hidden_dim: 2, + w1: vec![vec![0.1, 0.2], vec![0.3, 0.4]], + b1: vec![0.01, 0.02], + w2: vec![0.5, 0.6], + b2: -0.1, + tree_nodes: vec![ + (0, 0.5, 1, 2), + (255, 0.0, 0, 0), + (255, 1.0, 0, 0), + ], + threshold: 0.5, + norm_mins: vec![0.0, 0.0], + norm_maxs: vec![1.0, 10.0], + } + } + + #[test] + fn test_rust_source_contains_consts() { + let model = make_test_model(); + let src = generate_rust_source(&model); + + assert!(src.contains("pub const THRESHOLD: f32 ="), "missing THRESHOLD"); + assert!(src.contains("pub const NORM_MINS:"), "missing NORM_MINS"); + assert!(src.contains("pub const NORM_MAXS:"), "missing NORM_MAXS"); + assert!(src.contains("pub const W1:"), "missing W1"); + assert!(src.contains("pub const B1:"), "missing B1"); + assert!(src.contains("pub const W2:"), "missing W2"); + assert!(src.contains("pub const B2: f32 ="), "missing B2"); + assert!(src.contains("pub const TREE_NODES:"), "missing TREE_NODES"); + } + + #[test] + fn test_rust_source_array_dims() { + let model = make_test_model(); + let src = generate_rust_source(&model); + + // W1 should be [f32; 2]; 2] + assert!(src.contains("[[f32; 2]; 2]"), "W1 dimensions wrong"); + // B1 should be [f32; 2] + assert!(src.contains("B1: [f32; 2]"), "B1 dimensions wrong"); + // W2 should be [f32; 2] + assert!(src.contains("W2: [f32; 2]"), "W2 dimensions wrong"); + // TREE_NODES should have 3 entries + assert!( + src.contains("[(u8, f32, u16, u16); 3]"), + "TREE_NODES count wrong" + ); + } + + #[test] + fn test_weight_values_roundtrip() { + let model = make_test_model(); + let src = generate_rust_source(&model); + + // The threshold should appear with reasonable precision. + assert!(src.contains("0.50000000"), "threshold value missing"); + // B2 value. + assert!(src.contains("-0.10000000"), "b2 value missing"); + } + + #[test] + fn test_lean_source_structure() { + let model = make_test_model(); + let src = generate_lean_source(&model); + + assert!(src.contains("namespace Sunbeam.Ensemble.Scanner")); + assert!(src.contains("def inputDim : Nat := 2")); + assert!(src.contains("def hiddenDim : Nat := 2")); + assert!(src.contains("def threshold : Float :=")); + assert!(src.contains("def normMins : List Float :=")); + assert!(src.contains("def w1 : List (List Float) :=")); + assert!(src.contains("def treeNodes :")); + assert!(src.contains("end Sunbeam.Ensemble.Scanner")); + } + + #[test] + fn test_export_to_file() { + let model = make_test_model(); + let dir = tempfile::tempdir().unwrap(); + let path = dir.path().join("test_weights.rs"); + + export_to_file(&model, &path).unwrap(); + + let content = std::fs::read_to_string(&path).unwrap(); + assert!(content.contains("pub const THRESHOLD:")); + assert!(content.contains("pub const W1:")); + } +} diff --git a/src/training/mlp.rs b/src/training/mlp.rs new file mode 100644 index 0000000..0172492 --- /dev/null +++ b/src/training/mlp.rs @@ -0,0 +1,113 @@ +//! burn-rs MLP model definition for ensemble training. +//! +//! A two-layer network (linear -> ReLU -> linear -> sigmoid) used as the +//! "uncertain region" classifier in the tree+MLP ensemble. + +use burn::module::Module; +use burn::nn::{Linear, LinearConfig}; +use burn::prelude::*; + +/// Two-layer MLP: input -> hidden (ReLU) -> output (sigmoid). +#[derive(Module, Debug)] +pub struct MlpModel { + pub linear1: Linear, + pub linear2: Linear, +} + +/// Configuration for the MLP architecture. +#[derive(Config, Debug)] +pub struct MlpConfig { + /// Number of input features (12 for scanner, 14 for DDoS). + pub input_dim: usize, + /// Hidden layer width (typically 32). + pub hidden_dim: usize, +} + +impl MlpConfig { + /// Initialize a new MLP model on the given device. + pub fn init(&self, device: &B::Device) -> MlpModel { + MlpModel { + linear1: LinearConfig::new(self.input_dim, self.hidden_dim).init(device), + linear2: LinearConfig::new(self.hidden_dim, 1).init(device), + } + } +} + +impl MlpModel { + /// Forward pass: ReLU hidden activation, sigmoid output. + /// + /// Input shape: `[batch, input_dim]` + /// Output shape: `[batch, 1]` + pub fn forward(&self, x: Tensor) -> Tensor { + let h = self.linear1.forward(x); + let h = burn::tensor::activation::relu(h); + let out = self.linear2.forward(h); + burn::tensor::activation::sigmoid(out) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use burn::backend::NdArray; + + type TestBackend = NdArray; + + #[test] + fn test_forward_pass_shape() { + let device = Default::default(); + let config = MlpConfig { + input_dim: 12, + hidden_dim: 32, + }; + let model = config.init::(&device); + + let batch_size = 8; + let input = Tensor::::zeros([batch_size, 12], &device); + let output = model.forward(input); + let shape = output.shape(); + + assert_eq!(shape.dims[0], batch_size); + assert_eq!(shape.dims[1], 1); + } + + #[test] + fn test_output_bounded() { + let device = Default::default(); + let config = MlpConfig { + input_dim: 4, + hidden_dim: 16, + }; + let model = config.init::(&device); + + // Random-ish input values. + let input = Tensor::::from_data( + [[1.0, -2.0, 0.5, 3.0], [0.0, 0.0, 0.0, 0.0]], + &device, + ); + let output = model.forward(input); + let data = output.to_data(); + let values: Vec = data.to_vec().expect("flat vec"); + + for &v in &values { + assert!( + v >= 0.0 && v <= 1.0, + "sigmoid output should be in [0, 1], got {v}" + ); + } + } + + #[test] + fn test_ddos_input_dim() { + let device = Default::default(); + let config = MlpConfig { + input_dim: 14, + hidden_dim: 32, + }; + let model = config.init::(&device); + + let input = Tensor::::zeros([4, 14], &device); + let output = model.forward(input); + assert_eq!(output.shape().dims[1], 1); + } +} diff --git a/src/training/mod.rs b/src/training/mod.rs new file mode 100644 index 0000000..1e82804 --- /dev/null +++ b/src/training/mod.rs @@ -0,0 +1,5 @@ +pub mod tree; +pub mod mlp; +pub mod export; +pub mod train_scanner; +pub mod train_ddos; diff --git a/src/training/train_ddos.rs b/src/training/train_ddos.rs new file mode 100644 index 0000000..b14fb6d --- /dev/null +++ b/src/training/train_ddos.rs @@ -0,0 +1,493 @@ +//! DDoS MLP+tree training loop. +//! +//! Loads a `DatasetManifest`, trains a CART decision tree and a burn-rs MLP, +//! then exports the combined ensemble weights as a Rust source file that can +//! be dropped into `src/ensemble/gen/ddos_weights.rs`. + +use anyhow::{Context, Result}; +use std::path::Path; + +use burn::backend::ndarray::NdArray; +use burn::backend::Autodiff; +use burn::module::AutodiffModule; +use burn::optim::{AdamConfig, GradientsParams, Optimizer}; +use burn::prelude::*; + +use crate::dataset::sample::{load_dataset, TrainingSample}; +use crate::training::export::{export_to_file, ExportedModel}; +use crate::training::mlp::MlpConfig; +use crate::training::tree::{train_tree, tree_predict, TreeConfig, TreeDecision}; + +/// Number of DDoS features (matches `crate::ddos::features::NUM_FEATURES`). +const NUM_FEATURES: usize = 14; + +type TrainBackend = Autodiff>; + +/// Arguments for the DDoS MLP training command. +pub struct TrainDdosMlpArgs { + /// Path to a bincode `DatasetManifest` file. + pub dataset_path: String, + /// Directory to write output files (Rust source, model record). + pub output_dir: String, + /// Hidden layer width (default 32). + pub hidden_dim: usize, + /// Number of training epochs (default 100). + pub epochs: usize, + /// Adam learning rate (default 0.001). + pub learning_rate: f64, + /// Mini-batch size (default 64). + pub batch_size: usize, + /// CART max depth (default 6). + pub tree_max_depth: usize, + /// CART leaf purity threshold (default 0.90). + pub tree_min_purity: f32, +} + +impl Default for TrainDdosMlpArgs { + fn default() -> Self { + Self { + dataset_path: String::new(), + output_dir: ".".into(), + hidden_dim: 32, + epochs: 100, + learning_rate: 0.001, + batch_size: 64, + tree_max_depth: 6, + tree_min_purity: 0.90, + } + } +} + +/// Entry point: train DDoS ensemble and export weights. +pub fn run(args: TrainDdosMlpArgs) -> Result<()> { + // 1. Load dataset. + let manifest = load_dataset(Path::new(&args.dataset_path)) + .context("loading dataset manifest")?; + + let samples = &manifest.ddos_samples; + anyhow::ensure!(!samples.is_empty(), "no DDoS samples in dataset"); + + for s in samples { + anyhow::ensure!( + s.features.len() == NUM_FEATURES, + "expected {} features, got {}", + NUM_FEATURES, + s.features.len() + ); + } + + println!( + "[ddos] loaded {} samples ({} attack, {} normal)", + samples.len(), + samples.iter().filter(|s| s.label >= 0.5).count(), + samples.iter().filter(|s| s.label < 0.5).count(), + ); + + // 2. Compute normalization params from training data. + let (norm_mins, norm_maxs) = compute_norm_params(samples); + + // 3. Stratified 80/20 split. + let (train_set, val_set) = stratified_split(samples, 0.8); + println!( + "[ddos] train={}, val={}", + train_set.len(), + val_set.len() + ); + + // 4. Train CART tree. + let tree_config = TreeConfig { + max_depth: args.tree_max_depth, + min_samples_leaf: 5, + min_purity: args.tree_min_purity, + num_features: NUM_FEATURES, + }; + let tree_nodes = train_tree(&train_set, &tree_config); + println!("[ddos] CART tree: {} nodes", tree_nodes.len()); + + // Evaluate tree on validation set. + let (tree_correct, tree_deferred) = eval_tree(&tree_nodes, &val_set, &norm_mins, &norm_maxs); + println!( + "[ddos] tree validation: {:.2}% correct (of decided), {:.1}% deferred", + tree_correct * 100.0, + tree_deferred * 100.0, + ); + + // 5. Train MLP on the full training set. + let device = Default::default(); + let mlp_config = MlpConfig { + input_dim: NUM_FEATURES, + hidden_dim: args.hidden_dim, + }; + + let model = train_mlp( + &train_set, + &val_set, + &mlp_config, + &norm_mins, + &norm_maxs, + args.epochs, + args.learning_rate, + args.batch_size, + &device, + ); + + // 6. Extract weights from trained model. + let exported = extract_weights( + &model, + "ddos", + &tree_nodes, + 0.5, // threshold + &norm_mins, + &norm_maxs, + &device, + ); + + // 7. Write output. + let out_dir = Path::new(&args.output_dir); + std::fs::create_dir_all(out_dir).context("creating output directory")?; + + let rust_path = out_dir.join("ddos_weights.rs"); + export_to_file(&exported, &rust_path)?; + println!("[ddos] exported Rust weights to {}", rust_path.display()); + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Normalization +// --------------------------------------------------------------------------- + +fn compute_norm_params(samples: &[TrainingSample]) -> (Vec, Vec) { + let dim = samples[0].features.len(); + let mut mins = vec![f32::MAX; dim]; + let mut maxs = vec![f32::MIN; dim]; + for s in samples { + for i in 0..dim { + mins[i] = mins[i].min(s.features[i]); + maxs[i] = maxs[i].max(s.features[i]); + } + } + (mins, maxs) +} + +fn normalize_features(features: &[f32], mins: &[f32], maxs: &[f32]) -> Vec { + features + .iter() + .enumerate() + .map(|(i, &v)| { + let range = maxs[i] - mins[i]; + if range > f32::EPSILON { + ((v - mins[i]) / range).clamp(0.0, 1.0) + } else { + 0.0 + } + }) + .collect() +} + +// --------------------------------------------------------------------------- +// Stratified split +// --------------------------------------------------------------------------- + +fn stratified_split(samples: &[TrainingSample], train_ratio: f64) -> (Vec, Vec) { + let mut attacks: Vec<&TrainingSample> = samples.iter().filter(|s| s.label >= 0.5).collect(); + let mut normals: Vec<&TrainingSample> = samples.iter().filter(|s| s.label < 0.5).collect(); + + deterministic_shuffle(&mut attacks); + deterministic_shuffle(&mut normals); + + let attack_split = (attacks.len() as f64 * train_ratio) as usize; + let normal_split = (normals.len() as f64 * train_ratio) as usize; + + let mut train = Vec::new(); + let mut val = Vec::new(); + + for (i, s) in attacks.iter().enumerate() { + if i < attack_split { + train.push((*s).clone()); + } else { + val.push((*s).clone()); + } + } + for (i, s) in normals.iter().enumerate() { + if i < normal_split { + train.push((*s).clone()); + } else { + val.push((*s).clone()); + } + } + + (train, val) +} + +fn deterministic_shuffle(items: &mut [T]) { + let mut rng = 42u64; + for i in (1..items.len()).rev() { + rng = rng.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407); + let j = (rng >> 33) as usize % (i + 1); + items.swap(i, j); + } +} + +// --------------------------------------------------------------------------- +// Tree evaluation +// --------------------------------------------------------------------------- + +fn eval_tree( + nodes: &[(u8, f32, u16, u16)], + val_set: &[TrainingSample], + mins: &[f32], + maxs: &[f32], +) -> (f64, f64) { + let mut decided = 0usize; + let mut correct = 0usize; + let mut deferred = 0usize; + + for s in val_set { + let normed = normalize_features(&s.features, mins, maxs); + let decision = tree_predict(nodes, &normed); + match decision { + TreeDecision::Defer => deferred += 1, + TreeDecision::Block => { + decided += 1; + if s.label >= 0.5 { + correct += 1; + } + } + TreeDecision::Allow => { + decided += 1; + if s.label < 0.5 { + correct += 1; + } + } + } + } + + let accuracy = if decided > 0 { + correct as f64 / decided as f64 + } else { + 0.0 + }; + let defer_rate = deferred as f64 / val_set.len() as f64; + (accuracy, defer_rate) +} + +// --------------------------------------------------------------------------- +// MLP training +// --------------------------------------------------------------------------- + +fn train_mlp( + train_set: &[TrainingSample], + val_set: &[TrainingSample], + config: &MlpConfig, + mins: &[f32], + maxs: &[f32], + epochs: usize, + learning_rate: f64, + batch_size: usize, + device: &::Device, +) -> crate::training::mlp::MlpModel> { + let mut model = config.init::(device); + let mut optim = AdamConfig::new().init(); + + // Pre-normalize all training data. + let train_features: Vec> = train_set + .iter() + .map(|s| normalize_features(&s.features, mins, maxs)) + .collect(); + let train_labels: Vec = train_set.iter().map(|s| s.label).collect(); + let train_weights: Vec = train_set.iter().map(|s| s.weight).collect(); + + let n = train_features.len(); + + for epoch in 0..epochs { + let mut epoch_loss = 0.0f32; + let mut batches = 0usize; + + let mut offset = 0; + while offset < n { + let end = (offset + batch_size).min(n); + let batch_n = end - offset; + + // Build input tensor [batch, features]. + let flat: Vec = train_features[offset..end] + .iter() + .flat_map(|f| f.iter().copied()) + .collect(); + let x = Tensor::::from_floats(flat.as_slice(), device) + .reshape([batch_n, NUM_FEATURES]); + + // Labels [batch, 1]. + let y = Tensor::::from_floats( + &train_labels[offset..end], + device, + ) + .reshape([batch_n, 1]); + + // Sample weights [batch, 1]. + let w = Tensor::::from_floats( + &train_weights[offset..end], + device, + ) + .reshape([batch_n, 1]); + + // Forward pass. + let pred = model.forward(x); + + // Binary cross-entropy with sample weights. + let eps = 1e-7; + let pred_clamped = pred.clone().clamp(eps, 1.0 - eps); + let bce = (y.clone() * pred_clamped.clone().log() + + (y.clone().neg().add_scalar(1.0)) + * pred_clamped.neg().add_scalar(1.0).log()) + .neg(); + let weighted_bce = bce * w; + let loss = weighted_bce.mean(); + + epoch_loss += loss.clone().into_scalar().elem::(); + batches += 1; + + // Backward + optimizer step. + let grads = loss.backward(); + let grads = GradientsParams::from_grads(grads, &model); + model = optim.step(learning_rate, model, grads); + + offset = end; + } + + if (epoch + 1) % 10 == 0 || epoch == 0 { + let avg_loss = epoch_loss / batches as f32; + let val_acc = eval_mlp_accuracy(&model, val_set, mins, maxs, device); + println!( + "[ddos] epoch {:>4}/{}: loss={:.6}, val_acc={:.4}", + epoch + 1, + epochs, + avg_loss, + val_acc, + ); + } + } + + model.valid() +} + +fn eval_mlp_accuracy( + model: &crate::training::mlp::MlpModel, + val_set: &[TrainingSample], + mins: &[f32], + maxs: &[f32], + device: &::Device, +) -> f64 { + let flat: Vec = val_set + .iter() + .flat_map(|s| normalize_features(&s.features, mins, maxs)) + .collect(); + let x = Tensor::::from_floats(flat.as_slice(), device) + .reshape([val_set.len(), NUM_FEATURES]); + + let pred = model.forward(x); + let pred_data: Vec = pred.to_data().to_vec().expect("flat vec"); + + let mut correct = 0usize; + for (i, s) in val_set.iter().enumerate() { + let p = pred_data[i]; + let predicted_label = if p >= 0.5 { 1.0 } else { 0.0 }; + if (predicted_label - s.label).abs() < 0.1 { + correct += 1; + } + } + correct as f64 / val_set.len() as f64 +} + +// --------------------------------------------------------------------------- +// Weight extraction +// --------------------------------------------------------------------------- + +fn extract_weights( + model: &crate::training::mlp::MlpModel>, + name: &str, + tree_nodes: &[(u8, f32, u16, u16)], + threshold: f32, + norm_mins: &[f32], + norm_maxs: &[f32], + _device: & as Backend>::Device, +) -> ExportedModel { + let w1_tensor = model.linear1.weight.val(); + let b1_tensor = model.linear1.bias.as_ref().expect("linear1 has bias").val(); + let w2_tensor = model.linear2.weight.val(); + let b2_tensor = model.linear2.bias.as_ref().expect("linear2 has bias").val(); + + let w1_data: Vec = w1_tensor.to_data().to_vec().expect("w1 flat"); + let b1_data: Vec = b1_tensor.to_data().to_vec().expect("b1 flat"); + let w2_data: Vec = w2_tensor.to_data().to_vec().expect("w2 flat"); + let b2_data: Vec = b2_tensor.to_data().to_vec().expect("b2 flat"); + + let hidden_dim = b1_data.len(); + let input_dim = w1_data.len() / hidden_dim; + + let w1: Vec> = (0..hidden_dim) + .map(|h| w1_data[h * input_dim..(h + 1) * input_dim].to_vec()) + .collect(); + + ExportedModel { + model_name: name.to_string(), + input_dim, + hidden_dim, + w1, + b1: b1_data, + w2: w2_data, + b2: b2_data[0], + tree_nodes: tree_nodes.to_vec(), + threshold, + norm_mins: norm_mins.to_vec(), + norm_maxs: norm_maxs.to_vec(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::dataset::sample::{DataSource, TrainingSample}; + + fn make_ddos_sample(features: [f32; 14], label: f32) -> TrainingSample { + TrainingSample { + features: features.to_vec(), + label, + source: DataSource::ProductionLogs, + weight: 1.0, + } + } + + #[test] + fn test_stratified_split_preserves_ratio() { + let mut samples = Vec::new(); + for _ in 0..80 { + samples.push(make_ddos_sample([0.0; 14], 0.0)); + } + for _ in 0..20 { + samples.push(make_ddos_sample([1.0; 14], 1.0)); + } + + let (train, val) = stratified_split(&samples, 0.8); + + let train_attacks = train.iter().filter(|s| s.label >= 0.5).count(); + let val_attacks = val.iter().filter(|s| s.label >= 0.5).count(); + + assert_eq!(train_attacks, 16); + assert_eq!(val_attacks, 4); + assert_eq!(train.len() + val.len(), 100); + } + + #[test] + fn test_norm_params_14_features() { + let samples = vec![ + make_ddos_sample([0.0; 14], 0.0), + make_ddos_sample([1.0; 14], 1.0), + ]; + let (mins, maxs) = compute_norm_params(&samples); + assert_eq!(mins.len(), 14); + assert_eq!(maxs.len(), 14); + assert_eq!(mins[0], 0.0); + assert_eq!(maxs[0], 1.0); + } +} diff --git a/src/training/train_scanner.rs b/src/training/train_scanner.rs new file mode 100644 index 0000000..f5e42fd --- /dev/null +++ b/src/training/train_scanner.rs @@ -0,0 +1,515 @@ +//! Scanner MLP+tree training loop. +//! +//! Loads a `DatasetManifest`, trains a CART decision tree and a burn-rs MLP, +//! then exports the combined ensemble weights as a Rust source file that can +//! be dropped into `src/ensemble/gen/scanner_weights.rs`. + +use anyhow::{Context, Result}; +use std::path::Path; + +use burn::backend::ndarray::NdArray; +use burn::backend::Autodiff; +use burn::module::AutodiffModule; +use burn::optim::{AdamConfig, GradientsParams, Optimizer}; +use burn::prelude::*; + +use crate::dataset::sample::{load_dataset, TrainingSample}; +use crate::training::export::{export_to_file, ExportedModel}; +use crate::training::mlp::MlpConfig; +use crate::training::tree::{train_tree, tree_predict, TreeConfig, TreeDecision}; + +/// Number of scanner features (matches `crate::scanner::features::NUM_SCANNER_FEATURES`). +const NUM_FEATURES: usize = 12; + +type TrainBackend = Autodiff>; + +/// Arguments for the scanner MLP training command. +pub struct TrainScannerMlpArgs { + /// Path to a bincode `DatasetManifest` file. + pub dataset_path: String, + /// Directory to write output files (Rust source, model record). + pub output_dir: String, + /// Hidden layer width (default 32). + pub hidden_dim: usize, + /// Number of training epochs (default 100). + pub epochs: usize, + /// Adam learning rate (default 0.001). + pub learning_rate: f64, + /// Mini-batch size (default 64). + pub batch_size: usize, + /// CART max depth (default 6). + pub tree_max_depth: usize, + /// CART leaf purity threshold (default 0.90). + pub tree_min_purity: f32, +} + +impl Default for TrainScannerMlpArgs { + fn default() -> Self { + Self { + dataset_path: String::new(), + output_dir: ".".into(), + hidden_dim: 32, + epochs: 100, + learning_rate: 0.001, + batch_size: 64, + tree_max_depth: 6, + tree_min_purity: 0.90, + } + } +} + +/// Entry point: train scanner ensemble and export weights. +pub fn run(args: TrainScannerMlpArgs) -> Result<()> { + // 1. Load dataset. + let manifest = load_dataset(Path::new(&args.dataset_path)) + .context("loading dataset manifest")?; + + let samples = &manifest.scanner_samples; + anyhow::ensure!(!samples.is_empty(), "no scanner samples in dataset"); + + for s in samples { + anyhow::ensure!( + s.features.len() == NUM_FEATURES, + "expected {} features, got {}", + NUM_FEATURES, + s.features.len() + ); + } + + println!( + "[scanner] loaded {} samples ({} attack, {} normal)", + samples.len(), + samples.iter().filter(|s| s.label >= 0.5).count(), + samples.iter().filter(|s| s.label < 0.5).count(), + ); + + // 2. Compute normalization params from training data. + let (norm_mins, norm_maxs) = compute_norm_params(samples); + + // 3. Stratified 80/20 split. + let (train_set, val_set) = stratified_split(samples, 0.8); + println!( + "[scanner] train={}, val={}", + train_set.len(), + val_set.len() + ); + + // 4. Train CART tree. + let tree_config = TreeConfig { + max_depth: args.tree_max_depth, + min_samples_leaf: 5, + min_purity: args.tree_min_purity, + num_features: NUM_FEATURES, + }; + let tree_nodes = train_tree(&train_set, &tree_config); + println!("[scanner] CART tree: {} nodes", tree_nodes.len()); + + // Evaluate tree on validation set. + let (tree_correct, tree_deferred) = eval_tree(&tree_nodes, &val_set, &norm_mins, &norm_maxs); + println!( + "[scanner] tree validation: {:.2}% correct (of decided), {:.1}% deferred", + tree_correct * 100.0, + tree_deferred * 100.0, + ); + + // 5. Train MLP on the full training set (the MLP only fires on Defer + // at inference time, but we train it on all data so it learns the + // full decision boundary). + let device = Default::default(); + let mlp_config = MlpConfig { + input_dim: NUM_FEATURES, + hidden_dim: args.hidden_dim, + }; + + let model = train_mlp( + &train_set, + &val_set, + &mlp_config, + &norm_mins, + &norm_maxs, + args.epochs, + args.learning_rate, + args.batch_size, + &device, + ); + + // 6. Extract weights from trained model. + let exported = extract_weights( + &model, + "scanner", + &tree_nodes, + 0.5, // threshold + &norm_mins, + &norm_maxs, + &device, + ); + + // 7. Write output. + let out_dir = Path::new(&args.output_dir); + std::fs::create_dir_all(out_dir).context("creating output directory")?; + + let rust_path = out_dir.join("scanner_weights.rs"); + export_to_file(&exported, &rust_path)?; + println!("[scanner] exported Rust weights to {}", rust_path.display()); + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Normalization +// --------------------------------------------------------------------------- + +fn compute_norm_params(samples: &[TrainingSample]) -> (Vec, Vec) { + let dim = samples[0].features.len(); + let mut mins = vec![f32::MAX; dim]; + let mut maxs = vec![f32::MIN; dim]; + for s in samples { + for i in 0..dim { + mins[i] = mins[i].min(s.features[i]); + maxs[i] = maxs[i].max(s.features[i]); + } + } + (mins, maxs) +} + +fn normalize_features(features: &[f32], mins: &[f32], maxs: &[f32]) -> Vec { + features + .iter() + .enumerate() + .map(|(i, &v)| { + let range = maxs[i] - mins[i]; + if range > f32::EPSILON { + ((v - mins[i]) / range).clamp(0.0, 1.0) + } else { + 0.0 + } + }) + .collect() +} + +// --------------------------------------------------------------------------- +// Stratified split +// --------------------------------------------------------------------------- + +fn stratified_split(samples: &[TrainingSample], train_ratio: f64) -> (Vec, Vec) { + let mut attacks: Vec<&TrainingSample> = samples.iter().filter(|s| s.label >= 0.5).collect(); + let mut normals: Vec<&TrainingSample> = samples.iter().filter(|s| s.label < 0.5).collect(); + + // Deterministic shuffle using a simple index permutation seeded by length. + deterministic_shuffle(&mut attacks); + deterministic_shuffle(&mut normals); + + let attack_split = (attacks.len() as f64 * train_ratio) as usize; + let normal_split = (normals.len() as f64 * train_ratio) as usize; + + let mut train = Vec::new(); + let mut val = Vec::new(); + + for (i, s) in attacks.iter().enumerate() { + if i < attack_split { + train.push((*s).clone()); + } else { + val.push((*s).clone()); + } + } + for (i, s) in normals.iter().enumerate() { + if i < normal_split { + train.push((*s).clone()); + } else { + val.push((*s).clone()); + } + } + + (train, val) +} + +fn deterministic_shuffle(items: &mut [T]) { + // Simple Fisher-Yates with a fixed LCG seed for reproducibility. + let mut rng = 42u64; + for i in (1..items.len()).rev() { + rng = rng.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407); + let j = (rng >> 33) as usize % (i + 1); + items.swap(i, j); + } +} + +// --------------------------------------------------------------------------- +// Tree evaluation +// --------------------------------------------------------------------------- + +fn eval_tree( + nodes: &[(u8, f32, u16, u16)], + val_set: &[TrainingSample], + mins: &[f32], + maxs: &[f32], +) -> (f64, f64) { + let mut decided = 0usize; + let mut correct = 0usize; + let mut deferred = 0usize; + + for s in val_set { + let normed = normalize_features(&s.features, mins, maxs); + let decision = tree_predict(nodes, &normed); + match decision { + TreeDecision::Defer => deferred += 1, + TreeDecision::Block => { + decided += 1; + if s.label >= 0.5 { + correct += 1; + } + } + TreeDecision::Allow => { + decided += 1; + if s.label < 0.5 { + correct += 1; + } + } + } + } + + let accuracy = if decided > 0 { + correct as f64 / decided as f64 + } else { + 0.0 + }; + let defer_rate = deferred as f64 / val_set.len() as f64; + (accuracy, defer_rate) +} + +// --------------------------------------------------------------------------- +// MLP training +// --------------------------------------------------------------------------- + +fn train_mlp( + train_set: &[TrainingSample], + val_set: &[TrainingSample], + config: &MlpConfig, + mins: &[f32], + maxs: &[f32], + epochs: usize, + learning_rate: f64, + batch_size: usize, + device: &::Device, +) -> crate::training::mlp::MlpModel> { + let mut model = config.init::(device); + let mut optim = AdamConfig::new().init(); + + // Pre-normalize all training data. + let train_features: Vec> = train_set + .iter() + .map(|s| normalize_features(&s.features, mins, maxs)) + .collect(); + let train_labels: Vec = train_set.iter().map(|s| s.label).collect(); + let train_weights: Vec = train_set.iter().map(|s| s.weight).collect(); + + let n = train_features.len(); + + for epoch in 0..epochs { + let mut epoch_loss = 0.0f32; + let mut batches = 0usize; + + let mut offset = 0; + while offset < n { + let end = (offset + batch_size).min(n); + let batch_n = end - offset; + + // Build input tensor [batch, features]. + let flat: Vec = train_features[offset..end] + .iter() + .flat_map(|f| f.iter().copied()) + .collect(); + let x = Tensor::::from_floats(flat.as_slice(), device) + .reshape([batch_n, NUM_FEATURES]); + + // Labels [batch, 1]. + let y = Tensor::::from_floats( + &train_labels[offset..end], + device, + ) + .reshape([batch_n, 1]); + + // Sample weights [batch, 1]. + let w = Tensor::::from_floats( + &train_weights[offset..end], + device, + ) + .reshape([batch_n, 1]); + + // Forward pass. + let pred = model.forward(x); + + // Binary cross-entropy with sample weights: + // loss = -w * [y * log(p) + (1-y) * log(1-p)] + let eps = 1e-7; + let pred_clamped = pred.clone().clamp(eps, 1.0 - eps); + let bce = (y.clone() * pred_clamped.clone().log() + + (y.clone().neg().add_scalar(1.0)) + * pred_clamped.neg().add_scalar(1.0).log()) + .neg(); + let weighted_bce = bce * w; + let loss = weighted_bce.mean(); + + epoch_loss += loss.clone().into_scalar().elem::(); + batches += 1; + + // Backward + optimizer step. + let grads = loss.backward(); + let grads = GradientsParams::from_grads(grads, &model); + model = optim.step(learning_rate, model, grads); + + offset = end; + } + + if (epoch + 1) % 10 == 0 || epoch == 0 { + let avg_loss = epoch_loss / batches as f32; + let val_acc = eval_mlp_accuracy(&model, val_set, mins, maxs, device); + println!( + "[scanner] epoch {:>4}/{}: loss={:.6}, val_acc={:.4}", + epoch + 1, + epochs, + avg_loss, + val_acc, + ); + } + } + + // Return the inner (non-autodiff) model for weight extraction. + model.valid() +} + +fn eval_mlp_accuracy( + model: &crate::training::mlp::MlpModel, + val_set: &[TrainingSample], + mins: &[f32], + maxs: &[f32], + device: &::Device, +) -> f64 { + let flat: Vec = val_set + .iter() + .flat_map(|s| normalize_features(&s.features, mins, maxs)) + .collect(); + let x = Tensor::::from_floats(flat.as_slice(), device) + .reshape([val_set.len(), NUM_FEATURES]); + + let pred = model.forward(x); + let pred_data: Vec = pred.to_data().to_vec().expect("flat vec"); + + let mut correct = 0usize; + for (i, s) in val_set.iter().enumerate() { + let p = pred_data[i]; + let predicted_label = if p >= 0.5 { 1.0 } else { 0.0 }; + if (predicted_label - s.label).abs() < 0.1 { + correct += 1; + } + } + correct as f64 / val_set.len() as f64 +} + +// --------------------------------------------------------------------------- +// Weight extraction +// --------------------------------------------------------------------------- + +fn extract_weights( + model: &crate::training::mlp::MlpModel>, + name: &str, + tree_nodes: &[(u8, f32, u16, u16)], + threshold: f32, + norm_mins: &[f32], + norm_maxs: &[f32], + _device: & as Backend>::Device, +) -> ExportedModel { + // Extract weight tensors from the model. + // linear1.weight: [hidden_dim, input_dim] + // linear1.bias: [hidden_dim] + // linear2.weight: [1, hidden_dim] + // linear2.bias: [1] + let w1_tensor = model.linear1.weight.val(); + let b1_tensor = model.linear1.bias.as_ref().expect("linear1 has bias").val(); + let w2_tensor = model.linear2.weight.val(); + let b2_tensor = model.linear2.bias.as_ref().expect("linear2 has bias").val(); + + let w1_data: Vec = w1_tensor.to_data().to_vec().expect("w1 flat"); + let b1_data: Vec = b1_tensor.to_data().to_vec().expect("b1 flat"); + let w2_data: Vec = w2_tensor.to_data().to_vec().expect("w2 flat"); + let b2_data: Vec = b2_tensor.to_data().to_vec().expect("b2 flat"); + + let hidden_dim = b1_data.len(); + let input_dim = w1_data.len() / hidden_dim; + + // Reshape W1 into [hidden_dim][input_dim]. + let w1: Vec> = (0..hidden_dim) + .map(|h| w1_data[h * input_dim..(h + 1) * input_dim].to_vec()) + .collect(); + + ExportedModel { + model_name: name.to_string(), + input_dim, + hidden_dim, + w1, + b1: b1_data, + w2: w2_data, + b2: b2_data[0], + tree_nodes: tree_nodes.to_vec(), + threshold, + norm_mins: norm_mins.to_vec(), + norm_maxs: norm_maxs.to_vec(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::dataset::sample::{DataSource, TrainingSample}; + + fn make_scanner_sample(features: [f32; 12], label: f32) -> TrainingSample { + TrainingSample { + features: features.to_vec(), + label, + source: DataSource::ProductionLogs, + weight: 1.0, + } + } + + #[test] + fn test_stratified_split_preserves_ratio() { + let mut samples = Vec::new(); + for _ in 0..80 { + samples.push(make_scanner_sample([0.0; 12], 0.0)); + } + for _ in 0..20 { + samples.push(make_scanner_sample([1.0; 12], 1.0)); + } + + let (train, val) = stratified_split(&samples, 0.8); + + let train_attacks = train.iter().filter(|s| s.label >= 0.5).count(); + let val_attacks = val.iter().filter(|s| s.label >= 0.5).count(); + + // Should preserve the 80/20 attack ratio approximately. + assert_eq!(train_attacks, 16); // 80% of 20 + assert_eq!(val_attacks, 4); // 20% of 20 + assert_eq!(train.len() + val.len(), 100); + } + + #[test] + fn test_norm_params() { + let samples = vec![ + make_scanner_sample([0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 0.0), + make_scanner_sample([1.0, 20.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], 1.0), + ]; + let (mins, maxs) = compute_norm_params(&samples); + assert_eq!(mins[0], 0.0); + assert_eq!(maxs[0], 1.0); + assert_eq!(mins[1], 10.0); + assert_eq!(maxs[1], 20.0); + } + + #[test] + fn test_normalize_features() { + let mins = vec![0.0, 10.0]; + let maxs = vec![1.0, 20.0]; + let normed = normalize_features(&[0.5, 15.0], &mins, &maxs); + assert!((normed[0] - 0.5).abs() < 1e-6); + assert!((normed[1] - 0.5).abs() < 1e-6); + } +} diff --git a/src/training/tree.rs b/src/training/tree.rs new file mode 100644 index 0000000..8c5d37b --- /dev/null +++ b/src/training/tree.rs @@ -0,0 +1,409 @@ +//! CART decision tree trainer (pure Rust, no burn dependency). +//! +//! Trains a binary classification tree using Gini impurity and outputs +//! the packed node format used by `crate::ensemble::tree` for zero-alloc +//! inference. + +use crate::dataset::sample::TrainingSample; + +/// Packed tree node matching the inference format in `crate::ensemble::tree`. +/// +/// `(feature_index, threshold, left_child, right_child)` +/// +/// Leaf nodes use `feature_index = 255`. The threshold encodes the decision: +/// - `0.0` = Allow +/// - `0.5` = Defer +/// - `1.0` = Block +pub type PackedNode = (u8, f32, u16, u16); + +/// Decision from a tree leaf node. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TreeDecision { + Block, + Allow, + Defer, +} + +/// Configuration for CART tree training. +pub struct TreeConfig { + /// Maximum tree depth (typically 6-8). + pub max_depth: usize, + /// Minimum number of samples required in a leaf. + pub min_samples_leaf: usize, + /// Leaf purity threshold: if the dominant class ratio is below this, + /// the leaf becomes `Defer` (e.g. 0.90). + pub min_purity: f32, + /// Number of input features (12 for scanner, 14 for DDoS). + pub num_features: usize, +} + +/// Internal representation during tree construction. +#[derive(Debug)] +enum BuildNode { + Leaf { + decision: TreeDecision, + }, + Split { + feature: usize, + threshold: f32, + left: Box, + right: Box, + }, +} + +/// Train a CART decision tree and return packed nodes. +pub fn train_tree(samples: &[TrainingSample], config: &TreeConfig) -> Vec { + let indices: Vec = (0..samples.len()).collect(); + let root = build_node(samples, &indices, config, 0); + let mut packed = Vec::new(); + flatten(&root, &mut packed); + packed +} + +/// Walk a packed decision tree for validation (mirrors `crate::ensemble::tree::tree_predict`). +pub fn tree_predict(nodes: &[PackedNode], features: &[f32]) -> TreeDecision { + let mut idx = 0usize; + loop { + let (feature, threshold, left, right) = nodes[idx]; + if feature == 255 { + return if threshold < 0.25 { + TreeDecision::Allow + } else if threshold > 0.75 { + TreeDecision::Block + } else { + TreeDecision::Defer + }; + } + idx = if features[feature as usize] <= threshold { + left as usize + } else { + right as usize + }; + } +} + +// --------------------------------------------------------------------------- +// Tree construction +// --------------------------------------------------------------------------- + +fn build_node( + samples: &[TrainingSample], + indices: &[usize], + config: &TreeConfig, + depth: usize, +) -> BuildNode { + // Count attacks vs normal. + let (attack_w, normal_w) = weighted_counts(samples, indices); + let total_w = attack_w + normal_w; + + // Stopping conditions: max depth, min samples, or pure-enough leaf. + if depth >= config.max_depth + || indices.len() < 2 * config.min_samples_leaf + || total_w < f32::EPSILON + { + return make_leaf(attack_w, normal_w, config.min_purity); + } + + let attack_ratio = attack_w / total_w; + let normal_ratio = normal_w / total_w; + if attack_ratio >= config.min_purity || normal_ratio >= config.min_purity { + return make_leaf(attack_w, normal_w, config.min_purity); + } + + // Find best split across all features. + let parent_gini = gini(attack_w, normal_w); + let mut best_gain = 0.0f32; + let mut best_feature = 0usize; + let mut best_threshold = 0.0f32; + let mut best_left: Vec = Vec::new(); + let mut best_right: Vec = Vec::new(); + + for feat in 0..config.num_features { + // Gather and sort feature values. + let mut vals: Vec<(f32, usize)> = indices + .iter() + .map(|&i| (samples[i].features[feat], i)) + .collect(); + vals.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal)); + + // Scan for best threshold (midpoints between distinct values). + let mut left_attack_w = 0.0f32; + let mut left_normal_w = 0.0f32; + + for window_end in 0..vals.len() - 1 { + let (_, idx) = vals[window_end]; + let s = &samples[idx]; + if s.label >= 0.5 { + left_attack_w += s.weight; + } else { + left_normal_w += s.weight; + } + + // Skip if the next value is the same (no valid split point). + if (vals[window_end].0 - vals[window_end + 1].0).abs() < f32::EPSILON { + continue; + } + + // Check min_samples_leaf constraint. + let left_count = window_end + 1; + let right_count = vals.len() - left_count; + if left_count < config.min_samples_leaf || right_count < config.min_samples_leaf { + continue; + } + + let right_attack_w = attack_w - left_attack_w; + let right_normal_w = normal_w - left_normal_w; + let left_total = left_attack_w + left_normal_w; + let right_total = right_attack_w + right_normal_w; + + let left_gini = gini(left_attack_w, left_normal_w); + let right_gini = gini(right_attack_w, right_normal_w); + let weighted_gini = + (left_total / total_w) * left_gini + (right_total / total_w) * right_gini; + let gain = parent_gini - weighted_gini; + + if gain > best_gain { + best_gain = gain; + best_feature = feat; + best_threshold = (vals[window_end].0 + vals[window_end + 1].0) / 2.0; + best_left = vals[..=window_end].iter().map(|v| v.1).collect(); + best_right = vals[window_end + 1..].iter().map(|v| v.1).collect(); + } + } + } + + // If no informative split was found, make a leaf. + if best_gain <= 0.0 || best_left.is_empty() || best_right.is_empty() { + return make_leaf(attack_w, normal_w, config.min_purity); + } + + let left_child = build_node(samples, &best_left, config, depth + 1); + let right_child = build_node(samples, &best_right, config, depth + 1); + + BuildNode::Split { + feature: best_feature, + threshold: best_threshold, + left: Box::new(left_child), + right: Box::new(right_child), + } +} + +fn make_leaf(attack_w: f32, normal_w: f32, min_purity: f32) -> BuildNode { + let total = attack_w + normal_w; + let decision = if total < f32::EPSILON { + TreeDecision::Defer + } else { + let attack_ratio = attack_w / total; + let normal_ratio = normal_w / total; + if attack_ratio >= min_purity { + TreeDecision::Block + } else if normal_ratio >= min_purity { + TreeDecision::Allow + } else { + TreeDecision::Defer + } + }; + BuildNode::Leaf { decision } +} + +fn gini(class_a: f32, class_b: f32) -> f32 { + let total = class_a + class_b; + if total < f32::EPSILON { + return 0.0; + } + let p_a = class_a / total; + let p_b = class_b / total; + 1.0 - p_a * p_a - p_b * p_b +} + +fn weighted_counts(samples: &[TrainingSample], indices: &[usize]) -> (f32, f32) { + let mut attack = 0.0f32; + let mut normal = 0.0f32; + for &i in indices { + let s = &samples[i]; + if s.label >= 0.5 { + attack += s.weight; + } else { + normal += s.weight; + } + } + (attack, normal) +} + +/// Flatten the recursive `BuildNode` tree into a `Vec` using +/// BFS-order indexing. +fn flatten(node: &BuildNode, out: &mut Vec) { + match node { + BuildNode::Leaf { decision } => { + let threshold = match decision { + TreeDecision::Allow => 0.0, + TreeDecision::Defer => 0.5, + TreeDecision::Block => 1.0, + }; + out.push((255, threshold, 0, 0)); + } + BuildNode::Split { + feature, + threshold, + left, + right, + } => { + // Reserve this node's position, then recursively flatten children. + let self_idx = out.len(); + out.push((0, 0.0, 0, 0)); // placeholder + + let left_idx = out.len(); + flatten(left, out); + + let right_idx = out.len(); + flatten(right, out); + + out[self_idx] = ( + *feature as u8, + *threshold, + left_idx as u16, + right_idx as u16, + ); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::dataset::sample::{DataSource, TrainingSample}; + + fn sample(features: Vec, label: f32) -> TrainingSample { + TrainingSample { + features, + label, + source: DataSource::ProductionLogs, + weight: 1.0, + } + } + + #[test] + fn test_trivially_separable() { + // Feature 0 < 0.5 => Allow (label 0), >= 0.5 => Block (label 1) + let samples: Vec = (0..100) + .map(|i| { + let v = i as f32 / 100.0; + sample(vec![v, 0.0], if v < 0.5 { 0.0 } else { 1.0 }) + }) + .collect(); + + let config = TreeConfig { + max_depth: 6, + min_samples_leaf: 1, + min_purity: 0.90, + num_features: 2, + }; + + let tree = train_tree(&samples, &config); + assert!(!tree.is_empty()); + + // Low values should be Allow. + assert_eq!(tree_predict(&tree, &[0.1, 0.0]), TreeDecision::Allow); + // High values should be Block. + assert_eq!(tree_predict(&tree, &[0.9, 0.0]), TreeDecision::Block); + } + + #[test] + fn test_defer_for_mixed_region() { + // Create samples where the middle region is genuinely mixed. + let mut samples = Vec::new(); + for i in 0..50 { + let v = i as f32 / 100.0; + samples.push(sample(vec![v], 0.0)); // normal + } + for i in 50..100 { + let v = i as f32 / 100.0; + samples.push(sample(vec![v], 1.0)); // attack + } + // Add noise in the middle: some attacks below 0.5, some normals above 0.5. + for _ in 0..20 { + samples.push(sample(vec![0.45], 1.0)); + samples.push(sample(vec![0.55], 0.0)); + } + + let config = TreeConfig { + max_depth: 3, + min_samples_leaf: 5, + min_purity: 0.95, // Very high purity requirement. + num_features: 1, + }; + + let tree = train_tree(&samples, &config); + + // The boundary region should produce Defer. + let mid_decision = tree_predict(&tree, &[0.50]); + // It could be Defer or Allow/Block depending on how the split lands, + // but the tree should at least produce valid decisions. + assert!(matches!( + mid_decision, + TreeDecision::Allow | TreeDecision::Block | TreeDecision::Defer + )); + + // The extremes should be clear. + assert_eq!(tree_predict(&tree, &[0.05]), TreeDecision::Allow); + assert_eq!(tree_predict(&tree, &[0.95]), TreeDecision::Block); + } + + #[test] + fn test_max_depth_enforcement() { + // Even with perfect separability, depth should be capped. + let samples: Vec = (0..200) + .map(|i| { + let v = i as f32 / 200.0; + sample(vec![v, 0.0, 0.0, 0.0], if v < 0.5 { 0.0 } else { 1.0 }) + }) + .collect(); + + let config = TreeConfig { + max_depth: 2, + min_samples_leaf: 1, + min_purity: 0.90, + num_features: 4, + }; + + let tree = train_tree(&samples, &config); + + // With max_depth=2, we can have at most 2^3 - 1 = 7 nodes. + assert!( + tree.len() <= 7, + "tree should have at most 7 nodes at depth 2, got {}", + tree.len() + ); + } + + #[test] + fn test_single_class_becomes_leaf() { + // All samples are attack => immediate Block leaf. + let samples: Vec = (0..50) + .map(|i| sample(vec![i as f32 / 50.0], 1.0)) + .collect(); + + let config = TreeConfig { + max_depth: 6, + min_samples_leaf: 1, + min_purity: 0.90, + num_features: 1, + }; + + let tree = train_tree(&samples, &config); + assert_eq!(tree.len(), 1); // Just a single leaf. + assert_eq!(tree_predict(&tree, &[0.5]), TreeDecision::Block); + } + + #[test] + fn test_gini_pure() { + assert!((gini(10.0, 0.0) - 0.0).abs() < 1e-6); + assert!((gini(0.0, 10.0) - 0.0).abs() < 1e-6); + } + + #[test] + fn test_gini_max() { + // Maximum Gini for balanced binary: 1 - 2*(0.5^2) = 0.5 + assert!((gini(5.0, 5.0) - 0.5).abs() < 1e-6); + } +}